@symbo.ls/cli 2.11.309 → 2.11.315

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.
Files changed (3) hide show
  1. package/bin/fetch.js +79 -71
  2. package/bin/fs.js +261 -64
  3. package/package.json +2 -2
package/bin/fetch.js CHANGED
@@ -1,132 +1,140 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from 'fs'
4
- import chalk from 'chalk'
5
- import { loadModule } from './require.js'
6
- import { program } from './program.js'
7
- import * as fetch from '@symbo.ls/fetch'
8
- import * as utils from '@domql/utils'
9
- import { convertFromCli } from './convert.js'
10
- import { createDirs } from './fs.js'
11
-
12
- const { isObjectLike } = utils.default
13
- const { fetchRemote } = fetch.default
14
-
15
- const RC_PATH = process.cwd() + '/symbols.json'
3
+ import fs from "fs";
4
+ import chalk from "chalk";
5
+ import { loadModule } from "./require.js";
6
+ import { program } from "./program.js";
7
+ import * as fetch from "@symbo.ls/fetch";
8
+ import * as utils from "@domql/utils";
9
+ import { convertFromCli } from "./convert.js";
10
+ import { createFs } from "./fs.js";
11
+
12
+ const { isObjectLike } = utils.default;
13
+ const { fetchRemote } = fetch.default;
14
+
15
+ const RC_PATH = process.cwd() + "/symbols.json";
16
16
  const LOCAL_CONFIG_PATH =
17
- process.cwd() + '/node_modules/@symbo.ls/init/dynamic.json'
18
- const DEFAULT_REMOTE_REPOSITORY = 'https://github.com/symbo-ls/default-config/'
17
+ process.cwd() + "/node_modules/@symbo.ls/init/dynamic.json";
18
+ const DEFAULT_REMOTE_REPOSITORY = "https://github.com/symbo-ls/default-config/";
19
19
  const DEFAULT_REMOTE_CONFIG_PATH = "https://api.symbols.app/"; // eslint-disable-line
20
20
 
21
- const API_URL_LOCAL = 'http://localhost:13335/get/'
22
- const API_URL = 'https://api.symbols.app/get/'
21
+ const API_URL_LOCAL = "http://localhost:13335/get/";
22
+ const API_URL = "https://api.symbols.app/get/";
23
23
 
24
24
  const rcFile = loadModule(RC_PATH); // eslint-disable-line
25
25
  const localConfig = loadModule(LOCAL_CONFIG_PATH); // eslint-disable-line
26
26
 
27
27
  const debugMsg = chalk.dim(
28
- 'Use --verbose to debug the error or open the issue at https://github.com/symbo-ls/smbls'
29
- )
28
+ "Use --verbose to debug the error or open the issue at https://github.com/symbo-ls/smbls"
29
+ );
30
30
 
31
- let rc = {}
31
+ let rc = {};
32
32
  try {
33
33
  rc = loadModule(RC_PATH); // eslint-disable-line
34
34
  } catch (e) {
35
- console.error('Please include symbols.json to your root of respository')
35
+ console.error("Please include symbols.json to your root of respository");
36
36
  }
37
37
 
38
38
  export const fetchFromCli = async (opts) => {
39
- const { dev, verbose, prettify, convert: convertOpt } = opts
40
-
39
+ const { dev, verbose, prettify, convert: convertOpt, update } = opts;
41
40
  await rc.then(async (data) => {
42
- const { key, framework, distDir } = data
41
+ const { key, framework, distDir } = data;
43
42
 
44
- const endpoint = dev ? API_URL_LOCAL : API_URL
43
+ const endpoint = dev ? API_URL_LOCAL : API_URL;
45
44
 
46
- console.log('\nFetching from:', chalk.bold(endpoint), '\n')
45
+ console.log("\nFetching from:", chalk.bold(endpoint), "\n");
47
46
 
48
47
  const body = await fetchRemote(key, {
49
48
  endpoint,
50
49
  onError: (e) => {
51
- console.log(chalk.red('Failed to fetch:'), key)
52
- if (verbose) console.error(e)
53
- else console.log(debugMsg)
54
- }
55
- })
50
+ console.log(chalk.red("Failed to fetch:"), key);
51
+ if (verbose) console.error(e);
52
+ else console.log(debugMsg);
53
+ },
54
+ });
56
55
 
