@wuchale/svelte 0.13.5 → 0.14.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
+ // $$ cd .. && npm run test
1
2
  import { defaultGenerateLoadID, defaultHeuristic, deepMergeObjects } from 'wuchale';
2
- import { initRuntimeStmt, adapter as vanillaAdapter } from 'wuchale/adapter-vanilla';
3
3
  import { SvelteTransformer } from "./transformer.js";
4
4
  import { getDependencies } from 'wuchale/adapter-utils';
5
5
  const topLevelDeclarationsInside = ['$derived', '$derived.by'];
@@ -31,12 +31,32 @@ const defaultArgs = {
31
31
  bundleLoad: false,
32
32
  generateLoadID: defaultGenerateLoadID,
33
33
  writeFiles: {},
34
+ runtime: {
35
+ useReactive: ({ file, funcName, additional }) => {
36
+ const inTopLevel = funcName == null;
37
+ const inModule = file.endsWith('.svelte.js') || additional.module;
38
+ return {
39
+ init: inModule ? inTopLevel : (inTopLevel ? true : null),
40
+ use: inModule ? inTopLevel : true,
41
+ };
42
+ },
43
+ reactive: {
44
+ importName: 'default',
45
+ wrapInit: expr => `$derived(${expr})`,
46
+ wrapUse: expr => expr,
47
+ },
48
+ plain: {
49
+ importName: 'get',
50
+ wrapInit: expr => expr,
51
+ wrapUse: expr => expr,
52
+ },
53
+ },
34
54
  };
