Skip to content

Commit 60d1136

Browse files
committed
⭐ new(cli): squeeze and infuse commands
1 parent 26f0505 commit 60d1136

File tree

14 files changed

+951
-23
lines changed

14 files changed

+951
-23
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@
66
"name": "kazuya kawaguchi",
77
"email": "[email protected]"
88
},
9+
"bin": "lib/cli.js",
910
"bugs": {
1011
"url": "https://github.com/kazupon/vue-i18n-locale-message/issues"
1112
},
1213
"dependencies": {
1314
"@vue/component-compiler-utils": "^3.0.0",
1415
"debug": "^4.1.1",
16+
"glob": "^7.1.4",
1517
"js-yaml": "^3.13.1",
1618
"json5": "^2.1.0",
1719
"prettier": "^1.18.2",
18-
"vue-template-compiler": "^2.6.10"
20+
"vue-template-compiler": "^2.6.10",
21+
"yargs": "^13.3.0"
1922
},
2023
"devDependencies": {
2124
"@types/debug": "^4.1.4",
25+
"@types/glob": "^7.1.1",
2226
"@types/jest": "^24.0.15",
2327
"@types/js-yaml": "^3.12.1",
2428
"@types/json5": "^0.0.30",
2529
"@types/node": "^12.6.8",
2630
"@types/prettier": "^1.18.1",
31+
"@types/yargs": "^13.0.2",
2732
"@typescript-eslint/eslint-plugin": "^1.13.0",
2833
"@typescript-eslint/parser": "^1.13.0",
2934
"@typescript-eslint/typescript-estree": "^1.13.0",

src/cli.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env node
2+
3+
import * as yargs from 'yargs'
4+
5+
yargs
6+
.usage('Usage: $0 <command> [options]')
7+
.commandDir('./commands', {
8+
extensions: process.env.NODE_ENV === 'development' ? ['js', 'ts'] : ['js']
9+
})
10+
.demandCommand()
11+
.help()
12+
.version()
13+
.argv
14+
15+
process.on('uncaughtException', err => {
16+
console.error(`uncaught exception: ${err}\n`)
17+
process.exit(1)
18+
})
19+
20+
process.on('unhandledRejection', (reason, p) => {
21+
console.error('unhandled rejection at:', p, 'reason:', reason)
22+
process.exit(1)
23+
})

src/commands/infuse.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Arguments, Argv } from 'yargs'
2+
3+
import { resolve, readSFC } from '../utils'
4+
import infuse from '../infuser'
5+
import fs from 'fs'
6+
import { LocaleMessages, SFCFileInfo } from '../../types'
7+
8+
type InfuseOptions = {
9+
target: string
10+
messages: string
11+
}
12+
13+
export const command = 'infuse'
14+
export const aliases = 'inf'
15+
export const describe = 'infuse locale messages to single-file components'
16+
17+
export const builder = (args: Argv): Argv<InfuseOptions> => {
18+
return args
19+
.option('target', {
20+
type: 'string',
21+
alias: 't',
22+
describe: 'target path that single-file components is stored',
23+
demandOption: true
24+
})
25+
.option('messages', {
26+
type: 'string',
27+
alias: 'o',
28+
describe: 'locale messages path to be infused',
29+
demandOption: true
30+
})
31+
}
32+
33+
export const handler = (args: Arguments<InfuseOptions>): void => {
34+
const targetPath = resolve(args.target)
35+
const messagesPath = resolve(args.messages)
36+
const newSources = infuse(targetPath, readSFC(targetPath), readLocaleMessages(messagesPath))
37+
writeSFC(newSources)
38+
}
39+
40+
function readLocaleMessages (path: string): LocaleMessages {
41+
// TODO: async implementation
42+
const data = fs.readFileSync(path, { encoding: 'utf8' })
43+
return JSON.parse(data) as LocaleMessages
44+
}
45+
46+
function writeSFC (sources: SFCFileInfo[]) {
47+
// TODO: async implementation
48+
sources.forEach(({ path, content }) => {
49+
fs.writeFileSync(path, content)
50+
})
51+
}
52+
53+
export default {
54+
command,
55+
aliases,
56+
describe,
57+
builder,
58+
handler
59+
}

src/commands/squeeze.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Arguments, Argv } from 'yargs'
2+
import { LocaleMessages } from '../../types'
3+
4+
import { resolve, readSFC } from '../utils'
5+
import squeeze from '../squeezer'
6+
import fs from 'fs'
7+
8+
type SqueezeOptions = {
9+
target: string
10+
output: string
11+
}
12+
13+
export const command = 'squeeze'
14+
export const aliases = 'sqz'
15+
export const describe = 'squeeze locale messages from single-file components'
16+
17+
export const builder = (args: Argv): Argv<SqueezeOptions> => {
18+
const outputDefault = `${process.cwd()}/messages.json`
19+
return args
20+
.option('target', {
21+
type: 'string',
22+
alias: 't',
23+
describe: 'target path that single-file components is stored',
24+
demandOption: true
25+
})
26+
.option('output', {
27+
type: 'string',
28+
alias: 'o',
29+
default: outputDefault,
30+
describe: 'path to output squeezed locale messages'
31+
})
32+
}
33+
34+
export const handler = (args: Arguments<SqueezeOptions>): void => {
35+
const targetPath = resolve(args.target)
36+
const messages = squeeze(targetPath, readSFC(targetPath))
37+
writeLocaleMessages(resolve(args.output), messages)
38+
}
39+
40+
function writeLocaleMessages (output: string, messages: LocaleMessages) {
41+
// TODO: async implementation
42+
fs.writeFileSync(output, JSON.stringify(messages, null, 2))
43+
}
44+
45+
export default {
46+
command,
47+
aliases,
48+
describe,
49+
builder,
50+
handler
51+
}

