Skip to content

Commit

Permalink
⭐ new: support transformer
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Nov 15, 2019
1 parent 9aae6fb commit 8689848
Show file tree
Hide file tree
Showing 19 changed files with 1,290 additions and 46 deletions.
6 changes: 6 additions & 0 deletions jest-preset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const preset = require('@vue/cli-plugin-unit-jest/jest-preset')
const transformer = require('./lib/index').default

preset.transform['^.+\\.vue$'] = transformer

module.exports = preset
46 changes: 46 additions & 0 deletions lib/generate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const json5_1 = __importDefault(require("json5"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const debug_1 = require("debug");
// constants
exports.VUE_OPTIONS = '__vue__options__';
exports.VUE_I18N_OPTION = '__i18n';
const defaultLang = 'json';
const debug = debug_1.debug('vue-i18n-jest');
function generate(blocks) {
const base = `${exports.VUE_OPTIONS}.${exports.VUE_I18N_OPTION} = []`;
const codes = blocks.map(block => {
if (block.type === 'i18n') {
const lang = (block.attrs && block.attrs.lang) || defaultLang;
// const lang = block.attrs?lang ?? defaultLang
const data = convert(block.content, lang);
const value = JSON.stringify(JSON.parse(data))
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
.replace(/\\/g, '\\\\');
return `${exports.VUE_OPTIONS}.${exports.VUE_I18N_OPTION}.push('${value.replace(/\u0027/g, '\\u0027')}')`;
}
else {
return '';
}
});
const code = [base].concat(codes).join('\n');
debug('genrateCode', code);
return code;
}
exports.default = generate;
function convert(source, lang) {
switch (lang) {
case 'yaml':
case 'yml':
return JSON.stringify(js_yaml_1.default.safeLoad(source), undefined, '\t');
case 'json5':
return JSON.stringify(json5_1.default.parse(source));
default:
return source;
}
}
6 changes: 6 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const transform_1 = __importDefault(require("./transform"));
exports.default = transform_1.default;
53 changes: 53 additions & 0 deletions lib/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vueJest = require('vue-jest'); // vue-jest does not also provide types ...
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const crypto_1 = require("crypto");
const vue_template_compiler_1 = require("vue-template-compiler");
const debug_1 = require("debug");
const generate_1 = __importDefault(require("./generate"));
const THIS_FILE = fs.readFileSync(__filename);
const debug = debug_1.debug('vue-i18n-jest');
debug(`getCacheKey: ${vueJest.getCacheKey ? 'vue-jest' : 'vue-i18n-jest'}`);
function jestProcess(sourceText, sourcePath, config, options) {
const { code, map } = vueJest.process(sourceText, sourcePath, config, options);
const { customBlocks } = vue_template_compiler_1.parseComponent(sourceText, { pad: true });
let coding = ';\n';
if (customBlocks) {
coding += generate_1.default(customBlocks);
}
const retCode = code + coding;
debug('process', retCode);
return { code: retCode, map };
}
function getCacheKey(fileData, filePath, configStr, options) {
const hash = crypto_1.createHash('md5')
.update(THIS_FILE)
.update('\0', 'utf8')
.update(fileData)
.update('\0', 'utf8')
.update(path.relative(options.rootDir, filePath))
.update('\0', 'utf8')
.update(configStr)
.update('\0', 'utf8')
.update(process.env.NODE_ENV || '')
.digest('hex');
debug('getCacheKey', hash);
return hash;
}
const transformer = {
getCacheKey: vueJest.getCacheKey || getCacheKey,
process: jestProcess
};
exports.default = transformer;
25 changes: 22 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@
"bugs": {
"url": "https://github.com/kazupon/vue-i18n-jest/issues"
},
"dependencies": {
"@vue/cli-plugin-unit-jest": "^4.0.5",
"debug": "^4.1.1",
"js-yaml": "^3.13.1",
"json5": "^2.1.1",
"vue-jest": "^3.0.5",
"vue-template-compiler": "^2.6.10"
},
"devDependencies": {
"@types/debug": "^4.1.5",
"@types/jest": "^24.0.23",
"@types/js-yaml": "^3.12.1",
"@types/json5": "^0.0.30",
"@types/node": "^12.12.7",
"@types/source-map": "^0.5.7",
"@typescript-eslint/eslint-plugin": "^2.7.0",
"@typescript-eslint/parser": "^2.7.0",
"@typescript-eslint/typescript-estree": "^2.7.0",
Expand All @@ -22,13 +35,15 @@
"jest": "^24.9.0",
"opener": "^1.5.1",
"ts-jest": "^24.1.0",
"typescript": "^3.7.2"
"typescript": "^3.7.2",
"vue": "^2.6.10"
},
"engines": {
"node": ">= 8"
},
"files": [
"lib"
"lib",
"jest-preset.js"
],
"homepage": "https://github.com/kazupon/vue-i18n-jest#readme",
"keywords": [
Expand All @@ -38,7 +53,11 @@
"vue-i18n"
],
"license": "MIT",
"main": "index.js",
"main": "./lib/index.js",
"peerDependencies": {
"vue": "^2.x",
"vue-template-compiler": "^2.x"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kazupon/vue-i18n-jest.git"
Expand Down
47 changes: 47 additions & 0 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import JSON5 from 'json5'
import yaml from 'js-yaml'
import { debug as Debug } from 'debug'

// type importing
import { SFCBlock } from 'vue-template-compiler'

// constants
export const VUE_OPTIONS = '__vue__options__'
export const VUE_I18N_OPTION = '__i18n'
const defaultLang = 'json'

const debug = Debug('vue-i18n-jest')

export default function generate (blocks: SFCBlock[]) {
const base = `${VUE_OPTIONS}.${VUE_I18N_OPTION} = []`
const codes = blocks.map(block => {
if (block.type === 'i18n') {
const lang = (block.attrs && block.attrs.lang) || defaultLang
// const lang = block.attrs?lang ?? defaultLang
const data = convert(block.content, lang)
const value = JSON.stringify(JSON.parse(data))
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
.replace(/\\/g, '\\\\')
return `${VUE_OPTIONS}.${VUE_I18N_OPTION}.push('${value.replace(/\u0027/g, '\\u0027')}')`
} else {
return ''
}
})

const code = [base].concat(codes).join('\n')
debug('genrateCode', code)
return code
}

function convert (source: string, lang: string): string {
switch (lang) {
case 'yaml':
case 'yml':
return JSON.stringify(yaml.safeLoad(source), undefined, '\t')
case 'json5':
return JSON.stringify(JSON5.parse(source))
default:
return source
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import transform from './transform'

export default transform
81 changes: 81 additions & 0 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const vueJest = require('vue-jest') as Transformer // vue-jest does not also provide types ...
import * as fs from 'fs'
import * as path from 'path'
import { createHash } from 'crypto'
import { parseComponent } from 'vue-template-compiler'
import { debug as Debug } from 'debug'
import generate from './generate'

// impor jest types
import { Config } from '@jest/types'
import { RawSourceMap } from 'source-map'
import { Transformer } from '@jest/transform'
interface FixedRawSourceMap extends Omit<RawSourceMap, 'version'> {
version: number
}
type TransformedSource = {
code: string
map?: FixedRawSourceMap | string | null
}
type TransformOptions = {
instrument: boolean
}
type CacheKeyOptions = {
config: Config.ProjectConfig
instrument: boolean
rootDir: string
}

const THIS_FILE = fs.readFileSync(__filename)

const debug = Debug('vue-i18n-jest')

debug(`getCacheKey: ${vueJest.getCacheKey ? 'vue-jest' : 'vue-i18n-jest'}`)

function jestProcess (
sourceText: string,
sourcePath: Config.Path,
config: Config.ProjectConfig,
options?: TransformOptions
): string | TransformedSource {
const { code, map } = vueJest.process(sourceText, sourcePath, config, options) as TransformedSource
const { customBlocks } = parseComponent(sourceText, { pad: true })

let coding = ';\n'
if (customBlocks) {
coding += generate(customBlocks)
}

const retCode = code + coding
debug('process', retCode)

return { code: retCode, map }
}

function getCacheKey (
fileData: string,
filePath: Config.Path,
configStr: string,
options: CacheKeyOptions
): string {
const hash = createHash('md5')
.update(THIS_FILE)
.update('\0', 'utf8')
.update(fileData)
.update('\0', 'utf8')
.update(path.relative(options.rootDir, filePath))
.update('\0', 'utf8')
.update(configStr)
.update('\0', 'utf8')
.update(process.env.NODE_ENV || '')
.digest('hex')
debug('getCacheKey', hash)
return hash
}

const transformer: Transformer = {
getCacheKey: vueJest.getCacheKey || getCacheKey,
process: jestProcess
}

export default transformer
21 changes: 21 additions & 0 deletions test/__snapshots__/generate.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`generate: default.vue 1`] = `
"__vue__options__.__i18n = []
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
`;

exports[`generate: json.vue 1`] = `
"__vue__options__.__i18n = []
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
`;

exports[`generate: json5.vue 1`] = `
"__vue__options__.__i18n = []
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
`;

exports[`generate: yaml.vue 1`] = `
"__vue__options__.__i18n = []
__vue__options__.__i18n.push('{\\"ja\\":{\\"hello\\":\\"こんにちは!\\"},\\"en\\":{\\"hello\\":\\"hello!\\"}}')"
`;
Loading

0 comments on commit 8689848

Please sign in to comment.