-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcli.js
executable file
·146 lines (126 loc) · 4.35 KB
/
cli.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env node
const argv = require('yargs-parser')(process.argv.slice(2));
const fs = require('fs');
const yaml = require('js-yaml');
const path = require('path');
const commandLineUsage = require('command-line-usage');
const { sections, getAllStrings, getString, toType } = require('./cli-helpers');
// check for the required arguments
if (!argv.translations || !argv.utilPath || !argv.stringTypesPath) {
process.stdout.write(commandLineUsage(sections));
}
const { translation } = yaml.safeLoad(
fs.readFileSync(`./${argv.translations}`, 'utf8')
);
const generateTypes = async obj => {
// Turn json to key utils
const keyStringsArr = getAllStrings(obj);
// Generate string enum names that map to key utils
const stringsAsEnumProp = keyStringsArr.map(toType);
// Identify utils that require data
const allStrings = keyStringsArr.map(key => getString(obj, key));
const dataRe = /\{\{(\w+)\}\}/g;
const stringsWithData = allStrings.map(str => {
let match = dataRe.exec(str);
const matches = [];
while (match) {
matches.push(match[1]);
match = dataRe.exec(str);
}
return matches.length > 0 ? matches : null;
});
// Generate the enum
const noArgsStrings = keyStringsArr.filter(
(k, index) => !stringsWithData[index]
);
const stringsWithArgs = keyStringsArr.filter(
(k, index) => stringsWithData[index]
);
const stringArgsEnum = 'I18NStringsWithArgs';
const stringEnum = 'I18NStrings';
const comments = `/* tslint:disable */\n/* eslint-disable */\n// This file was automatically generated and should not be edited.`;
const enumsWithArgsString = `${stringsWithArgs.reduce((acc, key) => {
return `${acc}
${toType(key)} = '${key}',`;
}, `export enum ${stringArgsEnum} {`)}
}`;
const enumNoArgsString = `${noArgsStrings.reduce((acc, key) => {
return `${acc}
${toType(key)} = '${key}',`;
}, `export enum ${stringEnum} {`)}
}`;
// Write enums to stringTypesPath file
fs.writeFileSync(
`./${argv.stringTypesPath}`,
`${comments}\n\n${enumsWithArgsString}\n\n${enumNoArgsString}`
);
// Write overloaded signatures with data requirements
const overloadedSignature = `function translate(
key: ${stringArgsEnum}.REPLACE_ENUM,
REPLACE_DATA
): string;`;
const overloadedSignatures = `${stringsWithData
.map((arr, index) => {
if (arr === null) {
return false;
}
return overloadedSignature
.replace('REPLACE_ENUM', stringsAsEnumProp[index])
.replace(
'REPLACE_DATA',
`{ ${arr.join(', ')} }: { ${arr
.map(key => `${key}: string`)
.join(';')} }`
);
})
.filter(Boolean)
.join('\n')}\nfunction translate(key: ${stringEnum}): string;`;
// Write content to utilPath file
const i18nPath = `./${argv.utilPath}`;
const i18nPathDir = argv.utilPath.slice(0, argv.utilPath.lastIndexOf('/'));
const stringTypesDir = argv.stringTypesPath.replace(
path.extname(argv.stringTypesPath),
''
);
const readTranslation =
'const en = yaml.safeLoad(\n' +
` fs.readFileSync('./${argv.translations}', 'utf8')\n` +
`);\n\n`;
const sigils = [
'// ==== START OVERLOADED SIGNATURES',
'// ==== END OVERLOADED SIGNATURES',
];
const imports = `import i18n from 'i18next';\nimport yaml from 'js-yaml';\nimport fs from 'fs';\nimport { ${stringEnum}, ${stringArgsEnum} } from '${path.relative(
i18nPathDir,
stringTypesDir
)}';`;
const translate =
'function translate(key: string, data?: { [key: string]: string }) {\n' +
' if (boundT) {\n' +
' return boundT(key, data);\n' +
' }\n' +
' i18n.init({\n' +
" lng: 'en',\n" +
' resources: { en },\n' +
' interpolation: {\n' +
' escapeValue: false,\n' +
' },\n' +
' });\n' +
' const { t } = i18n;\n' +
' boundT = t.bind(i18n);\n' +
' return boundT(key, data);\n' +
'}\n\nexport default translate;';
const content = `${comments}\n\n${imports}\n\nexport { ${stringEnum}, ${stringArgsEnum} } from '${path.relative(
i18nPathDir,
stringTypesDir
)}';\n\nlet boundT: typeof i18n.t;\n\n${readTranslation}${
sigils[0]
}\n${overloadedSignatures}\n${sigils[1]}\n\n${translate}`;
fs.writeFileSync(i18nPath, content);
};
if (translation) {
generateTypes(translation);
}
module.exports = {
generateTypes,
};