@wuchale/jsx 0.5.2 → 0.6.1

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defaultGenerateLoadID, defaultHeuristic, deepMergeObjects } from 'wuchale';
2
- import { adapter as vanillaAdapter, initRuntimeStmt } from 'wuchale/adapter-vanilla';
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
- const { heuristic, pluralsFunc, variant, ...rest } = deepMergeObjects(args, defaultArgs);
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, initRuntimeStmt(header.expr)).transformJx(header.head, variant);
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
  };
@@ -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, JX.Comment[][]];
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, initRuntime: 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 {};
@@ -1,10 +1,10 @@
1
- import MagicString from "magic-string";
2
- import { Parser } from "acorn";
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, runtimeVars } from "wuchale/adapter-utils";
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, initRuntime) {
24
- super(content, filename, index, heuristic, pluralsFunc, initRuntime);
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 ? runtimeVars.nestCtx : '()'} => `);
63
+ this.mstr.appendRight(childStart, `${toAppend}${haveCtx ? this.vars().nestCtx : '()'} => `);
63
64
  }
64
65
  let begin = `]} ctx=`;
65
66
  if (this.inCompoundText) {
66
- begin += `{${runtimeVars.nestCtx}} nest`;
67
+ begin += `{${this.vars().nestCtx}} nest`;
67
68
  }
68
69
  else {
69
70
  const index = this.index.get(msgInfo.toKey());
70
- begin += `{${runtimeVars.rtCtx}(${index})}`;
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, `{${runtimeVars.rtTrans}(${this.index.get(msgInfo.toKey())})}`);
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);
@@ -168,7 +169,7 @@ export class JSXTransformer extends Transformer {
168
169
  // @ts-expect-error
169
170
  value.start,
170
171
  // @ts-expect-error
171
- value.end, `{${runtimeVars.rtTrans}(${this.index.get(msgInfo.toKey())})}`);
172
+ value.end, `{${this.vars().rtTrans}(${this.index.get(msgInfo.toKey())})}`);
172
173
  return [msgInfo];
173
174
  };
174
175
  visitJSXSpreadAttribute = (node) => this.visit(node.argument);
@@ -215,13 +216,13 @@ export class JSXTransformer extends Transformer {
215
216
  if (!msgs.length) {
216
217
  return this.finalize(msgs, 0);
217
218
  }
218
- let devInit = '';
219
219
  const headerFin = [
220
220
  `import ${rtComponent} from "@wuchale/jsx/runtime${lib === 'solidjs' ? '.solid' : ''}.jsx"`,
221
221
  headerHead,
222
- devInit,
222
+ this.initRuntime(this.filename, null, null, {}),
223
223
  ].join('\n');
224
- this.mstr.appendRight(0, headerFin + '\n');
225
- return this.finalize(msgs, 0);
224
+ const bodyStart = this.getRealBodyStart(ast.body);
225
+ this.mstr.appendRight(bodyStart, headerFin + '\n');
226
+ return this.finalize(msgs, bodyStart);
226
227
  };
227
228
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wuchale/jsx",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
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.14.2"
75
+ "wuchale": "^0.15.1"
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
- const callbacks = new Set()
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
- callbacks.add((/** @type {string} */ locale) => setLocale(locale))
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]
@@ -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: loadID => store[loadID],
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
  }
@@ -11,4 +11,6 @@ export { setLocale }
11
11
  /**
12
12
  * @param {{ [locale: string]: import('wuchale/runtime').CatalogModule }} catalogs
13
13
  */
14
- export default catalogs => catalogs[locale()]
14
+ export const get = catalogs => catalogs[locale()]
15
+ // same function, because solid-js can use them anywhere
16
+ export default get
@@ -9,7 +9,9 @@ import { createStore } from 'solid-js/store'
9
9
 
10
10
  const [store, setStore] = createStore({})
11
11
 
12
- export default registerLoaders(key, loadCatalog, loadIDs, {
12
+ // two exports. can be the same because solid-js can use them anywhere unlike react
13
+ export const get = registerLoaders(key, loadCatalog, loadIDs, {
13
14
  get: loadID => store[loadID],
14
15
  set: setStore,
15
16
  })
17
+ export default get