57
- if (!body) return
56
+ if (!body) return;
58
57
 
59
- const { version, ...config } = body
58
+ const { version, ...config } = body;
60
59
 
61
60
  if (verbose) {
62
61
  if (key) {
63
62
  console.log(
64
- chalk.bold('Symbols'),
65
- 'data fetched for',
63
+ chalk.bold("Symbols"),
64
+ "data fetched for",
66
65
  chalk.green(body.name)
67
- )
66
+ );
68
67
  } else {
69
68
  console.log(
70
- chalk.bold('Symbols'),
71
- 'config fetched from',
72
- chalk.bold('default-config from:'),
69
+ chalk.bold("Symbols"),
70
+ "config fetched from",
71
+ chalk.bold("default-config from:"),
73
72
  chalk.dim.underline(DEFAULT_REMOTE_REPOSITORY)
74
- )
73
+ );
75
74
  }
76
- console.log()
75
+ console.log();
77
76
  }
78
77
 
79
78
  for (const t in config) {
80
- const type = config[t]
81
- const arr = []
79
+ const type = config[t];
80
+ const arr = [];
82
81
  if (isObjectLike(type)) {
83
- for (const v in type) arr.push(v)
82
+ for (const v in type) arr.push(v);
84
83
  if (arr.length) {
85
- console.log(chalk.dim(t + ':'))
86
- console.log(chalk.bold(arr.join(', ')))
84
+ console.log(chalk.dim(t + ":"));
85
+ console.log(chalk.bold(arr.join(", ")));
87
86
  } else {
88
- console.log(chalk.dim(t + ':'), chalk.dim('- empty -'))
87
+ console.log(chalk.dim(t + ":"), chalk.dim("- empty -"));
89
88
  }
90
- } else console.log(chalk.dim(t + ':'), chalk.bold(type))
89
+ } else console.log(chalk.dim(t + ":"), chalk.bold(type));
91
90
  }
92
91
 
93
92
  if (body.designsystem) {
94
- body.designSystem = body.designsystem
95
- delete body.designsystem
93
+ body.designSystem = body.designsystem;
94
+ delete body.designsystem;
96
95
  }
97
96
 
98
- const bodyString = JSON.stringify(body, null, prettify ?? 2)
97
+ const bodyString = JSON.stringify(body, null, prettify ?? 2);
99
98
 
100
99
  try {
101
- await fs.writeFileSync(LOCAL_CONFIG_PATH, bodyString)
100
+ await fs.writeFileSync(LOCAL_CONFIG_PATH, bodyString);
102
101
 
103
102
  if (verbose) {
104
- console.log(chalk.dim('\ndynamic.json has been updated:'))
105
- console.log(chalk.dim.underline(LOCAL_CONFIG_PATH))
103
+ console.log(chalk.dim("\ndynamic.json has been updated:"));
104
+ console.log(chalk.dim.underline(LOCAL_CONFIG_PATH));
106
105
  }
107
106
 
108
- console.log(chalk.bold.green('\nSuccessfully wrote file'))
107
+ console.log(chalk.bold.green("\nSuccessfully wrote file"));
109
108
  } catch (e) {
110
- console.log(chalk.bold.red('\nError writing file'))
111
- if (verbose) console.error(e)
112
- else console.log(debugMsg)
109
+ console.log(chalk.bold.red("\nError writing file"));
110
+ if (verbose) console.error(e);
111
+ else console.log(debugMsg);
113
112
  }
114
113
 
115
- console.log(convertOpt)
114
+ console.log(convertOpt);
116
115
  if (body.components && convertOpt && framework) {
117
- convertFromCli(body.components, { ...opts, framework })
116
+ convertFromCli(body.components, { ...opts, framework });
118
117
  }
119
118
 