src/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ import { VueTemplateCompiler } from '@vue/component-compiler-utils/dist/types'
44

55
import { parse } from '@vue/component-compiler-utils'
66
import * as compiler from 'vue-template-compiler'
7+
import fs from 'fs'
8+
import glob from 'glob'
79
import path from 'path'
810
import JSON5 from 'json5'
911
import yaml from 'js-yaml'
1012

1113
import { debug as Debug } from 'debug'
1214
const debug = Debug('vue-i18n-locale-message:utils')
1315

16+
export function resolve (...paths: string[]): string {
17+
return path.resolve(...paths)
18+
}
19+
1420
export function reflectSFCDescriptor (basePath: string, components: SFCFileInfo[]): SFCDescriptor[] {
1521
return components.map(target => {
1622
const { template, script, styles, customBlocks } = parse({
@@ -68,3 +74,22 @@ export function stringfyContent (content: any, lang: string): string {
6874
return JSON.stringify(content, null, 2)
6975
}
7076
}
77+
78+
export function readSFC (target: string): SFCFileInfo[] {
79+
const targets = resolveGlob(target)
80+
debug('readSFC: targets = ', targets)
81+
82+
// TODO: async implementation
83+
return targets.map(target => {
84+
const data = fs.readFileSync(target)
85+
return {
86+
path: target,
87+
content: data.toString()
88+
}
89+
})
90+
}
91+
92+
function resolveGlob (target: string) {
93+
// TODO: async implementation
94+
return glob.sync(`${target}/**/*.vue`)
95+
}

test/__snapshots__/cli.test.ts.snap

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`infuse command output help 1`] = `
4+
"processChild.js infuse
5+
6+
infuse locale messages to single-file components
7+
8+
Options:
9+
--version Show version number [boolean]
10+
--help Show help [boolean]
11+
--target, -t target path that single-file components is stored
12+
[string] [required]
13+
--messages, -o locale messages path to be infused [string] [required]"
14+
`;
15+
16+
exports[`squeeze command output help 1`] = `
17+
"processChild.js squeeze
18+
19+
squeeze locale messages from single-file components
20+
21+
Options:
22+
--version Show version number [boolean]
23+
--help Show help [boolean]
24+
--target, -t target path that single-file components is stored
25+
[string] [required]
26+
--output, -o path to output squeezed locale messages
27+
[string] [default: \\"/path/to/project1/messages.json\\"]"
28+
`;
29+
30+
exports[`top output help 1`] = `
31+
"Usage: processChild.js <command> [options]
32+
33+
Commands:
34+
processChild.js squeeze squeeze locale messages from single-file components
35+
[aliases: sqz]
36+
processChild.js infuse infuse locale messages to single-file components
37+
[aliases: inf]
38+
39+
Options:
40+
--version Show version number [boolean]
41+
--help Show help [boolean]"
42+
`;

test/cli.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import * as yargs from 'yargs'
2+
import squeeze from '../src/commands/squeeze'
3+
import infuse from '../src/commands/infuse'
4+
5+
let orgCwd
6+
beforeEach(async () => {
7+
orgCwd = process.cwd
8+
process.cwd = jest.fn(() => '/path/to/project1')
9+
})
10+
11+
afterEach(() => {
12+
jest.clearAllMocks()
13+
process.cwd = orgCwd
14+
})
15+
16+
test('top output help', async () => {
17+
const cmd = yargs
18+
.usage('Usage: $0 <command> [options]')
19+
.command(squeeze)
20+
.command(infuse)
21+
.demandCommand()
22+
.locale('en')
23+
.help()
24+
const output = await new Promise(resolve => {
25+
// eslint-disable-next-line handle-callback-err
26+
cmd.parse('--help', (err, argv, output) => {
27+
resolve(output)
28+
})
29+
})
30+
31+
expect(output).toMatchSnapshot()
32+
})
33+
34+
test('squeeze command output help', async () => {
35+
const cmd = yargs
36+
.command(squeeze)
37+
.locale('en')
38+
.help()
39+
const output = await new Promise(resolve => {
40+
// eslint-disable-next-line handle-callback-err
41+
cmd.parse('squeeze --help', (err, argv, output) => {
42+
resolve(output)
43+
})
44+
})
45+
46+
expect(output).toMatchSnapshot()
47+
})
48+
49+
test('infuse command output help', async () => {
50+
const cmd = yargs
51+
.command(infuse)
52+
.locale('en')
53+
.help()
54+
const output = await new Promise(resolve => {
55+
// eslint-disable-next-line handle-callback-err
56+
cmd.parse('infuse --help', (err, argv, output) => {
57+
resolve(output)
58+
})
59+
})
60+
61+
expect(output).toMatchSnapshot()
62+
})

0 commit comments

Comments
 (0)