@brickflow/cli 0.0.5 → 0.0.7
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 +12 -0
- package/index.mjs +31 -80
- package/package.json +13 -1
- package/src/avif/index.js +79 -0
- package/src/filename/index.js +70 -0
- package/src/graph/index.js +78 -0
- package/src/icon/index.js +162 -0
- package/src/icon-check/index.js +928 -0
- package/src/latest/index.js +105 -0
- package/src/size/index.js +64 -0
- package/src/svg/index.js +97 -0
- package/src/translate/ai-context.js +321 -0
- package/src/translate/ai.js +168 -0
- package/src/translate/gemini.js +142 -0
- package/src/translate/index.js +362 -0
- package/src/translate/models.js +12 -0
- package/src/translate/runtime-config.js +118 -0
- package/src/translate/sync.js +238 -0
- package/src/translate/utils.js +378 -0
- package/src/translate-sync/index.js +25 -0
- package/src/types/index.js +127 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { parse as babelParse } from '@babel/parser'
|
|
2
|
+
import traverseModule from '@babel/traverse'
|
|
3
|
+
import bkt from '@babel/types'
|
|
4
|
+
const { isIdentifier, isMemberExpression, isStringLiteral, isTemplateLiteral } = bkt
|
|
5
|
+
import { compileTemplate, parse as parseSFC } from '@vue/compiler-sfc'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
import { createHash } from 'crypto'
|
|
8
|
+
import { existsSync } from 'fs'
|
|
9
|
+
import { globSync } from 'glob'
|
|
10
|
+
import { join, resolve } from 'path'
|
|
11
|
+
|
|
12
|
+
const tTraverse = traverseModule.default || traverseModule
|
|
13
|
+
const IGNORED_GLOB_PATTERNS = [
|
|
14
|
+
'**/node_modules/**',
|
|
15
|
+
'**/.nuxt/**',
|
|
16
|
+
'**/dist/**',
|
|
17
|
+
'**/.output/**',
|
|
18
|
+
'**/coverage/**',
|
|
19
|
+
'**/public/**',
|
|
20
|
+
]
|
|
21
|
+
const IGNORED_SOURCE_SEGMENTS = ['/node_modules/', '/.nuxt/', '/dist/', '/.output/', '/coverage/', '/public/']
|
|
22
|
+
|
|
23
|
+
export function compileVueToJS(code, filePath) {
|
|
24
|
+
const { descriptor } = parseSFC(code)
|
|
25
|
+
|
|
26
|
+
let result = ''
|
|
27
|
+
|
|
28
|
+
if (descriptor.script?.content) {
|
|
29
|
+
result += `${descriptor.script.content}\n`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (descriptor.scriptSetup?.content) {
|
|
33
|
+
result += `${descriptor.scriptSetup.content}\n`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (descriptor.template?.content) {
|
|
37
|
+
const compiled = compileTemplate({
|
|
38
|
+
filename: filePath,
|
|
39
|
+
id: filePath,
|
|
40
|
+
source: descriptor.template.content,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
result += compiled.code
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function extractStrings(code, id) {
|
|
50
|
+
const ast = babelParse(code, {
|
|
51
|
+
plugins: getBabelPlugins(id),
|
|
52
|
+
sourceType: 'module',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const result = new Map()
|
|
56
|
+
const component = getComponentName(id)
|
|
57
|
+
|
|
58
|
+
tTraverse(ast, {
|
|
59
|
+
CallExpression(pathAst) {
|
|
60
|
+
if (!isTCall(pathAst.node)) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const arg = pathAst.node.arguments[0]
|
|
65
|
+
const text = getStaticText(arg)
|
|
66
|
+
|
|
67
|
+
if (text === null) {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const key = generateKey(text, component)
|
|
72
|
+
|
|
73
|
+
result.set(key, text)
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
return result
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function generateKey(text, component) {
|
|
81
|
+
const normalized = normalize(text)
|
|
82
|
+
const cased = toSnake(normalized).slice(0, 10)
|
|
83
|
+
const hash = shortHash(normalized)
|
|
84
|
+
|
|
85
|
+
return `${component}.${cased}_${hash}`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function getComponentName(id) {
|
|
89
|
+
const normalizedId = id.replace(/[?#].*$/, '')
|
|
90
|
+
|
|
91
|
+
if (/\/pages\//.test(normalizedId)) {
|
|
92
|
+
const pagePath = normalizedId.split('/pages/')[1].replace(/\.\w+$/, '')
|
|
93
|
+
|
|
94
|
+
return pagePath
|
|
95
|
+
.split('/')
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.map((segment) => toPageSegmentName(segment))
|
|
98
|
+
.join('_')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (/\/layouts\//.test(normalizedId)) {
|
|
102
|
+
const layoutPath = normalizedId
|
|
103
|
+
.split('/layouts/')[1]
|
|
104
|
+
.replace(/\.\w+$/, '')
|
|
105
|
+
.replace(/\/index$/, '')
|
|
106
|
+
const segments = [getProjectName(normalizedId), 'layouts', ...layoutPath.split('/').filter(Boolean)]
|
|
107
|
+
|
|
108
|
+
return segments.map((segment) => toPascal(segment)).join('')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!normalizedId.endsWith('.vue')) {
|
|
112
|
+
return getScriptName(normalizedId)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const parts = normalizedId.split('/')
|
|
116
|
+
parts.pop()
|
|
117
|
+
|
|
118
|
+
const dirs = parts.slice(-2)
|
|
119
|
+
|
|
120
|
+
return dirs.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function getProjectName(id) {
|
|
124
|
+
return getProjectRoot(id)?.split('/').pop() ?? 'project'
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function getProjectRoot(id) {
|
|
128
|
+
const normalizedId = id.replace(/[?#].*$/, '')
|
|
129
|
+
const brickMatch = normalizedId.match(/^(.*\/packages\/brick)(?:\/|$)/)
|
|
130
|
+
|
|
131
|
+
if (brickMatch) {
|
|
132
|
+
return brickMatch[1]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const appMatch = normalizedId.match(/^(.*\/apps\/[^/]+)(?:\/|$)/)
|
|
136
|
+
|
|
137
|
+
return appMatch?.[1] ?? null
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function getScriptName(id) {
|
|
141
|
+
const relativePath = id.split('/packages/')[1] ?? id.split('/apps/')[1] ?? id.replace(/^\//, '')
|
|
142
|
+
|
|
143
|
+
return toPageName(relativePath.replace(/\.\w+$/, '').replace(/\//g, '_'))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function getTranslationPaths(id) {
|
|
147
|
+
if (isVueSubResourceId(id)) {
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const normalizedId = id.replace(/[?#].*$/, '')
|
|
152
|
+
if (isIgnoredSourcePath(normalizedId)) {
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (normalizedId.endsWith('/book.vue')) {
|
|
157
|
+
return null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const isComponent =
|
|
161
|
+
normalizedId.endsWith('.vue') &&
|
|
162
|
+
(normalizedId.includes('/packages/brick/components/') ||
|
|
163
|
+
(normalizedId.includes('/apps/') && normalizedId.includes('/components/')))
|
|
164
|
+
const isPage = normalizedId.endsWith('.vue') && normalizedId.includes('/pages/')
|
|
165
|
+
const isLayout = normalizedId.endsWith('.vue') && normalizedId.includes('/layouts/')
|
|
166
|
+
const projectRoot = getProjectRoot(normalizedId)
|
|
167
|
+
const isScript =
|
|
168
|
+
!normalizedId.endsWith('.vue') &&
|
|
169
|
+
Boolean(projectRoot) &&
|
|
170
|
+
/\.(?:js|ts)$/.test(normalizedId) &&
|
|
171
|
+
!normalizedId.endsWith('.d.ts')
|
|
172
|
+
|
|
173
|
+
if (!isComponent && !isPage && !isLayout && !isScript) {
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (isComponent) {
|
|
178
|
+
const componentDir = normalizedId.split('/').slice(0, -1).join('/')
|
|
179
|
+
const baseDir = join(componentDir, 'translate')
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
baseDir,
|
|
183
|
+
isComponent,
|
|
184
|
+
isPage,
|
|
185
|
+
isScript,
|
|
186
|
+
samplePath: join(baseDir, 'sample.json'),
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (isPage) {
|
|
191
|
+
const pagesRoot = `${normalizedId.split('/pages/')[0]}/pages`
|
|
192
|
+
const rootDir = join(pagesRoot, '..', 'pages-translate')
|
|
193
|
+
const name = getComponentName(normalizedId)
|
|
194
|
+
const baseDir = join(rootDir, name)
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
baseDir,
|
|
198
|
+
isComponent,
|
|
199
|
+
isPage,
|
|
200
|
+
isScript,
|
|
201
|
+
samplePath: join(baseDir, 'sample.json'),
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (isLayout) {
|
|
206
|
+
const layoutDir = normalizedId.split('/').slice(0, -1).join('/')
|
|
207
|
+
const fileName =
|
|
208
|
+
normalizedId
|
|
209
|
+
.split('/')
|
|
210
|
+
.pop()
|
|
211
|
+
?.replace(/\.\w+$/, '') ?? ''
|
|
212
|
+
const baseDir = join(layoutDir, fileName)
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
baseDir,
|
|
216
|
+
isComponent,
|
|
217
|
+
isLayout,
|
|
218
|
+
isPage,
|
|
219
|
+
isScript,
|
|
220
|
+
samplePath: join(baseDir, 'sample.json'),
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const baseDir = join(projectRoot, 'global', getComponentName(normalizedId))
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
baseDir,
|
|
228
|
+
isComponent,
|
|
229
|
+
isLayout,
|
|
230
|
+
isPage,
|
|
231
|
+
isScript,
|
|
232
|
+
samplePath: join(baseDir, 'sample.json'),
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function listWorkspaceFiles(workspaceRoot) {
|
|
237
|
+
try {
|
|
238
|
+
const output = execFileSync('git', ['ls-files', '-co', '--exclude-standard', '-z'], {
|
|
239
|
+
cwd: workspaceRoot,
|
|
240
|
+
encoding: 'utf-8',
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
return output
|
|
244
|
+
.split('\0')
|
|
245
|
+
.filter(Boolean)
|
|
246
|
+
.map((file) => resolve(workspaceRoot, file))
|
|
247
|
+
.filter((filePath) => existsSync(filePath))
|
|
248
|
+
} catch {
|
|
249
|
+
return globSync('**/*', {
|
|
250
|
+
absolute: true,
|
|
251
|
+
cwd: workspaceRoot,
|
|
252
|
+
ignore: IGNORED_GLOB_PATTERNS,
|
|
253
|
+
nodir: true,
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function normalize(input) {
|
|
259
|
+
return input.trim().toLowerCase().replace(/\s+/g, ' ')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function shortHash(input) {
|
|
263
|
+
return createHash('md5').update(input).digest('hex').slice(0, 4)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function sortJsonValue(value) {
|
|
267
|
+
if (Array.isArray(value)) {
|
|
268
|
+
return value.map((item) => sortJsonValue(item))
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (value && typeof value === 'object') {
|
|
272
|
+
return Object.fromEntries(
|
|
273
|
+
Object.entries(value)
|
|
274
|
+
.sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
|
|
275
|
+
.map(([key, item]) => [key, sortJsonValue(item)]),
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return value
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function sortObjectKeys(value) {
|
|
283
|
+
return Object.fromEntries(Object.entries(value).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function stringifySortedJson(value) {
|
|
287
|
+
return `${JSON.stringify(sortJsonValue(value), null, 2)}\n`
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function toPageName(input) {
|
|
291
|
+
return input
|
|
292
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
293
|
+
.replace(/[-.\s]+/g, '_')
|
|
294
|
+
.replace(/[^\w$]/g, '')
|
|
295
|
+
.replace(/_+/g, '_')
|
|
296
|
+
.replace(/^_+|_+$/g, '')
|
|
297
|
+
.toLowerCase()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function toSnake(input) {
|
|
301
|
+
return input
|
|
302
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
303
|
+
.replace(/[-.\s]+/g, '_')
|
|
304
|
+
.replace(/\W/g, '')
|
|
305
|
+
.replace(/_+/g, '_')
|
|
306
|
+
.replace(/^_+|_+$/g, '')
|
|
307
|
+
.toLowerCase()
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function getBabelPlugins(id) {
|
|
311
|
+
const normalizedId = id.replace(/[?#].*$/, '')
|
|
312
|
+
|
|
313
|
+
if (/\.(?:jsx|tsx)$/.test(normalizedId)) {
|
|
314
|
+
return ['typescript', 'jsx']
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return ['typescript']
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function getStaticText(node) {
|
|
321
|
+
if (!node) {
|
|
322
|
+
return null
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (isStringLiteral(node)) {
|
|
326
|
+
return node.value
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (isTemplateLiteral(node) && node.expressions.length === 0) {
|
|
330
|
+
return node.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return null
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function isIgnoredSourcePath(id) {
|
|
337
|
+
return IGNORED_SOURCE_SEGMENTS.some((segment) => id.includes(segment))
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function isTCall(node) {
|
|
341
|
+
const callee = node.callee
|
|
342
|
+
|
|
343
|
+
if (isIdentifier(callee) && callee.name === 't') {
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (isMemberExpression(callee) && isIdentifier(callee.property) && callee.property.name === 't') {
|
|
348
|
+
if (isIdentifier(callee.object, { name: 'currentI18n' })) {
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return true
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return false
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function isVueSubResourceId(id) {
|
|
359
|
+
return /[?&]vue&type=/.test(id)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function toPageSegmentName(segment) {
|
|
363
|
+
const dynamicMatch = segment.match(/^\[([^\]]+)\]$/)
|
|
364
|
+
|
|
365
|
+
if (dynamicMatch) {
|
|
366
|
+
return `$${dynamicMatch[1]}`
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return toSnake(segment)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function toPascal(input) {
|
|
373
|
+
return toSnake(input)
|
|
374
|
+
.split('_')
|
|
375
|
+
.filter(Boolean)
|
|
376
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
377
|
+
.join('')
|
|
378
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const args = process.argv.slice(3)
|
|
2
|
+
|
|
3
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
4
|
+
printHelp()
|
|
5
|
+
process.exit(0)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (args.length > 0) {
|
|
9
|
+
printHelp()
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
await import('../translate/sync.js')
|
|
14
|
+
|
|
15
|
+
function printHelp() {
|
|
16
|
+
console.log(`brick translate-sync
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
brick translate-sync
|
|
20
|
+
|
|
21
|
+
Notes:
|
|
22
|
+
Scans source files and regenerates translation sample.json files
|
|
23
|
+
Removes obsolete generated translation directories
|
|
24
|
+
Verifies and normalizes translation JSON key ordering`)
|
|
25
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readdirSync, statSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
const args = process.argv.slice(3)
|
|
5
|
+
|
|
6
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
7
|
+
printHelp()
|
|
8
|
+
process.exit(0)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const options = parseArgs(args)
|
|
12
|
+
|
|
13
|
+
if (!options.path || !options.typeName || !options.outputFile || !options.replacePattern) {
|
|
14
|
+
printHelp()
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const inputDir = path.resolve(process.cwd(), options.path)
|
|
19
|
+
const outputFile = path.resolve(process.cwd(), options.outputFile)
|
|
20
|
+
const replacePattern = parseReplacePattern(options.replacePattern)
|
|
21
|
+
const entries = readdirSync(inputDir)
|
|
22
|
+
.filter((entry) => statSync(path.join(inputDir, entry)).isFile())
|
|
23
|
+
.sort((first, second) => first.localeCompare(second))
|
|
24
|
+
|
|
25
|
+
const typeValues = new Set(entries.map((entry) => applyReplacePattern(entry, replacePattern)).filter(Boolean))
|
|
26
|
+
|
|
27
|
+
if (typeValues.size === 0) {
|
|
28
|
+
throw new Error(`No type values generated from: ${inputDir}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const declaration = `declare type ${options.typeName} = ${[...typeValues].map((value) => `'${value}'`).join(' | ')}\n`
|
|
32
|
+
writeFileSync(outputFile, declaration, 'utf8')
|
|
33
|
+
|
|
34
|
+
console.log(`✅ Types generated for ${options.typeName}`)
|
|
35
|
+
console.log(` input: ${inputDir}`)
|
|
36
|
+
console.log(` output: ${outputFile}`)
|
|
37
|
+
|
|
38
|
+
function applyReplacePattern(value, pattern) {
|
|
39
|
+
if (pattern instanceof RegExp) {
|
|
40
|
+
return value.replace(pattern, '')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return value.replaceAll(pattern, '')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function parseArgs(rawArgs) {
|
|
47
|
+
const parsedOptions = {
|
|
48
|
+
outputFile: null,
|
|
49
|
+
path: null,
|
|
50
|
+
replacePattern: null,
|
|
51
|
+
typeName: null,
|
|
52
|
+
}
|
|
53
|
+
const positional = []
|
|
54
|
+
|
|
55
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
56
|
+
const value = rawArgs[index]
|
|
57
|
+
|
|
58
|
+
if (value === '--path') {
|
|
59
|
+
parsedOptions.path = rawArgs[index + 1] ?? null
|
|
60
|
+
index += 1
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (value === '--type-name') {
|
|
65
|
+
parsedOptions.typeName = rawArgs[index + 1] ?? null
|
|
66
|
+
index += 1
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (value === '--output-file') {
|
|
71
|
+
parsedOptions.outputFile = rawArgs[index + 1] ?? null
|
|
72
|
+
index += 1
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (value === '--replace-pattern') {
|
|
77
|
+
parsedOptions.replacePattern = rawArgs[index + 1] ?? null
|
|
78
|
+
index += 1
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
positional.push(value)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!parsedOptions.path) {
|
|
86
|
+
parsedOptions.path = positional[0] ?? null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!parsedOptions.typeName) {
|
|
90
|
+
parsedOptions.typeName = positional[1] ?? null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!parsedOptions.outputFile) {
|
|
94
|
+
parsedOptions.outputFile = positional[2] ?? null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!parsedOptions.replacePattern) {
|
|
98
|
+
parsedOptions.replacePattern = positional[3] ?? null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return parsedOptions
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function parseReplacePattern(value) {
|
|
105
|
+
const match = value.match(/^\/([\s\S]*)\/([dgimsuvy]*)$/)
|
|
106
|
+
|
|
107
|
+
if (match) {
|
|
108
|
+
return new RegExp(match[1], match[2])
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return value
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function printHelp() {
|
|
115
|
+
console.log(`brick types <path> <typeName> <outputFile> <replacePattern>
|
|
116
|
+
|
|
117
|
+
Usage:
|
|
118
|
+
brick types ./path/to/files IconName ./types/icon.d.ts .svg
|
|
119
|
+
brick types ./path/to/files IconName ./types/icon.d.ts /\\.svg$/
|
|
120
|
+
brick types --path ./path/to/files --type-name IconName --output-file ./types/icon.d.ts --replace-pattern /\\.svg$/
|
|
121
|
+
|
|
122
|
+
Notes:
|
|
123
|
+
path: directory with source files
|
|
124
|
+
typeName: generated TypeScript type name
|
|
125
|
+
outputFile: file to write declaration into
|
|
126
|
+
replacePattern: string or regex literal used in replace(..., '') for each filename`)
|
|
127
|
+
}
|