120
- console.log(Object.keys(body))
121
- createDirs(body, distDir)
122
- })
123
- }
119
+ if (update) {
120
+ createFs(body, distDir, update);
121
+ } else {
122
+ createFs(body, distDir);
123
+ }
124
+ });
125
+ };
124
126
 
125
127
  program
126
- .command('fetch')
127
- .description('Fetch Symbols')
128
- .option('-d, --dev', 'Running from local server')
129
- .option('-v, --verbose', 'Verbose errors and warnings')
130
- .option('--convert', 'Verbose errors and warnings', true)
131
- .option('--verbose-code', 'Verbose errors and warnings')
132
- .action(fetchFromCli)
128
+ .command("fetch")
129
+ .description("Fetch Symbols")
130
+ .option("-d, --dev", "Running from local server")
131
+ .option("-v, --verbose", "Verbose errors and warnings")
132
+ .option("--convert", "Verbose errors and warnings", true)
133
+ .option("--update", "overriding changes from platform")
134
+ .option("--verbose-code", "Verbose errors and warnings")
135
+ .action(fetchFromCli);
136
+
137
+ // program
138
+ // .command("push")
139
+ // .description("Push changes to platform")
140
+ // .action(fetchFromCli({ cache: true }));
package/bin/fs.js CHANGED
@@ -1,97 +1,294 @@
1
- 'use strict'
2
-
3
1
  import fs from 'fs'
2
+ import chalk from 'chalk'
4
3
  import path from 'path'
5
4
  import utils from '@domql/utils'
6
- const { deepDestringify, objectToString, joinArrays } = utils
5
+ import inquirer from 'inquirer'
6
+ import { createPatch } from 'diff'
7
+
8
+ const { deepDestringify, objectToString, joinArrays, isString } = utils
7
9
 
8
10
  const keys = ['components', 'snippets', 'pages']
9
11
  const singleFileKeys = ['designSystem', 'state']
12
+ const defaultExports = ['pages', 'designSystem', 'state']
10
13
 
