@wuchale/svelte 0.8.2 → 0.8.3
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/package.json +6 -4
- package/src/adapter.ts +468 -0
- package/src/index.ts +1 -0
- package/src/runtime.svelte.ts +18 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wuchale/svelte",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "i18n for svelte without turning your codebase upside down",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "tsc --watch",
|
|
@@ -32,16 +32,18 @@
|
|
|
32
32
|
],
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|
|
35
|
-
"src
|
|
35
|
+
"src"
|
|
36
36
|
],
|
|
37
37
|
"exports": {
|
|
38
38
|
".": {
|
|
39
39
|
"types": "./dist/src/index.d.ts",
|
|
40
|
-
"import": "./dist/src/index.js"
|
|
40
|
+
"import": "./dist/src/index.js",
|
|
41
|
+
"source": "./src/index.ts"
|
|
41
42
|
},
|
|
42
43
|
"./runtime.svelte.js": {
|
|
43
44
|
"types": "./dist/src/runtime.svelte.d.ts",
|
|
44
|
-
"import": "./dist/src/runtime.svelte.js"
|
|
45
|
+
"import": "./dist/src/runtime.svelte.js",
|
|
46
|
+
"source": "./src/runtime.svelte.ts"
|
|
45
47
|
},
|
|
46
48
|
"./runtime.svelte": "./src/runtime.svelte"
|
|
47
49
|
},
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import MagicString from "magic-string"
|
|
2
|
+
import type { Program, AnyNode } from "acorn"
|
|
3
|
+
import { parse, type AST } from "svelte/compiler"
|
|
4
|
+
import { defaultHeuristic, NestText } from 'wuchale/adapter'
|
|
5
|
+
import { deepMergeObjects } from 'wuchale/config'
|
|
6
|
+
import { Transformer, parseScript, proxyModuleHotUpdate, proxyModuleDefault, runtimeConst } from 'wuchale/adapter-vanilla'
|
|
7
|
+
import type {
|
|
8
|
+
IndexTracker,
|
|
9
|
+
HeuristicFunc,
|
|
10
|
+
TransformOutput,
|
|
11
|
+
AdapterFunc,
|
|
12
|
+
AdapterArgs,
|
|
13
|
+
CommentDirectives,
|
|
14
|
+
ProxyModuleFunc
|
|
15
|
+
} from 'wuchale/adapter'
|
|
16
|
+
|
|
17
|
+
const nodesWithChildren = ['RegularElement', 'Component']
|
|
18
|
+
const topLevelDeclarationsInside = ['$derived', '$derived.by']
|
|
19
|
+
const ignoreElements = ['path']
|
|
20
|
+
|
|
21
|
+
const svelteHeuristic: HeuristicFunc = (text, details) => {
|
|
22
|
+
if (!defaultHeuristic(text, details)) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
if (ignoreElements.includes(details.element)) {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
if (details.scope !== 'script') {
|
|
29
|
+
return true
|
|
30
|
+
}
|
|
31
|
+
if (details.topLevel === 'variable' && !topLevelDeclarationsInside.includes(details.topLevelCall)) {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
if (details.call === '$inspect') {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const rtComponent = 'WuchaleTrans'
|
|
41
|
+
const snipPrefix = 'wuchaleSnippet'
|
|
42
|
+
const rtFuncCtx = `${runtimeConst}.cx`
|
|
43
|
+
const rtFuncCtxTrans = `${runtimeConst}.tx`
|
|
44
|
+
|
|
45
|
+
export class SvelteTransformer extends Transformer {
|
|
46
|
+
|
|
47
|
+
// state
|
|
48
|
+
currentElement?: string
|
|
49
|
+
inCompoundText: boolean = false
|
|
50
|
+
commentDirectivesStack: CommentDirectives[] = []
|
|
51
|
+
lastVisitIsComment: boolean = false
|
|
52
|
+
currentSnippet: number = 0
|
|
53
|
+
|
|
54
|
+
constructor(key: string, content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, pluralsFunc: string) {
|
|
55
|
+
super(key, content, filename, index, heuristic, pluralsFunc)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
visitExpressionTag = (node: AST.ExpressionTag): NestText[] => this.visit(node.expression)
|
|
59
|
+
|
|
60
|
+
nonWhitespaceText = (node: AST.Text): [number, string, number] => {
|
|
61
|
+
let trimmedS = node.data.trimStart()
|
|
62
|
+
const startWh = node.data.length - trimmedS.length
|
|
63
|
+
let trimmed = trimmedS.trimEnd()
|
|
64
|
+
const endWh = trimmedS.length - trimmed.length
|
|
65
|
+
return [startWh, trimmed, endWh]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
separatelyVisitChildren = (node: AST.Fragment): [boolean, boolean, boolean, NestText[]] => {
|
|
69
|
+
let hasTextChild = false
|
|
70
|
+
let hasNonTextChild = false
|
|
71
|
+
let heurTxt = ''
|
|
72
|
+
let hasCommentDirectives = false
|
|
73
|
+
for (const child of node.nodes) {
|
|
74
|
+
if (child.type === 'Text') {
|
|
75
|
+
const txt = child.data.trim()
|
|
76
|
+
if (!txt) {
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
79
|
+
hasTextChild = true
|
|
80
|
+
heurTxt += child.data + ' '
|
|
81
|
+
} else if (child.type === 'Comment') {
|
|
82
|
+
if (child.data.trim().startsWith('@wc-')) {
|
|
83
|
+
hasCommentDirectives = true
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
hasNonTextChild = true
|
|
87
|
+
heurTxt += `# `
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
heurTxt = heurTxt.trimEnd()
|
|
91
|
+
const [passHeuristic] = this.checkHeuristic(heurTxt, { scope: 'markup', element: this.currentElement })
|
|
92
|
+
let hasCompoundText = hasTextChild && hasNonTextChild
|
|
93
|
+
const visitAsOne = passHeuristic && !hasCommentDirectives
|
|
94
|
+
if (this.inCompoundText || hasCompoundText && visitAsOne) {
|
|
95
|
+
return [false, hasTextChild, hasCompoundText, []]
|
|
96
|
+
}
|
|
97
|
+
const txts = []
|
|
98
|
+
// can't be extracted as one; visitSv each separately
|
|
99
|
+
for (const child of node.nodes) {
|
|
100
|
+
txts.push(...this.visitSv(child))
|
|
101
|
+
}
|
|
102
|
+
return [true, false, false, txts]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
visitFragment = (node: AST.Fragment): NestText[] => {
|
|
106
|
+
if (node.nodes.length === 0) {
|
|
107
|
+
return []
|
|
108
|
+
}
|
|
109
|
+
const [visitedSeparately, hasTextChild, hasCompoundText, separateTxts] = this.separatelyVisitChildren(node)
|
|
110
|
+
if (visitedSeparately) {
|
|
111
|
+
return separateTxts
|
|
112
|
+
}
|
|
113
|
+
let txt = ''
|
|
114
|
+
let iArg = 0
|
|
115
|
+
let iTag = 0
|
|
116
|
+
const lastChildEnd = node.nodes.slice(-1)[0].end
|
|
117
|
+
const childrenForSnippets: [number, number, boolean][] = []
|
|
118
|
+
let hasTextDescendants = false
|
|
119
|
+
const txts = []
|
|
120
|
+
for (const child of node.nodes) {
|
|
121
|
+
if (child.type === 'Comment') {
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
if (child.type === 'Text') {
|
|
125
|
+
const [startWh, trimmed, endWh] = this.nonWhitespaceText(child)
|
|
126
|
+
const nTxt = new NestText(trimmed, 'markup', this.commentDirectives.context)
|
|
127
|
+
if (startWh && !txt.endsWith(' ')) {
|
|
128
|
+
txt += ' '
|
|
129
|
+
}
|
|
130
|
+
if (!trimmed) { // whitespace
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
txt += nTxt.text
|
|
134
|
+
if (endWh) {
|
|
135
|
+
txt += ' '
|
|
136
|
+
}
|
|
137
|
+
this.mstr.remove(child.start, child.end)
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
if (child.type === 'ExpressionTag') {
|
|
141
|
+
txts.push(...this.visitExpressionTag(child))
|
|
142
|
+
if (!hasCompoundText) {
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
txt += `{${iArg}}`
|
|
146
|
+
let moveStart = child.start
|
|
147
|
+
if (iArg > 0) {
|
|
148
|
+
this.mstr.update(child.start, child.start + 1, ', ')
|
|
149
|
+
} else {
|
|
150
|
+
moveStart++
|
|
151
|
+
this.mstr.remove(child.start, child.start + 1)
|
|
152
|
+
}
|
|
153
|
+
this.mstr.move(moveStart, child.end - 1, lastChildEnd)
|
|
154
|
+
this.mstr.remove(child.end - 1, child.end)
|
|
155
|
+
iArg++
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
// elements, components and other things as well
|
|
159
|
+
const nestedTextSupported = nodesWithChildren.includes(child.type)
|
|
160
|
+
const inCompoundTextPrev = this.inCompoundText
|
|
161
|
+
this.inCompoundText = nestedTextSupported
|
|
162
|
+
const childTxts = this.visitSv(child)
|
|
163
|
+
this.inCompoundText = inCompoundTextPrev // restore
|
|
164
|
+
let snippNeedsCtx = false
|
|
165
|
+
let chTxt = ''
|
|
166
|
+
for (const txt of childTxts) {
|
|
167
|
+
if (nodesWithChildren.includes(child.type) && txt.scope === 'markup') {
|
|
168
|
+
chTxt += txt.text[0]
|
|
169
|
+
hasTextDescendants = true
|
|
170
|
+
snippNeedsCtx = true
|
|
171
|
+
} else { // attributes, blocks
|
|
172
|
+
txts.push(txt)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
childrenForSnippets.push([child.start, child.end, snippNeedsCtx])
|
|
176
|
+
if (nodesWithChildren.includes(child.type) && chTxt) {
|
|
177
|
+
chTxt = `<${iTag}>${chTxt}</${iTag}>`
|
|
178
|
+
} else {
|
|
179
|
+
// childless elements and everything else
|
|
180
|
+
chTxt = `<${iTag}/>`
|
|
181
|
+
}
|
|
182
|
+
iTag++
|
|
183
|
+
txt += chTxt
|
|
184
|
+
}
|
|
185
|
+
txt = txt.trim()
|
|
186
|
+
if (!txt) {
|
|
187
|
+
return txts
|
|
188
|
+
}
|
|
189
|
+
const nTxt = new NestText(txt, 'markup', this.commentDirectives.context)
|
|
190
|
+
if (hasTextChild || hasTextDescendants) {
|
|
191
|
+
txts.push(nTxt)
|
|
192
|
+
} else {
|
|
193
|
+
return txts
|
|
194
|
+
}
|
|
195
|
+
if (childrenForSnippets.length) {
|
|
196
|
+
const snippets = []
|
|
197
|
+
// create and reference snippets
|
|
198
|
+
for (const [childStart, childEnd, haveCtx] of childrenForSnippets) {
|
|
199
|
+
const snippetName = `${snipPrefix}${this.currentSnippet}`
|
|
200
|
+
snippets.push(snippetName)
|
|
201
|
+
this.currentSnippet++
|
|
202
|
+
const snippetBegin = `\n{#snippet ${snippetName}(${haveCtx ? 'ctx' : ''})}\n`
|
|
203
|
+
this.mstr.appendRight(childStart, snippetBegin)
|
|
204
|
+
this.mstr.prependLeft(childEnd, '\n{/snippet}')
|
|
205
|
+
}
|
|
206
|
+
let begin = `\n<${rtComponent} tags={[${snippets.join(', ')}]} ctx=`
|
|
207
|
+
if (this.inCompoundText) {
|
|
208
|
+
begin += `{ctx} nest`
|
|
209
|
+
} else {
|
|
210
|
+
const index = this.index.get(nTxt.toKey())
|
|
211
|
+
begin += `{${rtFuncCtx}(${index})}`
|
|
212
|
+
}
|
|
213
|
+
let end = ' />\n'
|
|
214
|
+
if (iArg > 0) {
|
|
215
|
+
begin += ' args={['
|
|
216
|
+
end = ']}' + end
|
|
217
|
+
}
|
|
218
|
+
this.mstr.appendLeft(lastChildEnd, begin)
|
|
219
|
+
this.mstr.appendRight(lastChildEnd, end)
|
|
220
|
+
} else if (hasTextChild) {
|
|
221
|
+
// no need for component use
|
|
222
|
+
let begin = '{'
|
|
223
|
+
let end = ')}'
|
|
224
|
+
if (this.inCompoundText) {
|
|
225
|
+
begin += `${rtFuncCtxTrans}(ctx`
|
|
226
|
+
} else {
|
|
227
|
+
begin += `${this.rtFunc}(${this.index.get(nTxt.toKey())}`
|
|
228
|
+
}
|
|
229
|
+
if (iArg) {
|
|
230
|
+
begin += ', ['
|
|
231
|
+
end = ']' + end
|
|
232
|
+
}
|
|
233
|
+
this.mstr.appendLeft(lastChildEnd, begin)
|
|
234
|
+
this.mstr.appendRight(lastChildEnd, end)
|
|
235
|
+
}
|
|
236
|
+
return txts
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
visitRegularElement = (node: AST.ElementLike): NestText[] => {
|
|
240
|
+
const currentElement = this.currentElement
|
|
241
|
+
this.currentElement = node.name
|
|
242
|
+
const txts: NestText[] = []
|
|
243
|
+
for (const attrib of node.attributes) {
|
|
244
|
+
txts.push(...this.visitSv(attrib))
|
|
245
|
+
}
|
|
246
|
+
txts.push(...this.visitFragment(node.fragment))
|
|
247
|
+
this.currentElement = currentElement
|
|
248
|
+
return txts
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
visitComponent = this.visitRegularElement
|
|
252
|
+
|
|
253
|
+
visitText = (node: AST.Text): NestText[] => {
|
|
254
|
+
const [startWh, trimmed, endWh] = this.nonWhitespaceText(node)
|
|
255
|
+
const [pass, txt] = this.checkHeuristic(trimmed, { scope: 'markup' })
|
|
256
|
+
if (!pass) {
|
|
257
|
+
return []
|
|
258
|
+
}
|
|
259
|
+
this.mstr.update(node.start + startWh, node.end - endWh, `{${this.rtFunc}(${this.index.get(txt.toKey())})}`)
|
|
260
|
+
return [txt]
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
visitSpreadAttribute = (node: AST.SpreadAttribute): NestText[] => this.visit(node.expression)
|
|
264
|
+
|
|
265
|
+
visitAttribute = (node: AST.Attribute): NestText[] => {
|
|
266
|
+
if (node.value === true) {
|
|
267
|
+
return []
|
|
268
|
+
}
|
|
269
|
+
const txts = []
|
|
270
|
+
let values: (AST.ExpressionTag | AST.Text)[]
|
|
271
|
+
if (Array.isArray(node.value)) {
|
|
272
|
+
values = node.value
|
|
273
|
+
} else {
|
|
274
|
+
values = [node.value]
|
|
275
|
+
}
|
|
276
|
+
for (const value of values) {
|
|
277
|
+
if (value.type !== 'Text') { // ExpressionTag
|
|
278
|
+
txts.push(...this.visitSv(value))
|
|
279
|
+
continue
|
|
280
|
+
}
|
|
281
|
+
// Text
|
|
282
|
+
const { start, end } = value
|
|
283
|
+
const [pass, txt] = this.checkHeuristic(value.data, {
|
|
284
|
+
scope: 'attribute',
|
|
285
|
+
element: this.currentElement,
|
|
286
|
+
attribute: node.name,
|
|
287
|
+
})
|
|
288
|
+
if (!pass) {
|
|
289
|
+
continue
|
|
290
|
+
}
|
|
291
|
+
txts.push(txt)
|
|
292
|
+
this.mstr.update(value.start, value.end, `{${this.rtFunc}(${this.index.get(txt.toKey())})}`)
|
|
293
|
+
if (!`'"`.includes(this.content[start - 1])) {
|
|
294
|
+
continue
|
|
295
|
+
}
|
|
296
|
+
this.mstr.remove(start - 1, start)
|
|
297
|
+
this.mstr.remove(end, end + 1)
|
|
298
|
+
}
|
|
299
|
+
return txts
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
visitSnippetBlock = (node: AST.SnippetBlock): NestText[] => this.visitFragment(node.body)
|
|
303
|
+
|
|
304
|
+
visitIfBlock = (node: AST.IfBlock): NestText[] => {
|
|
305
|
+
const txts = this.visit(node.test)
|
|
306
|
+
txts.push(...this.visitSv(node.consequent))
|
|
307
|
+
if (node.alternate) {
|
|
308
|
+
txts.push(...this.visitSv(node.alternate))
|
|
309
|
+
}
|
|
310
|
+
return txts
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
visitEachBlock = (node: AST.EachBlock): NestText[] => {
|
|
314
|
+
const txts = [
|
|
315
|
+
...this.visit(node.expression),
|
|
316
|
+
...this.visitSv(node.body),
|
|
317
|
+
]
|
|
318
|
+
if (node.key) {
|
|
319
|
+
txts.push(...this.visit(node.key))
|
|
320
|
+
}
|
|
321
|
+
if (node.fallback) {
|
|
322
|
+
txts.push(...this.visitSv(node.fallback))
|
|
323
|
+
}
|
|
324
|
+
return txts
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
visitKeyBlock = (node: AST.KeyBlock): NestText[] => {
|
|
328
|
+
return [
|
|
329
|
+
...this.visit(node.expression),
|
|
330
|
+
...this.visitSv(node.fragment),
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
visitAwaitBlock = (node: AST.AwaitBlock): NestText[] => {
|
|
335
|
+
const txts = [
|
|
336
|
+
...this.visit(node.expression),
|
|
337
|
+
...this.visitFragment(node.then),
|
|
338
|
+
]
|
|
339
|
+
if (node.pending) {
|
|
340
|
+
txts.push(...this.visitFragment(node.pending),)
|
|
341
|
+
}
|
|
342
|
+
if (node.catch) {
|
|
343
|
+
txts.push(...this.visitFragment(node.catch),)
|
|
344
|
+
}
|
|
345
|
+
return txts
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
visitSvelteBody = (node: AST.SvelteBody): NestText[] => node.attributes.map(this.visitSv).flat()
|
|
349
|
+
|
|
350
|
+
visitSvelteDocument = (node: AST.SvelteDocument): NestText[] => node.attributes.map(this.visitSv).flat()
|
|
351
|
+
|
|
352
|
+
visitSvelteElement = (node: AST.SvelteElement): NestText[] => node.attributes.map(this.visitSv).flat()
|
|
353
|
+
|
|
354
|
+
visitSvelteBoundary = (node: AST.SvelteBoundary): NestText[] => [
|
|
355
|
+
...node.attributes.map(this.visitSv).flat(),
|
|
356
|
+
...this.visitSv(node.fragment),
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
visitSvelteHead = (node: AST.SvelteHead): NestText[] => this.visitSv(node.fragment)
|
|
360
|
+
|
|
361
|
+
visitSvelteWindow = (node: AST.SvelteWindow): NestText[] => node.attributes.map(this.visitSv).flat()
|
|
362
|
+
|
|
363
|
+
visitRoot = (node: AST.Root): NestText[] => {
|
|
364
|
+
const txts = this.visitFragment(node.fragment)
|
|
365
|
+
if (node.instance) {
|
|
366
|
+
this.commentDirectives = {} // reset
|
|
367
|
+
txts.push(...this.visitProgram(node.instance.content))
|
|
368
|
+
}
|
|
369
|
+
// @ts-ignore: module is a reserved keyword, not sure how to specify the type
|
|
370
|
+
if (node.module) {
|
|
371
|
+
this.commentDirectives = {} // reset
|
|
372
|
+
// @ts-ignore
|
|
373
|
+
txts.push(...this.visitProgram(node.module.content))
|
|
374
|
+
}
|
|
375
|
+
return txts
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
visitSv = (node: AST.SvelteNode | AnyNode): NestText[] => {
|
|
379
|
+
if (node.type === 'Comment') {
|
|
380
|
+
const directives = this.processCommentDirectives(node.data.trim())
|
|
381
|
+
if (this.lastVisitIsComment) {
|
|
382
|
+
this.commentDirectivesStack[this.commentDirectivesStack.length - 1] = directives
|
|
383
|
+
} else {
|
|
384
|
+
this.commentDirectivesStack.push(directives)
|
|
385
|
+
}
|
|
386
|
+
this.lastVisitIsComment = true
|
|
387
|
+
return []
|
|
388
|
+
}
|
|
389
|
+
let txts = []
|
|
390
|
+
const commentDirectivesPrev = this.commentDirectives
|
|
391
|
+
if (this.lastVisitIsComment) {
|
|
392
|
+
this.commentDirectives = this.commentDirectivesStack.pop()
|
|
393
|
+
}
|
|
394
|
+
if (this.commentDirectives.forceInclude !== false) {
|
|
395
|
+
txts = this.visit(node)
|
|
396
|
+
}
|
|
397
|
+
this.commentDirectives = commentDirectivesPrev
|
|
398
|
+
this.lastVisitIsComment = false
|
|
399
|
+
return txts
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
transform = (): TransformOutput => {
|
|
403
|
+
const isComponent = this.filename.endsWith('.svelte')
|
|
404
|
+
let ast: AST.Root | Program
|
|
405
|
+
if (isComponent) {
|
|
406
|
+
ast = parse(this.content, { modern: true })
|
|
407
|
+
} else {
|
|
408
|
+
ast = parseScript(this.content)
|
|
409
|
+
}
|
|
410
|
+
this.mstr = new MagicString(this.content)
|
|
411
|
+
const txts = this.visitSv(ast)
|
|
412
|
+
if (!txts.length) {
|
|
413
|
+
return this.finalize(txts)
|
|
414
|
+
}
|
|
415
|
+
const getCtxFunc = '_wrs_'
|
|
416
|
+
const importComponent = `import ${rtComponent} from "@wuchale/svelte/runtime.svelte"`
|
|
417
|
+
const importStmt = `
|
|
418
|
+
import { ${getCtxFunc} } from "@wuchale/svelte/runtime.svelte.js"
|
|
419
|
+
${ast.type === 'Root' ? importComponent : ''}
|
|
420
|
+
const ${runtimeConst} = $derived(${getCtxFunc}("${this.key}"))
|
|
421
|
+
`
|
|
422
|
+
if (ast.type === 'Program') {
|
|
423
|
+
this.mstr.appendRight(0, importStmt + '\n')
|
|
424
|
+
return this.finalize(txts)
|
|
425
|
+
}
|
|
426
|
+
if (ast.module) {
|
|
427
|
+
// @ts-ignore
|
|
428
|
+
this.mstr.appendRight(ast.module.content.start, importStmt)
|
|
429
|
+
} else if (ast.instance) {
|
|
430
|
+
// @ts-ignore
|
|
431
|
+
this.mstr.appendRight(ast.instance.content.start, importStmt)
|
|
432
|
+
} else {
|
|
433
|
+
this.mstr.prepend(`<script>${importStmt}</script>\n`)
|
|
434
|
+
}
|
|
435
|
+
return this.finalize(txts)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const proxyModuleDev: ProxyModuleFunc = (virtModEvent) => `
|
|
440
|
+
import defaultData, {key, pluralsRule} from '${virtModEvent}'
|
|
441
|
+
const data = $state(defaultData)
|
|
442
|
+
${proxyModuleHotUpdate(virtModEvent)}
|
|
443
|
+
export {key, pluralsRule}
|
|
444
|
+
export default data
|
|
445
|
+
`
|
|
446
|
+
|
|
447
|
+
const defaultArgs: AdapterArgs = {
|
|
448
|
+
files: ['src/**/*.svelte', 'src/**/*.svelte.{js,ts}'],
|
|
449
|
+
catalog: './src/locales/{locale}',
|
|
450
|
+
pluralsFunc: 'plural',
|
|
451
|
+
heuristic: svelteHeuristic,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export const adapter: AdapterFunc = (args: AdapterArgs = defaultArgs) => {
|
|
455
|
+
const { heuristic, pluralsFunc, files, catalog } = deepMergeObjects(args, defaultArgs)
|
|
456
|
+
return {
|
|
457
|
+
transform: (content, filename, index, key) => {
|
|
458
|
+
return new SvelteTransformer(key, content, filename, index, heuristic, pluralsFunc).transform()
|
|
459
|
+
},
|
|
460
|
+
files,
|
|
461
|
+
catalog,
|
|
462
|
+
compiledExt: '.svelte.js',
|
|
463
|
+
proxyModule: {
|
|
464
|
+
dev: proxyModuleDev,
|
|
465
|
+
default: proxyModuleDefault,
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { adapter } from './adapter.js'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Runtime, _wre_, type CatalogModule } from "wuchale/runtime"
|
|
2
|
+
|
|
3
|
+
export let _wrs_: (key: string) => Runtime
|
|
4
|
+
|
|
5
|
+
const dataCollection: {[key: string]: Runtime} = $state({})
|
|
6
|
+
|
|
7
|
+
// no $app/environment.browser because it must work without sveltekit
|
|
8
|
+
if (globalThis.window) {
|
|
9
|
+
_wrs_ = key => dataCollection[key] ?? fallback
|
|
10
|
+
} else {
|
|
11
|
+
_wrs_ = _wre_
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const fallback = new Runtime()
|
|
15
|
+
|
|
16
|
+
export function setCatalog(mod: CatalogModule) {
|
|
17
|
+
dataCollection[mod.key] = new Runtime(mod)
|
|
18
|
+
}
|