diff --git a/README.md b/README.md index 372a1c7..ffc0c61 100644 --- a/README.md +++ b/README.md @@ -324,35 +324,6 @@ module.exports = { } ``` -## :rocket: i18n resource optimization - -You can optimize your localization performance with pre-compiling the i18n resources. - -You need to specify the `preCompile: true` option in your webpack config as below: - -```javascript -module.exports = { - module: { - rules: [ - // ... - { - resourceQuery: /blockType=i18n/, - type: 'javascript/auto', - use: [ - { - loader: '@intlify/vue-i18n-loader', - options: { - preCompile: true // you need to specify at here! - } - } - ] - }, - // ... - ] - } -} -``` - ## :scroll: Changelog Details changes for each release are documented in the [CHANGELOG.md](https://github.com/intlify/vue-i18n-loader/blob/master/CHANGELOG.md). diff --git a/example/composition/en.yaml b/example/composition/locales/en.yaml similarity index 100% rename from example/composition/en.yaml rename to example/composition/locales/en.yaml diff --git a/example/composition/ja.json b/example/composition/locales/ja.json similarity index 100% rename from example/composition/ja.json rename to example/composition/locales/ja.json diff --git a/example/composition/main.js b/example/composition/main.js index 8941c1b..f7028a7 100644 --- a/example/composition/main.js +++ b/example/composition/main.js @@ -2,8 +2,8 @@ import { createApp } from 'vue' import { createI18n } from 'vue-i18n' import App from './App.vue' -import ja from './ja.json' -import en from './en.yaml' +import ja from './locales/ja.json' +import en from './locales/en.yaml' const i18n = createI18n({ legacy: false, diff --git a/example/legacy/en.yaml b/example/legacy/locales/en.yaml similarity index 100% rename from example/legacy/en.yaml rename to example/legacy/locales/en.yaml diff --git a/example/legacy/ja.json b/example/legacy/locales/ja.json similarity index 100% rename from example/legacy/ja.json rename to example/legacy/locales/ja.json diff --git a/example/legacy/main.js b/example/legacy/main.js index 9a56d6b..9a92e17 100644 --- a/example/legacy/main.js +++ b/example/legacy/main.js @@ -2,8 +2,8 @@ import { createApp } from 'vue' import { createI18n } from 'vue-i18n' import App from './App.vue' -import ja from './ja.json' -import en from './en.yaml' +import ja from './locales/ja.json' +import en from './locales/en.yaml' const i18n = createI18n({ legacy: true, diff --git a/example/webpack.config.js b/example/webpack.config.js index 2a10469..ee366b5 100644 --- a/example/webpack.config.js +++ b/example/webpack.config.js @@ -20,8 +20,7 @@ module.exports = { // is a simple `export * from '@vue/runtime-dom`. However having this // extra re-export somehow causes webpack to always invalidate the module // on the first HMR update and causes the page to reload. - vue: '@vue/runtime-dom', - 'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js' + vue: '@vue/runtime-dom' } }, devServer: { @@ -42,28 +41,24 @@ module.exports = { test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files type: 'javascript/auto', // Use `Rule.include` to specify the files of locale messages to be pre-compiled - include: [path.resolve(__dirname, './')], + include: [ + path.resolve(__dirname, './composition/locales'), + path.resolve(__dirname, './legacy/locales') + ], use: [ { loader: path.resolve(__dirname, '../lib/index.js'), options: { // Whether pre-compile number and boolean literal as message functions that return the string value, default `false` - forceStringify: true + // forceStringify: true } } ] }, { - resourceQuery: /blockType=i18n/, type: 'javascript/auto', - use: [ - { - loader: path.resolve(__dirname, '../lib/index.js'), - options: { - preCompile: true - } - } - ] + resourceQuery: /blockType=i18n/, + loader: path.resolve(__dirname, '../lib/index.js') } ] }, diff --git a/package.json b/package.json index c2ef2d7..8ee4d4a 100644 --- a/package.json +++ b/package.json @@ -24,30 +24,22 @@ } }, "dependencies": { - "@intlify/core-base": "^9.0.0-beta.14", - "@intlify/message-compiler": "^9.0.0-beta.14", - "@intlify/shared": "^9.0.0-beta.14", - "flat": "^5.0.2", - "js-yaml": "^3.14.0", - "json5": "^2.1.3", + "@intlify/core-base": "^9.0.0-beta.15", + "@intlify/message-compiler": "^9.0.0-beta.15", + "@intlify/shared": "^9.0.0-beta.15", "jsonc-eslint-parser": "^0.6.0", "loader-utils": "^2.0.0", - "prettier": "^2.2.1", "yaml-eslint-parser": "^0.2.0" }, "devDependencies": { - "@intlify/runtime": "^9.0.0-beta.14", + "@intlify/runtime": "^9.0.0-beta.15", "@types/eslint": "^7.2.6", "@types/eslint-visitor-keys": "^1.0.0", - "@types/flat": "^5.0.1", "@types/jest": "^26.0.16", - "@types/js-yaml": "^3.12.5", "@types/jsdom": "^16.2.5", - "@types/json5": "^0.0.30", "@types/loader-utils": "^2.0.0", "@types/memory-fs": "^0.3.2", "@types/node": "^14.14.10", - "@types/prettier": "^2.1.5", "@types/webpack": "^4.41.1", "@types/webpack-merge": "^4.1.5", "@typescript-eslint/eslint-plugin": "^4.9.0", @@ -73,8 +65,8 @@ "typescript": "^4.1.2", "typescript-eslint-language-service": "^4.1.2", "vue": "^3.0.4", - "vue-i18n": "^9.0.0-beta.14", - "vue-loader": "^16.1.0", + "vue-i18n": "^9.0.0-beta.15", + "vue-loader": "^16.1.2", "webpack": "^4.44.2", "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.11.0", @@ -122,6 +114,6 @@ "test:cover": "yarn test:unit --coverage", "test:e2e": "yarn build && jest --runInBand --config ./jest.e2e.config.js", "test:unit": "yarn clean:cache:jest && jest --env node", - "test:watch": "clean:cache:jest && jest --env node --watch" + "test:watch": "yarn clean:cache:jest && jest --env node --watch" } } diff --git a/src/gen.ts b/src/gen.ts deleted file mode 100644 index 69b6c34..0000000 --- a/src/gen.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { ParsedUrlQuery } from 'querystring' -import JSON5 from 'json5' -import yaml from 'js-yaml' -import { flatten } from 'flat' -import prettier from 'prettier' -import { baseCompile, CompileOptions } from '@intlify/message-compiler' -import { friendlyJSONstringify, generateFormatCacheKey } from '@intlify/shared' -import { Locale, LocaleMessages } from '@intlify/core-base' - -import type { VueI18nLoaderOptions } from './options' - -export function generateCode( - source: string | Buffer, - query: ParsedUrlQuery, - options: VueI18nLoaderOptions -): string { - const value = merge(parse(source, query), query) - - let code = '' - const preCompile = !!options.preCompile - - if (preCompile) { - if (query.global) { - console.warn( - '[vue-i18n-loader] cannot support global scope for pre-compilation' - ) - } else { - code += generateCompiledCode(value as LocaleMessages) - code += `export default function (Component) { - Component.__i18n = Component.__i18n || _getResource -}\n` - } - } else { - const variableName = query.global ? '__i18nGlobal' : '__i18n' - code += `export default function (Component) { - Component.${variableName} = Component.${variableName} || [] - Component.${variableName}.push(${stringify(value)}) -}\n` - } - - return prettier.format(code, { parser: 'babel' }) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function stringify(data: any): string { - return friendlyJSONstringify(data) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function merge(data: any, query: ParsedUrlQuery): any { - if (query.locale && typeof query.locale === 'string') { - return Object.assign({}, { [query.locale]: data }) - } else { - return data - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function parse(source: string | Buffer, query: ParsedUrlQuery): any { - const value = Buffer.isBuffer(source) ? source.toString() : source - const { lang } = query - switch (lang) { - case 'yaml': - case 'yml': - return yaml.safeLoad(value) - case 'json5': - return JSON5.parse(value) - default: - return JSON.parse(value) - } -} - -function generateCompiledCode(messages: LocaleMessages): string { - let code = '' - code += `function _register(functions, pathkey, msg) { - const path = JSON.stringify(pathkey) - functions[path] = msg -} -` - code += `const _getResource = () => { - const functions = Object.create(null) -` - - const locales = Object.keys(messages) as Locale[] - locales.forEach(locale => { - const message = flatten(messages[locale]) as { [key: string]: string } - const keys = Object.keys(message) - keys.forEach(key => { - const format = message[key] - let occured = false - const options = { - mode: 'arrow', - // TODO: source mapping ! - onError(err) { - console.error(err) - occured = true - } - } as CompileOptions - const result = baseCompile(format, options) - if (!occured) { - code += ` _register(functions, ${generateFormatCacheKey( - locale, - key, - format - )}, ${result.code})\n` - } - }) - }) - - code += ` - return { functions } -} -` - - return code -} diff --git a/src/generator/codegen.ts b/src/generator/codegen.ts index 4a38eec..73b85da 100644 --- a/src/generator/codegen.ts +++ b/src/generator/codegen.ts @@ -5,7 +5,12 @@ import { ResourceNode, CompileOptions } from '@intlify/message-compiler' -import { SourceMapGenerator, SourceMapConsumer } from 'source-map' +import { + SourceMapGenerator, + SourceMapConsumer, + MappedPosition, + MappingItem +} from 'source-map' import type { RawSourceMap } from 'source-map' @@ -25,9 +30,13 @@ export interface SourceLocationable { } export interface CodeGenOptions { + type?: 'plain' | 'sfc' source?: string sourceMap?: boolean filename?: string + inSourceMap?: RawSourceMap + isGlobal?: boolean + locale?: string env?: DevEnv forceStringify?: boolean onWarn?: (msg: string) => void @@ -206,23 +215,35 @@ export function generateMessageFunction( const { code, ast, map } = baseCompile(msg, newOptions) const genCode = !occured ? env === 'development' - ? `(()=>{const fn=${code};fn.source=${JSON.stringify(msg)};return fn})()` + ? `(()=>{const fn=${code};fn.source=${JSON.stringify(msg)};return fn;})()` : `${code}` : msg return { code: genCode, ast, map } } -export function mapColumns( +export function mapLinesColumns( resMap: RawSourceMap, - codeMaps: Map + codeMaps: Map, + inSourceMap?: RawSourceMap ): RawSourceMap | null { if (!resMap) { return null } const resMapConsumer = new SourceMapConsumer(resMap) + const inMapConsumer = inSourceMap ? new SourceMapConsumer(inSourceMap) : null const mergedMapGenerator = new SourceMapGenerator() + let inMapFirstItem: MappingItem | null = null + if (inMapConsumer) { + inMapConsumer.eachMapping(m => { + if (inMapFirstItem) { + return + } + inMapFirstItem = m + }) + } + resMapConsumer.eachMapping(res => { if (res.originalLine == null) { return @@ -230,21 +251,44 @@ export function mapColumns( const map = codeMaps.get(res.name) if (!map) { - return null + return + } + + let inMapOrigin: MappedPosition | null = null + if (inMapConsumer) { + inMapOrigin = inMapConsumer.originalPositionFor({ + line: res.originalLine, + column: res.originalColumn - 1 + }) + if (inMapOrigin.source == null) { + inMapOrigin = null + return + } } const mapConsumer = new SourceMapConsumer(map) mapConsumer.eachMapping(m => { mergedMapGenerator.addMapping({ original: { - line: res.originalLine, - column: res.originalColumn + line: inMapFirstItem + ? inMapFirstItem.originalLine + res.originalLine - 2 + : res.originalLine, + column: inMapFirstItem + ? inMapFirstItem.originalColumn + res.originalColumn + : res.originalColumn }, generated: { - line: res.originalLine, - column: res.originalColumn + m.generatedColumn // map column with message format compilation code map + line: inMapFirstItem + ? inMapFirstItem.generatedLine + res.originalLine - 2 + : res.originalLine, + // map column with message format compilation code map + column: inMapFirstItem + ? inMapFirstItem.generatedColumn + + res.originalColumn + + m.generatedColumn + : res.originalColumn + m.generatedColumn }, - source: res.source, + source: inMapOrigin ? inMapOrigin.source : res.source, name: m.name // message format compilation code }) }) @@ -252,17 +296,21 @@ export function mapColumns( // eslint-disable-next-line @typescript-eslint/no-explicit-any const generator = mergedMapGenerator as any + // const targetConsumer = inMapConsumer || resMapConsumer + const targetConsumer = inMapConsumer || resMapConsumer // eslint-disable-next-line @typescript-eslint/no-explicit-any - ;(resMapConsumer as any).sources.forEach((sourceFile: string) => { + ;(targetConsumer as any).sources.forEach((sourceFile: string) => { generator._sources.add(sourceFile) - const sourceContent = resMapConsumer.sourceContentFor(sourceFile) + const sourceContent = targetConsumer.sourceContentFor(sourceFile) if (sourceContent != null) { mergedMapGenerator.setSourceContent(sourceFile, sourceContent) } }) - generator._sourceRoot = resMap.sourceRoot - generator._file = resMap.file + generator._sourceRoot = inSourceMap + ? inSourceMap.sourceRoot + : resMap.sourceRoot + generator._file = inSourceMap ? inSourceMap.file : resMap.file return generator.toJSON() } diff --git a/src/generator/json.ts b/src/generator/json.ts index 95316af..0caab18 100644 --- a/src/generator/json.ts +++ b/src/generator/json.ts @@ -7,7 +7,7 @@ import { isString } from '@intlify/shared' import { createCodeGenerator, generateMessageFunction, - mapColumns + mapLinesColumns } from './codegen' import { RawSourceMap } from 'source-map' @@ -17,7 +17,11 @@ import type { CodeGenOptions, CodeGenerator, CodeGenResult } from './codegen' export function generate( targetSource: string | Buffer, { + type = 'plain', filename = 'vue-i18n-loader.json', + inSourceMap = undefined, + locale = '', + isGlobal = false, sourceMap = false, env = 'development', forceStringify = false @@ -32,8 +36,12 @@ export function generate( const value = target const options = { + type, source: value, sourceMap, + locale, + isGlobal, + inSourceMap, env, filename, forceStringify @@ -44,8 +52,15 @@ export function generate( const codeMaps = generateNode(generator, ast, options) 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 - ? mapColumns((map as any).toJSON(), codeMaps) || null // eslint-disable-line @typescript-eslint/no-explicit-any + ? mapLinesColumns((map as any).toJSON(), codeMaps, inSourceMap) || null // eslint-disable-line @typescript-eslint/no-explicit-any : null return { ast, @@ -63,12 +78,30 @@ function generateNode( const itemsCountStack = [] as number[] const { forceStringify } = generator.context() const codeMaps = new Map() + const { type, sourceMap, isGlobal, locale } = options traverseNodes(node, { enterNode(node: JSONNode, parent: JSONNode) { switch (node.type) { case 'Program': - generator.push(`export default `) + if (type === 'plain') { + generator.push(`export default `) + } else { + // for 'sfc' + const variableName = + type === 'sfc' ? (!isGlobal ? '__i18n' : '__i18nGlobal') : '' + const localeName = + type === 'sfc' ? (locale != null ? locale : `""`) : '' + generator.push(`export default function (Component) {`) + generator.indent() + generator.pushline( + `Component.${variableName} = Component.${variableName} || []` + ) + generator.push(`Component.${variableName}.push({`) + generator.indent() + generator.pushline(`"locale": ${JSON.stringify(localeName)},`) + generator.push(`"resource": `) + } break case 'JSONObjectExpression': generator.push(`{`) @@ -91,14 +124,14 @@ function generateNode( if (isString(value)) { generator.push(`${JSON.stringify(name)}: `) const { code, map } = generateMessageFunction(value, options) - options.sourceMap && map != null && codeMaps.set(value, map) + sourceMap && map != null && codeMaps.set(value, map) generator.push(`${code}`, node.value, value) } else { if (forceStringify) { const strValue = JSON.stringify(value) generator.push(`${JSON.stringify(name)}: `) const { code, map } = generateMessageFunction(strValue, options) - options.sourceMap && map != null && codeMaps.set(strValue, map) + sourceMap && map != null && codeMaps.set(strValue, map) generator.push(`${code}`, node.value, strValue) } else { generator.push( @@ -130,7 +163,7 @@ function generateNode( const value = node.value if (isString(value)) { const { code, map } = generateMessageFunction(value, options) - options.sourceMap && map != null && codeMaps.set(value, map) + sourceMap && map != null && codeMaps.set(value, map) generator.push(`${code}`, node, value) } else { if (forceStringify) { @@ -139,9 +172,7 @@ function generateNode( strValue, options ) - options.sourceMap && - map != null && - codeMaps.set(strValue, map) + sourceMap && map != null && codeMaps.set(strValue, map) generator.push(`${code}`, node, strValue) } else { generator.push(`${JSON.stringify(value)}`) @@ -158,6 +189,14 @@ function generateNode( }, leaveNode(node: JSONNode, parent: JSONNode) { switch (node.type) { + case 'Program': + if (type === 'sfc') { + generator.deindent() + generator.push(`})`) + generator.deindent() + generator.pushline(`}`) + } + break case 'JSONObjectExpression': if (propsCountStack[propsCountStack.length - 1] === 0) { propsCountStack.pop() diff --git a/src/generator/yaml.ts b/src/generator/yaml.ts index 1ab0dd1..889ab08 100644 --- a/src/generator/yaml.ts +++ b/src/generator/yaml.ts @@ -6,7 +6,7 @@ import { isString } from '@intlify/shared' import { createCodeGenerator, generateMessageFunction, - mapColumns + mapLinesColumns } from './codegen' import { parseYAML, traverseNodes } from 'yaml-eslint-parser' import { RawSourceMap } from 'source-map' @@ -17,7 +17,11 @@ import type { CodeGenOptions, CodeGenerator, CodeGenResult } from './codegen' export function generate( targetSource: string | Buffer, { + type = 'plain', filename = 'vue-i18n-loader.yaml', + inSourceMap = undefined, + locale = '', + isGlobal = false, sourceMap = false, env = 'development', forceStringify = false @@ -28,8 +32,12 @@ export function generate( : targetSource const options = { + type, source: value, sourceMap, + locale, + isGlobal, + inSourceMap, env, filename, forceStringify @@ -40,8 +48,9 @@ export function generate( const codeMaps = generateNode(generator, ast, options) const { code, map } = generator.context() + // prettier-ignore const newMap = map - ? mapColumns((map as any).toJSON(), codeMaps) || null // eslint-disable-line @typescript-eslint/no-explicit-any + ? mapLinesColumns((map as any).toJSON(), codeMaps, inSourceMap) || null // eslint-disable-line @typescript-eslint/no-explicit-any : null return { ast, @@ -59,12 +68,29 @@ function generateNode( const itemsCountStack = [] as number[] const { forceStringify } = generator.context() const codeMaps = new Map() + const { type, sourceMap, isGlobal, locale } = options traverseNodes(node, { enterNode(node: YAMLNode, parent: YAMLNode) { switch (node.type) { case 'Program': - generator.push(`export default `) + if (type === 'plain') { + generator.push(`export default `) + } else { + const variableName = + type === 'sfc' ? (!isGlobal ? '__i18n' : '__i18nGlobal') : '' + const localeName = + type === 'sfc' ? (locale != null ? locale : `""`) : '' + generator.push(`export default function (Component) {`) + generator.indent() + generator.pushline( + `Component.${variableName} = Component.${variableName} || []` + ) + generator.push(`Component.${variableName}.push({`) + generator.indent() + generator.pushline(`"locale": ${JSON.stringify(localeName)},`) + generator.push(`"resource": `) + } break case 'YAMLMapping': generator.push(`{`) @@ -87,14 +113,14 @@ function generateNode( if (isString(value)) { generator.push(`${JSON.stringify(name)}: `) const { code, map } = generateMessageFunction(value, options) - options.sourceMap && map != null && codeMaps.set(value, map) + sourceMap && map != null && codeMaps.set(value, map) generator.push(`${code}`, node.value, value) } else { if (forceStringify) { const strValue = JSON.stringify(value) generator.push(`${JSON.stringify(name)}: `) const { code, map } = generateMessageFunction(strValue, options) - options.sourceMap && map != null && codeMaps.set(strValue, map) + sourceMap && map != null && codeMaps.set(strValue, map) generator.push(`${code}`, node.value, strValue) } else { generator.push( @@ -126,7 +152,7 @@ function generateNode( const value = node.value if (isString(value)) { const { code, map } = generateMessageFunction(value, options) - options.sourceMap && map != null && codeMaps.set(value, map) + sourceMap && map != null && codeMaps.set(value, map) generator.push(`${code}`, node, value) } else { if (forceStringify) { @@ -135,9 +161,7 @@ function generateNode( strValue, options ) - options.sourceMap && - map != null && - codeMaps.set(strValue, map) + sourceMap && map != null && codeMaps.set(strValue, map) generator.push(`${code}`, node, strValue) } else { generator.push(`${JSON.stringify(value)}`) @@ -154,6 +178,14 @@ function generateNode( }, leaveNode(node: YAMLNode, parent: YAMLNode) { switch (node.type) { + case 'Program': + if (type === 'sfc') { + generator.deindent() + generator.push(`})`) + generator.deindent() + generator.push(`}`) + } + break case 'YAMLMapping': if (propsCountStack[propsCountStack.length - 1] === 0) { propsCountStack.pop() diff --git a/src/index.ts b/src/index.ts index adb87db..89a3e10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,9 @@ import path from 'path' import webpack from 'webpack' import loaderUtils from 'loader-utils' -import { parse } from 'querystring' +import { parse, ParsedUrlQuery } from 'querystring' import { RawSourceMap } from 'source-map' -import { isEmptyObject } from '@intlify/shared' -import { generateCode } from './gen' +import { isEmptyObject, isString } from '@intlify/shared' import { generateJSON, generateYAML } from './generator' import type { CodeGenOptions, DevEnv } from './generator/codegen' @@ -15,49 +14,74 @@ const loader: webpack.loader.Loader = function ( sourceMap: RawSourceMap | undefined ): void { const loaderContext = this // eslint-disable-line @typescript-eslint/no-this-alias + const query = parse(loaderContext.resourceQuery) + const options = getOptions(loaderContext, query, sourceMap) as CodeGenOptions + // console.log('query', this.resourcePath, this.resourceQuery, query, source) + const langInfo = !isEmptyObject(query) + ? isString(query.lang) + ? query.lang + : 'json' + : path.parse(loaderContext.resourcePath).ext + + try { + this.cacheable && this.cacheable() + // if (sourceMap) { + // console.log('in map', sourceMap) + // } + // if (sourceMap) { + // const s = new SourceMapConsumer(sourceMap) + // console.log('sourcemap raw', sourceMap) + // s.eachMapping(m => { + // console.log(m) + // }) + // } + const generate = /json5?/.test(langInfo) ? generateJSON : generateYAML + const { code, map } = generate(source, options) + // console.log('code', code) + this.callback(null, code, map) + } catch (err) { + this.emitError(`[vue-i18n-loader]: ${err.message}`) + } +} + +function getOptions( + loaderContext: webpack.loader.LoaderContext, + query: ParsedUrlQuery, + inSourceMap?: RawSourceMap +): Record { const loaderOptions = loaderUtils.getOptions(loaderContext) || {} - const query = parse(this.resourceQuery) + const { resourcePath: filename, mode, sourceMap } = loaderContext + const { forceStringify } = loaderOptions as VueI18nLoaderOptions - if (!isEmptyObject(query)) { - try { - this.cacheable && this.cacheable() - const code = `${generateCode( - source, - query, - loaderOptions as VueI18nLoaderOptions - )}` - this.callback(null, code, sourceMap) - } catch (err) { - this.emitError(`[vue-i18n-loader]: ${err.message}`) + const baseOptions = { + filename, + sourceMap, + inSourceMap, + forceStringify, + env: mode as DevEnv, + onWarn: (msg: string): void => { + loaderContext.emitWarning( + `[vue-i18n-loader]: ${loaderContext.resourcePath} ${msg}` + ) + }, + onError: (msg: string): void => { + loaderContext.emitError( + `[vue-i18n-loader]: ${loaderContext.resourcePath} ${msg}` + ) } - } else { - const { ext } = path.parse(loaderContext.resourcePath) - const { resourcePath: filename, mode } = loaderContext - const { forceStringify } = loaderOptions as VueI18nLoaderOptions + } - if (/\.(json5?|ya?ml)/.test(ext)) { - const options: CodeGenOptions = { - filename, - forceStringify, - sourceMap: loaderContext.sourceMap, - env: mode as DevEnv, - onWarn: (msg: string): void => { - loaderContext.emitWarning( - `[vue-i18n-loader]: ${loaderContext.resourcePath} ${msg}` - ) - }, - onError: (msg: string): void => { - loaderContext.emitError( - `[vue-i18n-loader]: ${loaderContext.resourcePath} ${msg}` - ) - } - } - const generate = /\.json5?/.test(ext) ? generateJSON : generateYAML - const { code, map } = generate(source, options) - this.callback(null, code, map) - } else { - this.callback(null, source, sourceMap) - } + if (!isEmptyObject(query)) { + return Object.assign(baseOptions, { + type: 'sfc', + locale: isString(query.locale) ? query.locale : '', + isGlobal: query.global != null + }) + } else { + return Object.assign(baseOptions, { + type: 'plain', + isGlobal: false + }) } } diff --git a/src/options.ts b/src/options.ts index a0f73b9..0349376 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,4 +1,3 @@ export type VueI18nLoaderOptions = { - preCompile?: boolean forceStringify?: boolean } diff --git a/test/__snapshots__/custom-block.test.ts.snap b/test/__snapshots__/custom-block.test.ts.snap new file mode 100644 index 0000000..1bb159f --- /dev/null +++ b/test/__snapshots__/custom-block.test.ts.snap @@ -0,0 +1,169 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`basic 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`global 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`global and local 1`] = ` +Array [ + Object { + "locale": "ja", + "resource": Object { + "hello": [Function], + }, + }, +] +`; + +exports[`global and local 2`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`import 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`json5 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`locale attr 1`] = ` +Array [ + Object { + "locale": "ja", + "resource": Object { + "hello": [Function], + }, + }, +] +`; + +exports[`locale attr and basic 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, + Object { + "locale": "ja", + "resource": Object { + "hello": [Function], + }, + }, +] +`; + +exports[`locale attr and import 1`] = ` +Array [ + Object { + "locale": "en", + "resource": Object { + "hello": [Function], + }, + }, +] +`; + +exports[`multiple 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, + Object { + "locale": "", + "resource": Object { + "ja": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`special characters 1`] = ` +Array [ + Object { + "locale": "", + "resource": Object { + "en": Object { + "hello": [Function], + }, + }, + }, +] +`; + +exports[`yaml 1`] = ` +Array [ + Object { + "locale": "en", + "resource": Object { + "hello": [Function], + }, + }, + Object { + "locale": "ja", + "resource": Object { + "hello": [Function], + }, + }, +] +`; diff --git a/test/__snapshots__/fundamental.test.ts.snap b/test/__snapshots__/fundamental.test.ts.snap deleted file mode 100644 index a471da3..0000000 --- a/test/__snapshots__/fundamental.test.ts.snap +++ /dev/null @@ -1,137 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`basic 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, -] -`; - -exports[`global 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello global!", - }, - }, -] -`; - -exports[`global and local 1`] = ` -Array [ - Object { - "ja": Object { - "hello": "hello local!", - }, - }, -] -`; - -exports[`global and local 2`] = ` -Array [ - Object { - "en": Object { - "hello": "hello global!", - }, - }, -] -`; - -exports[`import 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, -] -`; - -exports[`json5 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, -] -`; - -exports[`locale attr 1`] = ` -Array [ - Object { - "ja": Object { - "hello": "こんにちは、世界!", - }, - }, -] -`; - -exports[`locale attr and basic 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, - Object { - "ja": Object { - "hello": "こんにちは、世界!", - }, - }, -] -`; - -exports[`locale attr and import 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, -] -`; - -exports[`multiple 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, - Object { - "ja": Object { - "hello": "こんにちは、世界!", - }, - }, -] -`; - -exports[`special characters 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello -great \\"world\\"", - }, - }, -] -`; - -exports[`yaml 1`] = ` -Array [ - Object { - "en": Object { - "hello": "hello world!", - }, - }, - Object { - "ja": Object { - "hello": "こんにちは、世界!", - }, - }, -] -`; diff --git a/test/custom-block.test.ts b/test/custom-block.test.ts new file mode 100644 index 0000000..2cf5a6e --- /dev/null +++ b/test/custom-block.test.ts @@ -0,0 +1,117 @@ +import { bundleAndRun } from './utils' +import { createMessageContext } from '@intlify/runtime' + +test('basic', async () => { + const { module } = await bundleAndRun('basic.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual('hello world!') +}) + +test('special characters', async () => { + const { module } = await bundleAndRun('special-char.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual( + 'hello\ngreat\t"world"' + ) +}) + +test('multiple', async () => { + const { module } = await bundleAndRun('multiple.vue') + expect(module.__i18n).toMatchSnapshot() + expect(module.__i18n.length).toEqual(2) + let i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.ja.hello(createMessageContext())).toEqual( + 'こんにちは、世界!' + ) + i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual('hello world!') +}) + +test('import', async () => { + const { module } = await bundleAndRun('import.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual('hello world!') +}) + +test('locale attr', async () => { + const { module } = await bundleAndRun('locale.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('ja') + expect(i18n.resource.hello(createMessageContext())).toEqual( + 'こんにちは、世界!' + ) +}) + +test('locale attr and basic', async () => { + const { module } = await bundleAndRun('locale-mix.vue') + expect(module.__i18n).toMatchSnapshot() + let i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('ja') + expect(i18n.resource.hello(createMessageContext())).toEqual( + 'こんにちは、世界!' + ) + i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual('hello world!') +}) + +test('locale attr and import', async () => { + const { module } = await bundleAndRun('locale-import.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('en') + expect(i18n.resource.hello(createMessageContext())).toEqual('hello world!') +}) + +test('yaml', async () => { + const { module } = await bundleAndRun('yaml.vue') + expect(module.__i18n).toMatchSnapshot() + let i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('ja') + expect(i18n.resource.hello(createMessageContext())).toEqual( + 'こんにちは、世界!' + ) + i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('en') + expect(i18n.resource.hello(createMessageContext())).toEqual('hello world!') +}) + +test('json5', async () => { + const { module } = await bundleAndRun('json5.vue') + expect(module.__i18n).toMatchSnapshot() + const i18n = module.__i18n.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual('hello world!') +}) + +test('global', async () => { + const { module } = await bundleAndRun('global.vue') + expect(module.__i18n).toBeUndefined() + expect(module.__i18nGlobal).toMatchSnapshot() + const i18n = module.__i18nGlobal.pop() + expect(i18n.locale).toEqual('') + expect(i18n.resource.en.hello(createMessageContext())).toEqual( + 'hello global!' + ) +}) + +test('global and local', async () => { + const { module } = await bundleAndRun('global-mix.vue') + expect(module.__i18n).toMatchSnapshot() + expect(module.__i18nGlobal).toMatchSnapshot() + const l = module.__i18n.pop() + expect(l.locale).toEqual('ja') + expect(l.resource.hello(createMessageContext())).toEqual('hello local!') + const g = module.__i18nGlobal.pop() + expect(g.locale).toEqual('') + expect(g.resource.en.hello(createMessageContext())).toEqual('hello global!') +}) diff --git a/test/fundamental.test.ts b/test/fundamental.test.ts deleted file mode 100644 index cc7ddd8..0000000 --- a/test/fundamental.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { bundleAndRun, bundle } from './utils' -import { baseCompile } from '@intlify/message-compiler' -import { MessageFunction } from '@intlify/runtime' -import prettier from 'prettier' - -test('basic', async () => { - const { module } = await bundleAndRun('basic.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('special characters', async () => { - const { module } = await bundleAndRun('special-char.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('multiple', async () => { - const { module } = await bundleAndRun('multiple.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('import', async () => { - const { module } = await bundleAndRun('import.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('locale attr', async () => { - const { module } = await bundleAndRun('locale.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('locale attr and basic', async () => { - const { module } = await bundleAndRun('locale-mix.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('locale attr and import', async () => { - const { module } = await bundleAndRun('locale-import.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('yaml', async () => { - const { module } = await bundleAndRun('yaml.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('json5', async () => { - const { module } = await bundleAndRun('json5.vue') - expect(module.__i18n).toMatchSnapshot() -}) - -test('pre compile', async () => { - const options: prettier.Options = { parser: 'babel' } - const { module } = await bundleAndRun('compile.vue', bundle, { - preCompile: true - }) - const { functions } = module.__i18n() - for (const [key, value] of Object.entries(functions)) { - const msg = value as MessageFunction - const data = JSON.parse(key) - const result = baseCompile(data.s, { mode: 'arrow' }) - expect(prettier.format(msg.toString(), options)).toMatch( - prettier.format(result.code, options) - ) - } -}) - -test('global', async () => { - const { module } = await bundleAndRun('global.vue') - expect(module.__i18n).toBeUndefined() - expect(module.__i18nGlobal).toMatchSnapshot() -}) - -test('global and local', async () => { - const { module } = await bundleAndRun('global-mix.vue') - expect(module.__i18n).toMatchSnapshot() - expect(module.__i18nGlobal).toMatchSnapshot() -}) diff --git a/test/generator/__snapshots__/codegen.test.ts.snap b/test/generator/__snapshots__/codegen.test.ts.snap index 6cdffcd..3a46f9f 100644 --- a/test/generator/__snapshots__/codegen.test.ts.snap +++ b/test/generator/__snapshots__/codegen.test.ts.snap @@ -60,7 +60,7 @@ Object { "start": 0, "type": 0, }, - "code": "(()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello\\"])};fn.source=\\"hello\\";return fn})()", + "code": "(()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello\\"])};fn.source=\\"hello\\";return fn;})()", "map": Object { "mappings": "mEAAAA", "names": Array [ diff --git a/test/generator/__snapshots__/json.test.ts.snap b/test/generator/__snapshots__/json.test.ts.snap index ab6a51c..308c18d 100644 --- a/test/generator/__snapshots__/json.test.ts.snap +++ b/test/generator/__snapshots__/json.test.ts.snap @@ -2,30 +2,30 @@ exports[`complex: code 1`] = ` "export default { - \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn})(), + \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn;})(), \\"nested\\": { - \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn})(), + \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn;})(), \\"more\\": { - \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn})() + \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn;})() }, - \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn})() + \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn;})() }, - \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn})(), - \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn})(), - \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn})(), - \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn})(), - \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn})(), - \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn})(), - \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn})(), + \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn;})(), + \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn;})(), + \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn;})(), + \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn;})(), + \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn;})(), + \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn;})(), + \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn;})(), \\"errors\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn})(), - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn})() + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn;})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn;})() ], \\"complex\\": { \\"warnings\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn;})(), { - \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn})() + \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn;})() } ] } @@ -98,10 +98,10 @@ Object { exports[`force stringify: code 1`] = ` "export default { - \\"trueValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"true\\"])};fn.source=\\"true\\";return fn})(), - \\"falseValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"false\\"])};fn.source=\\"false\\";return fn})(), - \\"nullValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"null\\"])};fn.source=\\"null\\";return fn})(), - \\"numberValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"1\\"])};fn.source=\\"1\\";return fn})() + \\"trueValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"true\\"])};fn.source=\\"true\\";return fn;})(), + \\"falseValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"false\\"])};fn.source=\\"false\\";return fn;})(), + \\"nullValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"null\\"])};fn.source=\\"null\\";return fn;})(), + \\"numberValue\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"1\\"])};fn.source=\\"1\\";return fn;})() }" `; @@ -132,13 +132,13 @@ Object { exports[`simple: code 1`] = ` "export default { - \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn})(), - \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn})(), - \\"named\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"hi, \\", _interpolate(_named(\\"name\\")), \\" !\\"])};fn.source=\\"hi, {name} !\\";return fn})(), - \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn})(), - \\"literal\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi, \\", \\"kazupon\\", \\" !\\"])};fn.source=\\"hi, { 'kazupon' } !\\";return fn})(), - \\"linked\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked } = ctx;return _normalize([\\"hi, \\", _linked(\\"name\\"), \\" !\\"])};fn.source=\\"hi, @:name !\\";return fn})(), - \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn})() + \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn;})(), + \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn;})(), + \\"named\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"hi, \\", _interpolate(_named(\\"name\\")), \\" !\\"])};fn.source=\\"hi, {name} !\\";return fn;})(), + \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn;})(), + \\"literal\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi, \\", \\"kazupon\\", \\" !\\"])};fn.source=\\"hi, { 'kazupon' } !\\";return fn;})(), + \\"linked\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked } = ctx;return _normalize([\\"hi, \\", _linked(\\"name\\"), \\" !\\"])};fn.source=\\"hi, @:name !\\";return fn;})(), + \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn;})() }" `; diff --git a/test/generator/__snapshots__/json5.test.ts.snap b/test/generator/__snapshots__/json5.test.ts.snap index 89a8d6b..15f7630 100644 --- a/test/generator/__snapshots__/json5.test.ts.snap +++ b/test/generator/__snapshots__/json5.test.ts.snap @@ -2,30 +2,30 @@ exports[`json5: code 1`] = ` "export default { - \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn})(), + \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn;})(), \\"nested\\": { - \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn})(), + \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn;})(), \\"more\\": { - \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn})() + \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn;})() }, - \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn})() + \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn;})() }, - \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn})(), - \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn})(), - \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn})(), - \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn})(), - \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn})(), - \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn})(), - \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn})(), + \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn;})(), + \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn;})(), + \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn;})(), + \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn;})(), + \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn;})(), + \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn;})(), + \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn;})(), \\"errors\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn})(), - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn})() + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn;})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn;})() ], \\"complex\\": { \\"warnings\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn;})(), { - \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn})() + \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn;})() } ] } diff --git a/test/generator/__snapshots__/yaml.test.ts.snap b/test/generator/__snapshots__/yaml.test.ts.snap index 96464ad..c6cc3fc 100644 --- a/test/generator/__snapshots__/yaml.test.ts.snap +++ b/test/generator/__snapshots__/yaml.test.ts.snap @@ -2,30 +2,30 @@ exports[`yaml: code 1`] = ` "export default { - \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn})(), + \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn;})(), \\"nested\\": { - \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn})(), + \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn;})(), \\"more\\": { - \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn})() + \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn;})() }, - \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn})() + \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn;})() }, - \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn})(), - \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn})(), - \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn})(), - \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn})(), - \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn})(), - \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn})(), - \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn})(), + \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn;})(), + \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn;})(), + \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn;})(), + \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn;})(), + \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn;})(), + \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn;})(), + \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn;})(), \\"errors\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn})(), - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn})() + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn;})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn;})() ], \\"complex\\": { \\"warnings\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn;})(), { - \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn})() + \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn;})() } ] } @@ -92,30 +92,30 @@ complex: exports[`yml: code 1`] = ` "export default { - \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn})(), + \\"hi\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hi there!\\"])};fn.source=\\"hi there!\\";return fn;})(), \\"nested\\": { - \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn})(), + \\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"hello world!\\"])};fn.source=\\"hello world!\\";return fn;})(), \\"more\\": { - \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn})() + \\"plural\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, linked: _linked, interpolate: _interpolate, list: _list, named: _named, plural: _plural } = ctx;return _plural([_normalize([_linked(\\"no apples\\", \\"caml\\")]), _normalize([_interpolate(_list(0)), \\" apple\\"]), _normalize([_interpolate(_named(\\"n\\")), \\" apples\\"])])};fn.source=\\"@.caml:{'no apples'} | {0} apple | {n} apples\\";return fn;})() }, - \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn})() + \\"list\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, list: _list } = ctx;return _normalize([\\"hi, \\", _interpolate(_list(0)), \\" !\\"])};fn.source=\\"hi, {0} !\\";return fn;})() }, - \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn})(), - \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn})(), - \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn})(), - \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn})(), - \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn})(), - \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn})(), - \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn})(), + \\"こんにちは\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは!\\"])};fn.source=\\"こんにちは!\\";return fn;})(), + \\"single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"I don't know!\\"])};fn.source=\\"I don't know!\\";return fn;})(), + \\"emoji\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"😺\\"])};fn.source=\\"😺\\";return fn;})(), + \\"unicode\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"A\\"])};fn.source=\\"A\\";return fn;})(), + \\"unicode-escape\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\u0041\\"])};fn.source=\\"\\\\\\\\u0041\\";return fn;})(), + \\"backslash-single-quote\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\'\\"])};fn.source=\\"\\\\\\\\'\\";return fn;})(), + \\"backslash-backslash\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"\\\\\\\\\\\\\\\\\\"])};fn.source=\\"\\\\\\\\\\\\\\\\\\";return fn;})(), \\"errors\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn})(), - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn})() + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1001\\"])};fn.source=\\"ERROR1001\\";return fn;})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"ERROR1002\\"])};fn.source=\\"ERROR1002\\";return fn;})() ], \\"complex\\": { \\"warnings\\": [ - (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn})(), + (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"NOTE: This is warning\\"])};fn.source=\\"NOTE: This is warning\\";return fn;})(), { - \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn})() + \\"named-waring\\": (()=>{const fn=(ctx) => {const { normalize: _normalize, interpolate: _interpolate, named: _named } = ctx;return _normalize([\\"this is \\", _interpolate(_named(\\"type\\")), \\" warining\\"])};fn.source=\\"this is {type} warining\\";return fn;})() } ] } diff --git a/test/pre-compilation.test.ts b/test/resource-compilation.test.ts similarity index 100% rename from test/pre-compilation.test.ts rename to test/resource-compilation.test.ts diff --git a/test/utils.ts b/test/utils.ts index 7802bc0..f19bb28 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -22,7 +22,64 @@ type BundleResolveResolve = BundleResolve & { export function bundle(fixture: string, options = {}): Promise { const baseConfig: webpack.Configuration = { mode: 'development', - devtool: false, + devtool: 'source-map', + entry: path.resolve(__dirname, './fixtures/entry.js'), + resolve: { + alias: { + '~target': path.resolve(__dirname, './fixtures', fixture) + } + }, + output: { + path: '/', + filename: 'bundle.js' + }, + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader' + }, + { + resourceQuery: /blockType=i18n/, + type: 'javascript/auto', + use: [ + { + loader: path.resolve(__dirname, '../src/index.ts'), + options + } + ] + } + ] + }, + plugins: [new VueLoaderPlugin()] + } + + const config = merge({}, baseConfig) + const compiler = webpack(config) + + const mfs = new memoryfs() // eslint-disable-line + compiler.outputFileSystem = mfs + + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) { + return reject(err) + } + if (stats.hasErrors()) { + return reject(new Error(stats.toJson().errors.join(' | '))) + } + resolve({ code: mfs.readFileSync('/bundle.js').toString(), stats }) + }) + }) +} + +export function bundleEx( + fixture: string, + options = {} +): Promise { + const baseConfig: webpack.Configuration = { + mode: 'development', + devtool: 'source-map', entry: path.resolve(__dirname, './fixtures/entry.js'), resolve: { alias: { @@ -39,6 +96,17 @@ export function bundle(fixture: string, options = {}): Promise { test: /\.vue$/, loader: 'vue-loader' }, + { + test: /\.(json5?|ya?ml)$/, + type: 'javascript/auto', + include: [path.resolve(__dirname, './fixtures/locales')], + use: [ + { + loader: path.resolve(__dirname, '../src/index.ts'), + options + } + ] + }, { resourceQuery: /blockType=i18n/, type: 'javascript/auto', diff --git a/yarn.lock b/yarn.lock index 445223d..34d6b72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -333,43 +333,43 @@ dependencies: "@hapi/hoek" "^8.3.0" -"@intlify/core-base@9.0.0-beta.14", "@intlify/core-base@^9.0.0-beta.14": - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.0.0-beta.14.tgz#b190d1dd95d28977b26353c77121d2d84d15b7ee" - integrity sha512-ZX+JJvBtcdVZxrTg8oO6flXC965aURIvAeDOYT3DqlUWekHKQ2hUVc1J8SP7rzEgFUqDqCMrDMtv2gZNvxD2Aw== - dependencies: - "@intlify/message-compiler" "9.0.0-beta.14" - "@intlify/message-resolver" "9.0.0-beta.14" - "@intlify/runtime" "9.0.0-beta.14" - "@intlify/shared" "9.0.0-beta.14" - -"@intlify/message-compiler@9.0.0-beta.14", "@intlify/message-compiler@^9.0.0-beta.14": - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.0.0-beta.14.tgz#4b5a4467459c402e71652075e9d95e5d85e85588" - integrity sha512-fXgiQuLKsYINnzhnCQD3OJnT2/59HrPw8WWiG8MpuMSDcUkUXV4ie0DW+9x48QQqpel7TU11Lage3zuFxw27iQ== - dependencies: - "@intlify/message-resolver" "9.0.0-beta.14" - "@intlify/shared" "9.0.0-beta.14" +"@intlify/core-base@9.0.0-beta.15", "@intlify/core-base@^9.0.0-beta.15": + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.0.0-beta.15.tgz#038939c58daf1e71ff1653f9aa942013c60f80a7" + integrity sha512-afH2Cf+DvBs3FtJ5iHs7idP+1sHcZ4jsWhRzJu/BG6fLmthfMi13TUIItr1bdHBsB22M/syv3yq5gP305LCZ2A== + dependencies: + "@intlify/message-compiler" "9.0.0-beta.15" + "@intlify/message-resolver" "9.0.0-beta.15" + "@intlify/runtime" "9.0.0-beta.15" + "@intlify/shared" "9.0.0-beta.15" + +"@intlify/message-compiler@9.0.0-beta.15", "@intlify/message-compiler@^9.0.0-beta.15": + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.0.0-beta.15.tgz#8529070003a19036c45c2dce239afbac2e61f07b" + integrity sha512-N1bh5dxLIrBNGM99O1/Uxvyb1IYmHl+sYcae88BKB2T5pvOSDC18Oa52pLjM0PMDFpKbQN+m/SGgiRPPRkp0nQ== + dependencies: + "@intlify/message-resolver" "9.0.0-beta.15" + "@intlify/shared" "9.0.0-beta.15" source-map "0.6.1" -"@intlify/message-resolver@9.0.0-beta.14": - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@intlify/message-resolver/-/message-resolver-9.0.0-beta.14.tgz#f964706650d71ef06669c17c29cb60500ef2617a" - integrity sha512-/PPLMHX0w/ECkG+Fmne8L3WVVVwAp3tpdisf5G775b49Fspy4dKXqkLXM2NZKhdguJbXWHXXXiRkr+mlhq8G9Q== +"@intlify/message-resolver@9.0.0-beta.15": + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@intlify/message-resolver/-/message-resolver-9.0.0-beta.15.tgz#ac1bf84923e76bd4356daf8c2e36530601fc49a5" + integrity sha512-i64xy281nzNJbFSruc0EgFKJKSvXI/1bhYliWq0qtYi6Mv2sIXb4+arOB69YYYBKuDDNLBjSCNCuCmab62sP0A== -"@intlify/runtime@9.0.0-beta.14", "@intlify/runtime@^9.0.0-beta.14": - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@intlify/runtime/-/runtime-9.0.0-beta.14.tgz#367f6b09c991c71905b73224e238aa8382976b2d" - integrity sha512-WgFnXkniJIMrZfW1kcxejQ96te56r3us632/WME7SL1IYsGV+WErXiJMBrHf8ngwAy15WmfYoKWr32sRxWjCtw== +"@intlify/runtime@9.0.0-beta.15", "@intlify/runtime@^9.0.0-beta.15": + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@intlify/runtime/-/runtime-9.0.0-beta.15.tgz#1dc1ac3a24007d8146a55c179d6c98938cea3329" + integrity sha512-nMN1MVxg8ljSnYak+3iZ7WZ0fH7/YfpMWGYxMDiZaYdwGABracWHdJy/5ilzCKbt6qQ2xzSv6fIN+jr7wIMx6Q== dependencies: - "@intlify/message-compiler" "9.0.0-beta.14" - "@intlify/message-resolver" "9.0.0-beta.14" - "@intlify/shared" "9.0.0-beta.14" + "@intlify/message-compiler" "9.0.0-beta.15" + "@intlify/message-resolver" "9.0.0-beta.15" + "@intlify/shared" "9.0.0-beta.15" -"@intlify/shared@9.0.0-beta.14", "@intlify/shared@^9.0.0-beta.14": - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.0.0-beta.14.tgz#c221a45f666a40935f998d2e3c14451a516b9f56" - integrity sha512-f+Gev5GnrNLyieJCB6sB/qqe03XaMf6yJiAXG3IamZ4mp45oj2Lw9Oj3hAepDW36VUZK2wCIDmWy53pxJNIFpQ== +"@intlify/shared@9.0.0-beta.15", "@intlify/shared@^9.0.0-beta.15": + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.0.0-beta.15.tgz#beab8c49e0efd5cd5c4b9add2b71b9395e7cc7a1" + integrity sha512-f7qkzA8tUdGD5T7xUoNSiYA/qvPJSwu5DKt6xCrpitF2Ol+0QTLuk6jyZq81WKwo38DrTD/wjaM6STX/pF5zJg== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -780,11 +780,6 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== -"@types/flat@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/flat/-/flat-5.0.1.tgz#9d703bbfb59ad9ec9ce376bdeb93a0f85da27059" - integrity sha512-ykRODHi9G9exJdTZvQggsqCUtB7jqiwLHcXCjNMb7zgWx6Lc2bydIUYBG1+It6VXZVFaeROv6HqPjDCAsoPG3w== - "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" @@ -827,11 +822,6 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/js-yaml@^3.12.5": - version "3.12.5" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb" - integrity sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww== - "@types/jsdom@^16.2.5": version "16.2.5" resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.5.tgz#74ebad438741d249ecb416c5486dcde4217eb66c" @@ -846,11 +836,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== -"@types/json5@^0.0.30": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" - integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA== - "@types/loader-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/loader-utils/-/loader-utils-2.0.1.tgz#4073425aca25762099823f7b922e86599c2b85ec" @@ -896,7 +881,7 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== -"@types/prettier@^2.0.0", "@types/prettier@^2.1.5": +"@types/prettier@^2.0.0": version "2.1.5" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00" integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ== @@ -3772,11 +3757,6 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - flatted@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" @@ -5416,7 +5396,7 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1, js-yaml@^3.14.0: +js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -5501,7 +5481,7 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@2.x, json5@^2.1.2, json5@^2.1.3: +json5@2.x, json5@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== @@ -7064,7 +7044,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.0.0, prettier@^2.2.1: +prettier@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== @@ -9026,16 +9006,16 @@ vue-eslint-parser@^5.0.0: esquery "^1.0.1" lodash "^4.17.11" -vue-i18n@^9.0.0-beta.14: - version "9.0.0-beta.14" - resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.0.0-beta.14.tgz#2b2b89bc5371263d499bd17e3c0696bb9582c4f9" - integrity sha512-jPFtBXcRLuGc4YrI97JJuvj70BndqOhpQNJNthAIPC5x8eJIno44NkK/P769nqQWkbsnYO1sNwb+6oCO6QhaxA== +vue-i18n@^9.0.0-beta.15: + version "9.0.0-beta.15" + resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.0.0-beta.15.tgz#b6fa6ddad32f43f3c3c0ad7ec18580368692b143" + integrity sha512-DbSF82NZrLKZZ+UQSFWuSL6JfKS/yIZKpJbqc12byfUrlOw3rypJzoccfOPoEBgtVZy8/NrItU2dO2T0sL/UvQ== dependencies: - "@intlify/core-base" "9.0.0-beta.14" - "@intlify/shared" "9.0.0-beta.14" + "@intlify/core-base" "9.0.0-beta.15" + "@intlify/shared" "9.0.0-beta.15" "@vue/devtools-api" "^6.0.0-beta.2" -vue-loader@^16.1.0: +vue-loader@^16.1.2: version "16.1.2" resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-16.1.2.tgz#5c03b6c50d2a5f983c7ceba15c50d78ca2b298f4" integrity sha512-8QTxh+Fd+HB6fiL52iEVLKqE9N1JSlMXLR92Ijm6g8PZrwIxckgpqjPDWRP5TWxdiPaHR+alUWsnu1ShQOwt+Q==