Skip to content
This repository was archived by the owner on Dec 4, 2024. It is now read-only.

Commit 8689848

Browse files
committed
⭐ new: support transformer
1 parent 9aae6fb commit 8689848

19 files changed

+1290
-46
lines changed

jest-preset.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const preset = require('@vue/cli-plugin-unit-jest/jest-preset')
2+
const transformer = require('./lib/index').default
3+
4+
preset.transform['^.+\\.vue$'] = transformer
5+
6+
module.exports = preset

lib/generate.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"use strict";
2+
var __importDefault = (this && this.__importDefault) || function (mod) {
3+
return (mod && mod.__esModule) ? mod : { "default": mod };
4+
};
5+
Object.defineProperty(exports, "__esModule", { value: true });
6+
const json5_1 = __importDefault(require("json5"));
7+
const js_yaml_1 = __importDefault(require("js-yaml"));
8+
const debug_1 = require("debug");
9+
// constants
10+
exports.VUE_OPTIONS = '__vue__options__';
11+
exports.VUE_I18N_OPTION = '__i18n';
12+
const defaultLang = 'json';
13+
const debug = debug_1.debug('vue-i18n-jest');
14+
function generate(blocks) {
15+
const base = `${exports.VUE_OPTIONS}.${exports.VUE_I18N_OPTION} = []`;
16+
const codes = blocks.map(block => {
17+
if (block.type === 'i18n') {
18+
const lang = (block.attrs && block.attrs.lang) || defaultLang;
19+
// const lang = block.attrs?lang ?? defaultLang
20+
const data = convert(block.content, lang);
21+
const value = JSON.stringify(JSON.parse(data))
22+
.replace(/\u2028/g, '\\u2028')
23+
.replace(/\u2029/g, '\\u2029')
24+
.replace(/\\/g, '\\\\');
25+
return `${exports.VUE_OPTIONS}.${exports.VUE_I18N_OPTION}.push('${value.replace(/\u0027/g, '\\u0027')}')`;
26+
}
27+
else {
28+
return '';
29+
}
30+
});
31+
const code = [base].concat(codes).join('\n');
32+
debug('genrateCode', code);
33+
return code;
34+
}
35+
exports.default = generate;
36+
function convert(source, lang) {
37+
switch (lang) {
38+
case 'yaml':
39+
case 'yml':
40+
return JSON.stringify(js_yaml_1.default.safeLoad(source), undefined, '\t');
41+
case 'json5':
42+
return JSON.stringify(json5_1.default.parse(source));
43+
default:
44+
return source;
45+
}
46+
}

lib/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
"use strict";
2+
var __importDefault = (this && this.__importDefault) || function (mod) {
3+
return (mod && mod.__esModule) ? mod : { "default": mod };
4+
};
5+
Object.defineProperty(exports, "__esModule", { value: true });
6+
const transform_1 = __importDefault(require("./transform"));
7+
exports.default = transform_1.default;

lib/transform.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"use strict";
2+
var __importStar = (this && this.__importStar) || function (mod) {
3+
if (mod && mod.__esModule) return mod;
4+
var result = {};
5+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6+
result["default"] = mod;
7+
return result;
8+
};
9+
var __importDefault = (this && this.__importDefault) || function (mod) {
10+
return (mod && mod.__esModule) ? mod : { "default": mod };
11+
};
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
const vueJest = require('vue-jest'); // vue-jest does not also provide types ...
14+
const fs = __importStar(require("fs"));
15+
const path = __importStar(require("path"));
16+
const crypto_1 = require("crypto");
17+
const vue_template_compiler_1 = require("vue-template-compiler");
18+
const debug_1 = require("debug");
19+
const generate_1 = __importDefault(require("./generate"));
20+
const THIS_FILE = fs.readFileSync(__filename);
21+
const debug = debug_1.debug('vue-i18n-jest');
22+
debug(`getCacheKey: ${vueJest.getCacheKey ? 'vue-jest' : 'vue-i18n-jest'}`);
23+
function jestProcess(sourceText, sourcePath, config, options) {
24+
const { code, map } = vueJest.process(sourceText, sourcePath, config, options);
25+
const { customBlocks } = vue_template_compiler_1.parseComponent(sourceText, { pad: true });
26+
let coding = ';\n';
27+
if (customBlocks) {
28+
coding += generate_1.default(customBlocks);
29+
}
30+
const retCode = code + coding;
31+
debug('process', retCode);
32+
return { code: retCode, map };
33+
}
34+
function getCacheKey(fileData, filePath, configStr, options) {
35+
const hash = crypto_1.createHash('md5')
36+
.update(THIS_FILE)
37+
.update('\0', 'utf8')
38+
.update(fileData)
39+
.update('\0', 'utf8')
40+
.update(path.relative(options.rootDir, filePath))
41+
.update('\0', 'utf8')
42+
.update(configStr)
43+
.update('\0', 'utf8')
44+
.update(process.env.NODE_ENV || '')
45+
.digest('hex');
46+
debug('getCacheKey', hash);
47+
return hash;
48+
}
49+
const transformer = {
50+
getCacheKey: vueJest.getCacheKey || getCacheKey,
51+
process: jestProcess
52+
};
53+
exports.default = transformer;

