@localey/svelte 0.1.2
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/README.md +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/package.json +18 -0
- package/src/index.d.ts +12 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +103 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +79 -0
- package/tsconfig.json +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @localey/adapter-svelte
|
|
2
|
+
|
|
3
|
+
Svelte adapter for Localey. Powered by the Svelte compiler to accurately find strings within template blocks.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Automatically active when `"svelte"` is included in your `localey.config.json` frameworks list.
|
|
8
|
+
|
|
9
|
+
## Internal Tools
|
|
10
|
+
|
|
11
|
+
- **Svelte Compiler**: Parses `.svelte` files into a searchable AST.
|
|
12
|
+
- **Template Replacement**: Safely handles template text nodes and attributes.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FrameworkAdapter, ScanResult, ExtractResult } from "@localey/core";
|
|
2
|
+
export declare class SvelteAdapter extends FrameworkAdapter {
|
|
3
|
+
name: string;
|
|
4
|
+
extensions: string[];
|
|
5
|
+
scan(content: string, filePath: string): ScanResult[];
|
|
6
|
+
extract(content: string, filePath: string, replacements: Array<{
|
|
7
|
+
oldValue: string;
|
|
8
|
+
newValue: string;
|
|
9
|
+
key: string;
|
|
10
|
+
}>): ExtractResult;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG5E,qBAAa,aAAc,SAAQ,gBAAgB;IACjD,IAAI,SAAY;IAChB,UAAU,WAAe;IAEzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IA8CrD,OAAO,CACL,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,GACvE,aAAa;CAqBjB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { FrameworkAdapter } from "@localey/core";
|
|
2
|
+
import * as svelte from "svelte/compiler";
|
|
3
|
+
export class SvelteAdapter extends FrameworkAdapter {
|
|
4
|
+
name = "svelte";
|
|
5
|
+
extensions = [".svelte"];
|
|
6
|
+
scan(content, filePath) {
|
|
7
|
+
const results = [];
|
|
8
|
+
const ast = svelte.parse(content);
|
|
9
|
+
function walk(node) {
|
|
10
|
+
if (!node)
|
|
11
|
+
return;
|
|
12
|
+
if (node.type === "Text") {
|
|
13
|
+
const value = node.data.trim();
|
|
14
|
+
// Ignore whitespace-only nodes and nodes inside script/style tags if they somehow leaked
|
|
15
|
+
if (value && !/^[ \t\n\r]*$/.test(value)) {
|
|
16
|
+
results.push({
|
|
17
|
+
file: filePath,
|
|
18
|
+
line: node.start, // Svelte parser gives character offset, we'll need to convert or use as is for now
|
|
19
|
+
column: 0,
|
|
20
|
+
value,
|
|
21
|
+
context: "SvelteText",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (node.type === "Attribute" && typeof node.value === "string") {
|
|
26
|
+
// Svelte 4+ attributes can be simple strings
|
|
27
|
+
results.push({
|
|
28
|
+
file: filePath,
|
|
29
|
+
line: node.start,
|
|
30
|
+
column: 0,
|
|
31
|
+
value: node.value,
|
|
32
|
+
context: `SvelteAttribute:${node.name}`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Recursively walk children
|
|
36
|
+
if (node.children) {
|
|
37
|
+
node.children.forEach(walk);
|
|
38
|
+
}
|
|
39
|
+
if (node.html)
|
|
40
|
+
walk(node.html);
|
|
41
|
+
if (node.instance)
|
|
42
|
+
walk(node.instance);
|
|
43
|
+
if (node.module)
|
|
44
|
+
walk(node.module);
|
|
45
|
+
}
|
|
46
|
+
walk(ast);
|
|
47
|
+
return results;
|
|
48
|
+
}
|
|
49
|
+
extract(content, filePath, replacements) {
|
|
50
|
+
let newContent = content;
|
|
51
|
+
const keys = {};
|
|
52
|
+
// For Svelte, a simple string replacement is safer than full AST walk for MVP,
|
|
53
|
+
// as long as we use the oldValue matching precisely.
|
|
54
|
+
// In a real prod tool, we'd use MagicString to handle offsets.
|
|
55
|
+
for (const replacement of replacements) {
|
|
56
|
+
// Basic heuristic: replace the raw string if it's found.
|
|
57
|
+
// We wrap the replacement in {t("key")} for templates.
|
|
58
|
+
const escapedOldValue = replacement.oldValue.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
59
|
+
const regex = new RegExp(`(?![^{}]*})(${escapedOldValue})`, "g"); // Avoid replacing inside existing { }
|
|
60
|
+
newContent = newContent.replace(regex, `{t("${replacement.key}")}`);
|
|
61
|
+
keys[replacement.key] = replacement.oldValue;
|
|
62
|
+
}
|
|
63
|
+
return { code: newContent, keys };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA6B,MAAM,eAAe,CAAC;AAC5E,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAE1C,MAAM,OAAO,aAAc,SAAQ,gBAAgB;IACjD,IAAI,GAAG,QAAQ,CAAC;IAChB,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC;IAEzB,IAAI,CAAC,OAAe,EAAE,QAAgB;QACpC,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAElC,SAAS,IAAI,CAAC,IAAS;YACrB,IAAI,CAAC,IAAI;gBAAE,OAAO;YAElB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC/B,yFAAyF;gBACzF,IAAI,KAAK,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzC,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,mFAAmF;wBACrG,MAAM,EAAE,CAAC;wBACT,KAAK;wBACL,OAAO,EAAE,YAAY;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAChE,6CAA6C;gBAC7C,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,IAAI,CAAC,KAAK;oBAChB,MAAM,EAAE,CAAC;oBACT,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,OAAO,EAAE,mBAAmB,IAAI,CAAC,IAAI,EAAE;iBACxC,CAAC,CAAC;YACL,CAAC;YAED,4BAA4B;YAC5B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;YACD,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,CAAC;QAEV,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CACL,OAAe,EACf,QAAgB,EAChB,YAAwE;QAExE,IAAI,UAAU,GAAG,OAAO,CAAC;QACzB,MAAM,IAAI,GAA2B,EAAE,CAAC;QAExC,+EAA+E;QAC/E,qDAAqD;QACrD,+DAA+D;QAC/D,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,yDAAyD;YACzD,uDAAuD;YACvD,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAClD,qBAAqB,EACrB,MAAM,CACP,CAAC;YACF,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,eAAe,eAAe,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,sCAAsC;YACxG,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,WAAW,CAAC,GAAG,KAAK,CAAC,CAAC;YACpE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC;QAC/C,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@localey/svelte",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@localey/core": "*",
|
|
8
|
+
"svelte": "^4.0.0"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"typescript": "^5.0.0",
|
|
12
|
+
"@types/node": "^20.0.0"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc -w"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FrameworkAdapter, ScanResult, ExtractResult } from "@localey/core";
|
|
2
|
+
export declare class SvelteAdapter extends FrameworkAdapter {
|
|
3
|
+
name: string;
|
|
4
|
+
extensions: string[];
|
|
5
|
+
scan(content: string, filePath: string): ScanResult[];
|
|
6
|
+
extract(content: string, filePath: string, replacements: Array<{
|
|
7
|
+
oldValue: string;
|
|
8
|
+
newValue: string;
|
|
9
|
+
key: string;
|
|
10
|
+
}>): ExtractResult;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG5E,qBAAa,aAAc,SAAQ,gBAAgB;IACjD,IAAI,SAAY;IAChB,UAAU,WAAe;IAEzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IA8CrD,OAAO,CACL,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,GACvE,aAAa;CAqBjB"}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SvelteAdapter = void 0;
|
|
37
|
+
const core_1 = require("@localey/core");
|
|
38
|
+
const svelte = __importStar(require("svelte/compiler"));
|
|
39
|
+
class SvelteAdapter extends core_1.FrameworkAdapter {
|
|
40
|
+
name = "svelte";
|
|
41
|
+
extensions = [".svelte"];
|
|
42
|
+
scan(content, filePath) {
|
|
43
|
+
const results = [];
|
|
44
|
+
const ast = svelte.parse(content);
|
|
45
|
+
function walk(node) {
|
|
46
|
+
if (!node)
|
|
47
|
+
return;
|
|
48
|
+
if (node.type === "Text") {
|
|
49
|
+
const value = node.data.trim();
|
|
50
|
+
// Ignore whitespace-only nodes and nodes inside script/style tags if they somehow leaked
|
|
51
|
+
if (value && !/^[ \t\n\r]*$/.test(value)) {
|
|
52
|
+
results.push({
|
|
53
|
+
file: filePath,
|
|
54
|
+
line: node.start, // Svelte parser gives character offset, we'll need to convert or use as is for now
|
|
55
|
+
column: 0,
|
|
56
|
+
value,
|
|
57
|
+
context: "SvelteText",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (node.type === "Attribute" && typeof node.value === "string") {
|
|
62
|
+
// Svelte 4+ attributes can be simple strings
|
|
63
|
+
results.push({
|
|
64
|
+
file: filePath,
|
|
65
|
+
line: node.start,
|
|
66
|
+
column: 0,
|
|
67
|
+
value: node.value,
|
|
68
|
+
context: `SvelteAttribute:${node.name}`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Recursively walk children
|
|
72
|
+
if (node.children) {
|
|
73
|
+
node.children.forEach(walk);
|
|
74
|
+
}
|
|
75
|
+
if (node.html)
|
|
76
|
+
walk(node.html);
|
|
77
|
+
if (node.instance)
|
|
78
|
+
walk(node.instance);
|
|
79
|
+
if (node.module)
|
|
80
|
+
walk(node.module);
|
|
81
|
+
}
|
|
82
|
+
walk(ast);
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
extract(content, filePath, replacements) {
|
|
86
|
+
let newContent = content;
|
|
87
|
+
const keys = {};
|
|
88
|
+
// For Svelte, a simple string replacement is safer than full AST walk for MVP,
|
|
89
|
+
// as long as we use the oldValue matching precisely.
|
|
90
|
+
// In a real prod tool, we'd use MagicString to handle offsets.
|
|
91
|
+
for (const replacement of replacements) {
|
|
92
|
+
// Basic heuristic: replace the raw string if it's found.
|
|
93
|
+
// We wrap the replacement in {t("key")} for templates.
|
|
94
|
+
const escapedOldValue = replacement.oldValue.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
95
|
+
const regex = new RegExp(`(?![^{}]*})(${escapedOldValue})`, "g"); // Avoid replacing inside existing { }
|
|
96
|
+
newContent = newContent.replace(regex, `{t("${replacement.key}")}`);
|
|
97
|
+
keys[replacement.key] = replacement.oldValue;
|
|
98
|
+
}
|
|
99
|
+
return { code: newContent, keys };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.SvelteAdapter = SvelteAdapter;
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wCAA4E;AAC5E,wDAA0C;AAE1C,MAAa,aAAc,SAAQ,uBAAgB;IACjD,IAAI,GAAG,QAAQ,CAAC;IAChB,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC;IAEzB,IAAI,CAAC,OAAe,EAAE,QAAgB;QACpC,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAElC,SAAS,IAAI,CAAC,IAAS;YACrB,IAAI,CAAC,IAAI;gBAAE,OAAO;YAElB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC/B,yFAAyF;gBACzF,IAAI,KAAK,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzC,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,mFAAmF;wBACrG,MAAM,EAAE,CAAC;wBACT,KAAK;wBACL,OAAO,EAAE,YAAY;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAChE,6CAA6C;gBAC7C,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,IAAI,CAAC,KAAK;oBAChB,MAAM,EAAE,CAAC;oBACT,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,OAAO,EAAE,mBAAmB,IAAI,CAAC,IAAI,EAAE;iBACxC,CAAC,CAAC;YACL,CAAC;YAED,4BAA4B;YAC5B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;YACD,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,CAAC;QAEV,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CACL,OAAe,EACf,QAAgB,EAChB,YAAwE;QAExE,IAAI,UAAU,GAAG,OAAO,CAAC;QACzB,MAAM,IAAI,GAA2B,EAAE,CAAC;QAExC,+EAA+E;QAC/E,qDAAqD;QACrD,+DAA+D;QAC/D,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,yDAAyD;YACzD,uDAAuD;YACvD,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAClD,qBAAqB,EACrB,MAAM,CACP,CAAC;YACF,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,eAAe,eAAe,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,sCAAsC;YACxG,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,WAAW,CAAC,GAAG,KAAK,CAAC,CAAC;YACpE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC;QAC/C,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;CACF;AA3ED,sCA2EC"}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { FrameworkAdapter, ScanResult, ExtractResult } from "@localey/core";
|
|
2
|
+
import * as svelte from "svelte/compiler";
|
|
3
|
+
|
|
4
|
+
export class SvelteAdapter extends FrameworkAdapter {
|
|
5
|
+
name = "svelte";
|
|
6
|
+
extensions = [".svelte"];
|
|
7
|
+
|
|
8
|
+
scan(content: string, filePath: string): ScanResult[] {
|
|
9
|
+
const results: ScanResult[] = [];
|
|
10
|
+
const ast = svelte.parse(content);
|
|
11
|
+
|
|
12
|
+
function walk(node: any) {
|
|
13
|
+
if (!node) return;
|
|
14
|
+
|
|
15
|
+
if (node.type === "Text") {
|
|
16
|
+
const value = node.data.trim();
|
|
17
|
+
// Ignore whitespace-only nodes and nodes inside script/style tags if they somehow leaked
|
|
18
|
+
if (value && !/^[ \t\n\r]*$/.test(value)) {
|
|
19
|
+
results.push({
|
|
20
|
+
file: filePath,
|
|
21
|
+
line: node.start, // Svelte parser gives character offset, we'll need to convert or use as is for now
|
|
22
|
+
column: 0,
|
|
23
|
+
value,
|
|
24
|
+
context: "SvelteText",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (node.type === "Attribute" && typeof node.value === "string") {
|
|
30
|
+
// Svelte 4+ attributes can be simple strings
|
|
31
|
+
results.push({
|
|
32
|
+
file: filePath,
|
|
33
|
+
line: node.start,
|
|
34
|
+
column: 0,
|
|
35
|
+
value: node.value,
|
|
36
|
+
context: `SvelteAttribute:${node.name}`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Recursively walk children
|
|
41
|
+
if (node.children) {
|
|
42
|
+
node.children.forEach(walk);
|
|
43
|
+
}
|
|
44
|
+
if (node.html) walk(node.html);
|
|
45
|
+
if (node.instance) walk(node.instance);
|
|
46
|
+
if (node.module) walk(node.module);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
walk(ast);
|
|
50
|
+
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
extract(
|
|
55
|
+
content: string,
|
|
56
|
+
filePath: string,
|
|
57
|
+
replacements: Array<{ oldValue: string; newValue: string; key: string }>,
|
|
58
|
+
): ExtractResult {
|
|
59
|
+
let newContent = content;
|
|
60
|
+
const keys: Record<string, string> = {};
|
|
61
|
+
|
|
62
|
+
// For Svelte, a simple string replacement is safer than full AST walk for MVP,
|
|
63
|
+
// as long as we use the oldValue matching precisely.
|
|
64
|
+
// In a real prod tool, we'd use MagicString to handle offsets.
|
|
65
|
+
for (const replacement of replacements) {
|
|
66
|
+
// Basic heuristic: replace the raw string if it's found.
|
|
67
|
+
// We wrap the replacement in {t("key")} for templates.
|
|
68
|
+
const escapedOldValue = replacement.oldValue.replace(
|
|
69
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
70
|
+
"\\$&",
|
|
71
|
+
);
|
|
72
|
+
const regex = new RegExp(`(?![^{}]*})(${escapedOldValue})`, "g"); // Avoid replacing inside existing { }
|
|
73
|
+
newContent = newContent.replace(regex, `{t("${replacement.key}")}`);
|
|
74
|
+
keys[replacement.key] = replacement.oldValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { code: newContent, keys };
|
|
78
|
+
}
|
|
79
|
+
}
|