Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support allow dynamic resource for js and ts format #237

Merged
merged 2 commits into from Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/bundle-utils/src/codegen.ts
Expand Up @@ -51,6 +51,7 @@ export interface CodeGenOptions {
env?: DevEnv
forceStringify?: boolean
useClassComponent?: boolean
allowDynamic?: boolean
onWarn?: (msg: string) => void
onError?: (
msg: string,
Expand Down
42 changes: 36 additions & 6 deletions packages/bundle-utils/src/js.ts
Expand Up @@ -33,7 +33,8 @@ export function generate(
env = 'development',
forceStringify = false,
onError = undefined,
useClassComponent = false
useClassComponent = false,
allowDynamic = false
}: CodeGenOptions,
injector?: () => string
): CodeGenResult<Node> {
Expand Down Expand Up @@ -66,14 +67,43 @@ export function generate(
allowImportExportEverywhere: true
}) as Node

const selectedWithExportDefault = esquery(
const astExportDefaultWithObject = esquery(
ast,
'Program:has(ExportDefaultDeclaration, [declaration=ObjectExpression])'
'Program:has(ExportDefaultDeclaration):has(ObjectExpression)'
)
if (!selectedWithExportDefault.length) {
throw new Error(
`You need to define an object as the locale message with "export default'.`
console.log('astExportDefaultWithObject', astExportDefaultWithObject)

if (!allowDynamic) {
if (!astExportDefaultWithObject.length) {
throw new Error(
`You need to define an object as the locale message with 'export default'.`
)
}
} else {
const astExportDefault = esquery(
ast,
'Program:has(ExportDefaultDeclaration)'
)
if (!astExportDefault.length) {
throw new Error(
`You need to define 'export default' that will return the locale messages.`
)
}
console.log('astExportDefault', astExportDefault)

if (!astExportDefaultWithObject.length) {
/**
* NOTE:
* If `allowDynamic` is `true`, do not transform the code by this function, return it as is.
* This means that the user **must transform locale messages ownself**.
* Especially at the production, you need to do locale messages pre-compiling.
*/
return {
ast,
code: value,
map: inSourceMap
}
}
}

const codeMaps = generateNode(generator, ast, options, injector)
Expand Down
3 changes: 3 additions & 0 deletions packages/bundle-utils/test/fixtures/codegen/allow-dynamic.js
@@ -0,0 +1,3 @@
export default function loadResource(url) {
return fetch(url).then(response => response.json())
}
@@ -0,0 +1,3 @@
export default {
hello: 'こんにちは'
}
@@ -0,0 +1,3 @@
export const messages = {
hello: 'こんにちは'
}
@@ -1,3 +1,3 @@
export const messages = {
hello: 'こんにちは'
function loadResource(url) {
return fetch(url).then(response => response.json())
}
149 changes: 149 additions & 0 deletions packages/bundle-utils/test/generator/__snapshots__/js.test.ts.snap
@@ -1,5 +1,154 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`'allowDynamic' option generate: code 1`] = `
"export default {
\\"hello\\": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize([\\"こんにちは\\"])};fn.source=\\"こんにちは\\";return fn;})()
}"
`;

exports[`'allowDynamic' option generate: map 1`] = `
Object {
"mappings": "",
"names": Array [],
"sources": Array [],
"version": 3,
}
`;

exports[`'allowDynamic' option no generate 1`] = `
Node {
"body": Array [
Node {
"declaration": Node {
"async": false,
"body": Node {
"body": Array [
Node {
"argument": Node {
"arguments": Array [
Node {
"async": false,
"body": Node {
"arguments": Array [],
"callee": Node {
"computed": false,
"end": 94,
"object": Node {
"end": 89,
"name": "response",
"start": 81,
"type": "Identifier",
},
"optional": false,
"property": Node {
"end": 94,
"name": "json",
"start": 90,
"type": "Identifier",
},
"start": 81,
"type": "MemberExpression",
},
"end": 96,
"optional": false,
"start": 81,
"type": "CallExpression",
},
"end": 96,
"expression": true,
"generator": false,
"id": null,
"params": Array [
Node {
"end": 77,
"name": "response",
"start": 69,
"type": "Identifier",
},
],
"start": 69,
"type": "ArrowFunctionExpression",
},
],
"callee": Node {
"computed": false,
"end": 68,
"object": Node {
"arguments": Array [
Node {
"end": 62,
"name": "url",
"start": 59,
"type": "Identifier",
},
],
"callee": Node {
"end": 58,
"name": "fetch",
"start": 53,
"type": "Identifier",
},
"end": 63,
"optional": false,
"start": 53,
"type": "CallExpression",
},
"optional": false,
"property": Node {
"end": 68,
"name": "then",
"start": 64,
"type": "Identifier",
},
"start": 53,
"type": "MemberExpression",
},
"end": 97,
"optional": false,
"start": 53,
"type": "CallExpression",
},
"end": 97,
"start": 46,
"type": "ReturnStatement",
},
],
"end": 99,
"start": 42,
"type": "BlockStatement",
},
"end": 99,
"expression": false,
"generator": false,
"id": Node {
"end": 36,
"name": "loadResource",
"start": 24,
"type": "Identifier",
},
"params": Array [
Node {
"end": 40,
"name": "url",
"start": 37,
"type": "Identifier",
},
],
"start": 15,
"type": "FunctionDeclaration",
},
"end": 99,
"start": 0,
"type": "ExportDefaultDeclaration",
},
],
"end": 100,
"sourceType": "module",
"start": 0,
"type": "Program",
}
`;

exports[`array basic: code 1`] = `
"export default function (Component) {
Component.__i18n = Component.__i18n || []
Expand Down
54 changes: 50 additions & 4 deletions packages/bundle-utils/test/generator/js.test.ts
Expand Up @@ -200,9 +200,10 @@ test('invalid message syntax', async () => {
expect(map).toMatchSnapshot('map')
})

test('no export default', async () => {
console.log('ssss')
const { source } = await readFile('./fixtures/codegen/no-export-default.js')
test('no export default with object', async () => {
const { source } = await readFile(
'./fixtures/codegen/no-export-default-with-object.js'
)
function doGenerate() {
generate(source, {
sourceMap: true,
Expand All @@ -211,6 +212,51 @@ test('no export default', async () => {
}

expect(doGenerate).toThrowError(
`You need to define an object as the locale message with "export default'.`
`You need to define an object as the locale message with 'export default'.`
)
})

describe(`'allowDynamic' option`, () => {
test('no export default', async () => {
const { source } = await readFile('./fixtures/codegen/no-export-default.js')
function doGenerate() {
generate(source, {
allowDynamic: true,
sourceMap: true,
env: 'development'
})
}

expect(doGenerate).toThrowError(
`You need to define 'export default' that will return the locale messages.`
)
})

test('no generate', async () => {
const { source } = await readFile('./fixtures/codegen/allow-dynamic.js')
const { code, ast } = generate(source, {
allowDynamic: true,
sourceMap: true,
env: 'development'
})

expect(validateSyntax(code)).toBe(true)
expect(code).toBe(source)
expect(ast).toMatchSnapshot()
})

test('generate', async () => {
const { source } = await readFile(
'./fixtures/codegen/export-default-with-object.js'
)
const { code, map } = generate(source, {
allowDynamic: true,
sourceMap: true,
env: 'development'
})

expect(validateSyntax(code)).toBe(true)
expect(code).toMatchSnapshot('code')
expect(map).toMatchSnapshot('map')
})
})