@cocreate/cli 1.45.2 → 1.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # [1.46.0](https://github.com/CoCreate-app/CoCreate-cli/compare/v1.45.3...v1.46.0) (2023-12-31)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * relocated to '@cocreate/webpack' ([05941f1](https://github.com/CoCreate-app/CoCreate-cli/commit/05941f1370f5b91f2968d90e12cd1780b9e2b31f))
7
+ * relocated to thier relative modules ([3635e50](https://github.com/CoCreate-app/CoCreate-cli/commit/3635e50076ee2763aed28194c2b4d099591f82ce))
8
+ * require '@cocreate/nginx' ([acab9d3](https://github.com/CoCreate-app/CoCreate-cli/commit/acab9d3da10de5193dd573ad7198b7356ed35283))
9
+
10
+
11
+ ### Features
12
+
13
+ * add '@cocreate/acme' and '@cocreate/nginx' ([0eb81e8](https://github.com/CoCreate-app/CoCreate-cli/commit/0eb81e88a54931bc2fc78663393b15338a62740f))
14
+ * coc acme to manage certs ([13049fa](https://github.com/CoCreate-app/CoCreate-cli/commit/13049fa7316269d1fc64b0f9c378b10937c0e7b7))
15
+
16
+ ## [1.45.3](https://github.com/CoCreate-app/CoCreate-cli/compare/v1.45.2...v1.45.3) (2023-12-18)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * coc upload with no args ([a638868](https://github.com/CoCreate-app/CoCreate-cli/commit/a638868b991f39c5a3bdcdcf12285d69f43824f6))
22
+
1
23
  ## [1.45.2](https://github.com/CoCreate-app/CoCreate-cli/compare/v1.45.1...v1.45.2) (2023-12-01)
2
24
 
3
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/cli",
3
- "version": "1.45.2",
3
+ "version": "1.46.0",
4
4
  "description": "Polyrepo management bash CLI tool. Run all git commands and yarn commands on multiple repositories. Also includes a few custom macros for cloning, installing, etc.",
5
5
  "keywords": [
6
6
  "cli",
@@ -55,8 +55,10 @@
55
55
  "coc": "src/coc.js"
56
56
  },
57
57
  "dependencies": {
58
+ "@cocreate/acme": "^1.0.0",
58
59
  "@cocreate/config": "^1.8.0",
59
60
  "@cocreate/file": "^1.13.0",
61
+ "@cocreate/nginx": "^1.0.0",
60
62
  "glob": "^7.1.7",
61
63
  "prettier": "^2.3.2"
62
64
  }
@@ -0,0 +1,25 @@
1
+ const { requestCertificate } = require('@cocreate/acme')
2
+
3
+ module.exports = async function nginx(repos, args) {
4
+ let failed = [];
5
+
6
+ try {
7
+ if (args.length) {
8
+ if (args[0] === 'create') {
9
+ args.shift()
10
+ await createServer(args);
11
+ } else if (args[0] === 'delete') {
12
+ args.shift()
13
+ await deleteServer(args);
14
+ } else
15
+ await createServer(args);
16
+ }
17
+ } catch (err) {
18
+ failed.push({ name: 'GENERAL', des: err.message });
19
+ console.error(err.red);
20
+ } finally {
21
+ return failed;
22
+ }
23
+
24
+ }
25
+
@@ -1,4 +1,4 @@
1
- const {createServer, deleteServer} = require('./other/nginxConfigManager.js')
1
+ const { createServer, deleteServer } = require('@cocreate/nginx')
2
2
 
3
3
  module.exports = async function nginx(repos, args) {
4
4
  let failed = [];
@@ -11,13 +11,13 @@ module.exports = async function nginx(repos, args) {
11
11
  } else if (args[0] === 'delete') {
12
12
  args.shift()
13
13
  await deleteServer(args);
14
- } else
14
+ } else
15
15
  await createServer(args);
16
16
  }
17
17
  } catch (err) {
18
18
  failed.push({ name: 'GENERAL', des: err.message });
19
19
  console.error(err.red);
20
- } finally {
20
+ } finally {
21
21
  return failed;
22
22
  }
23
23
 
@@ -107,4 +107,25 @@ async function deleteServer(hosts) {
107
107
  return response
108
108
  }
109
109
 
110
+ async function hasServer(hosts) {
111
+ if (!Array.isArray(hosts))
112
+ hosts = [hosts]
113
+ for (let host of hosts) {
114
+ const { stdout, stderr } = await exec(`grep -Ri 'server_name.*${host}' /etc/nginx/sites-enabled`)
115
+ if (err) {
116
+ console.error(`exec error: ${err}`);
117
+ return;
118
+ }
119
+ if (stdout) {
120
+ console.log(`Host found in the following configuration file(s):\n${stdout}`);
121
+
122
+ } else {
123
+ console.log('Host not found in Nginx configurations.');
124
+ }
125
+
126
+ if (stderr) console.error(`stderr: ${stderr}`);
127
+
128
+ }
129
+ }
130
+
110
131
  module.exports = { createServer, deleteServer }
@@ -28,65 +28,62 @@ module.exports = async function upload(directory, args) {
28
28
  console.log('Watching: ', directory)
29
29
  fs.watch(directory, { recursive: true }, async (eventType, filename) => {
30
30
  if (!filename.includes('CoCreate.config.js')) {
31
- const filePath = path.resolve(directory, filename);
32
- if (!filePath.includes('node_modules')) {
33
- const configPath = findClosestConfig(filePath);
34
- if (configPath) {
35
- const config = require(configPath);
36
-
37
- if (config) {
38
- await file(config, configPath, filePath)
39
- } else {
40
- console.log('Failed to read or parse CoCreate.config.js.');
41
- }
42
- } else {
43
- console.log('No CoCreate.config file found in parent directories.');
44
- }
31
+ const { config, configPath, filePath } = await getConfig(directory, filename);
32
+ if (config) {
33
+ await file(config, configPath, filePath)
34
+ } else {
35
+ console.log('Failed to read or parse CoCreate.config.js.');
45
36
  }
46
37
  }
47
38
  });
48
39
 
49
40
  } else {
50
- let CoCreateConfig
51
41
  if (!args.length) {
52
- let configPath = path.resolve(process.cwd(), 'CoCreate.config.js');
53
- if (!CoCreateConfig && fs.existsSync(configPath)) {
54
- CoCreateConfig = require(configPath);
42
+ directory = process.cwd()
43
+ const { config, configPath, filePath } = await getConfig(directory);
44
+ if (config) {
45
+ await file(config, configPath, filePath)
55
46
  } else {
56
- console.log('CoCreate.config.js could not be found.')
57
- process.exit()
47
+ console.log('Failed to read or parse CoCreate.config.js.');
58
48
  }
59
49
 
60
- await file(CoCreateConfig, configPath)
61
-
62
50
  } else {
63
51
  for (let arg of args) {
52
+ let CoCreateConfig
53
+
64
54
  try {
65
55
  CoCreateConfig = JSON.parse(arg)
66
56
  } catch (error) { }
67
57
 
68
58
 
69
59
  if (!CoCreateConfig) {
70
- try {
71
- let configPath = path.resolve(process.cwd(), arg)
72
- if (fs.existsSync(configPath)) {
73
- CoCreateConfig = require(configPath);
74
- if (CoCreateConfig)
75
- await file(CoCreateConfig, configPath)
76
-
77
- } else {
78
- console.log(arg + ' could not be found.')
79
- process.exit()
80
- }
81
-
82
- } catch (error) { }
60
+ const { config, configPath, filePath } = await getConfig(arg);
61
+ if (config) {
62
+ await file(config, configPath, filePath)
63
+ } else {
64
+ console.log('Failed to read or parse CoCreate.config.js.');
65
+ }
83
66
  }
84
67
  }
85
68
  }
86
69
  }
87
70
 
71
+ async function getConfig(directory, filename = '') {
72
+ const filePath = path.resolve(directory, filename);
73
+ if (!filePath.includes('node_modules')) {
74
+ const configPath = findClosestConfig(filePath)
75
+ if (configPath) {
76
+ return { config: require(configPath), configPath, filePath };
77
+
78
+ } else {
79
+ console.log('No CoCreate.config file found in parent directories.');
80
+ }
81
+ }
82
+
83
+ }
84
+
88
85
  function findClosestConfig(filePath) {
89
- let currentDir = path.dirname(filePath);
86
+ let currentDir = filePath;
90
87
 
91
88
  while (currentDir !== '/' && currentDir !== '.') {
92
89
  let configFile = path.join(currentDir, 'CoCreate.config.js');
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const { spawn } = require('child_process');
4
-
5
- function runCertbot() {
6
- return new Promise((resolve, reject) => {
7
- const certbotProcess = spawn('sudo', [
8
- 'certbot',
9
- 'certonly',
10
- '--manual',
11
- '-d', '*.cocreate.zone',
12
- '-d', 'cocreate.zone',
13
- '--agree-tos',
14
- '-m', 'admin@cocreate.zone',
15
- '--preferred-challenges', 'dns-01',
16
- '--server', 'https://acme-v02.api.letsencrypt.org/directory'
17
- ]);
18
-
19
- // let promptsCount = 0;
20
-
21
- certbotProcess.stdout.on('data', (data) => {
22
- const output = data.toString();
23
- if (output.includes('Please deploy a DNS TXT record under the name:')) {
24
- const namePattern = /Please deploy a DNS TXT record under the name:\s+([\w\.-]+)\./;
25
- const valuePattern = /with the following value:\s+([\w\d]+)\s+/;
26
-
27
- const nameMatch = output.match(namePattern);
28
- const valueMatch = output.match(valuePattern);
29
-
30
- if (nameMatch && valueMatch) {
31
- const name = nameMatch[1];
32
- const value = valueMatch[1];
33
-
34
- console.log("Name:", name);
35
- console.log("Value:", value);
36
- } else {
37
- console.log("Name or value not found in the text.");
38
- }
39
- // TODO: send name and value to client and wait for clients response before continuing
40
- certbotProcess.stdin.write('\n');
41
- } else if (output.includes('Press Enter to Continue')) {
42
- certbotProcess.stdin.write('\n');
43
- }
44
- });
45
-
46
- certbotProcess.stderr.on('data', (data) => {
47
- reject(data.toString());
48
- });
49
-
50
- certbotProcess.on('close', (code) => {
51
- if (code === 0) {
52
- resolve('Certbot process completed successfully.');
53
- } else {
54
- reject(`Certbot process exited with code ${code}`);
55
- }
56
- });
57
- });
58
- }
59
-
60
- async function executeCertbot() {
61
- try {
62
- const result = await runCertbot();
63
- console.log(result);
64
- } catch (error) {
65
- console.error('An error occurred:', error);
66
- }
67
- }
68
-
69
- executeCertbot();
@@ -1,76 +0,0 @@
1
- const fs = require('fs');
2
- const { exec } = require('child_process');
3
-
4
- const haproxyConfigPath = '/etc/haproxy/haproxy.cfg';
5
- const backendSectionName = 'backend app_backend';
6
-
7
- // Function to update HAProxy config with new servers
8
- const updateHAProxyConfig = (newServers) => {
9
- fs.readFile(haproxyConfigPath, 'utf8', (err, data) => {
10
- if (err) {
11
- console.error('Error reading HAProxy config:', err);
12
- return;
13
- }
14
-
15
- const updatedConfig = updateBackendServers(data, newServers);
16
- fs.writeFile(haproxyConfigPath, updatedConfig, 'utf8', (err) => {
17
- if (err) {
18
- console.error('Error writing updated HAProxy config:', err);
19
- return;
20
- }
21
-
22
- reloadHAProxy();
23
- });
24
- });
25
- };
26
-
27
- // Function to replace backend server entries in the config
28
- const updateBackendServers = (configData, newServers) => {
29
- const lines = configData.split('\n');
30
- let backendSectionStart = -1;
31
- let backendSectionEnd = -1;
32
-
33
- // Find the start and end of the backend section
34
- lines.forEach((line, index) => {
35
- if (line.trim() === backendSectionName) {
36
- backendSectionStart = index;
37
- }
38
- if (backendSectionStart !== -1 && backendSectionEnd === -1 && line.trim() === '') {
39
- backendSectionEnd = index;
40
- }
41
- });
42
-
43
- if (backendSectionStart === -1 || backendSectionEnd === -1) {
44
- console.error('Backend section not found in HAProxy config');
45
- return configData;
46
- }
47
-
48
- // Replace the server list in the backend section
49
- const newServerLines = newServers.map(server => ` server ${server.name} ${server.address} check`);
50
- const updatedLines = [
51
- ...lines.slice(0, backendSectionStart + 1),
52
- ...newServerLines,
53
- ...lines.slice(backendSectionEnd)
54
- ];
55
-
56
- return updatedLines.join('\n');
57
- };
58
-
59
- // Function to reload HAProxy
60
- const reloadHAProxy = () => {
61
- exec('systemctl reload haproxy', (err, stdout, stderr) => {
62
- if (err) {
63
- console.error('Error reloading HAProxy:', err);
64
- return;
65
- }
66
- console.log('HAProxy reloaded successfully');
67
- });
68
- };
69
-
70
- // Example usage
71
- const newServers = [
72
- { name: 'app1', address: '10.0.0.1:80' },
73
- { name: 'app2', address: '10.0.0.2:80' }
74
- ];
75
-
76
- updateHAProxyConfig(newServers);
@@ -1,63 +0,0 @@
1
- const fs = require('fs');
2
- const { exec } = require('child_process');
3
-
4
- const haproxyConfigPath = '/etc/haproxy/haproxy.cfg';
5
-
6
- // Function to add a new configuration to HAProxy and restart it
7
- const addHAProxyConfig = (frontendName, backendName, backendServers) => {
8
- fs.readFile(haproxyConfigPath, 'utf8', (err, data) => {
9
- if (err) {
10
- console.error('Error reading HAProxy config:', err);
11
- return;
12
- }
13
-
14
- // Append new frontend and backend configuration
15
- const newConfig = `
16
- # Frontend Configuration
17
- frontend ${frontendName}
18
- bind *:80
19
- mode http
20
- default_backend ${backendName}
21
-
22
- # Backend Configuration
23
- backend ${backendName}
24
- mode http
25
- balance roundrobin`;
26
-
27
- // Add server entries
28
- backendServers.forEach((server, index) => {
29
- newConfig += `\n server server${index} ${server.address} check`;
30
- });
31
-
32
- // Write updated configuration
33
- fs.writeFile(haproxyConfigPath, data + newConfig, 'utf8', (err) => {
34
- if (err) {
35
- console.error('Error writing updated HAProxy config:', err);
36
- return;
37
- }
38
-
39
- restartHAProxy();
40
- });
41
- });
42
- };
43
-
44
- // Function to restart HAProxy
45
- const restartHAProxy = () => {
46
- exec('systemctl restart haproxy', (err, stdout, stderr) => {
47
- if (err) {
48
- console.error('Error restarting HAProxy:', err);
49
- return;
50
- }
51
- console.log('HAProxy restarted successfully');
52
- });
53
- };
54
-
55
- // Example usage
56
- const frontendName = 'my_frontend';
57
- const backendName = 'my_backend';
58
- const backendServers = [
59
- { address: '10.0.0.1:80' },
60
- { address: '10.0.0.2:80' }
61
- ];
62
-
63
- addHAProxyConfig(frontendName, backendName, backendServers);
@@ -1,76 +0,0 @@
1
- const fs = require('fs');
2
- const { exec } = require('child_process');
3
-
4
- const nginxConfigPath = '/etc/nginx/conf.d/myapp.conf';
5
- const upstreamBlockName = 'upstream app_backend';
6
-
7
- // Function to update NGINX config with new servers
8
- const updateNginxConfig = (newServers) => {
9
- fs.readFile(nginxConfigPath, 'utf8', (err, data) => {
10
- if (err) {
11
- console.error('Error reading NGINX config:', err);
12
- return;
13
- }
14
-
15
- const updatedConfig = updateUpstreamServers(data, newServers);
16
- fs.writeFile(nginxConfigPath, updatedConfig, 'utf8', (err) => {
17
- if (err) {
18
- console.error('Error writing updated NGINX config:', err);
19
- return;
20
- }
21
-
22
- reloadNginx();
23
- });
24
- });
25
- };
26
-
27
- // Function to replace upstream server entries in the config
28
- const updateUpstreamServers = (configData, newServers) => {
29
- const lines = configData.split('\n');
30
- let upstreamSectionStart = -1;
31
- let upstreamSectionEnd = -1;
32
-
33
- // Find the start and end of the upstream section
34
- lines.forEach((line, index) => {
35
- if (line.trim().startsWith(upstreamBlockName)) {
36
- upstreamSectionStart = index;
37
- }
38
- if (upstreamSectionStart !== -1 && upstreamSectionEnd === -1 && line.trim() === '}') {
39
- upstreamSectionEnd = index;
40
- }
41
- });
42
-
43
- if (upstreamSectionStart === -1 || upstreamSectionEnd === -1) {
44
- console.error('Upstream section not found in NGINX config');
45
- return configData;
46
- }
47
-
48
- // Replace the server list in the upstream section
49
- const newServerLines = newServers.map(server => ` server ${server.address};`);
50
- const updatedLines = [
51
- ...lines.slice(0, upstreamSectionStart + 1),
52
- ...newServerLines,
53
- ...lines.slice(upstreamSectionEnd)
54
- ];
55
-
56
- return updatedLines.join('\n');
57
- };
58
-
59
- // Function to reload NGINX
60
- const reloadNginx = () => {
61
- exec('systemctl reload nginx', (err, stdout, stderr) => {
62
- if (err) {
63
- console.error('Error reloading NGINX:', err);
64
- return;
65
- }
66
- console.log('NGINX reloaded successfully');
67
- });
68
- };
69
-
70
- // Example usage
71
- const newServers = [
72
- { address: '10.0.0.1:80' },
73
- { address: '10.0.0.2:80' }
74
- ];
75
-
76
- updateNginxConfig(newServers);
@@ -1,182 +0,0 @@
1
- const util = require('node:util');
2
- const exec = require('node:child_process').exec;
3
- const dns = require('dns');
4
- const child_process = require('child_process');
5
- const spawn = child_process.spawn;
6
-
7
- const localip = '3.231.17.247'
8
- const certificates = new Map()
9
- const certbotPath = `/etc/letsencrypt/live/`;
10
- const fullchainPath = `${certbotPath}/fullchain.pem`;
11
- const privkeyPath = `${certbotPath}/privkey.pem`;
12
- const combinedPath = `${certbotPath}/haproxy.pem`;
13
-
14
-
15
- async function checkDns(host) {
16
- return new Promise((resolve, reject) => {
17
-
18
- try {
19
- dns.resolve(host, 'A', (err, records) => {
20
- if (records && records[0] === localip) {
21
- resolve(true)
22
- } else {
23
- console.log('host A record need to point to', localip)
24
- resolve(false)
25
- }
26
- if (err)
27
- console.log(host, err);
28
- });
29
- } catch (err) {
30
- console.log('certificate', err)
31
- }
32
- });
33
- }
34
-
35
- async function createCert(host) {
36
- try {
37
- // let hosts = await exec(`sudo openssl x509 -dates -noout -in /etc/letsencrypt/live/${host}/fullchain.pem`);
38
- // console.log('hostst check', hosts)
39
- let test = await checkDns(host)
40
- console.log('checked dns from createCert', test)
41
- if (test) {
42
- await exec(`sudo certbot certonly -d ${host}`);
43
- // let exitCode = await spawn('sudo', ['certbot', 'certonly', '--manual', '-d', `*.${host}`, '-d', host, '--agree-tos', '--preferred-challenges', 'dns-01', '--server', 'https://acme-v02.api.letsencrypt.org/directory'], { stdio: 'inherit', cwd: process.cwd() })
44
- if (exitCode !== 0) {
45
- failed.push({ name: false, des: `creating directory failed` })
46
- } else
47
- console.log(true)
48
-
49
- // return true
50
- } else
51
- return false
52
- } catch (err) {
53
- return false
54
- }
55
- }
56
-
57
- async function deleteCert(host) {
58
- try {
59
- await exec(`sudo certbot delete --cert-name ${host}`);
60
- return true
61
- } catch (err) {
62
- return false
63
- }
64
- }
65
-
66
- async function checkCert(host) {
67
- try {
68
- let hosts = await exec(`host ${host}`);
69
- console.log('hostst check', hosts)
70
-
71
- if (certificates.has(host))
72
- return true
73
- else {
74
- let certs = await exec(`sudo openssl x509 -dates -noout -in /etc/letsencrypt/live/${host}/fullchain.pem`);
75
- let cert = certs.stdout.split('\n')
76
- let issued = Date.parse(cert[0].replace('notBefore=', ''))
77
- let expires = Date.parse(cert[1].replace('notAfter=', ''))
78
- let currentDate = new Date()
79
-
80
- if (!issued || !expires)
81
- console.log('not defined', { issued, expires })
82
- else if (!isNaN(expires)) {
83
- if (currentDate < expires) {
84
- certificates.set(host, { issued, expires })
85
- return true
86
- } else {
87
- let cert = await createCert(host)
88
- return cert
89
- }
90
- } else {
91
- let cert = await createCert(host)
92
- return cert
93
- }
94
- }
95
- } catch (err) {
96
- let cert = await createCert(host)
97
- if (cert)
98
- certificates.set(host, { issued, expires })
99
- return cert
100
- }
101
- }
102
-
103
- const combineCertificate = (host) => {
104
- const certbotPath = `/etc/letsencrypt/live/${host}`;
105
- const fullchainPath = `${certbotPath}/fullchain.pem`;
106
- const privkeyPath = `${certbotPath}/privkey.pem`;
107
- const combinedPath = `${certbotPath}/haproxy.pem`;
108
-
109
- fs.readFile(fullchainPath, (err, fullchainData) => {
110
- if (err) {
111
- console.error('Error reading fullchain.pem:', err);
112
- return;
113
- }
114
-
115
- fs.readFile(privkeyPath, (err, privkeyData) => {
116
- if (err) {
117
- console.error('Error reading privkey.pem:', err);
118
- return;
119
- }
120
-
121
- const combinedData = `${fullchainData}\n${privkeyData}`;
122
- fs.writeFile(combinedPath, combinedData, (err) => {
123
- if (err) {
124
- console.error('Error writing combined haproxy.pem:', err);
125
- } else {
126
- console.log('Successfully combined certificates for HAProxy.');
127
- }
128
- });
129
- });
130
- });
131
- };
132
-
133
- async function test(host) {
134
- try {
135
-
136
-
137
- await exec(`sudo certbot certonly --manual --test-cert -d *.${host} -d ${host} --agree-tos --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory`);
138
- let exitCode = await spawn('sudo', ['certbot', 'certonly', '--manual', '--test-cert', '-d', `*.${host}`, '-d', host, '--agree-tos', '--preferred-challenges', 'dns-01', '--server', 'https://acme-v02.api.letsencrypt.org/directory'], { stdio: 'inherit', cwd: process.cwd() })
139
- if (exitCode !== 0) {
140
- failed.push({ name: false, des: `creating directory failed` })
141
- } else
142
- console.log(true)
143
-
144
- // let child = exec('su -')
145
- // child.stdin.write("testserver\n");
146
-
147
- // child.stdout.on('data', (data) => {
148
- // console.log(`stdout: "${data}"`);
149
- // });
150
-
151
- // child.stdin.end(); // EOF
152
-
153
- // child.on('close', (code) => {
154
- // console.log(`Child process exited with code ${code}.`);
155
- // });
156
-
157
- // exitCode.on("data", data => {
158
- // console.log('test')
159
- // })
160
- // let test = exitCode
161
- // if (exitCode !== 0) {
162
- // exitCode.write('test', (err) => {
163
- // if (err) throw Error(err.message)
164
- // })
165
- // } else {
166
- // exitCode.write('test', (err) => {
167
- // if (err) throw Error(err.message)
168
- // })
169
- // }
170
-
171
- // return true
172
- // return false
173
- } catch (err) {
174
- process.exit(1)
175
- // return false
176
- }
177
- }
178
-
179
-
180
- // test('cocreate.app')
181
-
182
- module.exports = { checkDns, checkCert, createCert, deleteCert }
@@ -1,3 +0,0 @@
1
- module.exports = function (source) {
2
- return source.replace(/\$'/g, '\\u0024\'');
3
- };