11
- export function createDirs (body, distDir) {
14
+ export async function createFs (
15
+ body,
16
+ distDir = path.join(process.cwd(), 'dist'),
17
+ update = false
18
+ ) {
12
19
  if (!body) {
13
20
  console.error('No JSON object provided. Exiting.')
14
21
  return
15
22
  }
16
23
 
17
- distDir = distDir || path.join(process.cwd(), 'dist')
24
+ const targetDir = distDir
25
+
26
+ const filesExist = fs.existsSync(targetDir)
27
+
28
+ if (!filesExist || update) {
29
+ await fs.promises.mkdir(targetDir, { recursive: true })
30
+
31
+ const promises = [
32
+ ...keys.map((key) =>
33
+ createKeyDirectoryAndFiles(key, body, targetDir, update)
34
+ ),
35
+ ...singleFileKeys.map((key) => {
36
+ if (body[key] && typeof body[key] === 'object') {
37
+ return createSingleFileFolderAndFile(
38
+ key,
39
+ body[key],
40
+ targetDir,
41
+ update
42
+ )
43
+ }
44
+ })
45
+ ]
46
+
47
+ await Promise.all(promises)
48
+ await generateIndexjsFile(joinArrays(keys, singleFileKeys), targetDir, 'root')
49
+ }
50
+
51
+ if (filesExist) {
52
+ const cacheDir = path.join(distDir, '.cache')
53
+ await fs.promises.mkdir(cacheDir, { recursive: true })
54
+
55
+ const cachePromises = [
56
+ ...keys.map((key) =>
57
+ createKeyDirectoryAndFiles(key, body, cacheDir, true)
58
+ ),
59
+ ...singleFileKeys.map((key) => {
60
+ if (body[key] && typeof body[key] === 'object') {
61
+ return createSingleFileFolderAndFile(key, body[key], cacheDir, true)
62
+ }
63
+ })
64
+ ]
18
65
 
19
- keys.forEach((key) => {
20
- createKeyDirectoryAndFiles(key, body, distDir)
21
- })
66
+ await Promise.all(cachePromises)
67
+ await generateIndexjsFile(joinArrays(keys, singleFileKeys), cacheDir, 'root')
68
+
69
+ const diffs = await findDiff(cacheDir, targetDir)
70
+ if (diffs.length > 0) {
71
+ console.log('Differences found:')
72
+ diffs.forEach((diff) => {
73
+ console.log(chalk.green(`File: ${diff.file}`))
74
+ console.log(chalk.yellow('Diff:'))
75
+ console.log(chalk.yellow(diff.diff))
76
+ console.log('---')
77
+ })
78
+ if (!update) {
79
+ const { consent } = await askForConsent()
80
+ if (consent) {
81
+ await overrideFiles(cacheDir, targetDir)
82
+ console.log('Files overridden successfully.')
83
+ } else {
84
+ console.log('Files not overridden.')
85
+ }
86
+ } else {
87
+ await overrideFiles(cacheDir, targetDir)
88
+ console.log('Files overridden successfully.')
89
+ }
90
+ } else {
91
+ console.log('No differences found.')
92
+ }
93
+ }
94
+
95
+ async function createKeyDirectoryAndFiles (key, body, distDir, update) {
96
+ const dirPath = path.join(distDir, key)
97
+ await fs.promises.mkdir(dirPath, { recursive: true })
98
+
99
+ const dirs = []
22
100
 
23
- singleFileKeys.forEach((key) => {
24
101
  if (body[key] && typeof body[key] === 'object') {
25
- createSingleFileFolderAndFile(key, body[key], distDir)
102
+ const promises = Object.entries(body[key]).map(
103
+ async ([entryKey, value]) => {
104
+ // if pages
105
+ if (entryKey.startsWith('/')) entryKey = entryKey.slice(1)
106
+ if (entryKey === '') entryKey = 'main'
107
+ if (entryKey.includes('*')) entryKey = 'fallback'
108
+
109
+ await createOrUpdateFile(dirPath, entryKey, value, update)
110
+ dirs.push(entryKey)
111
+ }
112
+ )
113
+
114
+ await Promise.all(promises)
26
115
  }
27
- })
28
116
 
29
- generateRootIndexjsFile(joinArrays(keys, singleFileKeys), distDir)
30
- }
117
+ await generateIndexjsFile(dirs, dirPath, key)
118
+ }
31
119
 
32
- async function generateIndexjsFile (dirs, dirPath) {
33
- const indexContent = dirs.map(d => `export * from './${d}'`).join('\n') + '\n'
34
- const indexFilePath = path.join(dirPath, 'index.js')
35
- const fh = await fs.promises.open(indexFilePath, 'w')
36
- await fh.writeFile(indexContent, 'utf8')
37
- await fh.close()
38
- }
120
+ async function createOrUpdateFile (dirPath, childKey, value, update) {
121
+ const filePath = path.join(dirPath, `${childKey}.js`)
39
122
 
40
- async function generateRootIndexjsFile (dirs, dirPath) {
41
- const indexContent = dirs.map(d => {
42
- const isSingleFile = singleFileKeys.includes(d)
43
- if (isSingleFile) return `export { default as ${d} } from './${d}'`
44
- return `export * as ${d} from './${d}'`
45
- }).join('\n') + '\n'
46
- const indexFilePath = path.join(dirPath, 'index.js')
47
- const fh = await fs.promises.open(indexFilePath, 'w')
48
- await fh.writeFile(indexContent, 'utf8')
49
- await fh.close()
123
+ if (!update && fs.existsSync(filePath)) {
124
+ return
125
+ }
126
+
127
+ let stringifiedContent
128
+ if (isString(value)) {
129
+ stringifiedContent = `export const ${childKey} = ${value}`
130
+ } else {
131
+ const content = deepDestringify(value)
132
+ stringifiedContent = `export const ${childKey} = ${objectToString(content)};`
133
+ }
134
+
135
+ await fs.promises.writeFile(filePath, stringifiedContent, 'utf8')
136
+ }
137
+
138
+ async function createSingleFileFolderAndFile (key, data, distDir, update) {
139
+ const filePath = path.join(distDir, `${key}.js`)
140
+
141
+ if (!update && fs.existsSync(filePath)) {
142
+ return
143
+ }
144
+
145
+ if (isString(data)) data = { default: data }
146
+ const content = deepDestringify(data)
147
+ const stringifiedContent = `export default ${objectToString(content)};`
148
+
149
+ await fs.promises.writeFile(filePath, stringifiedContent, 'utf8')
150
+ }
50
151
  }
51
152
 
52
- async function createKeyDirectoryAndFiles (key, body, distDir) {
53
- const dirPath = path.join(distDir, key)
54
- fs.existsSync(dirPath) || fs.mkdirSync(dirPath, { recursive: true })
55
- console.log(
56
- `${fs.existsSync(dirPath) ? 'Found' : 'Created'} directory: ${dirPath}`
57
- )
58
-
59
- const dirs = []
60
- if (body[key] && typeof body[key] === 'object') {
61
- Object.entries(body[key]).forEach(([entryKey, value]) => {
62
- let childKey = entryKey
63
- if (childKey.startsWith('/')) {
64
- childKey = childKey.slice(1)
65
- if (!childKey.length) childKey = 'main'
153
+ async function findDiff (targetDir, distDir) {
154
+ const diffs = []
155
+
156
+ for (const key of keys) {
157
+ const targetDirPath = path.join(targetDir, key)
158
+ const distDirPath = path.join(distDir, key)
159
+
160
+ if (!fs.existsSync(targetDirPath)) {
161
+ continue
162
+ }
163
+
164
+ const targetFiles = await fs.promises.readdir(targetDirPath)
165
+ for (const file of targetFiles) {
166
+ if (file === 'index.js') {
167
+ continue // Skip comparing index.js files
66
168
  }
67
- createOrUpdateFile(dirPath, childKey, value)
68
- dirs.push(childKey)
69
- })
169
+
170
+ const targetFilePath = path.join(targetDirPath, file)
171
+ const distFilePath = path.join(distDirPath, file)
172
+
173
+ if (!fs.existsSync(distFilePath)) {
174
+ diffs.push({
175
+ file: path.join(key, file),
176
+ diff: `File ${path.join(
177
+ key,
178
+ file
179
+ )} does not exist in the dist directory.`
180
+ })
181
+ continue
182
+ }
183
+
184
+ const targetContent = await fs.promises.readFile(
185
+ targetFilePath,
186
+ 'utf8'
187
+ )
188
+ const distContent = await fs.promises.readFile(distFilePath, 'utf8')
189
+
190
+ if (targetContent !== distContent) {
191
+ const diff = createPatch(file, distContent, targetContent)
192
+ diffs.push({
193
+ file: path.join(key, file),
194
+ diff
195
+ })
196
+ }
197
+ }
70
198
  }
71
199
 
72
- generateIndexjsFile(dirs, dirPath, key)
200
+ for (const key of singleFileKeys) {
201
+ const targetFilePath = path.join(targetDir, `${key}.js`)
202
+ const distFilePath = path.join(distDir, `${key}.js`)
203
+
204
+ if (!fs.existsSync(targetFilePath)) {
205
+ continue
206
+ }
207
+
208
+ if (!fs.existsSync(distFilePath)) {
209
+ diffs.push({
210
+ file: `${key}.js`,
211
+ diff: `File ${key}.js does not exist in the dist directory.`
212
+ })
213
+ continue
214
+ }
215
+
216
+ const targetContent = await fs.promises.readFile(targetFilePath, 'utf8')
217
+ const distContent = await fs.promises.readFile(distFilePath, 'utf8')
218
+
219
+ if (targetContent !== distContent) {
220
+ const diff = createPatch(key, distContent, targetContent)
221
+ diffs.push({
222
+ file: `${key}.js`,
223
+ diff
224
+ })
225
+ }
226
+ }
227
+
228
+ return diffs
229
+ }
230
+
231
+ async function generateIndexjsFile (dirs, dirPath, key) {
232
+ let indexContent
233
+ if (key === 'pages') {
234
+ indexContent =
235
+ dirs.map((d) => `import { ${d} } from './${d}';`).join('\n') + '\n' +
236
+ `export default {
237
+ ${dirs.map((d) => `'/${d === 'main' ? '' : d}': ${d},`).join('\n') + '\n'}
238
+ }`
239
+ } else if (key === 'root') {
240
+ indexContent =
241
+ dirs.map((d) => {
242
+ if (defaultExports.includes(d)) return `export { default as ${d} } from './${d}';`
243
+ else return `export * as ${d} from './${d}';`
244
+ }).join('\n') + '\n'
245
+ } else {
246
+ indexContent =
247
+ dirs.map((d) => `export * from './${d}';`).join('\n') + '\n'
248
+ }
249
+ const indexFilePath = path.join(dirPath, 'index.js')
250
+ await fs.promises.writeFile(indexFilePath, indexContent, 'utf8')
73
251
  }
74
252
 
75
- function createOrUpdateFile (dirPath, childKey, value) {
76
- const filePath = path.join(dirPath, `${childKey}.js`)
253
+ async function overrideFiles (targetDir, distDir) {
254
+ for (const key of keys) {
255
+ const targetDirPath = path.join(targetDir, key)
256
+ const distDirPath = path.join(distDir, key)
257
+
258
+ if (!fs.existsSync(targetDirPath)) {
259
+ continue
260
+ }
261
+
262
+ const targetFiles = await fs.promises.readdir(targetDirPath)
263
+ for (const file of targetFiles) {
264
+ const targetFilePath = path.join(targetDirPath, file)
265
+ const distFilePath = path.join(distDirPath, file)
266
+
267
+ await fs.promises.copyFile(targetFilePath, distFilePath)
268
+ }
269
+ }
77
270
 
78
- const content = deepDestringify(value)
79
- const stringifiedContent = `export const ${childKey} = ${objectToString(content)}`
271
+ for (const key of singleFileKeys) {
272
+ const targetFilePath = path.join(targetDir, `${key}.js`)
273
+ const distFilePath = path.join(distDir, `${key}.js`)
80
274
 
81
- const fileExists = fs.existsSync(filePath)
275
+ if (!fs.existsSync(targetFilePath)) {
276
+ continue
277
+ }
82
278
 
83
- console.log(`${fileExists ? 'Updating' : 'Creating new'} file: ${filePath}`);
84
- (fileExists && fs.readFileSync(filePath, 'utf8') === content) ||
85
- fs.writeFileSync(filePath, stringifiedContent)
279
+ await fs.promises.copyFile(targetFilePath, distFilePath)
280
+ }
86
281
  }
87
282
 
88
- function createSingleFileFolderAndFile (key, data, distDir) {
89
- const filePath = path.join(distDir, `${key}.js`)
90
- const content = deepDestringify(data)
91
- const stringifiedContent = `export default ${objectToString(content)}`
92
- const fileExists = fs.existsSync(filePath)
283
+ async function askForConsent () {
284
+ const questions = [
285
+ {
286
+ type: 'confirm',
287
+ name: 'consent',
288
+ message: 'Do you want to override the files?',
289
+ default: false
290
+ }
291
+ ]
93
292
 
94
- console.log(`${fileExists ? 'Updating' : 'Creating new'} file: ${filePath}`);
95
- (fileExists && fs.readFileSync(filePath, 'utf8') === content) ||
96
- fs.writeFileSync(filePath, stringifiedContent)
293
+ return inquirer.prompt(questions)
97
294
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/cli",
3
- "version": "2.11.309",
3
+ "version": "2.11.315",
4
4
  "description": "Fetch your Symbols configuration",
5
5
  "main": "bin/fetch.js",
6
6
  "author": "Symbols",
@@ -27,5 +27,5 @@
27
27
  "peerDependencies": {
28
28
  "@symbo.ls/convert": "latest"
29
29
  },
30
- "gitHead": "22c3a3069fd57b6d539d661564f1ea9719a7f7cf"
30
+ "gitHead": "f7e5836ff0fad163a721cd8a823e2da1a7f346ef"
31
31
  }