Spaces:
Runtime error
Runtime error
| ; | |
| /** | |
| * Code generator for i18n js resource | |
| */ | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.generate = void 0; | |
| const shared_1 = require("@intlify/shared"); | |
| const acorn_1 = require("acorn"); | |
| const escodegen_1 = require("escodegen"); | |
| const estree_walker_1 = require("estree-walker"); | |
| const codegen_1 = require("./codegen"); | |
| /** | |
| * @internal | |
| */ | |
| function generate(targetSource, { type = 'plain', bridge = false, exportESM = false, filename = 'vue-i18n-loader.js', inSourceMap = undefined, locale = '', isGlobal = false, sourceMap = false, env = 'development', forceStringify = false, onError = undefined, strictMessage = true, escapeHtml = false, useClassComponent = false, allowDynamic = false }, injector) { | |
| const target = Buffer.isBuffer(targetSource) | |
| ? targetSource.toString() | |
| : targetSource; | |
| const value = target; | |
| const options = { | |
| type, | |
| bridge, | |
| exportESM, | |
| source: value, | |
| sourceMap, | |
| locale, | |
| isGlobal, | |
| inSourceMap, | |
| env, | |
| filename, | |
| forceStringify, | |
| onError, | |
| strictMessage, | |
| escapeHtml, | |
| useClassComponent | |
| }; | |
| const generator = (0, codegen_1.createCodeGenerator)(options); | |
| const ast = (0, acorn_1.parse)(value, { | |
| ecmaVersion: 'latest', | |
| sourceType: 'module', | |
| sourceFile: filename, | |
| allowImportExportEverywhere: true | |
| }); | |
| const exportResult = scanAst(ast); | |
| if (!allowDynamic) { | |
| // if (!astExportDefaultWithObject.length) { | |
| if (!exportResult || exportResult !== 'object') { | |
| throw new Error(`You need to define an object as the locale message with 'export default'.`); | |
| } | |
| } | |
| else { | |
| if (!exportResult) { | |
| throw new Error(`You need to define 'export default' that will return the locale messages.`); | |
| } | |
| if (exportResult !== 'object') { | |
| /** | |
| * NOTE: | |
| * If `allowDynamic` is `true`, do not transform the code by this function, return it as is. | |
| * This means that the user **must transform locale messages ownself**. | |
| * Especially at the production, you need to do locale messages pre-compiling. | |
| */ | |
| return { | |
| ast, | |
| code: value, | |
| map: inSourceMap | |
| }; | |
| } | |
| } | |
| const codeMaps = generateNode(generator, ast, options, injector); | |
| const { code, map } = generator.context(); | |
| // if (map) { | |
| // const s = new SourceMapConsumer((map as any).toJSON()) | |
| // s.eachMapping(m => { | |
| // console.log('sourcemap json', m) | |
| // }) | |
| // } | |
| // prettier-ignore | |
| const newMap = map | |
| ? (0, codegen_1.mapLinesColumns)(map.toJSON(), codeMaps, inSourceMap) || null // eslint-disable-line @typescript-eslint/no-explicit-any | |
| : null; | |
| return { | |
| ast, | |
| code, | |
| map: newMap != null ? newMap : undefined | |
| }; | |
| } | |
| exports.generate = generate; | |
| function scanAst(ast) { | |
| if (ast.type !== 'Program') { | |
| throw new Error('Invalid AST: does not have Program node'); | |
| } | |
| let ret = false; | |
| for (const node of ast.body) { | |
| if (node.type === 'ExportDefaultDeclaration') { | |
| if (node.declaration.type === 'ObjectExpression') { | |
| ret = 'object'; | |
| break; | |
| } | |
| else if (node.declaration.type === 'FunctionDeclaration') { | |
| ret = 'function'; | |
| break; | |
| } | |
| else if (node.declaration.type === 'ArrowFunctionExpression') { | |
| ret = 'arrow-function'; | |
| break; | |
| } | |
| } | |
| } | |
| return ret; | |
| } | |
| function generateNode(generator, node, options, injector) { | |
| const propsCountStack = []; | |
| const pathStack = []; | |
| const itemsCountStack = []; | |
| const skipStack = []; | |
| const { forceStringify } = generator.context(); | |
| const codeMaps = new Map(); | |
| const { type, bridge, exportESM, sourceMap, isGlobal, locale, useClassComponent } = options; | |
| const componentNamespace = '_Component'; | |
| (0, estree_walker_1.walk)(node, { | |
| /** | |
| * NOTE: | |
| * force cast to Node of `estree-walker@3.x`, | |
| * because `estree-walker@3.x` is not dual packages, | |
| * so it's support only esm only ... | |
| */ | |
| // @ts-ignore | |
| enter(node, parent) { | |
| switch (node.type) { | |
| case 'Program': | |
| if (type === 'plain') { | |
| generator.push(`const resource = `); | |
| } | |
| else if (type === 'sfc') { | |
| // for 'sfc' | |
| const variableName = type === 'sfc' ? (!isGlobal ? '__i18n' : '__i18nGlobal') : ''; | |
| const localeName = type === 'sfc' ? (locale != null ? locale : `""`) : ''; | |
| const exportSyntax = bridge | |
| ? exportESM | |
| ? `export default` | |
| : `module.exports =` | |
| : `export default`; | |
| generator.push(`${exportSyntax} function (Component) {`); | |
| generator.indent(); | |
| // prettier-ignore | |
| const componentVariable = bridge | |
| ? `Component.options || Component` | |
| : useClassComponent | |
| ? `Component.__o || Component` | |
| : `Component`; | |
| // prettier-ignore | |
| generator.pushline(`const ${componentNamespace} = ${componentVariable}`); | |
| generator.pushline(`${componentNamespace}.${variableName} = ${componentNamespace}.${variableName} || []`); | |
| generator.push(`${componentNamespace}.${variableName}.push({`); | |
| generator.indent(); | |
| generator.pushline(`"locale": ${JSON.stringify(localeName)},`); | |
| generator.push(`"resource": `); | |
| } | |
| break; | |
| case 'ObjectExpression': | |
| generator.push(`{`); | |
| generator.indent(); | |
| propsCountStack.push(node.properties.length); | |
| if (parent != null && parent.type === 'ArrayExpression') { | |
| const lastIndex = itemsCountStack.length - 1; | |
| const currentCount = parent.elements.length - itemsCountStack[lastIndex]; | |
| pathStack.push(currentCount.toString()); | |
| itemsCountStack[lastIndex] = --itemsCountStack[lastIndex]; | |
| } | |
| break; | |
| case 'Property': | |
| if (parent != null && parent.type === 'ObjectExpression') { | |
| if (node != null) { | |
| if (isJSONablePrimitiveLiteral(node.value) && | |
| (node.key.type === 'Literal' || node.key.type === 'Identifier')) { | |
| // prettier-ignore | |
| const name = node.key.type === 'Literal' | |
| ? String(node.key.value) | |
| : node.key.name; | |
| if ((node.value.type === 'Literal' && | |
| (0, shared_1.isString)(node.value.value)) || | |
| node.value.type === 'TemplateLiteral') { | |
| const value = getValue(node.value); | |
| generator.push(`${JSON.stringify(name)}: `); | |
| pathStack.push(name); | |
| const { code, map } = (0, codegen_1.generateMessageFunction)(value, options, pathStack); | |
| sourceMap && map != null && codeMaps.set(value, map); | |
| generator.push(`${code}`, node.value, value); | |
| skipStack.push(false); | |
| } | |
| else { | |
| const value = getValue(node.value); | |
| if (forceStringify) { | |
| const strValue = JSON.stringify(value); | |
| generator.push(`${JSON.stringify(name)}: `); | |
| pathStack.push(name); | |
| const { code, map } = (0, codegen_1.generateMessageFunction)(strValue, options, pathStack); | |
| sourceMap && map != null && codeMaps.set(strValue, map); | |
| generator.push(`${code}`, node.value, strValue); | |
| } | |
| else { | |
| generator.push(`${JSON.stringify(name)}: ${JSON.stringify(value)}`); | |
| pathStack.push(name); | |
| } | |
| skipStack.push(false); | |
| } | |
| } | |
| else if ((node.value.type === 'FunctionExpression' || | |
| node.value.type === 'ArrowFunctionExpression') && | |
| (node.key.type === 'Literal' || node.key.type === 'Identifier')) { | |
| // prettier-ignore | |
| const name = node.key.type === 'Literal' | |
| ? String(node.key.value) | |
| : node.key.name; | |
| generator.push(`${JSON.stringify(name)}: `); | |
| pathStack.push(name); | |
| const code = (0, escodegen_1.generate)(node.value); | |
| generator.push(`${code}`, node.value, code); | |
| skipStack.push(false); | |
| } | |
| else if ((node.value.type === 'ObjectExpression' || | |
| node.value.type === 'ArrayExpression') && | |
| (node.key.type === 'Literal' || node.key.type === 'Identifier')) { | |
| // prettier-ignore | |
| const name = node.key.type === 'Literal' | |
| ? String(node.key.value) | |
| : node.key.name; | |
| generator.push(`${JSON.stringify(name)}: `); | |
| pathStack.push(name); | |
| } | |
| else { | |
| // for Regex, function, etc. | |
| skipStack.push(true); | |
| } | |
| } | |
| const lastIndex = propsCountStack.length - 1; | |
| propsCountStack[lastIndex] = --propsCountStack[lastIndex]; | |
| } | |
| break; | |
| case 'ArrayExpression': | |
| generator.push(`[`); | |
| generator.indent(); | |
| if (parent != null && parent.type === 'ArrayExpression') { | |
| const lastIndex = itemsCountStack.length - 1; | |
| const currentCount = parent.elements.length - itemsCountStack[lastIndex]; | |
| pathStack.push(currentCount.toString()); | |
| itemsCountStack[lastIndex] = --itemsCountStack[lastIndex]; | |
| } | |
| itemsCountStack.push(node.elements.length); | |
| break; | |
| default: | |
| if (node != null && parent != null) { | |
| if (parent.type === 'ArrayExpression') { | |
| const lastIndex = itemsCountStack.length - 1; | |
| const currentCount = parent.elements.length - itemsCountStack[lastIndex]; | |
| pathStack.push(currentCount.toString()); | |
| if (isJSONablePrimitiveLiteral(node)) { | |
| if ((node.type === 'Literal' && (0, shared_1.isString)(node.value)) || | |
| node.type === 'TemplateLiteral') { | |
| const value = getValue(node); | |
| const { code, map } = (0, codegen_1.generateMessageFunction)(value, options, pathStack); | |
| sourceMap && map != null && codeMaps.set(value, map); | |
| generator.push(`${code}`, node, value); | |
| } | |
| else { | |
| const value = getValue(node); | |
| if (forceStringify) { | |
| const strValue = JSON.stringify(value); | |
| const { code, map } = (0, codegen_1.generateMessageFunction)(strValue, options, pathStack); | |
| sourceMap && map != null && codeMaps.set(strValue, map); | |
| generator.push(`${code}`, node, strValue); | |
| } | |
| else { | |
| generator.push(`${JSON.stringify(value)}`); | |
| } | |
| } | |
| skipStack.push(false); | |
| } | |
| else { | |
| // for Regex, function, etc. | |
| skipStack.push(true); | |
| } | |
| itemsCountStack[lastIndex] = --itemsCountStack[lastIndex]; | |
| } | |
| } | |
| else { | |
| // ... | |
| } | |
| break; | |
| } | |
| }, | |
| /** | |
| * NOTE: | |
| * force cast to Node of `estree-walker@3.x`, | |
| * because `estree-walker@3.x` is not dual packages, | |
| * so it's support only esm only ... | |
| */ | |
| // @ts-ignore | |
| leave(node, parent) { | |
| switch (node.type) { | |
| case 'Program': | |
| if (type === 'sfc') { | |
| generator.deindent(); | |
| generator.push(`})`); | |
| if (bridge && injector) { | |
| generator.newline(); | |
| generator.pushline(`${componentNamespace}.__i18nBridge = ${componentNamespace}.__i18nBridge || []`); | |
| generator.pushline(`${componentNamespace}.__i18nBridge.push('${injector()}')`); | |
| generator.pushline(`delete ${componentNamespace}._Ctor`); | |
| } | |
| generator.deindent(); | |
| generator.pushline(`}`); | |
| } | |
| else if (type === 'plain') { | |
| generator.push(`\n`); | |
| generator.push('export default resource'); | |
| } | |
| break; | |
| case 'ObjectExpression': | |
| if (propsCountStack[propsCountStack.length - 1] === 0) { | |
| pathStack.pop(); | |
| propsCountStack.pop(); | |
| } | |
| generator.deindent(); | |
| generator.push(`}`); | |
| if (parent != null && parent.type === 'ArrayExpression') { | |
| if (itemsCountStack[itemsCountStack.length - 1] !== 0) { | |
| pathStack.pop(); | |
| generator.pushline(`,`); | |
| } | |
| } | |
| break; | |
| case 'Property': | |
| if (parent != null && parent.type === 'ObjectExpression') { | |
| if (propsCountStack[propsCountStack.length - 1] !== 0) { | |
| pathStack.pop(); | |
| if (!skipStack.pop()) { | |
| generator.pushline(`,`); | |
| } | |
| } | |
| } | |
| break; | |
| case 'ArrayExpression': | |
| if (itemsCountStack[itemsCountStack.length - 1] === 0) { | |
| pathStack.pop(); | |
| itemsCountStack.pop(); | |
| } | |
| generator.deindent(); | |
| generator.push(`]`); | |
| if (parent != null && parent.type === 'ArrayExpression') { | |
| if (itemsCountStack[itemsCountStack.length - 1] !== 0) { | |
| pathStack.pop(); | |
| if (!skipStack.pop()) { | |
| generator.pushline(`,`); | |
| } | |
| } | |
| } | |
| break; | |
| case 'Literal': | |
| if (parent != null && parent.type === 'ArrayExpression') { | |
| if (itemsCountStack[itemsCountStack.length - 1] !== 0) { | |
| pathStack.pop(); | |
| if (!skipStack.pop()) { | |
| generator.pushline(`,`); | |
| } | |
| } | |
| else { | |
| if (!skipStack.pop()) { | |
| generator.pushline(`,`); | |
| } | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| }); | |
| return codeMaps; | |
| } | |
| function isJSONablePrimitiveLiteral(node) { | |
| return ((node.type === 'Literal' && | |
| ((0, shared_1.isString)(node.value) || | |
| (0, shared_1.isNumber)(node.value) || | |
| (0, shared_1.isBoolean)(node.value) || | |
| node.value === null)) || | |
| node.type === 'TemplateLiteral'); | |
| // NOTE: the following code is same the above code | |
| /* | |
| if (node.type === 'Literal') { | |
| if ( | |
| isString(node.value) || | |
| isNumber(node.value) || | |
| isBoolean(node.value) || | |
| node.value === null | |
| ) { | |
| return true | |
| } else if (isRegExp(node.value)) { | |
| return false | |
| } else { | |
| return false | |
| } | |
| } else if (node.type === 'TemplateLiteral') { | |
| return true | |
| } else { | |
| return false | |
| } | |
| */ | |
| } | |
| function getValue(node) { | |
| // prettier-ignore | |
| return node.type === 'Literal' | |
| ? node.value | |
| : node.type === 'TemplateLiteral' | |
| ? node.quasis.map(quasi => quasi.value.cooked).join('') | |
| : undefined; | |
| } | |