Skip to content
This repository has been archived by the owner on Jul 4, 2021. It is now read-only.

Commit

Permalink
feat: custom blocks (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Jun 5, 2020
1 parent a104239 commit 6056a00
Show file tree
Hide file tree
Showing 18 changed files with 1,776 additions and 41 deletions.
17 changes: 15 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,38 @@
"Type: Documentation": ":pencil: Documentation"
}
},
"dependencies": {
"js-yaml": "^3.14.0",
"json5": "^2.1.3",
"vue-i18n": "^9.0.0-alpha.10"
},
"devDependencies": {
"@rollup/plugin-alias": "^3.1.1",
"@types/debug": "^4.1.5",
"@types/jest": "^25.2.3",
"@types/js-yaml": "^3.12.4",
"@types/jsdom": "^16.2.3",
"@types/json5": "^0.0.30",
"@types/node": "^14.0.11",
"@typescript-eslint/eslint-plugin": "^3.1.0",
"@typescript-eslint/parser": "^3.1.0",
"debug": "^4.1.1",
"eslint": "^7.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^7.0.0-alpha.5",
"eslint-plugin-vue-libs": "^4.0.0",
"jest": "^26.0.1",
"jest-watch-typeahead": "^0.6.0",
"jsdom": "^16.2.2",
"lerna-changelog": "^1.0.1",
"npm-run-all": "^4.1.5",
"opener": "^1.5.1",
"shipjs": "^0.19.0",
"ts-jest": "^26.1.0",
"typescript": "^3.9.5",
"typescript-eslint-language-service": "^3.0.0"
"typescript-eslint-language-service": "^3.0.0",
"vite": "^0.20.4"
},
"engines": {
"node": ">= 10"
Expand All @@ -62,7 +75,7 @@
"url": "git+https://github.com/intlify/vite-plugin-vue-i18n.git"
},
"scripts": {
"build": "tsc -p .",
"build": "tsc --skipLibCheck -p .",
"clean": "npm-run-all clean:*",
"clean:cache:jest": "jest --clearCache",
"clean:coverage": "rm -rf ./coverage",
Expand Down
47 changes: 46 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
console.log('hello, @intlify/vite-plugin-vue-i18n !')
import { friendlyJSONstringify } from 'vue-i18n'
import yaml from 'js-yaml'
import JSON5 from 'json5'

import { debug as Debug } from 'debug'
const debug = Debug('vite-plugin-vue-i18n')

type Query = Record<string, string>

export default function i18n(source: string, query: Query) {
debug('vueSFCTransform: query', JSON.stringify(query))

return new Promise<string>(resolve => {
const code = `export default Comp => {
Comp.__i18n = Comp.__i18n || []
Comp.__i18n.push(${stringify(parse(source.trim(), query), query)})
}`.trim()
resolve(code)
})
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function stringify(data: any, query: Query): string {
const { locale } = query
if (locale) {
return friendlyJSONstringify(
Object.assign({}, { [locale as string]: data })
)
} else {
return friendlyJSONstringify(data)
}
}

function parse(source: string, query: Query): string {
const value = source.trim()
const { lang } = query
switch (lang) {
case 'yaml':
case 'yml':
return yaml.safeLoad(value)
case 'json5':
return JSON5.parse(value)
default:
return JSON.parse(value)
}
}
7 changes: 7 additions & 0 deletions test/fixtures/basic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<i18n>
{
"en": {
"hello": "hello world!"
}
}
</i18n>
7 changes: 7 additions & 0 deletions test/fixtures/entry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Component from '~target'
import * as exports from '~target'

if (typeof window !== 'undefined') {
window.module = Component
window.exports = exports
}
2 changes: 2 additions & 0 deletions test/fixtures/import.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<i18n src="./message.json">
</i18n>
8 changes: 8 additions & 0 deletions test/fixtures/json5.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<i18n lang="json5">
{
"en": {
// comments
"hello": "hello world!"
}
}
</i18n>
2 changes: 2 additions & 0 deletions test/fixtures/locale-import.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<i18n locale="en" src="./locale.json">
</i18n>
13 changes: 13 additions & 0 deletions test/fixtures/locale-mix.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<i18n>
{
"en": {
"hello": "hello world!"
}
}
</i18n>

<i18n locale="ja">
{
"hello": "こんにちは、世界!"
}
</i18n>
3 changes: 3 additions & 0 deletions test/fixtures/locale.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"hello": "hello world!"
}
5 changes: 5 additions & 0 deletions test/fixtures/locale.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<i18n locale="ja">
{
"hello": "こんにちは、世界!"
}
</i18n>
5 changes: 5 additions & 0 deletions test/fixtures/message.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"en": {
"hello": "hello world!"
}
}
15 changes: 15 additions & 0 deletions test/fixtures/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<i18n>
{
"en": {
"hello": "hello world!"
}
}
</i18n>