package.json

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,21 @@
99
"bugs": {
1010
"url": "https://github.com/kazupon/vue-i18n-jest/issues"
1111
},
12+
"dependencies": {
13+
"@vue/cli-plugin-unit-jest": "^4.0.5",
14+
"debug": "^4.1.1",
15+
"js-yaml": "^3.13.1",
16+
"json5": "^2.1.1",
17+
"vue-jest": "^3.0.5",
18+
"vue-template-compiler": "^2.6.10"
19+
},
1220
"devDependencies": {
21+
"@types/debug": "^4.1.5",
1322
"@types/jest": "^24.0.23",
23+
"@types/js-yaml": "^3.12.1",
24+
"@types/json5": "^0.0.30",
25+
"@types/node": "^12.12.7",
26+
"@types/source-map": "^0.5.7",
1427
"@typescript-eslint/eslint-plugin": "^2.7.0",
1528
"@typescript-eslint/parser": "^2.7.0",
1629
"@typescript-eslint/typescript-estree": "^2.7.0",
@@ -22,13 +35,15 @@
2235
"jest": "^24.9.0",
2336
"opener": "^1.5.1",
2437
"ts-jest": "^24.1.0",
25-
"typescript": "^3.7.2"
38+
"typescript": "^3.7.2",
39+
"vue": "^2.6.10"
2640
},
2741
"engines": {
2842
"node": ">= 8"
2943
},
3044
"files": [
31-
"lib"
45+
"lib",
46+
"jest-preset.js"
3247
],
3348
"homepage": "https://github.com/kazupon/vue-i18n-jest#readme",
3449
"keywords": [
@@ -38,7 +53,11 @@
3853
"vue-i18n"
3954
],
4055
"license": "MIT",
41-
"main": "index.js",
56+
"main": "./lib/index.js",
57+
"peerDependencies": {
58+
"vue": "^2.x",
59+
"vue-template-compiler": "^2.x"
60+
},
4261
"repository": {
4362
"type": "git",
4463
"url": "git+https://github.com/kazupon/vue-i18n-jest.git"

src/generate.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import JSON5 from 'json5'
2+
import yaml from 'js-yaml'
3+
import { debug as Debug } from 'debug'
4+
5+
// type importing
6+
import { SFCBlock } from 'vue-template-compiler'
7+
8+
// constants
9+
export const VUE_OPTIONS = '__vue__options__'
10+
export const VUE_I18N_OPTION = '__i18n'
11+
const defaultLang = 'json'
12+
13+
const debug = Debug('vue-i18n-jest')
14+
15+
export default function generate (blocks: SFCBlock[]) {
16+
const base = `${VUE_OPTIONS}.${VUE_I18N_OPTION} = []`
17+
const codes = blocks.map(block => {
18+
if (block.type === 'i18n') {
19+
const lang = (block.attrs && block.attrs.lang) || defaultLang
20+
// const lang = block.attrs?lang ?? defaultLang
21+
const data = convert(block.content, lang)
22+
const value = JSON.stringify(JSON.parse(data))
23+
.replace(/\u2028/g, '\\u2028')
24+
.replace(/\u2029/g, '\\u2029')
25+
.replace(/\\/g, '\\\\')
26+
return `${VUE_OPTIONS}.${VUE_I18N_OPTION}.push('${value.replace(/\u0027/g, '\\u0027')}')`
27+
} else {
28+
return ''
29+
}
30+
})
31+
32+
const code = [base].concat(codes).join('\n')
33+
debug('genrateCode', code)
34+
return code
35+
}
36+
37+
function convert (source: string, lang: string): string {
38+
switch (lang) {
39+
case 'yaml':
40+
case 'yml':
41+
return JSON.stringify(yaml.safeLoad(source), undefined, '\t')
42+
case 'json5':
43+
return JSON.stringify(JSON5.parse(source))
44+
default:
45+
return source
46+
}
47+
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import transform from './transform'
2+
3+
export default transform

src/transform.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const vueJest = require('vue-jest') as Transformer // vue-jest does not also provide types ...
2+
import * as fs from 'fs'
3+
import * as path from 'path'
4+
import { createHash } from 'crypto'
5+
import { parseComponent } from 'vue-template-compiler'
6+
import { debug as Debug } from 'debug'
7+
import generate from './generate'
8+
9+
// impor jest types
10+
import { Config } from '@jest/types'
11+
import { RawSourceMap } from 'source-map'
12+
import { Transformer } from '@jest/transform'
13+
interface FixedRawSourceMap extends Omit<RawSourceMap, 'version'> {
14+
version: number
15+
}
16+
type TransformedSource = {
17+
code: string
18+
map?: FixedRawSourceMap | string | null
19+
}
20+
type TransformOptions = {
21+
instrument: boolean
22+
}
23+
type CacheKeyOptions = {
24+
config: Config.ProjectConfig
25+
instrument: boolean
26+
rootDir: string
27+
}
28+
29+
const THIS_FILE = fs.readFileSync(__filename)
30+
31+
const debug = Debug('vue-i18n-jest')
32+
33+
debug(`getCacheKey: ${vueJest.getCacheKey ? 'vue-jest' : 'vue-i18n-jest'}`)
34+
35+
function jestProcess (
36+
sourceText: string,
37+
sourcePath: Config.Path,
38+
config: Config.ProjectConfig,
39+
options?: TransformOptions
40+
): string | TransformedSource {
41+
const { code, map } = vueJest.process(sourceText, sourcePath, config, options) as TransformedSource
42+
const { customBlocks } = parseComponent(sourceText, { pad: true })
43+
44+
let coding = ';\n'
45+
if (customBlocks) {
46+
coding += generate(customBlocks)
47+
}
48+
49+
const retCode = code + coding
50+
debug('process', retCode)
51+
52+
return { code: retCode, map }
53+
}
54+
55+
function getCacheKey (
56+
fileData: string,
57+
filePath: Config.Path,
58+
configStr: string,
59+
options: CacheKeyOptions
60+
): string {
61+
const hash = createHash('md5')
62+
.update(THIS_FILE)
63+
.update('\0', 'utf8')
64+
.update(fileData)
65+
.update('\0', 'utf8')
66+
.update(path.relative(options.rootDir, filePath))
67+
.update('\0', 'utf8')
68+
.update(configStr)
69+
.update('\0', 'utf8')
70+
.update(process.env.NODE_ENV || '')
71+
.digest('hex')
72+
debug('getCacheKey', hash)
73+
return hash
74+
}
75+
76+
const transformer: Transformer = {
77+
getCacheKey: vueJest.getCacheKey || getCacheKey,
78+
process: jestProcess
79+
}
80+
81+
export default transformer
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`generate: default.vue 1`] = `
4+
"__vue__options__.__i18n = []
5+
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
6+
`;
7+
8+
exports[`generate: json.vue 1`] = `
9+
"__vue__options__.__i18n = []
10+
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
11+
`;
12+
13+
exports[`generate: json5.vue 1`] = `
14+
"__vue__options__.__i18n = []
15+
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
16+
`;
17+
18+
exports[`generate: yaml.vue 1`] = `
19+
"__vue__options__.__i18n = []
20+
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
21+
`;

0 commit comments

Comments
 (0)