@brickflow/cli 0.0.6 → 0.0.8
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 +312 -0
- package/src/translate/ai.js +168 -0
- package/src/translate/gemini.js +142 -0
- package/src/translate/index.js +331 -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 +409 -0
- package/src/translate-context/index.js +3 -0
- package/src/translate-sync/index.js +25 -0
- package/src/types/index.js +127 -0
- package/src/upgrade/index.js +168 -0
package/CHANGELOG.md
CHANGED
package/index.mjs
CHANGED
|
@@ -1,109 +1,60 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { readdir, readFile, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { access, readdir } from 'node:fs/promises'
|
|
5
4
|
import path from 'node:path'
|
|
6
|
-
import { fileURLToPath } from 'node:url'
|
|
7
|
-
import { promisify } from 'node:util'
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
8
6
|
|
|
9
|
-
const execFileAsync = promisify(execFile)
|
|
10
7
|
const cliDir = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
-
const
|
|
12
|
-
const workspaceRoots = ['apps', 'packages']
|
|
8
|
+
const commandsDir = path.join(cliDir, 'src')
|
|
13
9
|
|
|
14
|
-
async function
|
|
15
|
-
const
|
|
10
|
+
async function getAvailableCommands() {
|
|
11
|
+
const entries = await readdir(commandsDir, { withFileTypes: true })
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (!entry.isDirectory()) {
|
|
23
|
-
continue
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
packagePaths.push(path.join(rootPath, entry.name, 'package.json'))
|
|
27
|
-
}
|
|
28
|
-
}
|
|
13
|
+
return entries
|
|
14
|
+
.filter((entry) => entry.isDirectory())
|
|
15
|
+
.map((entry) => entry.name)
|
|
16
|
+
.sort()
|
|
17
|
+
}
|
|
29
18
|
|
|
30
|
-
|
|
19
|
+
function isValidCommandName(command) {
|
|
20
|
+
return typeof command === 'string' && /^[a-z0-9-]+$/i.test(command)
|
|
31
21
|
}
|
|
32
22
|
|
|
33
23
|
async function main() {
|
|
34
24
|
const [command] = process.argv.slice(2)
|
|
25
|
+
const commands = await getAvailableCommands()
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return
|
|
40
|
-
default:
|
|
41
|
-
printHelp()
|
|
42
|
-
process.exitCode = 1
|
|
27
|
+
if (!command || !(await runCommand(command))) {
|
|
28
|
+
printHelp(commands)
|
|
29
|
+
process.exitCode = 1
|
|
43
30
|
}
|
|
44
31
|
}
|
|
45
32
|
|
|
46
|
-
function printHelp() {
|
|
33
|
+
function printHelp(commands) {
|
|
47
34
|
console.log(`brick cli
|
|
48
35
|
|
|
49
36
|
Usage:
|
|
50
|
-
brick
|
|
51
|
-
}
|
|
37
|
+
brick <command>
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return `${'#'.repeat(completed)}${'.'.repeat(10 - completed)}`
|
|
39
|
+
Commands:
|
|
40
|
+
${commands.join('\n ')}`)
|
|
56
41
|
}
|
|
57
42
|
|
|
58
|
-
async function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const packagePaths = await getWorkspacePackageJsonPaths()
|
|
62
|
-
let index = 0
|
|
63
|
-
|
|
64
|
-
for (const packagePath of packagePaths) {
|
|
65
|
-
index += 1
|
|
66
|
-
|
|
67
|
-
const packageJson = JSON.parse(await readFile(packagePath, 'utf8'))
|
|
68
|
-
await updatePackageVersions(packageJson)
|
|
69
|
-
await writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`)
|
|
70
|
-
|
|
71
|
-
const percent = Math.round((index * 100) / packagePaths.length)
|
|
72
|
-
process.stdout.write(`\rUpdating: [${renderProgress(percent)}] ${percent}%`)
|
|
43
|
+
async function runCommand(command) {
|
|
44
|
+
if (!isValidCommandName(command)) {
|
|
45
|
+
return false
|
|
73
46
|
}
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
console.log('\x1b[0m')
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function updatePackageVersions(packageJson) {
|
|
80
|
-
const dependencyEntries = [
|
|
81
|
-
...Object.entries(packageJson.dependencies || {}).map(([name, version]) => ({
|
|
82
|
-
group: 'dependencies',
|
|
83
|
-
name,
|
|
84
|
-
version,
|
|
85
|
-
})),
|
|
86
|
-
...Object.entries(packageJson.devDependencies || {}).map(([name, version]) => ({
|
|
87
|
-
group: 'devDependencies',
|
|
88
|
-
name,
|
|
89
|
-
version,
|
|
90
|
-
})),
|
|
91
|
-
]
|
|
48
|
+
const commandEntry = path.join(commandsDir, command, 'index.js')
|
|
92
49
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
50
|
+
try {
|
|
51
|
+
await access(commandEntry)
|
|
52
|
+
} catch {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
98
55
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
packageJson[group][name] = stdout.trim()
|
|
102
|
-
} catch (error) {
|
|
103
|
-
console.info(error instanceof Error ? error.message : String(error))
|
|
104
|
-
}
|
|
105
|
-
}),
|
|
106
|
-
)
|
|
56
|
+
await import(pathToFileURL(commandEntry).href)
|
|
57
|
+
return true
|
|
107
58
|
}
|
|
108
59
|
|
|
109
60
|
await main()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brickflow/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
@@ -14,6 +14,18 @@
|
|
|
14
14
|
"format": "pnpm exec prettier . --ignore-path ../../.prettierignore --write",
|
|
15
15
|
"format:check": "pnpm exec prettier . --ignore-path ../../.prettierignore --check"
|
|
16
16
|
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@babel/parser": "7.29.7",
|
|
19
|
+
"@babel/traverse": "7.29.7",
|
|
20
|
+
"@babel/types": "7.29.7",
|
|
21
|
+
"@google/genai": "2.6.0",
|
|
22
|
+
"@vue/compiler-sfc": "3.5.35",
|
|
23
|
+
"fantasticon": "4.1.0",
|
|
24
|
+
"glob": "13.0.6",
|
|
25
|
+
"looks-same": "10.0.1",
|
|
26
|
+
"sharp": "0.34.5",
|
|
27
|
+
"svgo": "4.0.1"
|
|
28
|
+
},
|
|
17
29
|
"publishConfig": {
|
|
18
30
|
"access": "public"
|
|
19
31
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { globSync } from 'glob'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(3)
|
|
6
|
+
const extensions = '.{png,jpg,jpeg,webp}'
|
|
7
|
+
|
|
8
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
9
|
+
printHelp()
|
|
10
|
+
process.exit(0)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!args[0]) {
|
|
14
|
+
printHelp()
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log('\x1b[32m', '\rIMG Optimize')
|
|
19
|
+
|
|
20
|
+
const patternPrefix = resolvePatternPrefix(args[0])
|
|
21
|
+
const searchPattern = `${patternPrefix}${extensions}`
|
|
22
|
+
const imgList = globSync(searchPattern)
|
|
23
|
+
|
|
24
|
+
if (imgList.length === 0) {
|
|
25
|
+
console.log(`\nNothing found for pattern: ${searchPattern}`)
|
|
26
|
+
console.log('\x1b[0m', '')
|
|
27
|
+
process.exit(0)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { default: sharp } = await import('sharp')
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < imgList.length; i++) {
|
|
33
|
+
const imgPath = imgList[i]
|
|
34
|
+
await sharp(imgPath)
|
|
35
|
+
.avif({
|
|
36
|
+
effort: 7,
|
|
37
|
+
quality: 70,
|
|
38
|
+
})
|
|
39
|
+
.toFile(`${imgPath.replace(/\.(png|jpg|jpeg|webp)$/i, '')}.avif`)
|
|
40
|
+
|
|
41
|
+
const percent = Math.round(((i + 1) * 100) / imgList.length)
|
|
42
|
+
fs.unlinkSync(imgPath)
|
|
43
|
+
process.stdout.write(`\r💎 Optimizing: [${'🌹'.repeat((percent * 10) / 100)}] ${percent}%`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('\x1b[0m', '')
|
|
47
|
+
|
|
48
|
+
function printHelp() {
|
|
49
|
+
console.log(`brick avif <pattern>
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
brick avif ../brick/public/**/*
|
|
53
|
+
brick avif ./src/assets/**/*
|
|
54
|
+
brick avif ./src/assets
|
|
55
|
+
|
|
56
|
+
Notes:
|
|
57
|
+
The command always searches only for ${extensions}
|
|
58
|
+
Pass a directory or a glob prefix without the extension part`)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolvePatternPrefix(input) {
|
|
62
|
+
if (/[?*[\]{}]/.test(input)) {
|
|
63
|
+
return stripTrailingExtensionGroup(input)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (/[\\/]$/.test(input)) {
|
|
67
|
+
return `${input}**/*`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (fs.existsSync(input) && fs.statSync(input).isDirectory()) {
|
|
71
|
+
return path.join(input, '**/*').replace(/\\/g, '/')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return stripTrailingExtensionGroup(input)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function stripTrailingExtensionGroup(input) {
|
|
78
|
+
return input.replace(/\.\{png,jpg,jpeg,webp\}$/i, '')
|
|
79
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { globSync } from 'glob'
|
|
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
|
+
if (args.length > 0) {
|
|
12
|
+
printHelp()
|
|
13
|
+
process.exit(1)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
console.log('\x1b[32m', '\rFilename analyse')
|
|
17
|
+
const dsStore = globSync('./**/.DS_Store')
|
|
18
|
+
if (dsStore.length > 0) {
|
|
19
|
+
console.log('\x1b[0m', '')
|
|
20
|
+
dsStore.forEach((item) => {
|
|
21
|
+
fs.unlinkSync(item)
|
|
22
|
+
console.log(item)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
throw `🥌 Remove .DS_Store ${dsStore[0]}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const allFile = globSync('./**/*.*')
|
|
29
|
+
|
|
30
|
+
let errorFilename = ''
|
|
31
|
+
allFile.forEach((path) => {
|
|
32
|
+
if (/\.md/.test(path)) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
if (/node_modules/.test(path)) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
const filename = path.match(/([^/\\]+).[a-z\d]$/)?.[0]
|
|
39
|
+
if (!filename) {
|
|
40
|
+
console.warn(path)
|
|
41
|
+
}
|
|
42
|
+
if (/[A-Z]{3}.svg/.test(filename)) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const isKebabCase = !/[^a-z./\d_-]/.test(filename)
|
|
46
|
+
if (!isKebabCase) {
|
|
47
|
+
errorFilename = `${errorFilename}
|
|
48
|
+
🍖 No Kebab 🗺️ ${path} | ${filename}
|
|
49
|
+
`
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (errorFilename.length > 0) {
|
|
54
|
+
console.log('\x1b[0m', '')
|
|
55
|
+
throw errorFilename
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log('\x1b[0m', '')
|
|
59
|
+
|
|
60
|
+
function printHelp() {
|
|
61
|
+
console.log(`brick filename
|
|
62
|
+
|
|
63
|
+
Usage:
|
|
64
|
+
brick filename
|
|
65
|
+
|
|
66
|
+
Notes:
|
|
67
|
+
Scans files under the current working directory
|
|
68
|
+
Removes .DS_Store files and fails on non-kebab-case filenames
|
|
69
|
+
Ignores markdown files and node_modules`)
|
|
70
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { globSync } from 'glob'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const args = process.argv.slice(3)
|
|
7
|
+
|
|
8
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
9
|
+
printHelp()
|
|
10
|
+
process.exit(0)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (args.length > 0) {
|
|
14
|
+
printHelp()
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
|
19
|
+
const workspaceRoot = path.resolve(currentDir, '../../../..')
|
|
20
|
+
const packageJsonPaths = globSync('**/package.json', {
|
|
21
|
+
absolute: true,
|
|
22
|
+
cwd: workspaceRoot,
|
|
23
|
+
ignore: ['**/node_modules/**'],
|
|
24
|
+
}).sort()
|
|
25
|
+
|
|
26
|
+
const dependenciesMap = new Map()
|
|
27
|
+
|
|
28
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
29
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
30
|
+
const packageLabel = getPackageLabel(packageJsonPath)
|
|
31
|
+
|
|
32
|
+
addDependencies(packageLabel, packageJson.dependencies)
|
|
33
|
+
addDependencies(packageLabel, packageJson.devDependencies)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const table = {}
|
|
37
|
+
|
|
38
|
+
for (const [dependencyName, versionsByPackage] of dependenciesMap) {
|
|
39
|
+
const uniqueVersions = new Set(Object.values(versionsByPackage))
|
|
40
|
+
|
|
41
|
+
if (uniqueVersions.size > 1) {
|
|
42
|
+
table[dependencyName] = versionsByPackage
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.table(table)
|
|
47
|
+
|
|
48
|
+
function addDependencies(packageLabel, dependencyGroup) {
|
|
49
|
+
if (!dependencyGroup) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const [dependencyName, version] of Object.entries(dependencyGroup)) {
|
|
54
|
+
const currentVersions = dependenciesMap.get(dependencyName) ?? {}
|
|
55
|
+
dependenciesMap.set(dependencyName, {
|
|
56
|
+
...currentVersions,
|
|
57
|
+
[packageLabel]: version,
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getPackageLabel(packageJsonPath) {
|
|
63
|
+
const relativePath = path.relative(workspaceRoot, packageJsonPath).replace(/\\/g, '/')
|
|
64
|
+
const packageDir = path.dirname(relativePath)
|
|
65
|
+
|
|
66
|
+
return packageDir === '.' ? 'root' : packageDir
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function printHelp() {
|
|
70
|
+
console.log(`brick graph
|
|
71
|
+
|
|
72
|
+
Usage:
|
|
73
|
+
brick graph
|
|
74
|
+
|
|
75
|
+
Notes:
|
|
76
|
+
Scans all package.json files in the repository, including the root one
|
|
77
|
+
Prints only dependencies that have different versions across packages`)
|
|
78
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { FontAssetType, generateFonts, OtherAssetType } from 'fantasticon'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const workspaceRoot = path.resolve(currentDir, '../../../..')
|
|
8
|
+
const args = process.argv.slice(3)
|
|
9
|
+
|
|
10
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
11
|
+
printHelp()
|
|
12
|
+
process.exit(0)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const options = parseArgs(args)
|
|
16
|
+
|
|
17
|
+
if (!options.path) {
|
|
18
|
+
printHelp()
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const inputDir = path.resolve(process.cwd(), options.path)
|
|
23
|
+
const iconName = options.name || path.basename(inputDir)
|
|
24
|
+
const outputDir = options.output
|
|
25
|
+
? path.resolve(process.cwd(), options.output)
|
|
26
|
+
: path.resolve(workspaceRoot, `brick/assets/icons/${iconName}`)
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(inputDir)) {
|
|
29
|
+
throw new Error(`Icon input directory is not found: ${inputDir}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!fs.statSync(inputDir).isDirectory()) {
|
|
33
|
+
throw new Error(`Icon input path must be a directory: ${inputDir}`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (/[\\/]/.test(iconName)) {
|
|
37
|
+
throw new Error(`Icon name must not contain path separators: ${iconName}`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fs.mkdirSync(outputDir, { recursive: true })
|
|
41
|
+
|
|
42
|
+
await generateFonts({
|
|
43
|
+
assetTypes: [OtherAssetType.CSS, OtherAssetType.JSON],
|
|
44
|
+
fontsUrl: '.',
|
|
45
|
+
fontTypes: [FontAssetType.EOT, FontAssetType.WOFF2, FontAssetType.WOFF],
|
|
46
|
+
formatOptions: {
|
|
47
|
+
json: {
|
|
48
|
+
indent: 2,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
inputDir,
|
|
52
|
+
name: iconName,
|
|
53
|
+
normalize: true,
|
|
54
|
+
outputDir,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const cssSourceFile = [`${iconName}.css`, 'icons.css', 'icon.css'].find((file) =>
|
|
58
|
+
fs.existsSync(path.join(outputDir, file)),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if (!cssSourceFile) {
|
|
62
|
+
throw new Error(`CSS output file was not generated for icon set "${iconName}"`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const cssPath = path.join(outputDir, cssSourceFile)
|
|
66
|
+
const minifiedCssPath = path.join(outputDir, `${path.parse(cssSourceFile).name}.minify.css`)
|
|
67
|
+
const cssContent = fs.readFileSync(cssPath, 'utf8')
|
|
68
|
+
const normalizedCssContent = normalizeGeneratedCss(cssContent)
|
|
69
|
+
|
|
70
|
+
if (normalizedCssContent !== cssContent) {
|
|
71
|
+
fs.writeFileSync(cssPath, normalizedCssContent)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fs.writeFileSync(minifiedCssPath, minifyCss(normalizedCssContent))
|
|
75
|
+
|
|
76
|
+
console.log(`✅ Icons generated for ${iconName}`)
|
|
77
|
+
console.log(` input: ${inputDir}`)
|
|
78
|
+
console.log(` output: ${outputDir}`)
|
|
79
|
+
|
|
80
|
+
function minifyCss(css) {
|
|
81
|
+
return css
|
|
82
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
83
|
+
.replace(/\s+/g, ' ')
|
|
84
|
+
.replace(/\s*([{}:;,>+~])\s*/g, '$1')
|
|
85
|
+
.replace(/;\}/g, '}')
|
|
86
|
+
.trim()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function normalizeGeneratedCss(css) {
|
|
90
|
+
return `${css
|
|
91
|
+
.replace(/"/g, "'")
|
|
92
|
+
.replace(/^ {4}/gm, ' ')
|
|
93
|
+
.replace(/src: ([^\n]+),\n([^\n]+),\n([^\n]+);/, 'src:\n $1,\n $2,\n $3;')
|
|
94
|
+
.replace(
|
|
95
|
+
/i\[class\^='icon-'\]:before, i\[class\*=' icon-'\]:before \{/,
|
|
96
|
+
"i[class^='icon-']:before,\ni[class*=' icon-']:before {",
|
|
97
|
+
)
|
|
98
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
99
|
+
.trim()}\n`
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseArgs(rawArgs) {
|
|
103
|
+
const parsedOptions = {
|
|
104
|
+
name: null,
|
|
105
|
+
output: null,
|
|
106
|
+
path: null,
|
|
107
|
+
}
|
|
108
|
+
const positional = []
|
|
109
|
+
|
|
110
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
111
|
+
const value = rawArgs[index]
|
|
112
|
+
|
|
113
|
+
if (value === '--path') {
|
|
114
|
+
parsedOptions.path = rawArgs[index + 1] ?? null
|
|
115
|
+
index += 1
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (value === '--name') {
|
|
120
|
+
parsedOptions.name = rawArgs[index + 1] ?? null
|
|
121
|
+
index += 1
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (value === '--output') {
|
|
126
|
+
parsedOptions.output = rawArgs[index + 1] ?? null
|
|
127
|
+
index += 1
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
positional.push(value)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!parsedOptions.path) {
|
|
135
|
+
parsedOptions.path = positional[0] ?? null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!parsedOptions.name) {
|
|
139
|
+
parsedOptions.name = positional[1] ?? null
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!parsedOptions.output) {
|
|
143
|
+
parsedOptions.output = positional[2] ?? null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return parsedOptions
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function printHelp() {
|
|
150
|
+
console.log(`brick icon <path> [name] [output]
|
|
151
|
+
|
|
152
|
+
Usage:
|
|
153
|
+
brick icon ./path/to/svg-icons
|
|
154
|
+
brick icon ./path/to/svg-icons marketing
|
|
155
|
+
brick icon ./path/to/svg-icons marketing ./path/to/output
|
|
156
|
+
brick icon --path ./path/to/svg-icons --name marketing --output ./path/to/output
|
|
157
|
+
|
|
158
|
+
Notes:
|
|
159
|
+
path: directory with source .svg icons
|
|
160
|
+
name: icon set name and generated asset prefix
|
|
161
|
+
output: directory for generated files; default is brick/assets/icons/<name>`)
|
|
162
|
+
}
|