wuchale 0.8.2 → 0.9.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.
Files changed (61) hide show
  1. package/README.md +8 -317
  2. package/dist/src/adapter-vanilla.d.ts +17 -10
  3. package/dist/src/adapter-vanilla.d.ts.map +1 -0
  4. package/dist/src/adapter-vanilla.js +54 -39
  5. package/dist/src/adapter-vanilla.js.map +1 -1
  6. package/dist/src/adapters.d.ts +100 -0
  7. package/dist/src/adapters.d.ts.map +1 -0
  8. package/dist/src/{adapter.js → adapters.js} +18 -11
  9. package/dist/src/adapters.js.map +1 -0
  10. package/dist/src/cli.d.ts +1 -0
  11. package/dist/src/cli.d.ts.map +1 -0
  12. package/dist/src/cli.js +78 -14
  13. package/dist/src/cli.js.map +1 -1
  14. package/dist/src/compile.d.ts +1 -0
  15. package/dist/src/compile.d.ts.map +1 -0
  16. package/dist/src/config.d.ts +4 -2
  17. package/dist/src/config.d.ts.map +1 -0
  18. package/dist/src/config.js +3 -2
  19. package/dist/src/config.js.map +1 -1
  20. package/dist/src/gemini.d.ts +1 -0
  21. package/dist/src/gemini.d.ts.map +1 -0
  22. package/dist/src/handler.d.ts +41 -19
  23. package/dist/src/handler.d.ts.map +1 -0
  24. package/dist/src/handler.js +304 -110
  25. package/dist/src/handler.js.map +1 -1
  26. package/dist/src/index.d.ts +1 -0
  27. package/dist/src/index.d.ts.map +1 -0
  28. package/dist/src/plugin.d.ts +15 -16
  29. package/dist/src/plugin.d.ts.map +1 -0
  30. package/dist/src/plugin.js +72 -38
  31. package/dist/src/plugin.js.map +1 -1
  32. package/dist/src/run-client.d.ts +23 -0
  33. package/dist/src/run-client.d.ts.map +1 -0
  34. package/dist/src/run-client.js +55 -0
  35. package/dist/src/run-client.js.map +1 -0
  36. package/dist/src/run-server.d.ts +5 -0
  37. package/dist/src/run-server.d.ts.map +1 -0
  38. package/dist/src/run-server.js +26 -0
  39. package/dist/src/run-server.js.map +1 -0
  40. package/dist/src/runtime.d.ts +3 -8
  41. package/dist/src/runtime.d.ts.map +1 -0
  42. package/dist/src/runtime.js +2 -29
  43. package/dist/src/runtime.js.map +1 -1
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +19 -18
  46. package/src/adapter-vanilla.ts +74 -46
  47. package/src/{adapter.ts → adapters.ts} +77 -40
  48. package/src/cli.ts +83 -17
  49. package/src/config.ts +5 -3
  50. package/src/handler.ts +323 -114
  51. package/src/loader.default.js +9 -0
  52. package/src/plugin.ts +76 -51
  53. package/src/run-client.ts +62 -0
  54. package/src/run-server.ts +30 -0
  55. package/src/runtime.ts +4 -40
  56. package/src/virtual.d.ts +18 -0
  57. package/dist/src/adapter.d.ts +0 -70
  58. package/dist/src/adapter.js.map +0 -1
  59. package/dist/src/runtime-server.d.ts +0 -4
  60. package/dist/src/runtime-server.js +0 -9
  61. package/dist/src/runtime-server.js.map +0 -1
