@wuchale/jsx 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +43 -3
- package/dist/transformer.d.ts +5 -5
- package/dist/transformer.js +18 -14
- package/package.json +2 -2
- package/src/loaders/react.bundle.js +9 -2
- package/src/loaders/react.js +6 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defaultGenerateLoadID, defaultHeuristic, deepMergeObjects } from 'wuchale';
|
|
2
|
-
import { adapter as vanillaAdapter
|
|
2
|
+
import { adapter as vanillaAdapter } from 'wuchale/adapter-vanilla';
|
|
3
3
|
import { JSXTransformer } from "./transformer.js";
|
|
4
4
|
import { getDependencies } from 'wuchale/adapter-utils';
|
|
5
5
|
const ignoreElements = ['style', 'path'];
|
|
@@ -18,6 +18,41 @@ const jsxHeuristic = (msgStr, details) => {
|
|
|
18
18
|
}
|
|
19
19
|
return true;
|
|
20
20
|
};
|
|
21
|
+
const defaultRuntime = {
|
|
22
|
+
useReactive: ({ funcName, nested }) => {
|
|
23
|
+
const inTopLevel = funcName == null;
|
|
24
|
+
const insideReactive = !inTopLevel && !nested && ((funcName.startsWith('use') && funcName.length > 3) || /[A-Z]/.test(funcName[0]));
|
|
25
|
+
return {
|
|
26
|
+
init: inTopLevel ? null : insideReactive,
|
|
27
|
+
use: insideReactive
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
reactive: {
|
|
31
|
+
importName: 'default',
|
|
32
|
+
wrapInit: expr => expr,
|
|
33
|
+
wrapUse: expr => expr,
|
|
34
|
+
},
|
|
35
|
+
plain: {
|
|
36
|
+
importName: 'get',
|
|
37
|
+
wrapInit: expr => expr,
|
|
38
|
+
wrapUse: expr => expr,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const defaultRuntimeSolid = {
|
|
42
|
+
...defaultRuntime,
|
|
43
|
+
useReactive: ({ funcName }) => {
|
|
44
|
+
const inTopLevel = funcName == null;
|
|
45
|
+
return {
|
|
46
|
+
init: inTopLevel ? true : null, // init only in top level
|
|
47
|
+
use: true, // always use reactive
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
reactive: {
|
|
51
|
+
importName: 'default',
|
|
52
|
+
wrapInit: expr => `() => ${expr}`,
|
|
53
|
+
wrapUse: expr => `${expr}()`
|
|
54
|
+
}
|
|
55
|
+
};
|
|
21
56
|
const defaultArgs = {
|
|
22
57
|
files: { include: 'src/**/*.{js,ts,jsx,tsx}', ignore: '**/*.d.ts' },
|
|
23
58
|
catalog: './src/locales/{locale}',
|
|
@@ -27,13 +62,17 @@ const defaultArgs = {
|
|
|
27
62
|
bundleLoad: false,
|
|
28
63
|
generateLoadID: defaultGenerateLoadID,
|
|
29
64
|
writeFiles: {},
|
|
65
|
+
runtime: defaultRuntime,
|
|
30
66
|
variant: 'default',
|
|
31
67
|
};
|
|
32
68
|
export const adapter = (args = defaultArgs) => {
|
|
33
|
-
|
|
69
|
+
let { heuristic, pluralsFunc, variant, runtime, ...rest } = deepMergeObjects(args, defaultArgs);
|
|
70
|
+
if (variant === 'solidjs' && args.runtime == null) {
|
|
71
|
+
runtime = defaultRuntimeSolid;
|
|
72
|
+
}
|
|
34
73
|
return {
|
|
35
74
|
transform: ({ content, filename, index, header }) => {
|
|
36
|
-
return new JSXTransformer(content, filename, index, heuristic, pluralsFunc,
|
|
75
|
+
return new JSXTransformer(content, filename, index, heuristic, pluralsFunc, header.expr, runtime).transformJx(header.head, variant);
|
|
37
76
|
},
|
|
38
77
|
loaderExts: ['.js', '.ts'],
|
|
39
78
|
defaultLoaders: async () => {
|
|
@@ -56,6 +95,7 @@ export const adapter = (args = defaultArgs) => {
|
|
|
56
95
|
}
|
|
57
96
|
return new URL(`../src/loaders/${loader}.js`, import.meta.url).pathname;
|
|
58
97
|
},
|
|
98
|
+
runtime,
|
|
59
99
|
...rest,
|
|
60
100
|
docsUrl: 'https://wuchale.dev/adapters/jsx'
|
|
61
101
|
};
|
package/dist/transformer.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type Program } from "acorn";
|
|
2
1
|
import { Message } from 'wuchale';
|
|
3
2
|
import type * as JX from 'estree-jsx';
|
|
3
|
+
import type * as Estree from 'acorn';
|
|
4
4
|
import { Transformer } from 'wuchale/adapter-vanilla';
|
|
5
|
-
import type { IndexTracker, HeuristicFunc, TransformOutput, CommentDirectives } from 'wuchale';
|
|
5
|
+
import type { IndexTracker, HeuristicFunc, TransformOutput, CommentDirectives, RuntimeConf, CatalogExpr } from 'wuchale';
|
|
6
6
|
import { MixedVisitor } from "wuchale/adapter-utils";
|
|
7
|
-
export declare function parseScript(content: string): [Program,
|
|
7
|
+
export declare function parseScript(content: string): [Estree.Program, Estree.Comment[][]];
|
|
8
8
|
type MixedNodesTypes = JX.JSXElement | JX.JSXFragment | JX.JSXText | JX.JSXExpressionContainer | JX.JSXSpreadChild;
|
|
9
9
|
export type JSXLib = 'default' | 'solidjs';
|
|
10
10
|
export declare class JSXTransformer extends Transformer {
|
|
@@ -14,7 +14,7 @@ export declare class JSXTransformer extends Transformer {
|
|
|
14
14
|
lastVisitIsComment: boolean;
|
|
15
15
|
currentElementI: number;
|
|
16
16
|
mixedVisitor: MixedVisitor<MixedNodesTypes>;
|
|
17
|
-
constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string,
|
|
17
|
+
constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string, catalogExpr: CatalogExpr, rtConf: RuntimeConf);
|
|
18
18
|
initMixedVisitor: () => MixedVisitor<MixedNodesTypes>;
|
|
19
19
|
visitChildrenJ: (node: JX.JSXElement | JX.JSXFragment) => Message[];
|
|
20
20
|
visitNameJSXNamespacedName: (node: JX.JSXNamespacedName) => string;
|
|
@@ -29,7 +29,7 @@ export declare class JSXTransformer extends Transformer {
|
|
|
29
29
|
visitJSXAttribute: (node: JX.JSXAttribute) => Message[];
|
|
30
30
|
visitJSXSpreadAttribute: (node: JX.JSXSpreadAttribute) => Message[];
|
|
31
31
|
visitJSXEmptyExpression: (node: JX.JSXEmptyExpression) => Message[];
|
|
32
|
-
visitJx: (node: JX.Node | JX.JSXSpreadChild | Program) => Message[];
|
|
32
|
+
visitJx: (node: JX.Node | JX.JSXSpreadChild | Estree.Program) => Message[];
|
|
33
33
|
transformJx: (headerHead: string, lib: JSXLib) => TransformOutput;
|
|
34
34
|
}
|
|
35
35
|
export {};
|
package/dist/transformer.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import MagicString from
|
|
2
|
-
import { Parser } from
|
|
1
|
+
import MagicString from 'magic-string';
|
|
2
|
+
import { Parser } from 'acorn';
|
|
3
3
|
import { Message } from 'wuchale';
|
|
4
4
|
import { tsPlugin } from '@sveltejs/acorn-typescript';
|
|
5
5
|
import jsx from 'acorn-jsx';
|
|
6
6
|
import { Transformer, scriptParseOptionsWithComments } from 'wuchale/adapter-vanilla';
|
|
7
|
-
import { nonWhitespaceText, MixedVisitor
|
|
7
|
+
import { nonWhitespaceText, MixedVisitor } from "wuchale/adapter-utils";
|
|
8
8
|
const JsxParser = Parser.extend(tsPlugin(), jsx());
|
|
9
9
|
export function parseScript(content) {
|
|
10
10
|
const [opts, comments] = scriptParseOptionsWithComments();
|
|
@@ -20,11 +20,12 @@ export class JSXTransformer extends Transformer {
|
|
|
20
20
|
lastVisitIsComment = false;
|
|
21
21
|
currentElementI = 0;
|
|
22
22
|
mixedVisitor;
|
|
23
|
-
constructor(content, filename, index, heuristic, pluralsFunc,
|
|
24
|
-
super(content, filename, index, heuristic, pluralsFunc,
|
|
23
|
+
constructor(content, filename, index, heuristic, pluralsFunc, catalogExpr, rtConf) {
|
|
24
|
+
super(content, filename, index, heuristic, pluralsFunc, catalogExpr, rtConf);
|
|
25
25
|
}
|
|
26
26
|
initMixedVisitor = () => new MixedVisitor({
|
|
27
27
|
mstr: this.mstr,
|
|
28
|
+
vars: this.vars,
|
|
28
29
|
getRange: node => ({
|
|
29
30
|
// @ts-expect-error
|
|
30
31
|
start: node.start,
|
|
@@ -59,15 +60,15 @@ export class JSXTransformer extends Transformer {
|
|
|
59
60
|
else {
|
|
60
61
|
toAppend = ', ';
|
|
61
62
|
}
|
|
62
|
-
this.mstr.appendRight(childStart, `${toAppend}${haveCtx ?
|
|
63
|
+
this.mstr.appendRight(childStart, `${toAppend}${haveCtx ? this.vars().nestCtx : '()'} => `);
|
|
63
64
|
}
|
|
64
65
|
let begin = `]} ctx=`;
|
|
65
66
|
if (this.inCompoundText) {
|
|
66
|
-
begin += `{${
|
|
67
|
+
begin += `{${this.vars().nestCtx}} nest`;
|
|
67
68
|
}
|
|
68
69
|
else {
|
|
69
70
|
const index = this.index.get(msgInfo.toKey());
|
|
70
|
-
begin += `{${
|
|
71
|
+
begin += `{${this.vars().rtCtx}(${index})}`;
|
|
71
72
|
}
|
|
72
73
|
let end = ' />';
|
|
73
74
|
if (hasExprs) {
|
|
@@ -123,7 +124,7 @@ export class JSXTransformer extends Transformer {
|
|
|
123
124
|
// @ts-expect-error
|
|
124
125
|
node.start + startWh,
|
|
125
126
|
// @ts-expect-error
|
|
126
|
-
node.end - endWh, `{${
|
|
127
|
+
node.end - endWh, `{${this.vars().rtTrans}(${this.index.get(msgInfo.toKey())})}`);
|
|
127
128
|
return [msgInfo];
|
|
128
129
|
};
|
|
129
130
|
visitJSXFragment = (node) => this.visitChildrenJ(node);
|
|
@@ -139,6 +140,9 @@ export class JSXTransformer extends Transformer {
|
|
|
139
140
|
return this.visit(node.expression);
|
|
140
141
|
};
|
|
141
142
|
visitJSXAttribute = (node) => {
|
|
143
|
+
if (node.value == null) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
142
146
|
if (node.value.type !== 'Literal') {
|
|
143
147
|
return this.visitJx(node.value);
|
|
144
148
|
}
|
|
@@ -165,7 +169,7 @@ export class JSXTransformer extends Transformer {
|
|
|
165
169
|
// @ts-expect-error
|
|
166
170
|
value.start,
|
|
167
171
|
// @ts-expect-error
|
|
168
|
-
value.end, `{${
|
|
172
|
+
value.end, `{${this.vars().rtTrans}(${this.index.get(msgInfo.toKey())})}`);
|
|
169
173
|
return [msgInfo];
|
|
170
174
|
};
|
|
171
175
|
visitJSXSpreadAttribute = (node) => this.visit(node.argument);
|
|
@@ -212,13 +216,13 @@ export class JSXTransformer extends Transformer {
|
|
|
212
216
|
if (!msgs.length) {
|
|
213
217
|
return this.finalize(msgs, 0);
|
|
214
218
|
}
|
|
215
|
-
let devInit = '';
|
|
216
219
|
const headerFin = [
|
|
217
220
|
`import ${rtComponent} from "@wuchale/jsx/runtime${lib === 'solidjs' ? '.solid' : ''}.jsx"`,
|
|
218
221
|
headerHead,
|
|
219
|
-
|
|
222
|
+
this.initRuntime(this.filename, null, null, {}),
|
|
220
223
|
].join('\n');
|
|
221
|
-
this.
|
|
222
|
-
|
|
224
|
+
const bodyStart = this.getRealBodyStart(ast.body);
|
|
225
|
+
this.mstr.appendRight(bodyStart, headerFin + '\n');
|
|
226
|
+
return this.finalize(msgs, bodyStart);
|
|
223
227
|
};
|
|
224
228
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wuchale/jsx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Protobuf-like i18n from plain code: JSX adapter",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "tsc --watch",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@sveltejs/acorn-typescript": "^1.0.5",
|
|
73
73
|
"acorn": "^8.15.0",
|
|
74
74
|
"acorn-jsx": "^5.3.2",
|
|
75
|
-
"wuchale": "^0.
|
|
75
|
+
"wuchale": "^0.15.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@types/estree-jsx": "^1.0.5",
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
import { useState, useEffect } from 'react'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
let locale = 'en'
|
|
9
|
+
|
|
10
|
+
const callbacks = new Set([(/** @type {string} */ loc) => {locale = loc}])
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @param {string} locale
|
|
@@ -19,7 +21,12 @@ export function setLocale(locale) {
|
|
|
19
21
|
export default (/** @type {{[locale: string]: import('wuchale/runtime').CatalogModule }} */ catalogs) => {
|
|
20
22
|
const [locale, setLocale] = useState('en')
|
|
21
23
|
useEffect(() => {
|
|
22
|
-
|
|
24
|
+
const cb = (/** @type {string} */ locale) => setLocale(locale)
|
|
25
|
+
callbacks.add(cb)
|
|
26
|
+
return () => callbacks.delete(cb)
|
|
23
27
|
})
|
|
24
28
|
return catalogs[locale]
|
|
25
29
|
}
|
|
30
|
+
|
|
31
|
+
// non-reactive
|
|
32
|
+
export const get = (/** @type {{[locale: string]: import('wuchale/runtime').CatalogModule }} */ catalogs) => catalogs[locale]
|
package/src/loaders/react.js
CHANGED
|
@@ -10,8 +10,11 @@ import { useState, useEffect } from 'react'
|
|
|
10
10
|
const callbacks = {}
|
|
11
11
|
const store = {}
|
|
12
12
|
|
|
13
|
+
// non-reactive
|
|
14
|
+
export const get = (/** @type {string} */ loadID) => store[loadID]
|
|
15
|
+
|
|
13
16
|
const collection = {
|
|
14
|
-
get
|
|
17
|
+
get,
|
|
15
18
|
set: (/** @type {string} */ loadID, /** @type {import('wuchale/runtime').CatalogModule} */ catalog) => {
|
|
16
19
|
store[loadID] = catalog // for when useEffect hasn't run yet
|
|
17
20
|
callbacks[loadID]?.(catalog)
|
|
@@ -20,13 +23,11 @@ const collection = {
|
|
|
20
23
|
|
|
21
24
|
registerLoaders(key, loadCatalog, loadIDs, collection)
|
|
22
25
|
|
|
23
|
-
/**
|
|
24
|
-
* @param { string } loadID
|
|
25
|
-
*/
|
|
26
|
-
export default loadID => {
|
|
26
|
+
export default (/** @type {string} */ loadID) => {
|
|
27
27
|
const [catalog, setCatalog] = useState(collection.get(loadID))
|
|
28
28
|
useEffect(() => {
|
|
29
29
|
callbacks[loadID] = (/** @type {import('wuchale/runtime').CatalogModule} */ catalog) => setCatalog(catalog)
|
|
30
|
+
return () => delete callbacks[loadID]
|
|
30
31
|
})
|
|
31
32
|
return catalog
|
|
32
33
|
}
|