35
55
  export const adapter = (args = defaultArgs) => {
36
- const { heuristic, pluralsFunc, ...rest } = deepMergeObjects(args, defaultArgs);
56
+ const { heuristic, pluralsFunc, runtime, ...rest } = deepMergeObjects(args, defaultArgs);
37
57
  return {
38
- transform: ({ content, filename, index, header }) => {
39
- return new SvelteTransformer(content, filename, index, heuristic, pluralsFunc, initRuntimeStmt(header.expr)).transformSv(header.head, header.expr);
58
+ transform: ({ content, filename, index, expr }) => {
59
+ return new SvelteTransformer(content, filename, index, heuristic, pluralsFunc, expr, runtime).transformSv();
40
60
  },
41
61
  loaderExts: ['.svelte.js', '.svelte.ts', '.js', '.ts'],
42
62
  defaultLoaders: async () => {
@@ -44,18 +64,22 @@ export const adapter = (args = defaultArgs) => {
44
64
  return ['bundle'];
45
65
  }
46
66
  const deps = await getDependencies();
47
- const available = ['reactive', 'vanilla'];
67
+ const available = ['svelte'];
48
68
  if (deps.has('@sveltejs/kit')) {
49
69
  available.unshift('sveltekit');
50
70
  }
51
71
  return available;
52
72
  },
53
- defaultLoaderPath: (loader) => {
54
- if (loader === 'vanilla') {
55
- return vanillaAdapter().defaultLoaderPath('vite');
73
+ defaultLoaderPath: loader => {
74
+ if (loader === 'sveltekit') {
75
+ return {
76
+ client: new URL(`../src/loaders/svelte.svelte.js`, import.meta.url).pathname,
77
+ ssr: new URL(`../src/loaders/sveltekit.ssr.svelte.js`, import.meta.url).pathname
78
+ };
56
79
  }
57
80
  return new URL(`../src/loaders/${loader}.svelte.js`, import.meta.url).pathname;
58
81
  },
82
+ runtime,
59
83
  ...rest,
60
84
  docsUrl: 'https://wuchale.dev/adapters/svelte'
61
85
  };
@@ -2,7 +2,7 @@ import type { AnyNode } from "acorn";
2
2
  import { type AST } from "svelte/compiler";
3
3
  import { Message } from 'wuchale';
4
4
  import { Transformer } from 'wuchale/adapter-vanilla';
5
- import type { IndexTracker, HeuristicFunc, TransformOutput, CommentDirectives } from 'wuchale';
5
+ import type { IndexTracker, HeuristicFunc, TransformOutput, CommentDirectives, CatalogExpr, RuntimeConf } from 'wuchale';
6
6
  import { MixedVisitor } from "wuchale/adapter-utils";
7
7
  type MixedNodesTypes = AST.Text | AST.Tag | AST.ElementLike | AST.Block | AST.Comment;
8
8
  export declare class SvelteTransformer extends Transformer {
@@ -12,7 +12,7 @@ export declare class SvelteTransformer extends Transformer {
12
12
  lastVisitIsComment: boolean;
13
13
  currentSnippet: number;
14
14
  mixedVisitor: MixedVisitor<MixedNodesTypes>;
15
- constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string, initRuntime: string);
15
+ constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string, catalogExpr: CatalogExpr, rtConf: RuntimeConf);
16
16
  visitExpressionTag: (node: AST.ExpressionTag) => Message[];
17
17
  initMixedVisitor: () => MixedVisitor<MixedNodesTypes>;
18
18
  visitFragment: (node: AST.Fragment) => Message[];
@@ -34,6 +34,6 @@ export declare class SvelteTransformer extends Transformer {
34
34
  visitSvelteWindow: (node: AST.SvelteWindow) => Message[];
35
35
  visitRoot: (node: AST.Root) => Message[];
36
36
  visitSv: (node: AST.SvelteNode | AnyNode) => Message[];
37
- transformSv: (headerHead: string, headerExpr: string) => TransformOutput;
37
+ transformSv: () => TransformOutput;
38
38
  }
39
39
  export {};
@@ -2,10 +2,10 @@ import MagicString from "magic-string";
2
2
  import { parse } from "svelte/compiler";
3
3
  import { Message } from 'wuchale';
4
4
  import { Transformer, parseScript } from 'wuchale/adapter-vanilla';
5
- import { MixedVisitor, nonWhitespaceText, runtimeVars } from "wuchale/adapter-utils";
5
+ import { MixedVisitor, nonWhitespaceText } from "wuchale/adapter-utils";
6
6
  const nodesWithChildren = ['RegularElement', 'Component'];
7
- const rtComponent = 'WuchaleTrans';
8
- const snipPrefix = 'wuchaleSnippet';
7
+ const rtComponent = 'W_tx_';
8
+ const snipPrefix = '_w_snippet_';
9
9
  export class SvelteTransformer extends Transformer {
10
10
  // state
11
11
  currentElement;
@@ -14,12 +14,13 @@ export class SvelteTransformer extends Transformer {
14
14
  lastVisitIsComment = false;
15
15
  currentSnippet = 0;
16
16
  mixedVisitor;
17
- constructor(content, filename, index, heuristic, pluralsFunc, initRuntime) {
18
- super(content, filename, index, heuristic, pluralsFunc, initRuntime);
17
+ constructor(content, filename, index, heuristic, pluralsFunc, catalogExpr, rtConf) {
18
+ super(content, filename, index, heuristic, pluralsFunc, catalogExpr, rtConf);
19
19
  }
20
20
  visitExpressionTag = (node) => this.visit(node.expression);
21
21
  initMixedVisitor = () => new MixedVisitor({
22
22
  mstr: this.mstr,
23
+ vars: this.vars,
23
24
  getRange: node => ({ start: node.start, end: node.end }),
24
25
  isText: node => node.type === 'Text',
25
26
  isComment: node => node.type === 'Comment',
@@ -44,21 +45,25 @@ export class SvelteTransformer extends Transformer {
44
45
  const snippetName = `${snipPrefix}${this.currentSnippet}`;
45
46
  snippets.push(snippetName);
46
47
  this.currentSnippet++;
47
- const snippetBegin = `\n{#snippet ${snippetName}(${haveCtx ? runtimeVars.nestCtx : ''})}\n`;
48
+ const snippetBegin = `\n{#snippet ${snippetName}(${haveCtx ? this.vars().nestCtx : ''})}\n`;
48
49
  this.mstr.appendRight(childStart, snippetBegin);
49
50
  this.mstr.prependLeft(childEnd, '\n{/snippet}');
50
51
  }
51
- let begin = `\n<${rtComponent} tags={[${snippets.join(', ')}]} ctx=`;
52
+ let begin = `\n<${rtComponent}`;
53
+ if (snippets.length) {
54
+ begin += ` t={[${snippets.join(', ')}]}`;
55
+ }
56
+ begin += ' x=';
52
57
  if (this.inCompoundText) {
53
- begin += `{${runtimeVars.nestCtx}} nest`;
58
+ begin += `{${this.vars().nestCtx}} n`;
54
59
  }
55
60
  else {
56
61
  const index = this.index.get(msgInfo.toKey());
57
- begin += `{${runtimeVars.rtCtx}(${index})}`;
62
+ begin += `{${this.vars().rtCtx}(${index})}`;
58
63
  }
59
64
  let end = ' />\n';
60
65
  if (hasExprs) {
61
- begin += ' args={[';
66
+ begin += ' a={[';
62
67
  end = ']}' + end;
63
68
  }
64
69
  this.mstr.appendLeft(lastChildEnd, begin);
@@ -93,7 +98,7 @@ export class SvelteTransformer extends Transformer {
93
98
  if (!pass) {
94
99
  return [];
95
100
  }
96
- this.mstr.update(node.start + startWh, node.end - endWh, `{${runtimeVars.rtTrans}(${this.index.get(msgInfo.toKey())})}`);
101
+ this.mstr.update(node.start + startWh, node.end - endWh, `{${this.vars().rtTrans}(${this.index.get(msgInfo.toKey())})}`);
97
102
  return [msgInfo];
98
103
  };
99
104
  visitSpreadAttribute = (node) => this.visit(node.expression);
@@ -130,7 +135,7 @@ export class SvelteTransformer extends Transformer {
130
135
  if (!pass) {
131
136
  return [];
132
137
  }
133
- this.mstr.update(value.start, value.end, `{${runtimeVars.rtTrans}(${this.index.get(msgInfo.toKey())})}`);
138
+ this.mstr.update(value.start, value.end, `{${this.vars().rtTrans}(${this.index.get(msgInfo.toKey())})}`);
134
139
  if (`'"`.includes(this.content[value.start - 1])) {
135
140
  this.mstr.remove(value.start - 1, value.start);
136
141
  this.mstr.remove(value.end, value.end + 1);
@@ -191,21 +196,17 @@ export class SvelteTransformer extends Transformer {
191
196
  const msgs = [];
192
197
  // @ts-ignore: module is a reserved keyword, not sure how to specify the type
193
198
  if (node.module) {
199
+ this.additionalState = { module: true };
194
200
  this.commentDirectives = {}; // reset
195
201
  // @ts-ignore
196
202
  msgs.push(...this.visitProgram(node.module.content));
203
+ this.additionalState = {}; // reset
197
204
  }
198
- // no need to init runtime inside components outside <script module>s
199
- // they run everytime they are rendered instead of once at startup
200
- const initRuntime = this.initRuntime;
201
- this.initRuntime = null;
202
205
  if (node.instance) {
203
206
  this.commentDirectives = {}; // reset
204
207
  msgs.push(...this.visitProgram(node.instance.content));
205
208
  }
206
209
  msgs.push(...this.visitFragment(node.fragment));
207
- // restore just in case
208
- this.initRuntime = initRuntime;
209
210
  return msgs;
210
211
  };
211
212
  visitSv = (node) => {
@@ -235,7 +236,7 @@ export class SvelteTransformer extends Transformer {
235
236
  this.commentDirectives = commentDirectivesPrev;
236
237
  return msgs;
237
238
  };
238
- transformSv = (headerHead, headerExpr) => {
239
+ transformSv = () => {
239
240
  const isComponent = this.filename.endsWith('.svelte');
240
241
  let ast;
241
242
  if (isComponent) {
@@ -249,36 +250,30 @@ export class SvelteTransformer extends Transformer {
249
250
  this.mstr = new MagicString(this.content);
250
251
  this.mixedVisitor = this.initMixedVisitor();
251
252
  const msgs = this.visitSv(ast);
252
- if (!msgs.length) {
253
- return this.finalize(msgs, 0);
254
- }
255
253
  const headerLines = [
256
254
  isComponent ? `\nimport ${rtComponent} from "@wuchale/svelte/runtime.svelte"` : '',
257
- headerHead,
258
- `const ${runtimeVars.rtConst} = $derived(${runtimeVars.rtWrap}(${headerExpr}))\n`,
255
+ this.initRuntime(this.filename, null, null, {}),
259
256
  ];
260
257
  const headerFin = headerLines.join('\n');
261
258
  if (ast.type === 'Program') {
262
- this.mstr.appendRight(0, headerFin + '\n');
263
- return this.finalize(msgs, 0);
259
+ const bodyStart = this.getRealBodyStart(ast.body);
260
+ return this.finalize(msgs, bodyStart, headerFin);
264
261
  }
265
262
  let hmrHeaderIndex = 0;
266
263
  if (ast.module) {
267
264
  // @ts-ignore
268
- hmrHeaderIndex = ast.module.content.start;
269
- this.mstr.appendRight(hmrHeaderIndex, headerFin);
265
+ hmrHeaderIndex = this.getRealBodyStart(ast.module.content.body);
270
266
  }
271
267
  else if (ast.instance) {
272
268
  // @ts-ignore
273
- hmrHeaderIndex = ast.instance.content.start;
274
- this.mstr.appendRight(hmrHeaderIndex, headerFin);
269
+ hmrHeaderIndex = this.getRealBodyStart(ast.instance.content.body);
275
270
  }
276
271
  else {
277
272
  this.mstr.prepend('<script>');
278
273
  // account index for hmr data here
279
- this.mstr.prependRight(0, `${headerFin}</script>\n`);
274
+ this.mstr.prependRight(0, `</script>\n`);
280
275
  // now hmr data can be prependRight(0, ...)
281
276
  }
282
- return this.finalize(msgs, hmrHeaderIndex);
277
+ return this.finalize(msgs, hmrHeaderIndex, headerFin);
283
278
  };
284
279
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wuchale/svelte",
3
- "version": "0.13.5",
3
+ "version": "0.14.1",
4
4
  "description": "Protobuf-like i18n from plain code: Svelte adapter",
5
5
  "scripts": {
6
6
  "dev": "tsc --watch",
@@ -52,7 +52,7 @@
52
52
  "license": "MIT",
53
53
  "dependencies": {
54
54
  "svelte": "^5.37.0",
55
- "wuchale": "^0.14.6"
55
+ "wuchale": "^0.15.4"
56
56
  },
57
57
  "devDependencies": {
58
58
  "acorn": "^8.15.0",
@@ -10,7 +10,11 @@ export function setLocale(newLocale) {
10
10
  locale = newLocale
11
11
  }
12
12
 
13
+ // for non-reactive
13
14
  /**
14
15
  * @param {{ [locale: string]: import("wuchale/runtime").CatalogModule }} catalogs
15
16
  */
16
- export default catalogs => catalogs[locale]
17
+ export const get = catalogs => catalogs[locale]
18
+
19
+ // same function, only will be inside $derived when used
20
+ export default get
@@ -8,4 +8,8 @@ import { registerLoaders, defaultCollection } from 'wuchale/load-utils'
8
8
 
9
9
  const catalogs = $state({})
10
10
 
11
- export default registerLoaders(key, loadCatalog, loadIDs, defaultCollection(catalogs))
11
+ // for non-reactive
12
+ export const get = registerLoaders(key, loadCatalog, loadIDs, defaultCollection(catalogs))
13
+
14
+ // same function, only will be inside $derived when used
15
+ export default get
@@ -0,0 +1,15 @@
1
+ // This is just the default loader.
2
+ // You can customize it however you want, it will not be overwritten once it exists and is not empty.
3
+
4
+ /// <reference types="wuchale/virtual" />
5
+
6
+ import { loadCatalog, loadIDs, key } from 'virtual:wuchale/proxy/sync' // because it's on the server
7
+ import { currentCatalog } from 'wuchale/load-utils/server'
8
+
9
+ export { loadCatalog, loadIDs, key } // for hooks.server.{js,ts}
10
+
11
+ // for non-reactive
12
+ export const get = (/** @type {string} */ loadID) => currentCatalog(key, loadID)
13
+
14
+ // same function, only will be inside $derived when used
15
+ export default get
@@ -1,16 +1,16 @@
1
1
  <script>
2
- const {nest = false, ctx, tags, args} = $props()
2
+ const {n = false, x, t, a} = $props()
3
3
  </script>
4
4
 
5
- {#each ctx as fragment, i}
5
+ {#each x as fragment, i}
6
6
  {#if typeof fragment === 'string'}
7
7
  {fragment}
8
8
  {:else if typeof fragment === 'number'}
9
- {#if !nest || i > 0}
10
- {args[fragment]}
9
+ {#if !n || i > 0}
10
+ {a[fragment]}
11
11
  {/if}
12
12
  {:else}
13
- {@const tag = tags[fragment[0]]}
13
+ {@const tag = t[fragment[0]]}
14
14
  {#if tag == null}
15
15
  [i18n-404:tag]
16
16
  {:else}
@@ -1,21 +0,0 @@
1
- // This is just the default loader.
2
- // You can customize it however you want, it will not be overwritten once it exists and is not empty.
3
-
4
- /// <reference types="wuchale/virtual" />
5
-
6
- import { loadCatalog, loadIDs, key } from 'virtual:wuchale/proxy' // or proxy/sync
7
- import { registerLoaders, defaultCollection } from 'wuchale/load-utils'
8
-
9
- export { loadCatalog, loadIDs, key } // for +layout.{js,ts} and hooks.server.{js,ts}
10
-
11
- let loadC
12
-
13
- if (import.meta.env.SSR) { // stripped from production client builds
14
- const { currentCatalog } = await import('wuchale/load-utils/server')
15
- loadC = (/** @type {string} */ loadID) => currentCatalog(key, loadID)
16
- } else { // client
17
- const catalogs = $state({})
18
- loadC = registerLoaders(key, loadCatalog, loadIDs, defaultCollection(catalogs))
19
- }
20
-
21
- export default loadC