<i18n>
{
"ja": {
"hello": "こんにちは、世界!"
}
}
</i18n>
7 changes: 7 additions & 0 deletions test/fixtures/special-char.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<i18n>
{
"en": {
"hello": "hello\ngreat\t\"world\""
}
}
</i18n>
4 changes: 4 additions & 0 deletions test/fixtures/yaml.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<i18n lang="yaml">
en:
hello: "hello world!"
</i18n>
111 changes: 109 additions & 2 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,110 @@
test('hello', () => {
expect(1 + 1).toBe(2)
import { bundleAndRun } from './utils'

test('basic', async () => {
const { module } = await bundleAndRun('basic.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
}
])
})

test('yaml', async () => {
const { module } = await bundleAndRun('yaml.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
}
])
})

test('json5', async () => {
const { module } = await bundleAndRun('json5.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
}
])
})

test('import', async () => {
const { module } = await bundleAndRun('import.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
}
])
})

test('multiple', async () => {
const { module } = await bundleAndRun('multiple.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
},
{
ja: {
hello: 'こんにちは、世界!'
}
}
])
})

test('locale', async () => {
const { module } = await bundleAndRun('locale.vue')
expect(module.__i18n).toMatchObject([
{
ja: {
hello: 'こんにちは、世界!'
}
}
])
})

test('locale attr and basic', async () => {
const { module } = await bundleAndRun('locale-mix.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
},
{
ja: {
hello: 'こんにちは、世界!'
}
}
])
})

test('locale attr and import', async () => {
const { module } = await bundleAndRun('locale-import.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello world!'
}
}
])
})

test('special characters', async () => {
const { module } = await bundleAndRun('special-char.vue')
expect(module.__i18n).toMatchObject([
{
en: {
hello: 'hello\ngreat\t"world"'
}
}
])
})
63 changes: 63 additions & 0 deletions test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import path from 'path'
import alias from '@rollup/plugin-alias'
import { build } from 'vite'
import { JSDOM, VirtualConsole } from 'jsdom'
import i18n from '../src/index'

async function bundle(fixture: string, options: Record<string, unknown> = {}) {
const { assets } = await build({
emitAssets: false,
emitIndex: false,
write: false,
minify: false,
silent: true,
rollupInputOptions: {
input: path.resolve(__dirname, './fixtures/entry.ts'),
plugins: [
alias({
entries: {
'~target': path.resolve(__dirname, './fixtures', fixture)
}
})
]
},
vueCustomBlockTransforms: {
i18n
}
})
return { code: assets[0].code }
}

export async function bundleAndRun(
fixture: string,
options: Record<string, unknown> = {}
) {
const { code } = await bundle(fixture, options)

let dom: JSDOM | null = null
let jsdomError
try {
dom = new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`, {
runScripts: 'outside-only',
virtualConsole: new VirtualConsole()
})
dom.window.eval(code)
} catch (e) {
console.error(`JSDOM error:\n${e.stack}`)
jsdomError = e
}

if (!dom) {
return Promise.reject(new Error('Cannot assigned JSDOM instance'))
}

const { window } = dom
const { module, exports } = window

return Promise.resolve({
window,
module,
exports,
jsdomError
})
}
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
/* List of folders to include type definitions from. */
"typeRoots": [
"./node_modules/@types"
"./node_modules/@types",
"./node_modules/vite/dist",
"./node_modules/vue-i18n/dist"
],
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
Expand Down
Loading

0 comments on commit 6056a00

Please sign in to comment.