experimental-ciao-oxc 1.0.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.cjs +248 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +248 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
let oxc_parser = require("oxc-parser");
|
|
2
|
+
|
|
3
|
+
//#region src/template.ts
|
|
4
|
+
function decodeHtmlEntities$1(str) {
|
|
5
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/'/g, "'").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
|
|
6
|
+
}
|
|
7
|
+
function extractTransTemplate(children, expressionCounter) {
|
|
8
|
+
const elementCounter = { current: 0 };
|
|
9
|
+
const exprCounter = expressionCounter || { current: 0 };
|
|
10
|
+
function processNode(node) {
|
|
11
|
+
if (node.type === "JSXText") return decodeHtmlEntities$1((node.value ?? "").replace(/\s+/g, " "));
|
|
12
|
+
if (node.type === "JSXExpressionContainer") {
|
|
13
|
+
const expr = node.expression;
|
|
14
|
+
if (!expr) return "";
|
|
15
|
+
if (expr.type === "StringLiteral" || expr.type === "Literal") {
|
|
16
|
+
const value = expr.value;
|
|
17
|
+
if (typeof value === "string") return value;
|
|
18
|
+
}
|
|
19
|
+
if (expr.type === "JSXEmptyExpression") return "";
|
|
20
|
+
return `{${exprCounter.current++}}`;
|
|
21
|
+
}
|
|
22
|
+
if (node.type === "JSXElement") {
|
|
23
|
+
const idx = elementCounter.current++;
|
|
24
|
+
return `<${idx}>${(node.children ?? []).map(processNode).join("")}</${idx}>`;
|
|
25
|
+
}
|
|
26
|
+
if (node.type === "JSXFragment") return (node.children ?? []).map(processNode).join("");
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
return children.map(processNode).join("").trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/walker.ts
|
|
34
|
+
function formatLocation(filename, start) {
|
|
35
|
+
return `${filename}:${start ?? 0}`;
|
|
36
|
+
}
|
|
37
|
+
function isCTContextBlock(name) {
|
|
38
|
+
if (name.type === "JSXIdentifier") return name.name === "CTContextBlock";
|
|
39
|
+
if (name.type === "JSXMemberExpression") {
|
|
40
|
+
const property = name.property;
|
|
41
|
+
return property?.type === "JSXIdentifier" && property.name === "CTContextBlock";
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function isTrans(name) {
|
|
46
|
+
if (name.type === "JSXIdentifier") return name.name === "Trans";
|
|
47
|
+
if (name.type === "JSXMemberExpression") {
|
|
48
|
+
const property = name.property;
|
|
49
|
+
return property?.type === "JSXIdentifier" && property.name === "Trans";
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
function decodeHtmlEntities(str) {
|
|
54
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/'/g, "'").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
|
|
55
|
+
}
|
|
56
|
+
function getStringAttributeValue(attributes, attrName, allowJsxExpression = false) {
|
|
57
|
+
for (const attr of attributes) {
|
|
58
|
+
if (attr.type === "JSXSpreadAttribute") continue;
|
|
59
|
+
if (attr.type === "JSXAttribute") {
|
|
60
|
+
const attrNameNode = attr.name;
|
|
61
|
+
if (attrNameNode?.type === "JSXIdentifier" && attrNameNode.name === attrName) {
|
|
62
|
+
const value = attr.value;
|
|
63
|
+
if (!value) return null;
|
|
64
|
+
if (value.type === "StringLiteral" || value.type === "Literal") {
|
|
65
|
+
const raw = value.value ?? null;
|
|
66
|
+
return raw !== null ? decodeHtmlEntities(raw) : null;
|
|
67
|
+
}
|
|
68
|
+
if (allowJsxExpression && value.type === "JSXExpressionContainer") {
|
|
69
|
+
const expr = value.expression;
|
|
70
|
+
if (expr?.type === "StringLiteral" || expr?.type === "Literal") {
|
|
71
|
+
const exprValue = expr.value;
|
|
72
|
+
if (typeof exprValue === "string") return decodeHtmlEntities(exprValue);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function hasNonStringIdAttribute(attributes) {
|
|
82
|
+
for (const attr of attributes) {
|
|
83
|
+
if (attr.type === "JSXSpreadAttribute") continue;
|
|
84
|
+
if (attr.type === "JSXAttribute") {
|
|
85
|
+
const attrNameNode = attr.name;
|
|
86
|
+
if (attrNameNode?.type === "JSXIdentifier" && attrNameNode.name === "id") {
|
|
87
|
+
const value = attr.value;
|
|
88
|
+
if (!value) return true;
|
|
89
|
+
if (value.type === "StringLiteral" || value.type === "Literal") return false;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function handleVariableDeclarator(declarator, state) {
|
|
97
|
+
const init = declarator.init;
|
|
98
|
+
const id = declarator.id;
|
|
99
|
+
if (init && init.type === "CallExpression" && init.callee?.type === "Identifier" && init.callee.name === "useCt") {
|
|
100
|
+
if (id?.type === "Identifier") state.ctVariableNames.add(id.name ?? "");
|
|
101
|
+
else if (id?.type === "ObjectPattern") {
|
|
102
|
+
const properties = id.properties ?? [];
|
|
103
|
+
for (const prop of properties) if (prop.type === "ObjectProperty") {
|
|
104
|
+
const propValue = prop.value;
|
|
105
|
+
if (propValue?.type === "Identifier") state.ctVariableNames.add(propValue.name ?? "");
|
|
106
|
+
} else if (prop.type === "RestElement") {
|
|
107
|
+
const arg = prop.argument;
|
|
108
|
+
if (arg?.type === "Identifier") state.ctVariableNames.add(arg.name ?? "");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function handleCallExpression(callExpr, state) {
|
|
114
|
+
const callee = callExpr.callee;
|
|
115
|
+
if (callee?.type === "Identifier" && state.ctVariableNames.has(callee.name ?? "")) {
|
|
116
|
+
const locationKey = `${state.filename}:${callExpr.start ?? 0}`;
|
|
117
|
+
if (state.processedLocations.has(locationKey)) return;
|
|
118
|
+
state.processedLocations.add(locationKey);
|
|
119
|
+
const args = callExpr.arguments ?? [];
|
|
120
|
+
const calleeName = callee.name ?? "ct";
|
|
121
|
+
if (args.length === 0) {
|
|
122
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with no arguments at ${formatLocation(state.filename, callExpr.start)}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const textArg = args[0];
|
|
126
|
+
if (textArg.type === "SpreadElement") {
|
|
127
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const isStringLiteral = textArg.type === "StringLiteral" || textArg.type === "Literal";
|
|
131
|
+
const textValue = textArg.value;
|
|
132
|
+
if (!isStringLiteral || typeof textValue !== "string") {
|
|
133
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const text = textValue;
|
|
137
|
+
let context = null;
|
|
138
|
+
if (args.length >= 2) {
|
|
139
|
+
const contextArg = args[1];
|
|
140
|
+
const isContextString = contextArg.type === "StringLiteral" || contextArg.type === "Literal";
|
|
141
|
+
const contextValue = contextArg.value;
|
|
142
|
+
if (isContextString && typeof contextValue === "string") context = contextValue;
|
|
143
|
+
}
|
|
144
|
+
const parentContextBlockId = state.contextBlockStack.at(-1) ?? null;
|
|
145
|
+
if (!state.collectedStrings.some((s) => s.text === text && s.context === (context || void 0) && s.parentContextBlockId === (parentContextBlockId || void 0))) {
|
|
146
|
+
const entry = { text };
|
|
147
|
+
if (context) entry.context = context;
|
|
148
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
149
|
+
state.collectedStrings.push(entry);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function handleJSXElement(elem, state) {
|
|
154
|
+
const openingElement = elem.openingElement;
|
|
155
|
+
if (!openingElement) return;
|
|
156
|
+
const name = openingElement.name;
|
|
157
|
+
if (!name) return;
|
|
158
|
+
if (isCTContextBlock(name)) {
|
|
159
|
+
const attributes = openingElement.attributes ?? [];
|
|
160
|
+
if (hasNonStringIdAttribute(attributes)) {
|
|
161
|
+
console.warn(`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state.filename, elem.start)}`);
|
|
162
|
+
walkChildren(elem, state);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const id = getStringAttributeValue(attributes, "id");
|
|
166
|
+
if (id !== null) {
|
|
167
|
+
if (!state.collectedContextBlocks.some((b) => b.id === id)) state.collectedContextBlocks.push({ id });
|
|
168
|
+
if (id !== "") {
|
|
169
|
+
state.contextBlockStack.push(id);
|
|
170
|
+
walkChildren(elem, state);
|
|
171
|
+
state.contextBlockStack.pop();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
walkChildren(elem, state);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (isTrans(name)) {
|
|
179
|
+
const locationKey = `${state.filename}:jsx:${elem.start ?? 0}`;
|
|
180
|
+
if (state.processedLocations.has(locationKey)) return;
|
|
181
|
+
state.processedLocations.add(locationKey);
|
|
182
|
+
const template = extractTransTemplate(elem.children ?? [], { current: 0 });
|
|
183
|
+
if (!template) return;
|
|
184
|
+
let context = getStringAttributeValue(openingElement.attributes ?? [], "context", true);
|
|
185
|
+
const parentContextBlockId = state.contextBlockStack.at(-1) ?? null;
|
|
186
|
+
if (!state.collectedStrings.some((s) => s.text === template && s.context === (context || void 0) && s.parentContextBlockId === (parentContextBlockId || void 0))) {
|
|
187
|
+
const entry = { text: template };
|
|
188
|
+
if (context) entry.context = context;
|
|
189
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
190
|
+
state.collectedStrings.push(entry);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
walkChildren(elem, state);
|
|
195
|
+
}
|
|
196
|
+
function walkChildren(node, state) {
|
|
197
|
+
for (const key of Object.keys(node)) {
|
|
198
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
199
|
+
const value = node[key];
|
|
200
|
+
if (Array.isArray(value)) {
|
|
201
|
+
for (const child of value) if (child && typeof child === "object" && "type" in child) walk(child, state);
|
|
202
|
+
} else if (value && typeof value === "object" && "type" in value) walk(value, state);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function walk(node, state) {
|
|
206
|
+
if (!node || typeof node !== "object") return;
|
|
207
|
+
switch (node.type) {
|
|
208
|
+
case "VariableDeclarator":
|
|
209
|
+
handleVariableDeclarator(node, state);
|
|
210
|
+
walkChildren(node, state);
|
|
211
|
+
break;
|
|
212
|
+
case "CallExpression":
|
|
213
|
+
handleCallExpression(node, state);
|
|
214
|
+
walkChildren(node, state);
|
|
215
|
+
break;
|
|
216
|
+
case "JSXElement":
|
|
217
|
+
handleJSXElement(node, state);
|
|
218
|
+
break;
|
|
219
|
+
default: walkChildren(node, state);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function walkProgram(program, state) {
|
|
223
|
+
for (const stmt of program.body) walk(stmt, state);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/extractor.ts
|
|
228
|
+
function extractStrings(code, filename = "test.tsx") {
|
|
229
|
+
const result = (0, oxc_parser.parseSync)(filename, code, { sourceType: "module" });
|
|
230
|
+
if (result.errors && result.errors.length > 0) for (const error of result.errors) console.warn(`[ciao-tools] Parse error in ${filename}: ${error.message}`);
|
|
231
|
+
const state = {
|
|
232
|
+
ctVariableNames: /* @__PURE__ */ new Set(),
|
|
233
|
+
collectedStrings: [],
|
|
234
|
+
collectedContextBlocks: [],
|
|
235
|
+
contextBlockStack: [],
|
|
236
|
+
processedLocations: /* @__PURE__ */ new Set(),
|
|
237
|
+
filename
|
|
238
|
+
};
|
|
239
|
+
walkProgram(result.program, state);
|
|
240
|
+
return {
|
|
241
|
+
strings: state.collectedStrings,
|
|
242
|
+
contextBlocks: state.collectedContextBlocks
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
exports.extractStrings = extractStrings;
|
|
248
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["decodeHtmlEntities","elementCounter: ElementCounter","context: string | null","entry: TranslatableString","state: WalkerState"],"sources":["../src/template.ts","../src/walker.ts","../src/extractor.ts"],"sourcesContent":["type Node = Record<string, unknown> & { type: string };\n\ninterface ExpressionCounter {\n\tcurrent: number;\n}\n\ninterface ElementCounter {\n\tcurrent: number;\n}\n\nfunction decodeHtmlEntities(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/"/g, '\"')\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))\n\t\t.replace(/&#(\\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));\n}\n\nexport function extractTransTemplate(\n\tchildren: Node[],\n\texpressionCounter?: ExpressionCounter,\n): string {\n\tconst elementCounter: ElementCounter = { current: 0 };\n\tconst exprCounter = expressionCounter || { current: 0 };\n\n\tfunction processNode(node: Node): string {\n\t\tif (node.type === \"JSXText\") {\n\t\t\tconst value = (node as { value?: string }).value ?? \"\";\n\t\t\treturn decodeHtmlEntities(value.replace(/\\s+/g, \" \"));\n\t\t}\n\n\t\tif (node.type === \"JSXExpressionContainer\") {\n\t\t\tconst expr = (node as { expression?: Node }).expression;\n\t\t\tif (!expr) return \"\";\n\n\t\t\tif (expr.type === \"StringLiteral\" || expr.type === \"Literal\") {\n\t\t\t\tconst value = (expr as { value?: unknown }).value;\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (expr.type === \"JSXEmptyExpression\") {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tconst idx = exprCounter.current++;\n\t\t\treturn `{${idx}}`;\n\t\t}\n\n\t\tif (node.type === \"JSXElement\") {\n\t\t\tconst idx = elementCounter.current++;\n\t\t\tconst elemChildren = (node as { children?: Node[] }).children ?? [];\n\t\t\tconst innerContent = elemChildren.map(processNode).join(\"\");\n\t\t\treturn `<${idx}>${innerContent}</${idx}>`;\n\t\t}\n\n\t\tif (node.type === \"JSXFragment\") {\n\t\t\tconst fragChildren = (node as { children?: Node[] }).children ?? [];\n\t\t\treturn fragChildren.map(processNode).join(\"\");\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\treturn children.map(processNode).join(\"\").trim();\n}\n","import type {\n\tProgram,\n\tVariableDeclarator,\n} from \"oxc-parser\";\nimport type { TranslatableString, WalkerState } from \"./types\";\nimport { extractTransTemplate } from \"./template\";\n\ntype Node = Record<string, unknown> & { type: string; start?: number; end?: number };\n\nfunction formatLocation(filename: string, start: number | undefined): string {\n\treturn `${filename}:${start ?? 0}`;\n}\n\nfunction getNodeType(name: Node): string {\n\treturn name.type;\n}\n\nfunction isCTContextBlock(name: Node): boolean {\n\tif (name.type === \"JSXIdentifier\") {\n\t\treturn (name as { name?: string }).name === \"CTContextBlock\";\n\t}\n\tif (name.type === \"JSXMemberExpression\") {\n\t\tconst property = (name as { property?: Node }).property;\n\t\treturn (\n\t\t\tproperty?.type === \"JSXIdentifier\" &&\n\t\t\t(property as { name?: string }).name === \"CTContextBlock\"\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction isTrans(name: Node): boolean {\n\tif (name.type === \"JSXIdentifier\") {\n\t\treturn (name as { name?: string }).name === \"Trans\";\n\t}\n\tif (name.type === \"JSXMemberExpression\") {\n\t\tconst property = (name as { property?: Node }).property;\n\t\treturn (\n\t\t\tproperty?.type === \"JSXIdentifier\" &&\n\t\t\t(property as { name?: string }).name === \"Trans\"\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction decodeHtmlEntities(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/"/g, '\"')\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))\n\t\t.replace(/&#(\\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));\n}\n\nfunction getStringAttributeValue(\n\tattributes: Node[],\n\tattrName: string,\n\tallowJsxExpression = false,\n): string | null {\n\tfor (const attr of attributes) {\n\t\tif (attr.type === \"JSXSpreadAttribute\") continue;\n\t\tif (attr.type === \"JSXAttribute\") {\n\t\t\tconst attrNameNode = (attr as { name?: Node }).name;\n\t\t\tif (\n\t\t\t\tattrNameNode?.type === \"JSXIdentifier\" &&\n\t\t\t\t(attrNameNode as { name?: string }).name === attrName\n\t\t\t) {\n\t\t\t\tconst value = (attr as { value?: Node }).value;\n\t\t\t\tif (!value) return null;\n\t\t\t\tif (value.type === \"StringLiteral\" || value.type === \"Literal\") {\n\t\t\t\t\tconst raw = (value as { value?: string }).value ?? null;\n\t\t\t\t\treturn raw !== null ? decodeHtmlEntities(raw) : null;\n\t\t\t\t}\n\t\t\t\tif (allowJsxExpression && value.type === \"JSXExpressionContainer\") {\n\t\t\t\t\tconst expr = (value as { expression?: Node }).expression;\n\t\t\t\t\tif (expr?.type === \"StringLiteral\" || expr?.type === \"Literal\") {\n\t\t\t\t\t\tconst exprValue = (expr as { value?: unknown }).value;\n\t\t\t\t\t\tif (typeof exprValue === \"string\") {\n\t\t\t\t\t\t\treturn decodeHtmlEntities(exprValue);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction hasNonStringIdAttribute(attributes: Node[]): boolean {\n\tfor (const attr of attributes) {\n\t\tif (attr.type === \"JSXSpreadAttribute\") continue;\n\t\tif (attr.type === \"JSXAttribute\") {\n\t\t\tconst attrNameNode = (attr as { name?: Node }).name;\n\t\t\tif (\n\t\t\t\tattrNameNode?.type === \"JSXIdentifier\" &&\n\t\t\t\t(attrNameNode as { name?: string }).name === \"id\"\n\t\t\t) {\n\t\t\t\tconst value = (attr as { value?: Node }).value;\n\t\t\t\tif (!value) return true;\n\t\t\t\tif (value.type === \"StringLiteral\" || value.type === \"Literal\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction handleVariableDeclarator(\n\tdeclarator: Node,\n\tstate: WalkerState,\n): void {\n\tconst init = (declarator as { init?: Node }).init;\n\tconst id = (declarator as { id?: Node }).id;\n\n\tif (\n\t\tinit &&\n\t\tinit.type === \"CallExpression\" &&\n\t\t(init as { callee?: Node }).callee?.type === \"Identifier\" &&\n\t\t((init as { callee?: Node }).callee as { name?: string }).name === \"useCt\"\n\t) {\n\t\tif (id?.type === \"Identifier\") {\n\t\t\tstate.ctVariableNames.add((id as { name?: string }).name ?? \"\");\n\t\t} else if (id?.type === \"ObjectPattern\") {\n\t\t\tconst properties = (id as { properties?: Node[] }).properties ?? [];\n\t\t\tfor (const prop of properties) {\n\t\t\t\tif (prop.type === \"ObjectProperty\") {\n\t\t\t\t\tconst propValue = (prop as { value?: Node }).value;\n\t\t\t\t\tif (propValue?.type === \"Identifier\") {\n\t\t\t\t\t\tstate.ctVariableNames.add((propValue as { name?: string }).name ?? \"\");\n\t\t\t\t\t}\n\t\t\t\t} else if (prop.type === \"RestElement\") {\n\t\t\t\t\tconst arg = (prop as { argument?: Node }).argument;\n\t\t\t\t\tif (arg?.type === \"Identifier\") {\n\t\t\t\t\t\tstate.ctVariableNames.add((arg as { name?: string }).name ?? \"\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction handleCallExpression(\n\tcallExpr: Node,\n\tstate: WalkerState,\n): void {\n\tconst callee = (callExpr as { callee?: Node }).callee;\n\n\tif (callee?.type === \"Identifier\" && state.ctVariableNames.has((callee as { name?: string }).name ?? \"\")) {\n\t\tconst locationKey = `${state.filename}:${callExpr.start ?? 0}`;\n\t\tif (state.processedLocations.has(locationKey)) {\n\t\t\treturn;\n\t\t}\n\t\tstate.processedLocations.add(locationKey);\n\n\t\tconst args = (callExpr as { arguments?: Node[] }).arguments ?? [];\n\t\tconst calleeName = (callee as { name?: string }).name ?? \"ct\";\n\n\t\tif (args.length === 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with no arguments at ${formatLocation(state.filename, callExpr.start)}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst textArg = args[0];\n\n\t\tif (textArg.type === \"SpreadElement\") {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isStringLiteral = textArg.type === \"StringLiteral\" || textArg.type === \"Literal\";\n\t\tconst textValue = (textArg as { value?: unknown }).value;\n\n\t\tif (!isStringLiteral || typeof textValue !== \"string\") {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst text = textValue;\n\t\tlet context: string | null = null;\n\n\t\tif (args.length >= 2) {\n\t\t\tconst contextArg = args[1];\n\t\t\tconst isContextString = contextArg.type === \"StringLiteral\" || contextArg.type === \"Literal\";\n\t\t\tconst contextValue = (contextArg as { value?: unknown }).value;\n\t\t\tif (isContextString && typeof contextValue === \"string\") {\n\t\t\t\tcontext = contextValue;\n\t\t\t}\n\t\t}\n\n\t\tconst parentContextBlockId = state.contextBlockStack.at(-1) ?? null;\n\n\t\tconst isDuplicate = state.collectedStrings.some(\n\t\t\t(s) =>\n\t\t\t\ts.text === text &&\n\t\t\t\ts.context === (context || undefined) &&\n\t\t\t\ts.parentContextBlockId === (parentContextBlockId || undefined),\n\t\t);\n\t\tif (!isDuplicate) {\n\t\t\tconst entry: TranslatableString = { text };\n\t\t\tif (context) {\n\t\t\t\tentry.context = context;\n\t\t\t}\n\t\t\tif (parentContextBlockId) {\n\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t}\n\t\t\tstate.collectedStrings.push(entry);\n\t\t}\n\t}\n}\n\nfunction handleJSXElement(elem: Node, state: WalkerState): void {\n\tconst openingElement = (elem as { openingElement?: Node }).openingElement;\n\tif (!openingElement) return;\n\n\tconst name = (openingElement as { name?: Node }).name;\n\tif (!name) return;\n\n\tif (isCTContextBlock(name)) {\n\t\tconst attributes = ((openingElement as { attributes?: Node[] }).attributes ?? []);\n\n\t\tif (hasNonStringIdAttribute(attributes)) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state.filename, elem.start)}`,\n\t\t\t);\n\t\t\twalkChildren(elem, state);\n\t\t\treturn;\n\t\t}\n\n\t\tconst id = getStringAttributeValue(attributes, \"id\");\n\n\t\tif (id !== null) {\n\t\t\tconst isDuplicate = state.collectedContextBlocks.some((b) => b.id === id);\n\t\t\tif (!isDuplicate) {\n\t\t\t\tstate.collectedContextBlocks.push({ id });\n\t\t\t}\n\n\t\t\tif (id !== \"\") {\n\t\t\t\tstate.contextBlockStack.push(id);\n\t\t\t\twalkChildren(elem, state);\n\t\t\t\tstate.contextBlockStack.pop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\twalkChildren(elem, state);\n\t\treturn;\n\t}\n\n\tif (isTrans(name)) {\n\t\tconst locationKey = `${state.filename}:jsx:${elem.start ?? 0}`;\n\t\tif (state.processedLocations.has(locationKey)) {\n\t\t\treturn;\n\t\t}\n\t\tstate.processedLocations.add(locationKey);\n\n\t\tconst children = (elem as { children?: Node[] }).children ?? [];\n\t\tconst expressionCounter = { current: 0 };\n\t\tconst template = extractTransTemplate(children as any, expressionCounter);\n\t\tif (!template) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst attributes = ((openingElement as { attributes?: Node[] }).attributes ?? []);\n\n\t\tlet context = getStringAttributeValue(attributes, \"context\", true);\n\n\t\tconst parentContextBlockId = state.contextBlockStack.at(-1) ?? null;\n\n\t\tconst isDuplicate = state.collectedStrings.some(\n\t\t\t(s) =>\n\t\t\t\ts.text === template &&\n\t\t\t\ts.context === (context || undefined) &&\n\t\t\t\ts.parentContextBlockId === (parentContextBlockId || undefined),\n\t\t);\n\n\t\tif (!isDuplicate) {\n\t\t\tconst entry: TranslatableString = { text: template };\n\t\t\tif (context) {\n\t\t\t\tentry.context = context;\n\t\t\t}\n\t\t\tif (parentContextBlockId) {\n\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t}\n\t\t\tstate.collectedStrings.push(entry);\n\t\t}\n\n\t\treturn;\n\t}\n\n\twalkChildren(elem, state);\n}\n\nfunction walkChildren(node: Node, state: WalkerState): void {\n\tfor (const key of Object.keys(node)) {\n\t\tif (key === \"type\" || key === \"start\" || key === \"end\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = node[key];\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const child of value) {\n\t\t\t\tif (child && typeof child === \"object\" && \"type\" in child) {\n\t\t\t\t\twalk(child as Node, state);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (value && typeof value === \"object\" && \"type\" in value) {\n\t\t\twalk(value as Node, state);\n\t\t}\n\t}\n}\n\nexport function walk(node: Node, state: WalkerState): void {\n\tif (!node || typeof node !== \"object\") return;\n\n\tswitch (node.type) {\n\t\tcase \"VariableDeclarator\":\n\t\t\thandleVariableDeclarator(node, state);\n\t\t\twalkChildren(node, state);\n\t\t\tbreak;\n\n\t\tcase \"CallExpression\":\n\t\t\thandleCallExpression(node, state);\n\t\t\twalkChildren(node, state);\n\t\t\tbreak;\n\n\t\tcase \"JSXElement\":\n\t\t\thandleJSXElement(node, state);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\twalkChildren(node, state);\n\t}\n}\n\nexport function walkProgram(program: Program, state: WalkerState): void {\n\tfor (const stmt of program.body) {\n\t\twalk(stmt as unknown as Node, state);\n\t}\n}\n","import { parseSync } from \"oxc-parser\";\nimport type { ExtractionResult, WalkerState } from \"./types\";\nimport { walkProgram } from \"./walker\";\n\nexport function extractStrings(\n\tcode: string,\n\tfilename = \"test.tsx\",\n): ExtractionResult {\n\tconst result = parseSync(filename, code, {\n\t\tsourceType: \"module\",\n\t});\n\n\tif (result.errors && result.errors.length > 0) {\n\t\tfor (const error of result.errors) {\n\t\t\tconsole.warn(`[ciao-tools] Parse error in ${filename}: ${error.message}`);\n\t\t}\n\t}\n\n\tconst state: WalkerState = {\n\t\tctVariableNames: new Set<string>(),\n\t\tcollectedStrings: [],\n\t\tcollectedContextBlocks: [],\n\t\tcontextBlockStack: [],\n\t\tprocessedLocations: new Set<string>(),\n\t\tfilename,\n\t};\n\n\twalkProgram(result.program, state);\n\n\treturn {\n\t\tstrings: state.collectedStrings,\n\t\tcontextBlocks: state.collectedContextBlocks,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface TranslatableString {
|
|
3
|
+
text: string;
|
|
4
|
+
context?: string;
|
|
5
|
+
parentContextBlockId?: string;
|
|
6
|
+
}
|
|
7
|
+
interface ContextBlock {
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
interface ExtractionResult {
|
|
11
|
+
strings: TranslatableString[];
|
|
12
|
+
contextBlocks: ContextBlock[];
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/extractor.d.ts
|
|
16
|
+
declare function extractStrings(code: string, filename?: string): ExtractionResult;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { type ContextBlock, type ExtractionResult, type TranslatableString, extractStrings };
|
|
19
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/extractor.ts"],"sourcesContent":[],"mappings":";UAAiB,kBAAA;EAAA,IAAA,EAAA,MAAA;EAMA,OAAA,CAAA,EAAA,MAAY;EAIZ,oBAAgB,CAAA,EAAA,MAAA;;UAJhB,YAAA;;ACFjB;UDMiB,gBAAA;WACP;iBACM;;;;AAZC,iBCID,cAAA,CDJmB,IAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,CAAA,ECOhC,gBDPgC"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface TranslatableString {
|
|
3
|
+
text: string;
|
|
4
|
+
context?: string;
|
|
5
|
+
parentContextBlockId?: string;
|
|
6
|
+
}
|
|
7
|
+
interface ContextBlock {
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
interface ExtractionResult {
|
|
11
|
+
strings: TranslatableString[];
|
|
12
|
+
contextBlocks: ContextBlock[];
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/extractor.d.ts
|
|
16
|
+
declare function extractStrings(code: string, filename?: string): ExtractionResult;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { type ContextBlock, type ExtractionResult, type TranslatableString, extractStrings };
|
|
19
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/extractor.ts"],"sourcesContent":[],"mappings":";UAAiB,kBAAA;EAAA,IAAA,EAAA,MAAA;EAMA,OAAA,CAAA,EAAA,MAAY;EAIZ,oBAAgB,CAAA,EAAA,MAAA;;UAJhB,YAAA;;ACFjB;UDMiB,gBAAA;WACP;iBACM;;;;AAZC,iBCID,cAAA,CDJmB,IAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAAA,MAAA,CAAA,ECOhC,gBDPgC"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { parseSync } from "oxc-parser";
|
|
2
|
+
|
|
3
|
+
//#region src/template.ts
|
|
4
|
+
function decodeHtmlEntities$1(str) {
|
|
5
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/'/g, "'").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
|
|
6
|
+
}
|
|
7
|
+
function extractTransTemplate(children, expressionCounter) {
|
|
8
|
+
const elementCounter = { current: 0 };
|
|
9
|
+
const exprCounter = expressionCounter || { current: 0 };
|
|
10
|
+
function processNode(node) {
|
|
11
|
+
if (node.type === "JSXText") return decodeHtmlEntities$1((node.value ?? "").replace(/\s+/g, " "));
|
|
12
|
+
if (node.type === "JSXExpressionContainer") {
|
|
13
|
+
const expr = node.expression;
|
|
14
|
+
if (!expr) return "";
|
|
15
|
+
if (expr.type === "StringLiteral" || expr.type === "Literal") {
|
|
16
|
+
const value = expr.value;
|
|
17
|
+
if (typeof value === "string") return value;
|
|
18
|
+
}
|
|
19
|
+
if (expr.type === "JSXEmptyExpression") return "";
|
|
20
|
+
return `{${exprCounter.current++}}`;
|
|
21
|
+
}
|
|
22
|
+
if (node.type === "JSXElement") {
|
|
23
|
+
const idx = elementCounter.current++;
|
|
24
|
+
return `<${idx}>${(node.children ?? []).map(processNode).join("")}</${idx}>`;
|
|
25
|
+
}
|
|
26
|
+
if (node.type === "JSXFragment") return (node.children ?? []).map(processNode).join("");
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
return children.map(processNode).join("").trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/walker.ts
|
|
34
|
+
function formatLocation(filename, start) {
|
|
35
|
+
return `${filename}:${start ?? 0}`;
|
|
36
|
+
}
|
|
37
|
+
function isCTContextBlock(name) {
|
|
38
|
+
if (name.type === "JSXIdentifier") return name.name === "CTContextBlock";
|
|
39
|
+
if (name.type === "JSXMemberExpression") {
|
|
40
|
+
const property = name.property;
|
|
41
|
+
return property?.type === "JSXIdentifier" && property.name === "CTContextBlock";
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function isTrans(name) {
|
|
46
|
+
if (name.type === "JSXIdentifier") return name.name === "Trans";
|
|
47
|
+
if (name.type === "JSXMemberExpression") {
|
|
48
|
+
const property = name.property;
|
|
49
|
+
return property?.type === "JSXIdentifier" && property.name === "Trans";
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
function decodeHtmlEntities(str) {
|
|
54
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/'/g, "'").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
|
|
55
|
+
}
|
|
56
|
+
function getStringAttributeValue(attributes, attrName, allowJsxExpression = false) {
|
|
57
|
+
for (const attr of attributes) {
|
|
58
|
+
if (attr.type === "JSXSpreadAttribute") continue;
|
|
59
|
+
if (attr.type === "JSXAttribute") {
|
|
60
|
+
const attrNameNode = attr.name;
|
|
61
|
+
if (attrNameNode?.type === "JSXIdentifier" && attrNameNode.name === attrName) {
|
|
62
|
+
const value = attr.value;
|
|
63
|
+
if (!value) return null;
|
|
64
|
+
if (value.type === "StringLiteral" || value.type === "Literal") {
|
|
65
|
+
const raw = value.value ?? null;
|
|
66
|
+
return raw !== null ? decodeHtmlEntities(raw) : null;
|
|
67
|
+
}
|
|
68
|
+
if (allowJsxExpression && value.type === "JSXExpressionContainer") {
|
|
69
|
+
const expr = value.expression;
|
|
70
|
+
if (expr?.type === "StringLiteral" || expr?.type === "Literal") {
|
|
71
|
+
const exprValue = expr.value;
|
|
72
|
+
if (typeof exprValue === "string") return decodeHtmlEntities(exprValue);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function hasNonStringIdAttribute(attributes) {
|
|
82
|
+
for (const attr of attributes) {
|
|
83
|
+
if (attr.type === "JSXSpreadAttribute") continue;
|
|
84
|
+
if (attr.type === "JSXAttribute") {
|
|
85
|
+
const attrNameNode = attr.name;
|
|
86
|
+
if (attrNameNode?.type === "JSXIdentifier" && attrNameNode.name === "id") {
|
|
87
|
+
const value = attr.value;
|
|
88
|
+
if (!value) return true;
|
|
89
|
+
if (value.type === "StringLiteral" || value.type === "Literal") return false;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function handleVariableDeclarator(declarator, state) {
|
|
97
|
+
const init = declarator.init;
|
|
98
|
+
const id = declarator.id;
|
|
99
|
+
if (init && init.type === "CallExpression" && init.callee?.type === "Identifier" && init.callee.name === "useCt") {
|
|
100
|
+
if (id?.type === "Identifier") state.ctVariableNames.add(id.name ?? "");
|
|
101
|
+
else if (id?.type === "ObjectPattern") {
|
|
102
|
+
const properties = id.properties ?? [];
|
|
103
|
+
for (const prop of properties) if (prop.type === "ObjectProperty") {
|
|
104
|
+
const propValue = prop.value;
|
|
105
|
+
if (propValue?.type === "Identifier") state.ctVariableNames.add(propValue.name ?? "");
|
|
106
|
+
} else if (prop.type === "RestElement") {
|
|
107
|
+
const arg = prop.argument;
|
|
108
|
+
if (arg?.type === "Identifier") state.ctVariableNames.add(arg.name ?? "");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function handleCallExpression(callExpr, state) {
|
|
114
|
+
const callee = callExpr.callee;
|
|
115
|
+
if (callee?.type === "Identifier" && state.ctVariableNames.has(callee.name ?? "")) {
|
|
116
|
+
const locationKey = `${state.filename}:${callExpr.start ?? 0}`;
|
|
117
|
+
if (state.processedLocations.has(locationKey)) return;
|
|
118
|
+
state.processedLocations.add(locationKey);
|
|
119
|
+
const args = callExpr.arguments ?? [];
|
|
120
|
+
const calleeName = callee.name ?? "ct";
|
|
121
|
+
if (args.length === 0) {
|
|
122
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with no arguments at ${formatLocation(state.filename, callExpr.start)}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const textArg = args[0];
|
|
126
|
+
if (textArg.type === "SpreadElement") {
|
|
127
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const isStringLiteral = textArg.type === "StringLiteral" || textArg.type === "Literal";
|
|
131
|
+
const textValue = textArg.value;
|
|
132
|
+
if (!isStringLiteral || typeof textValue !== "string") {
|
|
133
|
+
console.warn(`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const text = textValue;
|
|
137
|
+
let context = null;
|
|
138
|
+
if (args.length >= 2) {
|
|
139
|
+
const contextArg = args[1];
|
|
140
|
+
const isContextString = contextArg.type === "StringLiteral" || contextArg.type === "Literal";
|
|
141
|
+
const contextValue = contextArg.value;
|
|
142
|
+
if (isContextString && typeof contextValue === "string") context = contextValue;
|
|
143
|
+
}
|
|
144
|
+
const parentContextBlockId = state.contextBlockStack.at(-1) ?? null;
|
|
145
|
+
if (!state.collectedStrings.some((s) => s.text === text && s.context === (context || void 0) && s.parentContextBlockId === (parentContextBlockId || void 0))) {
|
|
146
|
+
const entry = { text };
|
|
147
|
+
if (context) entry.context = context;
|
|
148
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
149
|
+
state.collectedStrings.push(entry);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function handleJSXElement(elem, state) {
|
|
154
|
+
const openingElement = elem.openingElement;
|
|
155
|
+
if (!openingElement) return;
|
|
156
|
+
const name = openingElement.name;
|
|
157
|
+
if (!name) return;
|
|
158
|
+
if (isCTContextBlock(name)) {
|
|
159
|
+
const attributes = openingElement.attributes ?? [];
|
|
160
|
+
if (hasNonStringIdAttribute(attributes)) {
|
|
161
|
+
console.warn(`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state.filename, elem.start)}`);
|
|
162
|
+
walkChildren(elem, state);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const id = getStringAttributeValue(attributes, "id");
|
|
166
|
+
if (id !== null) {
|
|
167
|
+
if (!state.collectedContextBlocks.some((b) => b.id === id)) state.collectedContextBlocks.push({ id });
|
|
168
|
+
if (id !== "") {
|
|
169
|
+
state.contextBlockStack.push(id);
|
|
170
|
+
walkChildren(elem, state);
|
|
171
|
+
state.contextBlockStack.pop();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
walkChildren(elem, state);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (isTrans(name)) {
|
|
179
|
+
const locationKey = `${state.filename}:jsx:${elem.start ?? 0}`;
|
|
180
|
+
if (state.processedLocations.has(locationKey)) return;
|
|
181
|
+
state.processedLocations.add(locationKey);
|
|
182
|
+
const template = extractTransTemplate(elem.children ?? [], { current: 0 });
|
|
183
|
+
if (!template) return;
|
|
184
|
+
let context = getStringAttributeValue(openingElement.attributes ?? [], "context", true);
|
|
185
|
+
const parentContextBlockId = state.contextBlockStack.at(-1) ?? null;
|
|
186
|
+
if (!state.collectedStrings.some((s) => s.text === template && s.context === (context || void 0) && s.parentContextBlockId === (parentContextBlockId || void 0))) {
|
|
187
|
+
const entry = { text: template };
|
|
188
|
+
if (context) entry.context = context;
|
|
189
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
190
|
+
state.collectedStrings.push(entry);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
walkChildren(elem, state);
|
|
195
|
+
}
|
|
196
|
+
function walkChildren(node, state) {
|
|
197
|
+
for (const key of Object.keys(node)) {
|
|
198
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
199
|
+
const value = node[key];
|
|
200
|
+
if (Array.isArray(value)) {
|
|
201
|
+
for (const child of value) if (child && typeof child === "object" && "type" in child) walk(child, state);
|
|
202
|
+
} else if (value && typeof value === "object" && "type" in value) walk(value, state);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function walk(node, state) {
|
|
206
|
+
if (!node || typeof node !== "object") return;
|
|
207
|
+
switch (node.type) {
|
|
208
|
+
case "VariableDeclarator":
|
|
209
|
+
handleVariableDeclarator(node, state);
|
|
210
|
+
walkChildren(node, state);
|
|
211
|
+
break;
|
|
212
|
+
case "CallExpression":
|
|
213
|
+
handleCallExpression(node, state);
|
|
214
|
+
walkChildren(node, state);
|
|
215
|
+
break;
|
|
216
|
+
case "JSXElement":
|
|
217
|
+
handleJSXElement(node, state);
|
|
218
|
+
break;
|
|
219
|
+
default: walkChildren(node, state);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function walkProgram(program, state) {
|
|
223
|
+
for (const stmt of program.body) walk(stmt, state);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/extractor.ts
|
|
228
|
+
function extractStrings(code, filename = "test.tsx") {
|
|
229
|
+
const result = parseSync(filename, code, { sourceType: "module" });
|
|
230
|
+
if (result.errors && result.errors.length > 0) for (const error of result.errors) console.warn(`[ciao-tools] Parse error in ${filename}: ${error.message}`);
|
|
231
|
+
const state = {
|
|
232
|
+
ctVariableNames: /* @__PURE__ */ new Set(),
|
|
233
|
+
collectedStrings: [],
|
|
234
|
+
collectedContextBlocks: [],
|
|
235
|
+
contextBlockStack: [],
|
|
236
|
+
processedLocations: /* @__PURE__ */ new Set(),
|
|
237
|
+
filename
|
|
238
|
+
};
|
|
239
|
+
walkProgram(result.program, state);
|
|
240
|
+
return {
|
|
241
|
+
strings: state.collectedStrings,
|
|
242
|
+
contextBlocks: state.collectedContextBlocks
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
export { extractStrings };
|
|
248
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["decodeHtmlEntities","elementCounter: ElementCounter","context: string | null","entry: TranslatableString","state: WalkerState"],"sources":["../src/template.ts","../src/walker.ts","../src/extractor.ts"],"sourcesContent":["type Node = Record<string, unknown> & { type: string };\n\ninterface ExpressionCounter {\n\tcurrent: number;\n}\n\ninterface ElementCounter {\n\tcurrent: number;\n}\n\nfunction decodeHtmlEntities(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/"/g, '\"')\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))\n\t\t.replace(/&#(\\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));\n}\n\nexport function extractTransTemplate(\n\tchildren: Node[],\n\texpressionCounter?: ExpressionCounter,\n): string {\n\tconst elementCounter: ElementCounter = { current: 0 };\n\tconst exprCounter = expressionCounter || { current: 0 };\n\n\tfunction processNode(node: Node): string {\n\t\tif (node.type === \"JSXText\") {\n\t\t\tconst value = (node as { value?: string }).value ?? \"\";\n\t\t\treturn decodeHtmlEntities(value.replace(/\\s+/g, \" \"));\n\t\t}\n\n\t\tif (node.type === \"JSXExpressionContainer\") {\n\t\t\tconst expr = (node as { expression?: Node }).expression;\n\t\t\tif (!expr) return \"\";\n\n\t\t\tif (expr.type === \"StringLiteral\" || expr.type === \"Literal\") {\n\t\t\t\tconst value = (expr as { value?: unknown }).value;\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (expr.type === \"JSXEmptyExpression\") {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tconst idx = exprCounter.current++;\n\t\t\treturn `{${idx}}`;\n\t\t}\n\n\t\tif (node.type === \"JSXElement\") {\n\t\t\tconst idx = elementCounter.current++;\n\t\t\tconst elemChildren = (node as { children?: Node[] }).children ?? [];\n\t\t\tconst innerContent = elemChildren.map(processNode).join(\"\");\n\t\t\treturn `<${idx}>${innerContent}</${idx}>`;\n\t\t}\n\n\t\tif (node.type === \"JSXFragment\") {\n\t\t\tconst fragChildren = (node as { children?: Node[] }).children ?? [];\n\t\t\treturn fragChildren.map(processNode).join(\"\");\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\treturn children.map(processNode).join(\"\").trim();\n}\n","import type {\n\tProgram,\n\tVariableDeclarator,\n} from \"oxc-parser\";\nimport type { TranslatableString, WalkerState } from \"./types\";\nimport { extractTransTemplate } from \"./template\";\n\ntype Node = Record<string, unknown> & { type: string; start?: number; end?: number };\n\nfunction formatLocation(filename: string, start: number | undefined): string {\n\treturn `${filename}:${start ?? 0}`;\n}\n\nfunction getNodeType(name: Node): string {\n\treturn name.type;\n}\n\nfunction isCTContextBlock(name: Node): boolean {\n\tif (name.type === \"JSXIdentifier\") {\n\t\treturn (name as { name?: string }).name === \"CTContextBlock\";\n\t}\n\tif (name.type === \"JSXMemberExpression\") {\n\t\tconst property = (name as { property?: Node }).property;\n\t\treturn (\n\t\t\tproperty?.type === \"JSXIdentifier\" &&\n\t\t\t(property as { name?: string }).name === \"CTContextBlock\"\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction isTrans(name: Node): boolean {\n\tif (name.type === \"JSXIdentifier\") {\n\t\treturn (name as { name?: string }).name === \"Trans\";\n\t}\n\tif (name.type === \"JSXMemberExpression\") {\n\t\tconst property = (name as { property?: Node }).property;\n\t\treturn (\n\t\t\tproperty?.type === \"JSXIdentifier\" &&\n\t\t\t(property as { name?: string }).name === \"Trans\"\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction decodeHtmlEntities(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/"/g, '\"')\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/'/g, \"'\")\n\t\t.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))\n\t\t.replace(/&#(\\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));\n}\n\nfunction getStringAttributeValue(\n\tattributes: Node[],\n\tattrName: string,\n\tallowJsxExpression = false,\n): string | null {\n\tfor (const attr of attributes) {\n\t\tif (attr.type === \"JSXSpreadAttribute\") continue;\n\t\tif (attr.type === \"JSXAttribute\") {\n\t\t\tconst attrNameNode = (attr as { name?: Node }).name;\n\t\t\tif (\n\t\t\t\tattrNameNode?.type === \"JSXIdentifier\" &&\n\t\t\t\t(attrNameNode as { name?: string }).name === attrName\n\t\t\t) {\n\t\t\t\tconst value = (attr as { value?: Node }).value;\n\t\t\t\tif (!value) return null;\n\t\t\t\tif (value.type === \"StringLiteral\" || value.type === \"Literal\") {\n\t\t\t\t\tconst raw = (value as { value?: string }).value ?? null;\n\t\t\t\t\treturn raw !== null ? decodeHtmlEntities(raw) : null;\n\t\t\t\t}\n\t\t\t\tif (allowJsxExpression && value.type === \"JSXExpressionContainer\") {\n\t\t\t\t\tconst expr = (value as { expression?: Node }).expression;\n\t\t\t\t\tif (expr?.type === \"StringLiteral\" || expr?.type === \"Literal\") {\n\t\t\t\t\t\tconst exprValue = (expr as { value?: unknown }).value;\n\t\t\t\t\t\tif (typeof exprValue === \"string\") {\n\t\t\t\t\t\t\treturn decodeHtmlEntities(exprValue);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction hasNonStringIdAttribute(attributes: Node[]): boolean {\n\tfor (const attr of attributes) {\n\t\tif (attr.type === \"JSXSpreadAttribute\") continue;\n\t\tif (attr.type === \"JSXAttribute\") {\n\t\t\tconst attrNameNode = (attr as { name?: Node }).name;\n\t\t\tif (\n\t\t\t\tattrNameNode?.type === \"JSXIdentifier\" &&\n\t\t\t\t(attrNameNode as { name?: string }).name === \"id\"\n\t\t\t) {\n\t\t\t\tconst value = (attr as { value?: Node }).value;\n\t\t\t\tif (!value) return true;\n\t\t\t\tif (value.type === \"StringLiteral\" || value.type === \"Literal\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction handleVariableDeclarator(\n\tdeclarator: Node,\n\tstate: WalkerState,\n): void {\n\tconst init = (declarator as { init?: Node }).init;\n\tconst id = (declarator as { id?: Node }).id;\n\n\tif (\n\t\tinit &&\n\t\tinit.type === \"CallExpression\" &&\n\t\t(init as { callee?: Node }).callee?.type === \"Identifier\" &&\n\t\t((init as { callee?: Node }).callee as { name?: string }).name === \"useCt\"\n\t) {\n\t\tif (id?.type === \"Identifier\") {\n\t\t\tstate.ctVariableNames.add((id as { name?: string }).name ?? \"\");\n\t\t} else if (id?.type === \"ObjectPattern\") {\n\t\t\tconst properties = (id as { properties?: Node[] }).properties ?? [];\n\t\t\tfor (const prop of properties) {\n\t\t\t\tif (prop.type === \"ObjectProperty\") {\n\t\t\t\t\tconst propValue = (prop as { value?: Node }).value;\n\t\t\t\t\tif (propValue?.type === \"Identifier\") {\n\t\t\t\t\t\tstate.ctVariableNames.add((propValue as { name?: string }).name ?? \"\");\n\t\t\t\t\t}\n\t\t\t\t} else if (prop.type === \"RestElement\") {\n\t\t\t\t\tconst arg = (prop as { argument?: Node }).argument;\n\t\t\t\t\tif (arg?.type === \"Identifier\") {\n\t\t\t\t\t\tstate.ctVariableNames.add((arg as { name?: string }).name ?? \"\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction handleCallExpression(\n\tcallExpr: Node,\n\tstate: WalkerState,\n): void {\n\tconst callee = (callExpr as { callee?: Node }).callee;\n\n\tif (callee?.type === \"Identifier\" && state.ctVariableNames.has((callee as { name?: string }).name ?? \"\")) {\n\t\tconst locationKey = `${state.filename}:${callExpr.start ?? 0}`;\n\t\tif (state.processedLocations.has(locationKey)) {\n\t\t\treturn;\n\t\t}\n\t\tstate.processedLocations.add(locationKey);\n\n\t\tconst args = (callExpr as { arguments?: Node[] }).arguments ?? [];\n\t\tconst calleeName = (callee as { name?: string }).name ?? \"ct\";\n\n\t\tif (args.length === 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with no arguments at ${formatLocation(state.filename, callExpr.start)}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst textArg = args[0];\n\n\t\tif (textArg.type === \"SpreadElement\") {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isStringLiteral = textArg.type === \"StringLiteral\" || textArg.type === \"Literal\";\n\t\tconst textValue = (textArg as { value?: unknown }).value;\n\n\t\tif (!isStringLiteral || typeof textValue !== \"string\") {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: ${calleeName}() called with non-string literal at ${formatLocation(state.filename, callExpr.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst text = textValue;\n\t\tlet context: string | null = null;\n\n\t\tif (args.length >= 2) {\n\t\t\tconst contextArg = args[1];\n\t\t\tconst isContextString = contextArg.type === \"StringLiteral\" || contextArg.type === \"Literal\";\n\t\t\tconst contextValue = (contextArg as { value?: unknown }).value;\n\t\t\tif (isContextString && typeof contextValue === \"string\") {\n\t\t\t\tcontext = contextValue;\n\t\t\t}\n\t\t}\n\n\t\tconst parentContextBlockId = state.contextBlockStack.at(-1) ?? null;\n\n\t\tconst isDuplicate = state.collectedStrings.some(\n\t\t\t(s) =>\n\t\t\t\ts.text === text &&\n\t\t\t\ts.context === (context || undefined) &&\n\t\t\t\ts.parentContextBlockId === (parentContextBlockId || undefined),\n\t\t);\n\t\tif (!isDuplicate) {\n\t\t\tconst entry: TranslatableString = { text };\n\t\t\tif (context) {\n\t\t\t\tentry.context = context;\n\t\t\t}\n\t\t\tif (parentContextBlockId) {\n\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t}\n\t\t\tstate.collectedStrings.push(entry);\n\t\t}\n\t}\n}\n\nfunction handleJSXElement(elem: Node, state: WalkerState): void {\n\tconst openingElement = (elem as { openingElement?: Node }).openingElement;\n\tif (!openingElement) return;\n\n\tconst name = (openingElement as { name?: Node }).name;\n\tif (!name) return;\n\n\tif (isCTContextBlock(name)) {\n\t\tconst attributes = ((openingElement as { attributes?: Node[] }).attributes ?? []);\n\n\t\tif (hasNonStringIdAttribute(attributes)) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state.filename, elem.start)}`,\n\t\t\t);\n\t\t\twalkChildren(elem, state);\n\t\t\treturn;\n\t\t}\n\n\t\tconst id = getStringAttributeValue(attributes, \"id\");\n\n\t\tif (id !== null) {\n\t\t\tconst isDuplicate = state.collectedContextBlocks.some((b) => b.id === id);\n\t\t\tif (!isDuplicate) {\n\t\t\t\tstate.collectedContextBlocks.push({ id });\n\t\t\t}\n\n\t\t\tif (id !== \"\") {\n\t\t\t\tstate.contextBlockStack.push(id);\n\t\t\t\twalkChildren(elem, state);\n\t\t\t\tstate.contextBlockStack.pop();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\twalkChildren(elem, state);\n\t\treturn;\n\t}\n\n\tif (isTrans(name)) {\n\t\tconst locationKey = `${state.filename}:jsx:${elem.start ?? 0}`;\n\t\tif (state.processedLocations.has(locationKey)) {\n\t\t\treturn;\n\t\t}\n\t\tstate.processedLocations.add(locationKey);\n\n\t\tconst children = (elem as { children?: Node[] }).children ?? [];\n\t\tconst expressionCounter = { current: 0 };\n\t\tconst template = extractTransTemplate(children as any, expressionCounter);\n\t\tif (!template) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst attributes = ((openingElement as { attributes?: Node[] }).attributes ?? []);\n\n\t\tlet context = getStringAttributeValue(attributes, \"context\", true);\n\n\t\tconst parentContextBlockId = state.contextBlockStack.at(-1) ?? null;\n\n\t\tconst isDuplicate = state.collectedStrings.some(\n\t\t\t(s) =>\n\t\t\t\ts.text === template &&\n\t\t\t\ts.context === (context || undefined) &&\n\t\t\t\ts.parentContextBlockId === (parentContextBlockId || undefined),\n\t\t);\n\n\t\tif (!isDuplicate) {\n\t\t\tconst entry: TranslatableString = { text: template };\n\t\t\tif (context) {\n\t\t\t\tentry.context = context;\n\t\t\t}\n\t\t\tif (parentContextBlockId) {\n\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t}\n\t\t\tstate.collectedStrings.push(entry);\n\t\t}\n\n\t\treturn;\n\t}\n\n\twalkChildren(elem, state);\n}\n\nfunction walkChildren(node: Node, state: WalkerState): void {\n\tfor (const key of Object.keys(node)) {\n\t\tif (key === \"type\" || key === \"start\" || key === \"end\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst value = node[key];\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const child of value) {\n\t\t\t\tif (child && typeof child === \"object\" && \"type\" in child) {\n\t\t\t\t\twalk(child as Node, state);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (value && typeof value === \"object\" && \"type\" in value) {\n\t\t\twalk(value as Node, state);\n\t\t}\n\t}\n}\n\nexport function walk(node: Node, state: WalkerState): void {\n\tif (!node || typeof node !== \"object\") return;\n\n\tswitch (node.type) {\n\t\tcase \"VariableDeclarator\":\n\t\t\thandleVariableDeclarator(node, state);\n\t\t\twalkChildren(node, state);\n\t\t\tbreak;\n\n\t\tcase \"CallExpression\":\n\t\t\thandleCallExpression(node, state);\n\t\t\twalkChildren(node, state);\n\t\t\tbreak;\n\n\t\tcase \"JSXElement\":\n\t\t\thandleJSXElement(node, state);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\twalkChildren(node, state);\n\t}\n}\n\nexport function walkProgram(program: Program, state: WalkerState): void {\n\tfor (const stmt of program.body) {\n\t\twalk(stmt as unknown as Node, state);\n\t}\n}\n","import { parseSync } from \"oxc-parser\";\nimport type { ExtractionResult, WalkerState } from \"./types\";\nimport { walkProgram } from \"./walker\";\n\nexport function extractStrings(\n\tcode: string,\n\tfilename = \"test.tsx\",\n): ExtractionResult {\n\tconst result = parseSync(filename, code, {\n\t\tsourceType: \"module\",\n\t});\n\n\tif (result.errors && result.errors.length > 0) {\n\t\tfor (const error of result.errors) {\n\t\t\tconsole.warn(`[ciao-tools] Parse error in ${filename}: ${error.message}`);\n\t\t}\n\t}\n\n\tconst state: WalkerState = {\n\t\tctVariableNames: new Set<string>(),\n\t\tcollectedStrings: [],\n\t\tcollectedContextBlocks: [],\n\t\tcontextBlockStack: [],\n\t\tprocessedLocations: new Set<string>(),\n\t\tfilename,\n\t};\n\n\twalkProgram(result.program, state);\n\n\treturn {\n\t\tstrings: state.collectedStrings,\n\t\tcontextBlocks: state.collectedContextBlocks,\n\t};\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "experimental-ciao-oxc",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OXC-based string extraction for ciao-tools - faster alternative to Babel",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/index.d.cts",
|
|
15
|
+
"default": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsdown",
|
|
24
|
+
"dev": "tsdown --watch",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
26
|
+
"test": "bun test"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"ciao-tools",
|
|
30
|
+
"oxc",
|
|
31
|
+
"i18n",
|
|
32
|
+
"translation",
|
|
33
|
+
"extraction"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"author": "Ciao Tools",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/ciao-tools/core.git",
|
|
40
|
+
"directory": "packages/oxc"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://docs.ciao-tools.com",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/ciao-tools/core/issues"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"oxc-parser": "^0.60.0"
|
|
51
|
+
}
|
|
52
|
+
}
|