package/README.md CHANGED
@@ -1,328 +1,19 @@
1
- # `wuchale` core
1
+ # 📜`wuchale`🪶
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/wuchale)](https://www.npmjs.com/package/wuchale) ![License](https://img.shields.io/github/license/K1DV5/wuchale)
4
4
 
5
- A non-invasive compile-time internationalization (i18n) toolkit.
6
- Inspired by Lingui, built from scratch with performance, clarity, and
7
- simplicity in mind.
8
-
9
- > 🎯 **Smart translations, tiny runtime, full HMR.** Extract strings at build
10
- > time, generate optimized translation catalogs, support live translations
11
- > (even with Gemini AI), and ship minimal code to production.
12
-
13
- ## Why `wuchale`?
14
-
15
- Traditional i18n solutions require you to wrap every translatable string with
16
- function calls or components. `wuchale` doesn't.
17
-
18
- ```typescript
19
- // Traditional i18n
20
- const t = i18n('Hello')
21
-
22
- // With wuchale
23
- const t = 'Hello'
24
- ```
25
-
26
- Write your code naturally. No imports, no wrappers, no annotations.
27
- `wuchale` handles everything at compile time.
28
-
29
- Try the live example in your browser, no setup required:
30
-
31
- - Vanilla TS: [![Vanilla TS example on StackBlitz](https://img.shields.io/badge/StackBlitz-Demo-blue?logo=stackblitz)](https://stackblitz.com/github/K1DV5/wuchale/tree/main/examples/vanilla)
32
-
33
- ## ✨ Key Features
5
+ **`wuchale`** is a non-invasive, normal code based compile-time internationalization (i18n) toolkit.
34
6
 
7
+ - **🔤 No extra syntax!** - your normal code is enough
8
+ - **📦 Tiny catalogs to bundle** - Text catalogs are just arrays, no keys necessary
35
9
  - **🔧 Zero-effort integration** - Add i18n to existing projects without rewriting code
36
10
  - **🚀 Compile-time optimization** - All transformations happen during build, minimal runtime overhead
37
- - **🔄 Full, granular HMR support** - Live updates during development, including auto-translation
38
- - **📦 Tiny footprint** - Only 2 additional dependencies (`wuchale` + `pofile`), no bloated `node_modules`
11
+ - **🔄 Full, granular HMR support** - Live updates during development, including AI auto-translation
12
+ - **📦 Tiny footprint** - Only 2 or 3 additional dependencies (`wuchale` + `pofile`), no bloated `node_modules`
39
13
  - **🎯 Smart extraction** - Uses AST analysis: handles nested markup, conditionals, loops, and complex interpolations
40
14
  - **🌍 Standard .po files** - Compatible with existing translation tools and workflows
41
15
  - **🤖 Optional AI translation** - Gemini integration for automatic translations during development
42
16
 
43
- ## 📦 Available adapters
44
-
45
- To use `wuchale` you need the main `vite` plugin (this package) and an adapter
46
- for your project type. The following adapters are currently available:
47
-
48
- - JavaScript/TypeScript (vanilla adapter): included in this package.
49
- - Svelte: [here](https://www.npmjs.com/package/@wuchale/svelte)
50
-
51
- ## 🚀 Quick Start
52
-
53
- We will use the vanilla adapter as an example.
54
-
55
- ### 1. Install
56
-
57
- ```bash
58
- npm install wuchale
59
- ```
60
-
61
- ### 2. Configure Vite
62
-
63
- ```javascript
64
- // vite.config.js
65
- import { wuchale } from 'wuchale'
66
-
67
- export default {
68
- plugins: [
69
- wuchale(),
70
- ]
71
- }
72
- ```
73
-
74
- ### 3. Create Configuration
75
-
76
- Create `wuchale.config.js` in your project root:
77
-
78
- ```javascript
79
- // @ts-check
80
- import { adapter as vanillaAdapter } from "wuchale/adapter-vanilla"
81
- import { defineConfig } from "wuchale/config"
82
-
83
- export default defineConfig({
84
- locales: {
85
- // English included by default
86
- es: { name: 'Spanish' },
87
- fr: { name: 'French' }
88
- },
89
- adapters: {
90
- main: vanillaAdapter(),
91
- }
92
- })
93
- ```
94
-
95
- ### 4. Create the locales directory
96
-
97
- ```bash
98
- mkdir src/locales
99
- ```
100
-
101
- ### 5. Add CLI Scripts
102
-
103
- ```jsonc
104
- // package.json
105
- {
106
- "scripts": {
107
- "extract": "wuchale",
108
- "clean": "wuchale --clean"
109
- }
110
- }
111
- ```
112
-
113
- ### 6. Use in Your App!
114
-
115
- ```javascript
116
- // src/index.js
117
-
118
- import { runWithCatalog } from 'wuchale/runtime-server'
119
-
120
- const catalogs = {
121
- en: await import(`./locales/en.js`),
122
- es: await import(`./locales/es.js`),
123
- fr: await import(`./locales/fr.js`),
124
- }
125
-
126
- // adapted from an express.js example
127
- // only to show how to use runWithCatalog
128
- app.get('/', (req, res) => {
129
- runWithCatalog(catalogs.es, () => res.send('Hello')) // will return Hola
130
- })
131
- ```
132
-
133
- ### 7. Start Coding!
134
-
135
- Write your code naturally. `wuchale` will extract and compile translations automatically:
136
-
137
- ```javascript
138
- function eventHandler(event) {
139
- event.target.value = 'Hello!'
140
- }
141
- ```
142
-
143
- ## 📖 How It Works
144
-
145
- [See main README](https://github.com/K1DV5/wuchale)
146
-
147
- ## AI Translation
148
-
149
- Enable Gemini translations by setting `GEMINI_API_KEY`:
150
-
151
- ```bash
152
- GEMINI_API_KEY=your-key npm run dev
153
- ```
154
-
155
- ## 📁 File Structure
156
-
157
- ```
158
- src/
159
- ├── locales/
160
- │ ├── en.po # Source catalog (commit this)
161
- │ ├── en.js # Compiled data module (gitignore)
162
- │ ├── es.po # Translation catalog (commit this)
163
- │ └── es.js # Compiled data module (gitignore)
164
- └── index.js # Your code
165
- ```
166
-
167
- ## 🧠 Behavior Explanation (vanilla adapter)
168
-
169
- ### What Gets Extracted?
170
-
171
- This is decided by the heuristic function which you can customize. A sensible
172
- default heuristic function is provided out of the box. Here's how it works:
173
-
174
- - If the text contains no letters used in any natural language (e.g., just numbers or symbols), it is ignored.
175
- - If it's in a top-level expression (not inside an assignment or a function definition) it is ignored.
176
- - If the value is inside `console.*()` call, it is ignored.
177
- - If the first character is a lowercase English letter (`[a-z]`) or is any non-letter, it is ignored.
178
- - Otherwise, it is extracted.
179
-
180
- Examples:
181
-
182
- ```javascript
183
-
184
- const message = 'This is extracted'
185
- const lowercase = 'not extracted'
186
-
187
- // Force extraction with comment
188
- const forced = /* @wc-include */ 'force extracted'
189
-
190
- function foo() {
191
- const extracted = 'Hello!'
192
- }
193
- ```
194
-
195
- If you need more control, you can supply your own heuristic function in the
196
- configuration. Custom heuristics can return `undefined` or `null` to fall back
197
- to the default. For convenience, the default heuristic is exported by the
198
- package.
199
-
200
- > 💡 You can override extraction with comment directives:
201
- > - `@wc-ignore` — skips extraction
202
- > - `@wc-include` — forces extraction
203
- > These always take precedence.
204
-
205
- ### Pluralization
206
-
207
- Define your function
208
- ```javascript
209
- // in e.g. src/utils.js
210
- export function plural(num, candidates, rule = n => n === 1 ? 0 : 1) {
211
- const index = rule(num)
212
- return candidates[index].replace('#', num)
213
- }
214
- ```
215
-
216
- Use it
217
-
218
- ```javascript
219
- import {plural} from '/src/utils.js'
220
-
221
- function eventHandler(e) {
222
- let itemCount = 5
223
- e.target.value = plural(itemCount, ['One item', '# items'])
224
- }
225
- ```
226
-
227
- ### Context
228
-
229
- Disambiguate identical texts:
230
-
231
- ```typescript
232
- // @wc-context: navigation
233
- const msg = 'Home'
234
-
235
- // @wc-context: building
236
- const bldg = 'Home'
237
- ```
238
- ### Useful Usage Pattern
239
-
240
- A common scenario is needing to prevent string extraction inside functions, but
241
- you may not want to modify the global heuristic or litter your code with
242
- comment directives. A cleaner approach is to extract constants to the top
243
- level, which are ignored by default:
244
-
245
- ```js
246
- const keys = {
247
- Escape: 'Escape',
248
- ArrowUp: 'ArrowUp',
249
- // ...
250
- };
251
-
252
- function eventHandler(event) {
253
- if (event.key === keys.Escape) {
254
- // ...
255
- }
256
- }
257
- ```
258
-
259
- ## 🛠️ Configuration Reference
260
-
261
- ### Main plugin
262
-
263
- ```javascript
264
- export default {
265
- // Source language code
266
- sourceLocale: 'en',
267
-
268
- // Available locales with plural rules
269
- locales: {
270
- en: {
271
- name: 'English',
272
- // the number of plurals in the language
273
- nPlurals: 2,
274
- // The expression to use to decide which candidate to choose when using your plural() function
275
- // The number should be used as 'n' because this will be the body of an arrow function with n as an argument.
276
- pluralRule: 'n == 1 ? 0 : 1'
277
- }
278
- },
279
-
280
- // Adapters are the project type specific bindings for wuchale. For the vanilla adapter configuration, look below.
281
- // You can repeat the same adapter with different keys and catalog configurations
282
- // to break the translations into smaller parts
283
- adapters: {
284
- // key: AdapterConf
285
- }
286
-
287
- // Enable HMR updates during development. You can disable this to avoid the small overhead
288
- // of live translation updates and work solely with the source language.
289
- // HMR is highly optimized -- it updates only the affected components,
290
- // preserving application state and avoiding full reloads.
291
- hmr: true,
292
-
293
- // Gemini API key (or 'env' to use GEMINI_API_KEY)
294
- // if it's 'env', and GEMINI_API_KEY is not set, it is disabled
295
- // set it to null to disable it entirely
296
- geminiAPIKey: 'env'
297
- }
298
- ```
299
-
300
- ### Basic Adapter
301
-
302
- ```javascript
303
-
304
- import { adapter as vanillaAdapter } from "wuchale/adapter-vanilla"
17
+ ## 📚 Documentation
305
18
 
306
- const vanillaAdapterConf = vanillaAdapter({
307
- // Where to store translation files. {locale} will be replaced with the respective locale.
308
- catalog: './src/locales/{locale}',
309
-
310
- // Files to scan for translations and transform
311
- files: ['src/**/*.{js,ts}'],
312
-
313
- // Custom extraction logic
314
- // signature should be: (text: string, details: object) => boolean | undefined
315
- // details has the following properties:
316
- // scope: "markup" | "attribute" | "script",
317
- // topLevel?: "variable" | "function" | "expression",
318
- // topLevelCall?: string,
319
- // call?: string,
320
- // element?: string,
321
- // attribute?: string,
322
- // file?: string,
323
- heuristic: defaultHeuristic,
324
-
325
- // Your plural function name
326
- pluralFunc: 'plural',
327
- })
328
- ```
19
+ See the full guide at: [wuchale.dev](https://wuchale.dev/).
@@ -1,9 +1,9 @@
1
1
  import MagicString from "magic-string";
2
2
  import type Estree from 'estree';
3
- import { NestText } from './adapter.js';
4
- import type { AdapterFunc, CommentDirectives, HeuristicDetailsBase, HeuristicFunc, IndexTracker, ProxyModuleFunc, ScriptTopLevel, TransformOutput } from "./adapter.js";
3
+ import { NestText } from './adapters.js';
4
+ import type { AdapterArgs, Adapter, CommentDirectives, HeuristicDetailsBase, HeuristicFunc, IndexTracker, ScriptDeclType, TransformOutput } from "./adapters.js";
5
5
  export declare function parseScript(content: string): import("acorn").Program;
6
- export declare const runtimeConst = "wuchaleRuntime";
6
+ export declare const runtimeConst = "_w_runtime_";
7
7
  export declare class Transformer {
8
8
  index: IndexTracker;
9
9
  heuristic: HeuristicFunc;
@@ -11,16 +11,17 @@ export declare class Transformer {
11
11
  filename: string;
12
12
  mstr: MagicString;
13
13
  pluralFunc: string;
14
- key: string;
14
+ initInsideFuncLoadID: string | null;
15
15
  rtFunc: string;
16
16
  rtFuncPlural: string;
17
17
  rtPluralsRule: string;
18
18
  commentDirectives: CommentDirectives;
19
19
  insideProgram: boolean;
20
- topLevel: ScriptTopLevel;
20
+ declaring: ScriptDeclType;
21
+ insideFuncDef: boolean;
21
22
  currentCall: string;
22
23
  currentTopLevelCall: string;
23
- constructor(key: string, content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string);
24
+ constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string, initInsideFuncLoadID?: string);
24
25
  checkHeuristic: (text: string, detailsBase: HeuristicDetailsBase) => [boolean, NestText];
25
26
  visitLiteral: (node: Estree.Literal & {
26
27
  start: number;
@@ -48,8 +49,10 @@ export declare class Transformer {
48
49
  visitVariableDeclaration: (node: Estree.VariableDeclaration) => NestText[];
49
50
  visitExportNamedDeclaration: (node: Estree.ExportNamedDeclaration) => NestText[];
50
51
  visitExportDefaultDeclaration: (node: Estree.ExportNamedDeclaration) => NestText[];
52
+ visitFunctionBody: (node: Estree.BlockStatement | Estree.Expression) => NestText[];
51
53
  visitFunctionDeclaration: (node: Estree.FunctionDeclaration) => NestText[];
52
54
  visitArrowFunctionExpression: (node: Estree.ArrowFunctionExpression) => NestText[];
55
+ visitFunctionExpression: (node: Estree.FunctionExpression) => NestText[];
53
56
  visitBlockStatement: (node: Estree.BlockStatement) => NestText[];
54
57
  visitReturnStatement: (node: Estree.ReturnStatement) => NestText[];
55
58
  visitIfStatement: (node: Estree.IfStatement) => NestText[];
@@ -58,8 +61,12 @@ export declare class Transformer {
58
61
  processCommentDirectives: (data: string) => CommentDirectives;
59
62
  visit: (node: Estree.BaseNode) => NestText[];
60
63
  finalize: (txts: NestText[]) => TransformOutput;
61
- transform: () => TransformOutput;
64
+ transform: (loaderPath: string, loadID: string) => TransformOutput;
62
65
  }
63
- export declare const proxyModuleHotUpdate: (virtModEvent: string, targetVar?: string) => string;
64
- export declare const proxyModuleDefault: ProxyModuleFunc;
65
- export declare const adapter: AdapterFunc;
66
+ export declare const proxyModuleHotUpdate: (loadID: string | null, eventSend: string, eventReceive: string, targetVar?: string) => string;
67
+ type VanillaAdapArgs = AdapterArgs & {
68
+ initInsideFunc?: boolean;
69
+ };
70
+ export declare const adapter: (args?: VanillaAdapArgs) => Adapter;
71
+ export {};
72
+ //# sourceMappingURL=adapter-vanilla.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-vanilla.d.ts","sourceRoot":"","sources":["../../src/adapter-vanilla.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import MagicString from "magic-string";
3
3
  import { Parser } from 'acorn';
4
4
  import { tsPlugin } from '@sveltejs/acorn-typescript';
5
- import { defaultHeuristicFuncOnly, NestText } from './adapter.js';
5
+ import { defaultGenerateLoadID, defaultHeuristicFuncOnly, NestText } from './adapters.js';
6
6
  import { deepMergeObjects } from "./config.js";
7
7
  const scriptParseOptions = {
8
8
  sourceType: 'module',
@@ -13,7 +13,8 @@ const ScriptParser = Parser.extend(tsPlugin());
13
13
  export function parseScript(content) {
14
14
  return ScriptParser.parse(content, scriptParseOptions);
15
15
  }
16
- export const runtimeConst = 'wuchaleRuntime';
16
+ export const runtimeConst = '_w_runtime_';
17
+ const rtFuncInit = '_w_load_';
17
18
  export class Transformer {
18
19
  index;
19
20
  heuristic;
@@ -21,24 +22,25 @@ export class Transformer {
21
22
  filename;
22
23
  mstr;
23
24
  pluralFunc;
25
+ initInsideFuncLoadID;
24
26
  // for runtime
25
- key;
26
27
  rtFunc = `${runtimeConst}.t`;
27
28
  rtFuncPlural = `${runtimeConst}.tp`;
28
29
  rtPluralsRule = `${runtimeConst}.plr`;
29
30
  // state
30
31
  commentDirectives = {};
31
32
  insideProgram = false;
32
- topLevel = null;
33
+ declaring = null;
34
+ insideFuncDef = false;
33
35
  currentCall;
34
36
  currentTopLevelCall;
35
- constructor(key, content, filename, index, heuristic, pluralsFunc) {
36
- this.key = key;
37
+ constructor(content, filename, index, heuristic, pluralsFunc, initInsideFuncLoadID) {
37
38
  this.index = index;
38
39
  this.heuristic = heuristic;
39
40
  this.pluralFunc = pluralsFunc;
40
41
  this.content = content;
41
42
  this.filename = filename;
43
+ this.initInsideFuncLoadID = initInsideFuncLoadID;
42
44
  }
43
45
  checkHeuristic = (text, detailsBase) => {
44
46
  if (!text) {
@@ -50,7 +52,8 @@ export class Transformer {
50
52
  const details = {
51
53
  file: this.filename,
52
54
  call: this.currentCall,
53
- topLevel: this.topLevel,
55
+ topLevel: this.declaring,
56
+ insideFuncDef: this.insideFuncDef,
54
57
  topLevelCall: this.currentTopLevelCall,
55
58
  ...detailsBase,
56
59
  };
@@ -195,7 +198,7 @@ export class Transformer {
195
198
  };
196
199
  visitVariableDeclaration = (node) => {
197
200
  const txts = [];
198
- let atTopLevelDefn = this.insideProgram && !this.topLevel;
201
+ let atTopLevelDefn = this.insideProgram && !this.declaring;
199
202
  for (const dec of node.declarations) {
200
203
  if (!dec.init) {
201
204
  continue;
@@ -203,10 +206,10 @@ export class Transformer {
203
206
  // store the name of the function after =
204
207
  if (atTopLevelDefn) {
205
208
  if (dec.init.type === 'ArrowFunctionExpression') {
206
- this.topLevel = 'function';
209
+ this.declaring = 'function';
207
210
  }
208
211
  else {
209
- this.topLevel = 'variable';
212
+ this.declaring = 'variable';
210
213
  if (dec.init.type === 'CallExpression') {
211
214
  this.currentTopLevelCall = this.getCalleeName(dec.init.callee);
212
215
  }
@@ -220,22 +223,32 @@ export class Transformer {
220
223
  }
221
224
  if (atTopLevelDefn) {
222
225
  this.currentTopLevelCall = null; // reset
223
- this.topLevel = null;
226
+ this.declaring = null;
224
227
  }
225
228
  return txts;
226
229
  };
227
230
  visitExportNamedDeclaration = (node) => node.declaration ? this.visit(node.declaration) : [];
228
231
  visitExportDefaultDeclaration = this.visitExportNamedDeclaration;
232
+ visitFunctionBody = (node) => {
233
+ const insideFuncDef = this.insideFuncDef;
234
+ this.insideFuncDef = true;
235
+ const txts = this.visit(node);
236
+ if (this.initInsideFuncLoadID && node.type === 'BlockStatement') {
237
+ // @ts-expect-error
238
+ this.mstr.prependLeft(node.start + 1, `const ${runtimeConst} = ${rtFuncInit}('${this.initInsideFuncLoadID}')\n`);
239
+ }
240
+ this.insideFuncDef = insideFuncDef;
241
+ return txts;
242
+ };
229
243
  visitFunctionDeclaration = (node) => {
230
- const topLevelDef = this.topLevel;
231
- this.topLevel = 'function';
232
- const txts = this.visit(node.body);
233
- if (!topLevelDef) {
234
- this.topLevel = null;
235
- }
244
+ const declaring = this.declaring;
245
+ this.declaring = 'function';
246
+ const txts = this.visitFunctionBody(node.body);
247
+ this.declaring = declaring;
236
248
  return txts;
237
249
  };
238
- visitArrowFunctionExpression = (node) => this.visit(node.body);
250
+ visitArrowFunctionExpression = (node) => this.visitFunctionBody(node.body);
251
+ visitFunctionExpression = (node) => this.visitFunctionBody(node.body);
239
252
  visitBlockStatement = (node) => {
240
253
  const txts = [];
241
254
  for (const statement of node.body) {
@@ -355,59 +368,61 @@ export class Transformer {
355
368
  map: this.mstr.generateMap(),
356
369
  };
357
370
  };
358
- transform = () => {
371
+ transform = (loaderPath, loadID) => {
359
372
  const ast = parseScript(this.content);
360
373
  this.mstr = new MagicString(this.content);
361
374
  const txts = this.visit(ast);
362
375
  if (txts.length) {
363
- const collectionFunc = '_wre_';
364
376
  const importModule = `
365
- import { ${collectionFunc} } from "wuchale/runtime"
366
- const ${runtimeConst} = ${collectionFunc}("${this.key}")
377
+ import ${rtFuncInit} from "${loaderPath}"
378
+ const ${runtimeConst} = ${rtFuncInit}('${loadID}')
367
379
  `;
368
380
  this.mstr.appendRight(0, importModule);
369
381
  }
370
382
  return this.finalize(txts);
371
383
  };
372
384
  }
373
- export const proxyModuleHotUpdate = (virtModEvent, targetVar = 'data') => `
385
+ export const proxyModuleHotUpdate = (loadID, eventSend, eventReceive, targetVar = 'data') => `
374
386
  if (import.meta.hot) {
375
- import.meta.hot.on('${virtModEvent}', newData => {
387
+ import.meta.hot.on('${eventSend}', newData => {
376
388
  for (let i = 0; i < newData.length; i++) {
377
389
  if (JSON.stringify(data[i]) !== JSON.stringify(newData[i])) {
378
390
  ${targetVar}[i] = newData[i]
379
391
  }
380
392
  }
381
393
  })
382
- import.meta.hot.send('${virtModEvent}')
394
+ import.meta.hot.send('${eventReceive}'${loadID == null ? '' : `, {loadID: '${loadID}'}`})
383
395
  }
384
396
  `;
385
- export const proxyModuleDefault = virtModEvent => `export {key, default, pluralsRule} from '${virtModEvent}'`;
386
- const proxyModuleDev = (virtModEvent) => `
387
- import data, {key, pluralsRule} from '${virtModEvent}'
388
- ${proxyModuleHotUpdate(virtModEvent)}
389
- export {key, pluralsRule}
390
- export default data
397
+ const dataModuleDev = ({ loadID: loadID, eventSend, eventReceive, compiled, plural }) => `
398
+ export const plural = ${plural}
399
+ export const data = ${compiled}
400
+ ${proxyModuleHotUpdate(loadID, eventSend, eventReceive)}
391
401
  `;
392
402
  const defaultArgs = {
393
403
  files: ['src/**/*.{js,ts}'],
394
404
  catalog: './src/locales/{locale}',
395
405
  pluralsFunc: 'plural',
396
406
  heuristic: defaultHeuristicFuncOnly,
407
+ generateLoadID: defaultGenerateLoadID,
408
+ granularLoad: false,
409
+ writeFiles: {},
410
+ initInsideFunc: false,
397
411
  };
398
412
  export const adapter = (args = defaultArgs) => {
399
- const { heuristic, pluralsFunc, files, catalog } = deepMergeObjects(args, defaultArgs);
413
+ const { heuristic, pluralsFunc, files, catalog, granularLoad, generateLoadID: generateID, writeFiles, initInsideFunc, } = deepMergeObjects(args, defaultArgs);
400
414
  return {
401
- transform: (content, filename, index, key) => {
402
- return new Transformer(key, content, filename, index, heuristic, pluralsFunc).transform();
415
+ transform: ({ content, filename, index, loaderPath, loadID }) => {
416
+ return new Transformer(content, filename, index, heuristic, pluralsFunc, initInsideFunc ? loadID : null).transform(loaderPath, loadID);
403
417
  },
404
418
  files,
405
419
  catalog,
406
- compiledExt: '.js',
407
- proxyModule: {
408
- dev: proxyModuleDev,
409
- default: proxyModuleDefault,
410
- }
420
+ granularLoad,
421
+ generateLoadID: generateID,
422
+ loaderExts: ['.js', '.ts'],
423
+ dataModuleDev,
424
+ writeFiles,
425
+ defaultLoaderPath: () => new URL('../../src/loader.default.js', import.meta.url).pathname,
411
426
  };
412
427
  };
413
428
  //# sourceMappingURL=adapter-vanilla.js.map