@wuchale/svelte 0.19.4 → 0.20.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,4 +1,4 @@
1
- import { createHeuristic, defaultGenerateLoadID, defaultHeuristicOpts, fillDefaults, pofile } from 'wuchale';
1
+ import { createHeuristic, defaultHeuristicOpts, fillDefaults, pofile } from 'wuchale';
2
2
  import { loaderPathResolver } from 'wuchale/adapter-utils';
3
3
  import { pluralPattern } from 'wuchale/adapter-vanilla';
4
4
  import { SvelteTransformer } from './transformer.js';
@@ -46,9 +46,11 @@ export const defaultArgs = {
46
46
  storage: pofile(),
47
47
  patterns: [pluralPattern],
48
48
  heuristic: svelteDefaultHeuristic,
49
- granularLoad: false,
50
- bundleLoad: false,
51
- generateLoadID: defaultGenerateLoadID,
49
+ loading: {
50
+ direct: false,
51
+ granular: false,
52
+ group: [],
53
+ },
52
54
  loader: 'svelte',
53
55
  runtime: {
54
56
  initReactive: ({ file, funcName, ctx: { module } }) => {
@@ -91,11 +93,9 @@ export const adapter = (args = defaultArgs) => {
91
93
  }
92
94
  const { heuristic, patterns, runtime, loader, ...rest } = fillDefaults(args, defaultArgs);
93
95
  return {
94
- transform: ({ content, filename, index, expr, matchUrl }) => {
95
- return new SvelteTransformer(content, filename, index, heuristic, patterns, expr, runtime, matchUrl).transformSv();
96
- },
96
+ transform: ctx => new SvelteTransformer(ctx, heuristic, patterns, runtime).transformSv(),
97
97
  loaderExts: ['.svelte.js', '.svelte.ts', '.js', '.ts'],
98
- defaultLoaderPath: getDefaultLoaderPath(loader, rest.bundleLoad),
98
+ defaultLoaderPath: getDefaultLoaderPath(loader, rest.loading.direct),
99
99
  runtime,
100
100
  ...rest,
101
101
  };
@@ -1,50 +1,49 @@
1
1
  import type { AnyNode, VariableDeclarator } from 'acorn';
2
2
  import { type AST } from 'svelte/compiler';
3
- import type { CatalogExpr, CodePattern, HeuristicFunc, IndexTracker, Message, RuntimeConf, TransformOutput, UrlMatcher } from 'wuchale';
3
+ import type { CodePattern, HeuristicFunc, Message, RuntimeConf, TransformCtx, TransformOutput } from 'wuchale';
4
4
  import { MixedVisitor } from 'wuchale/adapter-utils';
5
5
  import { Transformer } from 'wuchale/adapter-vanilla';
6
- type MixedNodesTypes = AST.Text | AST.Tag | AST.ElementLike | AST.Block | AST.Comment;
6
+ type MixedNodesTypes = AST.Text | AST.Tag | AST.ElementLike | AST.SvelteElement | AST.Block | AST.Comment;
7
7
  type MixedVisitorSvelte = MixedVisitor<MixedNodesTypes, AST.Text, AST.Comment, AST.ExpressionTag>;
8
8
  export type RuntimeCtxSv = {
9
9
  module: boolean;
10
10
  };
11
11
  export declare class SvelteTransformer extends Transformer {
12
12
  currentElement?: string | undefined;
13
- inCompoundText: boolean;
14
13
  currentSnippet: number;
15
14
  moduleExportExprs: AnyNode[];
16
15
  mixedVisitor: MixedVisitorSvelte;
17
- constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, patterns: CodePattern[], catalogExpr: CatalogExpr, rtConf: RuntimeConf, matchUrl: UrlMatcher);
18
- visitExpressionTag: (node: AST.ExpressionTag) => Message[];
19
- visitVariableDeclarator: (node: VariableDeclarator) => Message[];
20
- initMixedVisitor: () => MixedVisitorSvelte;
21
- visitFragment: (node: AST.Fragment) => Message[];
22
- visitRegularElement: (node: AST.ElementLike) => Message[];
23
- visitComponent: (node: AST.ElementLike) => Message[];
24
- visitText: (node: AST.Text) => Message[];
25
- visitSpreadAttribute: (node: AST.SpreadAttribute) => Message[];
26
- visitAttribute: (node: AST.Attribute) => Message[];
27
- visitConstTag: (node: AST.ConstTag) => Message[];
28
- visitRenderTag: (node: AST.RenderTag) => Message[];
29
- visitHtmlTag: (node: AST.HtmlTag) => Message[];
30
- visitOnDirective: (node: AST.OnDirective) => Message[];
31
- hasIdentifier: (node: AnyNode | AnyNode[], name: string) => boolean;
32
- visitSnippetBlock: (node: AST.SnippetBlock) => Message[];
33
- visitIfBlock: (node: AST.IfBlock) => Message[];
34
- visitEachBlock: (node: AST.EachBlock) => Message[];
35
- visitKeyBlock: (node: AST.KeyBlock) => Message[];
36
- visitAwaitBlock: (node: AST.AwaitBlock) => Message[];
37
- visitSvelteBody: (node: AST.SvelteBody) => Message[];
38
- visitSvelteDocument: (node: AST.SvelteDocument) => Message[];
39
- visitSvelteElement: (node: AST.SvelteElement) => Message[];
40
- visitSvelteBoundary: (node: AST.SvelteBoundary) => Message[];
41
- visitSvelteHead: (node: AST.SvelteHead) => Message[];
42
- visitTitleElement: (node: AST.TitleElement) => Message[];
43
- visitSvelteWindow: (node: AST.SvelteWindow) => Message[];
44
- visitRoot: (node: AST.Root) => Message[];
45
- visitSv: (node: AST.SvelteNode | AnyNode) => Message[];
16
+ constructor(ctx: TransformCtx, heuristic: HeuristicFunc, patterns: CodePattern[], rtConf: RuntimeConf);
17
+ visitExpressionTag(node: AST.ExpressionTag): Message[];
18
+ visitVariableDeclarator(node: VariableDeclarator): Message[];
19
+ initMixedVisitor(): MixedVisitorSvelte;
20
+ visitFragment(node: AST.Fragment): Message[];
21
+ visitRegularElement(node: AST.ElementLike): Message[];
22
+ visitComponent(node: AST.Component): Message[];
23
+ visitSpreadAttribute(node: AST.SpreadAttribute): Message[];
24
+ visitAttribute(node: AST.Attribute): Message[];
25
+ visitConstTag(node: AST.ConstTag): Message[];
26
+ visitDeclarationTag(node: AST.DeclarationTag): Message[];
27
+ visitRenderTag(node: AST.RenderTag): Message[];
28
+ visitHtmlTag(node: AST.HtmlTag): Message[];
29
+ visitOnDirective(node: AST.OnDirective): Message[];
30
+ hasIdentifier(node: AnyNode | AnyNode[], name: string): boolean;
31
+ visitSnippetBlock(node: AST.SnippetBlock): Message[];
32
+ visitIfBlock(node: AST.IfBlock): Message[];
33
+ visitEachBlock(node: AST.EachBlock): Message[];
34
+ visitKeyBlock(node: AST.KeyBlock): Message[];
35
+ visitAwaitBlock(node: AST.AwaitBlock): Message[];
36
+ visitSvelteBody(node: AST.SvelteBody): Message[];
37
+ visitSvelteDocument(node: AST.SvelteDocument): Message[];
38
+ visitSvelteElement(node: AST.SvelteElement): Message[];
39
+ visitSvelteBoundary(node: AST.SvelteBoundary): Message[];
40
+ visitSvelteHead(node: AST.SvelteHead): Message[];
41
+ visitTitleElement(node: AST.TitleElement): Message[];
42
+ visitSvelteWindow(node: AST.SvelteWindow): Message[];
43
+ visitRoot(node: AST.Root): Message[];
44
+ visitSv(node: AST.SvelteNode | AnyNode): Message[];
46
45
  /** collects the ranges that will be checked if a snippet identifier is exported using RegExp test to simplify */
47
- collectModuleExportExprs: (script: AST.Script) => void;
48
- transformSv: () => Promise<TransformOutput>;
46
+ collectModuleExportExprs(script: AST.Script): void;
47
+ transformSv(): Promise<TransformOutput>;
49
48
  }
50
49
  export {};
@@ -1,8 +1,7 @@
1
1
  import { parse, preprocess } from 'svelte/compiler';
2
2
  import { getKey } from 'wuchale';
3
- import { MixedVisitor, nonWhitespaceText, varNames } from 'wuchale/adapter-utils';
3
+ import { MixedVisitor, varNames } from 'wuchale/adapter-utils';
4
4
  import { parseScript, Transformer } from 'wuchale/adapter-vanilla';
5
- const nodesWithChildren = ['RegularElement', 'Component'];
6
5
  const noWrapTopCalls = ['$props', '$state', '$derived', '$effect'];
7
6
  const rtComponent = 'W_tx_';
8
7
  const headerAdd = `\nimport ${rtComponent} from "@wuchale/svelte/runtime.svelte"`;
@@ -17,23 +16,25 @@ const removeCSS = ({ content }) => ({
17
16
  export class SvelteTransformer extends Transformer {
18
17
  // state
19
18
  currentElement;
20
- inCompoundText = false;
21
19
  currentSnippet = 0;
22
20
  moduleExportExprs = []; // to choose which runtime var to use for snippets
23
21
  mixedVisitor;
24
- constructor(content, filename, index, heuristic, patterns, catalogExpr, rtConf, matchUrl) {
25
- super(content, filename, index, heuristic, patterns, catalogExpr, rtConf, matchUrl, [varNames.rt, rtModuleVar]);
22
+ constructor(ctx, heuristic, patterns, rtConf) {
23
+ super(ctx, heuristic, patterns, rtConf, [varNames.rt, rtModuleVar]);
26
24
  this.heuristciDetails.insideProgram = false;
27
25
  this.mixedVisitor = this.initMixedVisitor();
28
26
  }
29
- visitExpressionTag = (node) => this.visit(node.expression);
30
- visitVariableDeclarator = (node) => {
31
- const msgs = this.defaultVisitVariableDeclarator(node);
27
+ visitExpressionTag(node) {
28
+ return this.visit(node.expression);
29
+ }
30
+ visitVariableDeclarator(node) {
31
+ const msgs = super.visitVariableDeclarator(node);
32
32
  const init = node.init;
33
33
  if (!msgs.length ||
34
- this.heuristciDetails.declaring != null ||
34
+ (this.heuristciDetails.declaring != null && this.heuristciDetails.declaring !== 'variable') ||
35
35
  init == null ||
36
- ['ArrowFunctionExpression', 'FunctionExpression'].includes(init.type)) {
36
+ init.type === 'ArrowFunctionExpression' ||
37
+ init.type === 'FunctionExpression') {
37
38
  return msgs;
38
39
  }
39
40
  const needsWrapping = msgs.some(msg => {
@@ -53,75 +54,72 @@ export class SvelteTransformer extends Transformer {
53
54
  return msgs;
54
55
  }
55
56
  const isExported = this.moduleExportExprs.some(node => init.start >= node.start && init.end <= node.end);
56
- if (!isExported) {
57
+ if (!isExported && this.initReactive()) {
57
58
  this.mstr.appendLeft(init.start, '$derived(');
58
59
  this.mstr.appendRight(init.end, ')');
59
60
  }
60
61
  return msgs;
61
- };
62
- initMixedVisitor = () => new MixedVisitor({
63
- mstr: this.mstr,
64
- vars: this.vars,
65
- getRange: node => ({ start: node.start, end: node.end }),
66
- isText: node => node.type === 'Text',
67
- isComment: node => node.type === 'Comment',
68
- leaveInPlace: node => ['ConstTag', 'SnippetBlock'].includes(node.type),
69
- isExpression: node => node.type === 'ExpressionTag',
70
- getTextContent: node => node.data,
71
- getCommentData: node => node.data.trim(),
72
- canHaveChildren: node => nodesWithChildren.includes(node.type),
73
- visitFunc: (child, inCompoundText) => {
74
- const inCompoundTextPrev = this.inCompoundText;
75
- this.inCompoundText = inCompoundText;
76
- const childTxts = this.visitSv(child);
77
- this.inCompoundText = inCompoundTextPrev; // restore
78
- return childTxts;
79
- },
80
- visitExpressionTag: this.visitExpressionTag,
81
- fullHeuristicDetails: this.fullHeuristicDetails,
82
- checkHeuristic: this.getHeuristicMessageType,
83
- index: this.index,
84
- wrapNested: (msgInfo, hasExprs, nestedRanges, lastChildEnd) => {
85
- const snippets = [];
86
- // create and reference snippets
87
- for (const [childStart, childEnd, haveCtx] of nestedRanges) {
88
- const snippetName = `${snipPrefix}${this.currentSnippet}`;
89
- snippets.push(snippetName);
90
- this.currentSnippet++;
91
- const snippetBegin = `\n{#snippet ${snippetName}(${haveCtx ? this.vars().nestCtx : ''})}\n`;
92
- this.mstr.appendRight(childStart, snippetBegin);
93
- this.mstr.prependLeft(childEnd, '\n{/snippet}\n');
94
- }
95
- let begin = `\n<${rtComponent}`;
96
- if (snippets.length) {
97
- begin += ` t={[${snippets.join(', ')}]}`;
98
- }
99
- begin += ' x=';
100
- if (this.inCompoundText) {
101
- begin += `{${this.vars().nestCtx}} n`;
102
- }
103
- else {
104
- const index = this.index.get(getKey(msgInfo.msgStr, msgInfo.context));
105
- begin += `{${this.vars().rtCtx}(${index})}`;
106
- }
107
- let end = ' />\n';
108
- if (hasExprs) {
109
- begin += ' a={[';
110
- end = `]}${end}`;
111
- }
112
- this.mstr.appendLeft(lastChildEnd, begin);
113
- this.mstr.appendRight(lastChildEnd, end);
114
- },
115
- });
116
- visitFragment = (node) => this.mixedVisitor.visit({
117
- children: node.nodes,
118
- commentDirectives: this.commentDirectives,
119
- inCompoundText: this.inCompoundText,
120
- scope: 'markup',
121
- element: this.currentElement,
122
- useComponent: this.currentElement !== 'title',
123
- });
124
- visitRegularElement = (node) => {
62
+ }
63
+ initMixedVisitor() {
64
+ return new MixedVisitor({
65
+ mstr: this.mstr,
66
+ index: this.index,
67
+ content: this.content,
68
+ vars: this.vars.bind(this),
69
+ getRange: node => ({ start: node.start, end: node.end }),
70
+ isText: node => node.type === 'Text',
71
+ isComment: node => node.type === 'Comment',
72
+ leaveInPlace: node => ['ConstTag', 'SnippetBlock'].includes(node.type),
73
+ isExpression: node => node.type === 'ExpressionTag',
74
+ getTextContent: node => node.data,
75
+ getCommentData: node => node.data.trim(),
76
+ visitFunc: this.visitSv.bind(this),
77
+ fullHeuristicDetails: this.fullHeuristicDetails.bind(this),
78
+ checkHeuristic: this.getHeuristicMessageType.bind(this),
79
+ wrapNested: (inNested, msgInfo, hasExprs, nestedRanges, lastChildEnd) => {
80
+ const snippets = [];
81
+ const vars = this.vars();
82
+ // create and reference snippets
83
+ for (const [childStart, childEnd, haveCtx] of nestedRanges) {
84
+ const snippetName = `${snipPrefix}${this.currentSnippet}`;
85
+ snippets.push(snippetName);
86
+ this.currentSnippet++;
87
+ const snippetBegin = `\n{#snippet ${snippetName}(${haveCtx ? vars.nestCtx : ''})}\n`;
88
+ this.mstr.appendRight(childStart, snippetBegin);
89
+ this.mstr.prependLeft(childEnd, '\n{/snippet}\n');
90
+ }
91
+ let begin = `\n<${rtComponent}`;
92
+ if (snippets.length) {
93
+ begin += ` t={[${snippets.join(', ')}]}`;
94
+ }
95
+ begin += ' x=';
96
+ if (inNested) {
97
+ begin += `{${vars.nestCtx}} n`;
98
+ }
99
+ else {
100
+ const index = this.index.get(getKey(msgInfo.msgStr, msgInfo.context));
101
+ begin += `{${vars.rtCtx}(${index})}`;
102
+ }
103
+ let end = ' />\n';
104
+ if (hasExprs) {
105
+ begin += ' a={[';
106
+ end = `]}${end}`;
107
+ }
108
+ this.mstr.appendLeft(lastChildEnd, begin);
109
+ this.mstr.appendRight(lastChildEnd, end);
110
+ },
111
+ });
112
+ }
113
+ visitFragment(node) {
114
+ return this.mixedVisitor.visit({
115
+ children: node.nodes,
116
+ commentDirectives: this.commentDirectives,
117
+ scope: 'markup',
118
+ element: this.currentElement,
119
+ useComponent: this.currentElement !== 'title',
120
+ });
121
+ }
122
+ visitRegularElement(node) {
125
123
  const currentElement = this.currentElement;
126
124
  this.currentElement = node.name;
127
125
  const msgs = [];
@@ -131,22 +129,14 @@ export class SvelteTransformer extends Transformer {
131
129
  msgs.push(...this.visitFragment(node.fragment));
132
130
  this.currentElement = currentElement;
133
131
  return msgs;
134
- };
135
- visitComponent = this.visitRegularElement;
136
- visitText = (node) => {
137
- const [startWh, trimmed, endWh] = nonWhitespaceText(node.data);
138
- const [pass, msgInfo] = this.checkHeuristic(trimmed, {
139
- scope: 'markup',
140
- element: this.currentElement,
141
- });
142
- if (!pass) {
143
- return [];
144
- }
145
- this.mstr.update(node.start + startWh, node.end - endWh, `{${this.literalRepl(msgInfo)}}`);
146
- return [msgInfo];
147
- };
148
- visitSpreadAttribute = (node) => this.visit(node.expression);
149
- visitAttribute = (node) => {
132
+ }
133
+ visitComponent(node) {
134
+ return this.visitRegularElement(node);
135
+ }
136
+ visitSpreadAttribute(node) {
137
+ return this.visit(node.expression);
138
+ }
139
+ visitAttribute(node) {
150
140
  if (node.value === true) {
151
141
  return [];
152
142
  }
@@ -158,14 +148,15 @@ export class SvelteTransformer extends Transformer {
158
148
  values = [node.value];
159
149
  }
160
150
  if (values.length > 1) {
161
- return this.mixedVisitor.visit({
151
+ const msgs = this.mixedVisitor.visit({
162
152
  children: values,
163
153
  commentDirectives: this.commentDirectives,
164
- inCompoundText: false,
165
154
  scope: 'attribute',
166
155
  element: this.currentElement,
167
156
  attribute: node.name,
168
157
  });
158
+ msgs.push(...this.mixedVisitor.applyMod('attribute'));
159
+ return msgs;
169
160
  }
170
161
  const value = values[0];
171
162
  const heuDetails = {
@@ -195,15 +186,29 @@ export class SvelteTransformer extends Transformer {
195
186
  this.mstr.remove(value.end, value.end + 1);
196
187
  }
197
188
  return [msgInfo];
198
- };
199
- visitConstTag = (node) => {
189
+ }
190
+ visitConstTag(node) {
200
191
  // @ts-expect-error
201
192
  return this.visitVariableDeclaration(node.declaration);
202
- };
203
- visitRenderTag = (node) => this.visit(node.expression);
204
- visitHtmlTag = (node) => this.visit(node.expression);
205
- visitOnDirective = (node) => this.visit(node.expression);
206
- hasIdentifier = (node, name) => {
193
+ }
194
+ visitDeclarationTag(node) {
195
+ const prevDeclaring = this.heuristciDetails.declaring;
196
+ this.heuristciDetails.declaring = 'variable';
197
+ // @ts-expect-error
198
+ const msgs = this.visitVariableDeclaration(node.declaration);
199
+ this.heuristciDetails.declaring = prevDeclaring;
200
+ return msgs;
201
+ }
202
+ visitRenderTag(node) {
203
+ return this.visit(node.expression);
204
+ }
205
+ visitHtmlTag(node) {
206
+ return this.visit(node.expression);
207
+ }
208
+ visitOnDirective(node) {
209
+ return this.visit(node.expression);
210
+ }
211
+ hasIdentifier(node, name) {
207
212
  if (!node || typeof node !== 'object') {
208
213
  return false;
209
214
  }
@@ -214,8 +219,8 @@ export class SvelteTransformer extends Transformer {
214
219
  return node.name === name;
215
220
  }
216
221
  return Object.values(node).some(value => this.hasIdentifier(value, name));
217
- };
218
- visitSnippetBlock = (node) => {
222
+ }
223
+ visitSnippetBlock(node) {
219
224
  // use module runtime var because the snippet may be exported from the module
220
225
  const prevRtVar = this.currentRtVar;
221
226
  if (this.hasIdentifier(this.moduleExportExprs, node.expression.name)) {
@@ -224,16 +229,16 @@ export class SvelteTransformer extends Transformer {
224
229
  const msgs = this.visitFragment(node.body);
225
230
  this.currentRtVar = prevRtVar;
226
231
  return msgs;
227
- };
228
- visitIfBlock = (node) => {
232
+ }
233
+ visitIfBlock(node) {
229
234
  const msgs = this.visit(node.test);
230
235
  msgs.push(...this.visitSv(node.consequent));
231
236
  if (node.alternate) {
232
237
  msgs.push(...this.visitSv(node.alternate));
233
238
  }
234
239
  return msgs;
235
- };
236
- visitEachBlock = (node) => {
240
+ }
241
+ visitEachBlock(node) {
237
242
  const msgs = [...this.visit(node.expression), ...this.visitSv(node.body)];
238
243
  if (node.key) {
239
244
  msgs.push(...this.visit(node.key));
@@ -242,11 +247,11 @@ export class SvelteTransformer extends Transformer {
242
247
  msgs.push(...this.visitSv(node.fallback));
243
248
  }
244
249
  return msgs;
245
- };
246
- visitKeyBlock = (node) => {
250
+ }
251
+ visitKeyBlock(node) {
247
252
  return [...this.visit(node.expression), ...this.visitSv(node.fragment)];
248
- };
249
- visitAwaitBlock = (node) => {
253
+ }
254
+ visitAwaitBlock(node) {
250
255
  const msgs = this.visit(node.expression);
251
256
  if (node.then) {
252
257
  msgs.push(...this.visitFragment(node.then));
@@ -258,18 +263,38 @@ export class SvelteTransformer extends Transformer {
258
263
  msgs.push(...this.visitFragment(node.catch));
259
264
  }
260
265
  return msgs;
261
- };
262
- visitSvelteBody = (node) => node.attributes.flatMap(this.visitSv);
263
- visitSvelteDocument = (node) => node.attributes.flatMap(this.visitSv);
264
- visitSvelteElement = (node) => node.attributes.flatMap(this.visitSv);
265
- visitSvelteBoundary = (node) => [
266
- ...node.attributes.flatMap(this.visitSv),
267
- ...this.visitSv(node.fragment),
268
- ];
269
- visitSvelteHead = (node) => this.visitSv(node.fragment);
270
- visitTitleElement = (node) => this.visitRegularElement(node);
271
- visitSvelteWindow = (node) => node.attributes.flatMap(this.visitSv);
272
- visitRoot = (node) => {
266
+ }
267
+ visitSvelteBody(node) {
268
+ return node.attributes.flatMap(n => this.visitSv(n));
269
+ }
270
+ visitSvelteDocument(node) {
271
+ return node.attributes.flatMap(n => this.visitSv(n));
272
+ }
273
+ visitSvelteElement(node) {
274
+ const currentElement = this.currentElement;
275
+ if (node.tag.type === 'Literal' && typeof node.tag.value === 'string') {
276
+ this.currentElement = node.tag.value;
277
+ }
278
+ else {
279
+ this.currentElement = 'svelte:element';
280
+ }
281
+ const msgs = [...node.attributes.flatMap(n => this.visitSv(n)), ...this.visitFragment(node.fragment)];
282
+ this.currentElement = currentElement;
283
+ return msgs;
284
+ }
285
+ visitSvelteBoundary(node) {
286
+ return [...node.attributes.flatMap(n => this.visitSv(n)), ...this.visitSv(node.fragment)];
287
+ }
288
+ visitSvelteHead(node) {
289
+ return this.visitSv(node.fragment);
290
+ }
291
+ visitTitleElement(node) {
292
+ return this.visitRegularElement(node);
293
+ }
294
+ visitSvelteWindow(node) {
295
+ return node.attributes.flatMap(n => this.visitSv(n));
296
+ }
297
+ visitRoot(node) {
273
298
  const msgs = [];
274
299
  if (node.module) {
275
300
  const prevRtVar = this.currentRtVar;
@@ -291,12 +316,14 @@ export class SvelteTransformer extends Transformer {
291
316
  this.commentDirectives = {}; // reset
292
317
  msgs.push(...this.visitProgram(node.instance.content));
293
318
  }
294
- msgs.push(...this.visitFragment(node.fragment));
319
+ msgs.push(...this.visitFragment(node.fragment), ...this.mixedVisitor.applyMod());
295
320
  return msgs;
296
- };
297
- visitSv = (node) => this.visit(node);
321
+ }
322
+ visitSv(node) {
323
+ return this.visit(node);
324
+ }
298
325
  /** collects the ranges that will be checked if a snippet identifier is exported using RegExp test to simplify */
299
- collectModuleExportExprs = (script) => {
326
+ collectModuleExportExprs(script) {
300
327
  for (const stmt of script.content.body) {
301
328
  if (stmt.type !== 'ExportNamedDeclaration') {
302
329
  continue;
@@ -322,8 +349,8 @@ export class SvelteTransformer extends Transformer {
322
349
  this.moduleExportExprs.push(decl.init);
323
350
  }
324
351
  }
325
- };
326
- transformSv = async () => {
352
+ }
353
+ async transformSv() {
327
354
  const isComponent = this.heuristciDetails.file.endsWith('.svelte');
328
355
  let ast;
329
356
  if (isComponent) {
@@ -369,5 +396,5 @@ export class SvelteTransformer extends Transformer {
369
396
  // now hmr data can be prependRight(0, ...)
370
397
  }
371
398
  return this.finalize(msgs, headerIndex, headerAdd);
372
- };
399
+ }
373
400
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wuchale/svelte",
3
- "version": "0.19.4",
3
+ "version": "0.20.1",
4
4
  "description": "Protobuf-like i18n from plain code: Svelte adapter",
5
5
  "scripts": {
6
6
  "dev": "tsc --watch",
@@ -50,14 +50,16 @@
50
50
  "bugs": "https://github.com/wuchalejs/wuchale/issues",
51
51
  "author": "K1DV5",
52
52
  "license": "MIT",
53
+ "peerDependencies": {
54
+ "svelte": "^5"
55
+ },
53
56
  "dependencies": {
54
- "magic-string": "^0.30.21",
55
- "svelte": "^5",
56
- "wuchale": "^0.23.0"
57
+ "wuchale": "^0.25.0"
57
58
  },
58
59
  "devDependencies": {
59
- "@types/node": "~24.12.2",
60
- "acorn": "^8.16.0",
60
+ "@types/node": "~24.13.2",
61
+ "svelte": "^5.56.3",
62
+ "acorn": "^8.17.0",
61
63
  "typescript": "^6.0.3"
62
64
  },
63
65
  "type": "module"
@@ -12,7 +12,7 @@ export function setLocale(newLocale) {
12
12
 
13
13
  // for non-reactive
14
14
  /**
15
- * @param {{ [locale: string]: import("wuchale/runtime").CatalogModule }} catalogs
15
+ * @param {{ [locale in import('${DATA}').Locale]: import("wuchale/runtime").CatalogModule }} catalogs
16
16
  */
17
17
  export const getRuntime = catalogs => toRuntime(catalogs[locale], locale)
18
18
 
@@ -1,12 +1,13 @@
1
1
  import { defaultCollection, registerLoaders } from 'wuchale/load-utils'
2
- import { loadCatalog, loadIDs } from '${PROXY}'
2
+ import { loadCatalog, loadCount } from '${PROXY}'
3
3
 
4
4
  const key = '${KEY}'
5
5
 
6
- const runtimes = $state({})
6
+ /** @type import('wuchale/runtime').Runtime[] */
7
+ const runtimes = $state([])
7
8
 
8
9
  // for non-reactive
9
- export const getRuntime = registerLoaders(key, loadCatalog, loadIDs, defaultCollection(runtimes))
10
+ export const getRuntime = registerLoaders(key, loadCatalog, loadCount, defaultCollection(runtimes))
10
11
 
11
12
  // same function, only will be inside $derived when used
12
13
  export const getRuntimeRx = getRuntime
@@ -1,12 +1,12 @@
1
1
  import { currentRuntime } from 'wuchale/load-utils/server'
2
- import { loadCatalog, loadIDs } from '${PROXY_SYNC}'
2
+ import { loadCatalog, loadCount } from '${PROXY_SYNC}'
3
3
 
4
4
  const key = '${KEY}'
5
5
 
6
- export { key, loadCatalog, loadIDs } // for hooks.server.{js,ts}
6
+ export { key, loadCatalog, loadCount } // for hooks.server.{js,ts}
7
7
 
8
8
  // for non-reactive
9
- export const getRuntime = (/** @type {string} */ loadID) => currentRuntime(key, loadID)
9
+ export const getRuntime = (loadID = 0) => currentRuntime(key, loadID)
10
10
 
11
11
  // same function, only will be inside $derived when used
12
12
  export const getRuntimeRx = getRuntime