experimental-ciao-babel 1.0.0
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 +70 -0
- package/dist/index.cjs +180 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +38 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +38 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +176 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @ciao-tools/babel
|
|
2
|
+
|
|
3
|
+
Babel plugin for Ciao Tools - extracts translatable strings at build time.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @ciao-tools/babel
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Add to your Babel config:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// babel.config.js
|
|
17
|
+
module.exports = {
|
|
18
|
+
plugins: ["@ciao-tools/babel"],
|
|
19
|
+
};
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or with Vite:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// vite.config.ts
|
|
26
|
+
import { defineConfig } from "vite";
|
|
27
|
+
import react from "@vitejs/plugin-react";
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
plugins: [
|
|
31
|
+
react({
|
|
32
|
+
babel: {
|
|
33
|
+
plugins: ["@ciao-tools/babel"],
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## What it extracts
|
|
41
|
+
|
|
42
|
+
The plugin scans your code for:
|
|
43
|
+
|
|
44
|
+
- `ct()` function calls with string literals
|
|
45
|
+
- `<CTContextBlock id="...">` components for context grouping
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
// These strings are extracted:
|
|
49
|
+
ct("Hello, world!");
|
|
50
|
+
ct("Welcome back, {name}", { name: userName });
|
|
51
|
+
|
|
52
|
+
<CTContextBlock id="checkout-page">
|
|
53
|
+
<p>{ct("Review your order")}</p>
|
|
54
|
+
<p>{ct("Proceed to payment")}</p>
|
|
55
|
+
</CTContextBlock>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Exports
|
|
59
|
+
|
|
60
|
+
- `default` - Babel plugin function
|
|
61
|
+
- `buildSchema()` - Generate schema from extraction result
|
|
62
|
+
- `createExtractionPlugin()` - Create plugin with custom options
|
|
63
|
+
|
|
64
|
+
## Documentation
|
|
65
|
+
|
|
66
|
+
See [docs.ciao-tools.com/babel](https://docs.ciao-tools.com/api/babel) for full documentation.
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
//#region src/visitor.ts
|
|
4
|
+
function formatLocation(state, loc) {
|
|
5
|
+
const filename = state.filename || state.file?.opts?.filename || "unknown";
|
|
6
|
+
if (loc) return `${filename}:${loc.line}:${loc.column}`;
|
|
7
|
+
return filename;
|
|
8
|
+
}
|
|
9
|
+
function extractTransTemplate(children) {
|
|
10
|
+
let elementIndex = 0;
|
|
11
|
+
function processNode(node) {
|
|
12
|
+
if (node.type === "JSXText") return node.value.replace(/\s+/g, " ");
|
|
13
|
+
if (node.type === "JSXExpressionContainer") {
|
|
14
|
+
const expr = node.expression;
|
|
15
|
+
if (expr.type === "StringLiteral") return expr.value;
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
if (node.type === "JSXElement") {
|
|
19
|
+
const elem = node;
|
|
20
|
+
const idx = elementIndex++;
|
|
21
|
+
return `<${idx}>${elem.children.map(processNode).join("")}</${idx}>`;
|
|
22
|
+
}
|
|
23
|
+
if (node.type === "JSXFragment") return node.children.map(processNode).join("");
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
return children.map(processNode).join("").trim();
|
|
27
|
+
}
|
|
28
|
+
function getContextBlockIdForJSX(path) {
|
|
29
|
+
let current = path.parentPath;
|
|
30
|
+
while (current) {
|
|
31
|
+
if (current.isJSXElement()) {
|
|
32
|
+
const openingElement = current.node.openingElement;
|
|
33
|
+
const name = openingElement.name;
|
|
34
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
35
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id" && attr.value?.type === "StringLiteral") return attr.value.value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
current = current.parentPath;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
function getContextBlockId(path) {
|
|
43
|
+
let current = path.parentPath;
|
|
44
|
+
while (current) {
|
|
45
|
+
if (current.isJSXElement()) {
|
|
46
|
+
const openingElement = current.node.openingElement;
|
|
47
|
+
const name = openingElement.name;
|
|
48
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
49
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id" && attr.value?.type === "StringLiteral") return attr.value.value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
current = current.parentPath;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function createExtractionVisitor(collectedStrings, collectedContextBlocks, ctVariableNames, processedLocations) {
|
|
57
|
+
return {
|
|
58
|
+
VariableDeclarator(path) {
|
|
59
|
+
const init = path.node.init;
|
|
60
|
+
const id = path.node.id;
|
|
61
|
+
if (init && init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "useCt") {
|
|
62
|
+
if (id.type === "Identifier") ctVariableNames.add(id.name);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
CallExpression(path, state) {
|
|
66
|
+
const callee = path.node.callee;
|
|
67
|
+
if (callee.type === "Identifier" && ctVariableNames.has(callee.name)) {
|
|
68
|
+
const loc = path.node.loc;
|
|
69
|
+
if (loc) {
|
|
70
|
+
const locationKey = `${loc.start.line}:${loc.start.column}`;
|
|
71
|
+
if (processedLocations.has(locationKey)) return;
|
|
72
|
+
processedLocations.add(locationKey);
|
|
73
|
+
}
|
|
74
|
+
const args = path.node.arguments;
|
|
75
|
+
if (args.length === 0) {
|
|
76
|
+
console.warn(`[ciao-tools] Warning: ${callee.name}() called with no arguments at ${formatLocation(state, loc?.start)}`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const textArg = args[0];
|
|
80
|
+
if (textArg.type !== "StringLiteral") {
|
|
81
|
+
console.warn(`[ciao-tools] Warning: ${callee.name}() called with non-string literal at ${formatLocation(state, loc?.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const text = textArg.value;
|
|
85
|
+
let context = null;
|
|
86
|
+
if (args.length >= 2) {
|
|
87
|
+
const contextArg = args[1];
|
|
88
|
+
if (contextArg.type === "StringLiteral") context = contextArg.value;
|
|
89
|
+
}
|
|
90
|
+
const parentContextBlockId = getContextBlockId(path);
|
|
91
|
+
if (!collectedStrings.some((s) => s.text === text && s.context === (context ?? void 0) && s.parentContextBlockId === (parentContextBlockId ?? void 0))) {
|
|
92
|
+
const entry = { text };
|
|
93
|
+
if (context) entry.context = context;
|
|
94
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
95
|
+
collectedStrings.push(entry);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
JSXElement(path, state) {
|
|
100
|
+
const openingElement = path.node.openingElement;
|
|
101
|
+
const name = openingElement.name;
|
|
102
|
+
const loc = path.node.loc;
|
|
103
|
+
if (name.type === "JSXIdentifier" && name.name === "Trans") {
|
|
104
|
+
if (loc) {
|
|
105
|
+
const locationKey = `jsx:${loc.start.line}:${loc.start.column}`;
|
|
106
|
+
if (processedLocations.has(locationKey)) return;
|
|
107
|
+
processedLocations.add(locationKey);
|
|
108
|
+
}
|
|
109
|
+
const template = extractTransTemplate(path.node.children);
|
|
110
|
+
if (!template) return;
|
|
111
|
+
let context = null;
|
|
112
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "context") {
|
|
113
|
+
if (attr.value?.type === "StringLiteral") context = attr.value.value;
|
|
114
|
+
else if (attr.value?.type === "JSXExpressionContainer" && attr.value.expression.type === "StringLiteral") context = attr.value.expression.value;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
const parentContextBlockId = getContextBlockIdForJSX(path);
|
|
118
|
+
if (!collectedStrings.some((s) => s.text === template && s.context === (context ?? void 0) && s.parentContextBlockId === (parentContextBlockId ?? void 0))) {
|
|
119
|
+
const entry = { text: template };
|
|
120
|
+
if (context) entry.context = context;
|
|
121
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
122
|
+
collectedStrings.push(entry);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
126
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id") {
|
|
127
|
+
if (attr.value && attr.value.type === "StringLiteral") {
|
|
128
|
+
const id = attr.value.value;
|
|
129
|
+
if (!collectedContextBlocks.some((b) => b.id === id)) collectedContextBlocks.push({ id });
|
|
130
|
+
} else console.warn(`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state, loc?.start)}`);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function createExtractionPlugin(options = {}) {
|
|
138
|
+
const { onComplete } = options;
|
|
139
|
+
const collectedStrings = [];
|
|
140
|
+
const collectedContextBlocks = [];
|
|
141
|
+
const ctVariableNames = /* @__PURE__ */ new Set();
|
|
142
|
+
const processedLocations = /* @__PURE__ */ new Set();
|
|
143
|
+
return () => ({
|
|
144
|
+
name: "@ciao-tools/babel-extraction",
|
|
145
|
+
visitor: createExtractionVisitor(collectedStrings, collectedContextBlocks, ctVariableNames, processedLocations),
|
|
146
|
+
post() {
|
|
147
|
+
if (onComplete) onComplete({
|
|
148
|
+
strings: [...collectedStrings],
|
|
149
|
+
contextBlocks: [...collectedContextBlocks]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/index.ts
|
|
157
|
+
function ciaoToolsBabelPlugin() {
|
|
158
|
+
return {
|
|
159
|
+
name: "@ciao-tools/babel",
|
|
160
|
+
visitor: createExtractionVisitor([], [], /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set())
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function buildSchema(result) {
|
|
164
|
+
return {
|
|
165
|
+
version: "1.0",
|
|
166
|
+
strings: result.strings,
|
|
167
|
+
contextBlocks: result.contextBlocks,
|
|
168
|
+
metadata: {
|
|
169
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
170
|
+
totalStrings: result.strings.length,
|
|
171
|
+
totalContextBlocks: result.contextBlocks.length
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//#endregion
|
|
177
|
+
exports.buildSchema = buildSchema;
|
|
178
|
+
exports.createExtractionPlugin = createExtractionPlugin;
|
|
179
|
+
exports.default = ciaoToolsBabelPlugin;
|
|
180
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["current: NodePath | null","context: string | null","entry: TranslatableString","collectedStrings: TranslatableString[]","collectedContextBlocks: ContextBlock[]"],"sources":["../src/visitor.ts","../src/index.ts"],"sourcesContent":["import type { NodePath, PluginObj, PluginPass } from \"@babel/core\";\nimport type {\n\tCallExpression,\n\tJSXElement,\n\tJSXText,\n\tJSXExpressionContainer,\n\tJSXFragment,\n\tVariableDeclarator,\n\tNode,\n} from \"@babel/types\";\nimport type {\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n} from \"./types\";\n\nfunction formatLocation(\n\tstate: PluginPass,\n\tloc: { line: number; column: number } | null | undefined,\n): string {\n\tconst filename = state.filename || state.file?.opts?.filename || \"unknown\";\n\tif (loc) {\n\t\treturn `${filename}:${loc.line}:${loc.column}`;\n\t}\n\treturn filename;\n}\n\nfunction extractTransTemplate(children: Node[]): string {\n\tlet elementIndex = 0;\n\n\tfunction processNode(node: Node): string {\n\t\tif (node.type === \"JSXText\") {\n\t\t\treturn (node as JSXText).value.replace(/\\s+/g, \" \");\n\t\t}\n\n\t\tif (node.type === \"JSXExpressionContainer\") {\n\t\t\tconst expr = (node as JSXExpressionContainer).expression;\n\t\t\tif (expr.type === \"StringLiteral\") {\n\t\t\t\treturn expr.value;\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tif (node.type === \"JSXElement\") {\n\t\t\tconst elem = node as JSXElement;\n\t\t\tconst idx = elementIndex++;\n\t\t\tconst innerContent = elem.children.map(processNode).join(\"\");\n\t\t\treturn `<${idx}>${innerContent}</${idx}>`;\n\t\t}\n\n\t\tif (node.type === \"JSXFragment\") {\n\t\t\tconst frag = node as JSXFragment;\n\t\t\treturn frag.children.map(processNode).join(\"\");\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\treturn children.map(processNode).join(\"\").trim();\n}\n\nfunction getContextBlockIdForJSX(path: NodePath<JSXElement>): string | null {\n\tlet current: NodePath | null = path.parentPath;\n\n\twhile (current) {\n\t\tif (current.isJSXElement()) {\n\t\t\tconst openingElement = current.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\" &&\n\t\t\t\t\t\tattr.value?.type === \"StringLiteral\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn attr.value.value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcurrent = current.parentPath;\n\t}\n\n\treturn null;\n}\n\nfunction getContextBlockId(path: NodePath<CallExpression>): string | null {\n\tlet current: NodePath | null = path.parentPath;\n\n\twhile (current) {\n\t\tif (current.isJSXElement()) {\n\t\t\tconst openingElement = current.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\" &&\n\t\t\t\t\t\tattr.value?.type === \"StringLiteral\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn attr.value.value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcurrent = current.parentPath;\n\t}\n\n\treturn null;\n}\n\nexport function createExtractionVisitor(\n\tcollectedStrings: TranslatableString[],\n\tcollectedContextBlocks: ContextBlock[],\n\tctVariableNames: Set<string>,\n\tprocessedLocations: Set<string>,\n): PluginObj[\"visitor\"] {\n\treturn {\n\t\tVariableDeclarator(path: NodePath<VariableDeclarator>) {\n\t\t\tconst init = path.node.init;\n\t\t\tconst id = path.node.id;\n\n\t\t\tif (\n\t\t\t\tinit &&\n\t\t\t\tinit.type === \"CallExpression\" &&\n\t\t\t\tinit.callee.type === \"Identifier\" &&\n\t\t\t\tinit.callee.name === \"useCt\"\n\t\t\t) {\n\t\t\t\tif (id.type === \"Identifier\") {\n\t\t\t\t\tctVariableNames.add(id.name);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tCallExpression(path: NodePath<CallExpression>, state: PluginPass) {\n\t\t\tconst callee = path.node.callee;\n\n\t\t\tif (callee.type === \"Identifier\" && ctVariableNames.has(callee.name)) {\n\t\t\t\tconst loc = path.node.loc;\n\t\t\t\tif (loc) {\n\t\t\t\t\tconst locationKey = `${loc.start.line}:${loc.start.column}`;\n\t\t\t\t\tif (processedLocations.has(locationKey)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tprocessedLocations.add(locationKey);\n\t\t\t\t}\n\n\t\t\t\tconst args = path.node.arguments;\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[ciao-tools] Warning: ${callee.name}() called with no arguments at ${formatLocation(state, loc?.start)}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst textArg = args[0];\n\n\t\t\t\tif (textArg.type !== \"StringLiteral\") {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[ciao-tools] Warning: ${callee.name}() called with non-string literal at ${formatLocation(state, loc?.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst text = textArg.value;\n\t\t\t\tlet context: string | null = null;\n\n\t\t\t\tif (args.length >= 2) {\n\t\t\t\t\tconst contextArg = args[1];\n\t\t\t\t\tif (contextArg.type === \"StringLiteral\") {\n\t\t\t\t\t\tcontext = contextArg.value;\n\t\t\t\t\t}\n\t\t\t\t\t// Note: ObjectExpression is valid (interpolation values), so we don't warn about it\n\t\t\t\t\t// Only warn for dynamic context strings (identifiers, member expressions, etc.)\n\t\t\t\t}\n\n\t\t\t\tconst parentContextBlockId = getContextBlockId(path);\n\n\t\t\t\tconst isDuplicate = collectedStrings.some(\n\t\t\t\t\t(s) =>\n\t\t\t\t\t\ts.text === text &&\n\t\t\t\t\t\ts.context === (context ?? undefined) &&\n\t\t\t\t\t\ts.parentContextBlockId === (parentContextBlockId ?? undefined),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tconst entry: TranslatableString = { text };\n\t\t\t\t\tif (context) {\n\t\t\t\t\t\tentry.context = context;\n\t\t\t\t\t}\n\t\t\t\t\tif (parentContextBlockId) {\n\t\t\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t\t\t}\n\t\t\t\t\tcollectedStrings.push(entry);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tJSXElement(path: NodePath<JSXElement>, state: PluginPass) {\n\t\t\tconst openingElement = path.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\t\t\tconst loc = path.node.loc;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"Trans\") {\n\t\t\t\tif (loc) {\n\t\t\t\t\tconst locationKey = `jsx:${loc.start.line}:${loc.start.column}`;\n\t\t\t\t\tif (processedLocations.has(locationKey)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tprocessedLocations.add(locationKey);\n\t\t\t\t}\n\n\t\t\t\tconst template = extractTransTemplate(path.node.children);\n\t\t\t\tif (!template) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Extract context prop from Trans component\n\t\t\t\tlet context: string | null = null;\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"context\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (attr.value?.type === \"StringLiteral\") {\n\t\t\t\t\t\t\tcontext = attr.value.value;\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tattr.value?.type === \"JSXExpressionContainer\" &&\n\t\t\t\t\t\t\tattr.value.expression.type === \"StringLiteral\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext = attr.value.expression.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst parentContextBlockId = getContextBlockIdForJSX(path);\n\n\t\t\t\tconst isDuplicate = collectedStrings.some(\n\t\t\t\t\t(s) =>\n\t\t\t\t\t\ts.text === template &&\n\t\t\t\t\t\ts.context === (context ?? undefined) &&\n\t\t\t\t\t\ts.parentContextBlockId === (parentContextBlockId ?? undefined),\n\t\t\t\t);\n\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tconst entry: TranslatableString = { text: template };\n\t\t\t\t\tif (context) {\n\t\t\t\t\t\tentry.context = context;\n\t\t\t\t\t}\n\t\t\t\t\tif (parentContextBlockId) {\n\t\t\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t\t\t}\n\t\t\t\t\tcollectedStrings.push(entry);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (attr.value && attr.value.type === \"StringLiteral\") {\n\t\t\t\t\t\t\tconst id = attr.value.value;\n\t\t\t\t\t\t\tconst isDuplicate = collectedContextBlocks.some(\n\t\t\t\t\t\t\t\t(b) => b.id === id,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\t\t\t\tcollectedContextBlocks.push({ id });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state, loc?.start)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function createExtractionPlugin(\n\toptions: ExtractionPluginOptions = {},\n): () => PluginObj {\n\tconst { onComplete } = options;\n\tconst collectedStrings: TranslatableString[] = [];\n\tconst collectedContextBlocks: ContextBlock[] = [];\n\tconst ctVariableNames = new Set<string>();\n\tconst processedLocations = new Set<string>();\n\n\treturn (): PluginObj => ({\n\t\tname: \"@ciao-tools/babel-extraction\",\n\t\tvisitor: createExtractionVisitor(\n\t\t\tcollectedStrings,\n\t\t\tcollectedContextBlocks,\n\t\t\tctVariableNames,\n\t\t\tprocessedLocations,\n\t\t),\n\t\tpost() {\n\t\t\tif (onComplete) {\n\t\t\t\tconst result: ExtractionResult = {\n\t\t\t\t\tstrings: [...collectedStrings],\n\t\t\t\t\tcontextBlocks: [...collectedContextBlocks],\n\t\t\t\t};\n\t\t\t\tonComplete(result);\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport function getCollectedData(\n\tcollectedStrings: TranslatableString[],\n\tcollectedContextBlocks: ContextBlock[],\n): ExtractionResult {\n\treturn {\n\t\tstrings: [...collectedStrings],\n\t\tcontextBlocks: [...collectedContextBlocks],\n\t};\n}\n","import type { PluginObj } from \"@babel/core\";\nimport type {\n\tBuildSchema,\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n} from \"./types\";\nimport { createExtractionVisitor } from \"./visitor\";\n\nexport type {\n\tBuildSchema,\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n};\nexport { createExtractionPlugin } from \"./visitor\";\n\nexport default function ciaoToolsBabelPlugin(): PluginObj {\n\tconst collectedStrings: TranslatableString[] = [];\n\tconst collectedContextBlocks: ContextBlock[] = [];\n\tconst ctVariableNames = new Set<string>();\n\tconst processedLocations = new Set<string>();\n\n\treturn {\n\t\tname: \"@ciao-tools/babel\",\n\t\tvisitor: createExtractionVisitor(\n\t\t\tcollectedStrings,\n\t\t\tcollectedContextBlocks,\n\t\t\tctVariableNames,\n\t\t\tprocessedLocations,\n\t\t),\n\t};\n}\n\nexport function buildSchema(result: ExtractionResult): BuildSchema {\n\treturn {\n\t\tversion: \"1.0\",\n\t\tstrings: result.strings,\n\t\tcontextBlocks: result.contextBlocks,\n\t\tmetadata: {\n\t\t\tgeneratedAt: new Date().toISOString(),\n\t\t\ttotalStrings: result.strings.length,\n\t\t\ttotalContextBlocks: result.contextBlocks.length,\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PluginObj } from "@babel/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
interface TranslatableString {
|
|
5
|
+
text: string;
|
|
6
|
+
context?: string;
|
|
7
|
+
parentContextBlockId?: string;
|
|
8
|
+
}
|
|
9
|
+
interface ContextBlock {
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
interface ExtractionResult {
|
|
13
|
+
strings: TranslatableString[];
|
|
14
|
+
contextBlocks: ContextBlock[];
|
|
15
|
+
}
|
|
16
|
+
interface BuildSchema {
|
|
17
|
+
version: string;
|
|
18
|
+
strings: TranslatableString[];
|
|
19
|
+
contextBlocks: ContextBlock[];
|
|
20
|
+
metadata: {
|
|
21
|
+
generatedAt: string;
|
|
22
|
+
totalStrings: number;
|
|
23
|
+
totalContextBlocks: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface ExtractionPluginOptions {
|
|
27
|
+
onComplete?: (result: ExtractionResult) => void;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/visitor.d.ts
|
|
31
|
+
declare function createExtractionPlugin(options?: ExtractionPluginOptions): () => PluginObj;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/index.d.ts
|
|
34
|
+
declare function ciaoToolsBabelPlugin(): PluginObj;
|
|
35
|
+
declare function buildSchema(result: ExtractionResult): BuildSchema;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type BuildSchema, type ContextBlock, type ExtractionPluginOptions, type ExtractionResult, type TranslatableString, buildSchema, createExtractionPlugin, ciaoToolsBabelPlugin as default };
|
|
38
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/visitor.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;UAAiB,kBAAA;;;EAAA,oBAAA,CAAkB,EAAA,MAAA;AAMnC;AAIiB,UAJA,YAAA,CAIgB;EAKhB,EAAA,EAAA,MAAA;AAWjB;UAhBiB,gBAAA;WACP;iBACM;ACuRhB;UDpRiB,WAAA;;WAEP;EEEc,aAAA,EFDR,YEC4B,EAAA;EAiB5B,QAAA,EAAA;;;;;;UFVC,uBAAA;wBACM;;;;AA3BN,iBCmSD,sBAAA,CDnSmB,OAAA,CAAA,ECoSzB,uBDpSyB,CAAA,EAAA,GAAA,GCqS1B,SDrS0B;;;AAMlB,iBEaO,oBAAA,CAAA,CFbK,EEamB,SFbnB;AAIZ,iBE0BD,WAAA,CFzBN,MAAA,EEyB0B,gBFxBpB,CAAA,EEwBuC,WFxB3B"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PluginObj } from "@babel/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
interface TranslatableString {
|
|
5
|
+
text: string;
|
|
6
|
+
context?: string;
|
|
7
|
+
parentContextBlockId?: string;
|
|
8
|
+
}
|
|
9
|
+
interface ContextBlock {
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
interface ExtractionResult {
|
|
13
|
+
strings: TranslatableString[];
|
|
14
|
+
contextBlocks: ContextBlock[];
|
|
15
|
+
}
|
|
16
|
+
interface BuildSchema {
|
|
17
|
+
version: string;
|
|
18
|
+
strings: TranslatableString[];
|
|
19
|
+
contextBlocks: ContextBlock[];
|
|
20
|
+
metadata: {
|
|
21
|
+
generatedAt: string;
|
|
22
|
+
totalStrings: number;
|
|
23
|
+
totalContextBlocks: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface ExtractionPluginOptions {
|
|
27
|
+
onComplete?: (result: ExtractionResult) => void;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/visitor.d.ts
|
|
31
|
+
declare function createExtractionPlugin(options?: ExtractionPluginOptions): () => PluginObj;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/index.d.ts
|
|
34
|
+
declare function ciaoToolsBabelPlugin(): PluginObj;
|
|
35
|
+
declare function buildSchema(result: ExtractionResult): BuildSchema;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type BuildSchema, type ContextBlock, type ExtractionPluginOptions, type ExtractionResult, type TranslatableString, buildSchema, createExtractionPlugin, ciaoToolsBabelPlugin as default };
|
|
38
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/visitor.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;UAAiB,kBAAA;;;EAAA,oBAAA,CAAkB,EAAA,MAAA;AAMnC;AAIiB,UAJA,YAAA,CAIgB;EAKhB,EAAA,EAAA,MAAA;AAWjB;UAhBiB,gBAAA;WACP;iBACM;ACuRhB;UDpRiB,WAAA;;WAEP;EEEc,aAAA,EFDR,YEC4B,EAAA;EAiB5B,QAAA,EAAA;;;;;;UFVC,uBAAA;wBACM;;;;AA3BN,iBCmSD,sBAAA,CDnSmB,OAAA,CAAA,ECoSzB,uBDpSyB,CAAA,EAAA,GAAA,GCqS1B,SDrS0B;;;AAMlB,iBEaO,oBAAA,CAAA,CFbK,EEamB,SFbnB;AAIZ,iBE0BD,WAAA,CFzBN,MAAA,EEyB0B,gBFxBpB,CAAA,EEwBuC,WFxB3B"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
//#region src/visitor.ts
|
|
2
|
+
function formatLocation(state, loc) {
|
|
3
|
+
const filename = state.filename || state.file?.opts?.filename || "unknown";
|
|
4
|
+
if (loc) return `${filename}:${loc.line}:${loc.column}`;
|
|
5
|
+
return filename;
|
|
6
|
+
}
|
|
7
|
+
function extractTransTemplate(children) {
|
|
8
|
+
let elementIndex = 0;
|
|
9
|
+
function processNode(node) {
|
|
10
|
+
if (node.type === "JSXText") return node.value.replace(/\s+/g, " ");
|
|
11
|
+
if (node.type === "JSXExpressionContainer") {
|
|
12
|
+
const expr = node.expression;
|
|
13
|
+
if (expr.type === "StringLiteral") return expr.value;
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
if (node.type === "JSXElement") {
|
|
17
|
+
const elem = node;
|
|
18
|
+
const idx = elementIndex++;
|
|
19
|
+
return `<${idx}>${elem.children.map(processNode).join("")}</${idx}>`;
|
|
20
|
+
}
|
|
21
|
+
if (node.type === "JSXFragment") return node.children.map(processNode).join("");
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
return children.map(processNode).join("").trim();
|
|
25
|
+
}
|
|
26
|
+
function getContextBlockIdForJSX(path) {
|
|
27
|
+
let current = path.parentPath;
|
|
28
|
+
while (current) {
|
|
29
|
+
if (current.isJSXElement()) {
|
|
30
|
+
const openingElement = current.node.openingElement;
|
|
31
|
+
const name = openingElement.name;
|
|
32
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
33
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id" && attr.value?.type === "StringLiteral") return attr.value.value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
current = current.parentPath;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function getContextBlockId(path) {
|
|
41
|
+
let current = path.parentPath;
|
|
42
|
+
while (current) {
|
|
43
|
+
if (current.isJSXElement()) {
|
|
44
|
+
const openingElement = current.node.openingElement;
|
|
45
|
+
const name = openingElement.name;
|
|
46
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
47
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id" && attr.value?.type === "StringLiteral") return attr.value.value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
current = current.parentPath;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function createExtractionVisitor(collectedStrings, collectedContextBlocks, ctVariableNames, processedLocations) {
|
|
55
|
+
return {
|
|
56
|
+
VariableDeclarator(path) {
|
|
57
|
+
const init = path.node.init;
|
|
58
|
+
const id = path.node.id;
|
|
59
|
+
if (init && init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "useCt") {
|
|
60
|
+
if (id.type === "Identifier") ctVariableNames.add(id.name);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
CallExpression(path, state) {
|
|
64
|
+
const callee = path.node.callee;
|
|
65
|
+
if (callee.type === "Identifier" && ctVariableNames.has(callee.name)) {
|
|
66
|
+
const loc = path.node.loc;
|
|
67
|
+
if (loc) {
|
|
68
|
+
const locationKey = `${loc.start.line}:${loc.start.column}`;
|
|
69
|
+
if (processedLocations.has(locationKey)) return;
|
|
70
|
+
processedLocations.add(locationKey);
|
|
71
|
+
}
|
|
72
|
+
const args = path.node.arguments;
|
|
73
|
+
if (args.length === 0) {
|
|
74
|
+
console.warn(`[ciao-tools] Warning: ${callee.name}() called with no arguments at ${formatLocation(state, loc?.start)}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const textArg = args[0];
|
|
78
|
+
if (textArg.type !== "StringLiteral") {
|
|
79
|
+
console.warn(`[ciao-tools] Warning: ${callee.name}() called with non-string literal at ${formatLocation(state, loc?.start)}. Only string literals are supported. Skipping dynamic string.`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const text = textArg.value;
|
|
83
|
+
let context = null;
|
|
84
|
+
if (args.length >= 2) {
|
|
85
|
+
const contextArg = args[1];
|
|
86
|
+
if (contextArg.type === "StringLiteral") context = contextArg.value;
|
|
87
|
+
}
|
|
88
|
+
const parentContextBlockId = getContextBlockId(path);
|
|
89
|
+
if (!collectedStrings.some((s) => s.text === text && s.context === (context ?? void 0) && s.parentContextBlockId === (parentContextBlockId ?? void 0))) {
|
|
90
|
+
const entry = { text };
|
|
91
|
+
if (context) entry.context = context;
|
|
92
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
93
|
+
collectedStrings.push(entry);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
JSXElement(path, state) {
|
|
98
|
+
const openingElement = path.node.openingElement;
|
|
99
|
+
const name = openingElement.name;
|
|
100
|
+
const loc = path.node.loc;
|
|
101
|
+
if (name.type === "JSXIdentifier" && name.name === "Trans") {
|
|
102
|
+
if (loc) {
|
|
103
|
+
const locationKey = `jsx:${loc.start.line}:${loc.start.column}`;
|
|
104
|
+
if (processedLocations.has(locationKey)) return;
|
|
105
|
+
processedLocations.add(locationKey);
|
|
106
|
+
}
|
|
107
|
+
const template = extractTransTemplate(path.node.children);
|
|
108
|
+
if (!template) return;
|
|
109
|
+
let context = null;
|
|
110
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "context") {
|
|
111
|
+
if (attr.value?.type === "StringLiteral") context = attr.value.value;
|
|
112
|
+
else if (attr.value?.type === "JSXExpressionContainer" && attr.value.expression.type === "StringLiteral") context = attr.value.expression.value;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
const parentContextBlockId = getContextBlockIdForJSX(path);
|
|
116
|
+
if (!collectedStrings.some((s) => s.text === template && s.context === (context ?? void 0) && s.parentContextBlockId === (parentContextBlockId ?? void 0))) {
|
|
117
|
+
const entry = { text: template };
|
|
118
|
+
if (context) entry.context = context;
|
|
119
|
+
if (parentContextBlockId) entry.parentContextBlockId = parentContextBlockId;
|
|
120
|
+
collectedStrings.push(entry);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (name.type === "JSXIdentifier" && name.name === "CTContextBlock") {
|
|
124
|
+
for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "id") {
|
|
125
|
+
if (attr.value && attr.value.type === "StringLiteral") {
|
|
126
|
+
const id = attr.value.value;
|
|
127
|
+
if (!collectedContextBlocks.some((b) => b.id === id)) collectedContextBlocks.push({ id });
|
|
128
|
+
} else console.warn(`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state, loc?.start)}`);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function createExtractionPlugin(options = {}) {
|
|
136
|
+
const { onComplete } = options;
|
|
137
|
+
const collectedStrings = [];
|
|
138
|
+
const collectedContextBlocks = [];
|
|
139
|
+
const ctVariableNames = /* @__PURE__ */ new Set();
|
|
140
|
+
const processedLocations = /* @__PURE__ */ new Set();
|
|
141
|
+
return () => ({
|
|
142
|
+
name: "@ciao-tools/babel-extraction",
|
|
143
|
+
visitor: createExtractionVisitor(collectedStrings, collectedContextBlocks, ctVariableNames, processedLocations),
|
|
144
|
+
post() {
|
|
145
|
+
if (onComplete) onComplete({
|
|
146
|
+
strings: [...collectedStrings],
|
|
147
|
+
contextBlocks: [...collectedContextBlocks]
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/index.ts
|
|
155
|
+
function ciaoToolsBabelPlugin() {
|
|
156
|
+
return {
|
|
157
|
+
name: "@ciao-tools/babel",
|
|
158
|
+
visitor: createExtractionVisitor([], [], /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set())
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function buildSchema(result) {
|
|
162
|
+
return {
|
|
163
|
+
version: "1.0",
|
|
164
|
+
strings: result.strings,
|
|
165
|
+
contextBlocks: result.contextBlocks,
|
|
166
|
+
metadata: {
|
|
167
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
+
totalStrings: result.strings.length,
|
|
169
|
+
totalContextBlocks: result.contextBlocks.length
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//#endregion
|
|
175
|
+
export { buildSchema, createExtractionPlugin, ciaoToolsBabelPlugin as default };
|
|
176
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["current: NodePath | null","context: string | null","entry: TranslatableString","collectedStrings: TranslatableString[]","collectedContextBlocks: ContextBlock[]"],"sources":["../src/visitor.ts","../src/index.ts"],"sourcesContent":["import type { NodePath, PluginObj, PluginPass } from \"@babel/core\";\nimport type {\n\tCallExpression,\n\tJSXElement,\n\tJSXText,\n\tJSXExpressionContainer,\n\tJSXFragment,\n\tVariableDeclarator,\n\tNode,\n} from \"@babel/types\";\nimport type {\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n} from \"./types\";\n\nfunction formatLocation(\n\tstate: PluginPass,\n\tloc: { line: number; column: number } | null | undefined,\n): string {\n\tconst filename = state.filename || state.file?.opts?.filename || \"unknown\";\n\tif (loc) {\n\t\treturn `${filename}:${loc.line}:${loc.column}`;\n\t}\n\treturn filename;\n}\n\nfunction extractTransTemplate(children: Node[]): string {\n\tlet elementIndex = 0;\n\n\tfunction processNode(node: Node): string {\n\t\tif (node.type === \"JSXText\") {\n\t\t\treturn (node as JSXText).value.replace(/\\s+/g, \" \");\n\t\t}\n\n\t\tif (node.type === \"JSXExpressionContainer\") {\n\t\t\tconst expr = (node as JSXExpressionContainer).expression;\n\t\t\tif (expr.type === \"StringLiteral\") {\n\t\t\t\treturn expr.value;\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tif (node.type === \"JSXElement\") {\n\t\t\tconst elem = node as JSXElement;\n\t\t\tconst idx = elementIndex++;\n\t\t\tconst innerContent = elem.children.map(processNode).join(\"\");\n\t\t\treturn `<${idx}>${innerContent}</${idx}>`;\n\t\t}\n\n\t\tif (node.type === \"JSXFragment\") {\n\t\t\tconst frag = node as JSXFragment;\n\t\t\treturn frag.children.map(processNode).join(\"\");\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\treturn children.map(processNode).join(\"\").trim();\n}\n\nfunction getContextBlockIdForJSX(path: NodePath<JSXElement>): string | null {\n\tlet current: NodePath | null = path.parentPath;\n\n\twhile (current) {\n\t\tif (current.isJSXElement()) {\n\t\t\tconst openingElement = current.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\" &&\n\t\t\t\t\t\tattr.value?.type === \"StringLiteral\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn attr.value.value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcurrent = current.parentPath;\n\t}\n\n\treturn null;\n}\n\nfunction getContextBlockId(path: NodePath<CallExpression>): string | null {\n\tlet current: NodePath | null = path.parentPath;\n\n\twhile (current) {\n\t\tif (current.isJSXElement()) {\n\t\t\tconst openingElement = current.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\" &&\n\t\t\t\t\t\tattr.value?.type === \"StringLiteral\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn attr.value.value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcurrent = current.parentPath;\n\t}\n\n\treturn null;\n}\n\nexport function createExtractionVisitor(\n\tcollectedStrings: TranslatableString[],\n\tcollectedContextBlocks: ContextBlock[],\n\tctVariableNames: Set<string>,\n\tprocessedLocations: Set<string>,\n): PluginObj[\"visitor\"] {\n\treturn {\n\t\tVariableDeclarator(path: NodePath<VariableDeclarator>) {\n\t\t\tconst init = path.node.init;\n\t\t\tconst id = path.node.id;\n\n\t\t\tif (\n\t\t\t\tinit &&\n\t\t\t\tinit.type === \"CallExpression\" &&\n\t\t\t\tinit.callee.type === \"Identifier\" &&\n\t\t\t\tinit.callee.name === \"useCt\"\n\t\t\t) {\n\t\t\t\tif (id.type === \"Identifier\") {\n\t\t\t\t\tctVariableNames.add(id.name);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tCallExpression(path: NodePath<CallExpression>, state: PluginPass) {\n\t\t\tconst callee = path.node.callee;\n\n\t\t\tif (callee.type === \"Identifier\" && ctVariableNames.has(callee.name)) {\n\t\t\t\tconst loc = path.node.loc;\n\t\t\t\tif (loc) {\n\t\t\t\t\tconst locationKey = `${loc.start.line}:${loc.start.column}`;\n\t\t\t\t\tif (processedLocations.has(locationKey)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tprocessedLocations.add(locationKey);\n\t\t\t\t}\n\n\t\t\t\tconst args = path.node.arguments;\n\n\t\t\t\tif (args.length === 0) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[ciao-tools] Warning: ${callee.name}() called with no arguments at ${formatLocation(state, loc?.start)}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst textArg = args[0];\n\n\t\t\t\tif (textArg.type !== \"StringLiteral\") {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[ciao-tools] Warning: ${callee.name}() called with non-string literal at ${formatLocation(state, loc?.start)}. Only string literals are supported. Skipping dynamic string.`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst text = textArg.value;\n\t\t\t\tlet context: string | null = null;\n\n\t\t\t\tif (args.length >= 2) {\n\t\t\t\t\tconst contextArg = args[1];\n\t\t\t\t\tif (contextArg.type === \"StringLiteral\") {\n\t\t\t\t\t\tcontext = contextArg.value;\n\t\t\t\t\t}\n\t\t\t\t\t// Note: ObjectExpression is valid (interpolation values), so we don't warn about it\n\t\t\t\t\t// Only warn for dynamic context strings (identifiers, member expressions, etc.)\n\t\t\t\t}\n\n\t\t\t\tconst parentContextBlockId = getContextBlockId(path);\n\n\t\t\t\tconst isDuplicate = collectedStrings.some(\n\t\t\t\t\t(s) =>\n\t\t\t\t\t\ts.text === text &&\n\t\t\t\t\t\ts.context === (context ?? undefined) &&\n\t\t\t\t\t\ts.parentContextBlockId === (parentContextBlockId ?? undefined),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tconst entry: TranslatableString = { text };\n\t\t\t\t\tif (context) {\n\t\t\t\t\t\tentry.context = context;\n\t\t\t\t\t}\n\t\t\t\t\tif (parentContextBlockId) {\n\t\t\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t\t\t}\n\t\t\t\t\tcollectedStrings.push(entry);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tJSXElement(path: NodePath<JSXElement>, state: PluginPass) {\n\t\t\tconst openingElement = path.node.openingElement;\n\t\t\tconst name = openingElement.name;\n\t\t\tconst loc = path.node.loc;\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"Trans\") {\n\t\t\t\tif (loc) {\n\t\t\t\t\tconst locationKey = `jsx:${loc.start.line}:${loc.start.column}`;\n\t\t\t\t\tif (processedLocations.has(locationKey)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tprocessedLocations.add(locationKey);\n\t\t\t\t}\n\n\t\t\t\tconst template = extractTransTemplate(path.node.children);\n\t\t\t\tif (!template) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Extract context prop from Trans component\n\t\t\t\tlet context: string | null = null;\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"context\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (attr.value?.type === \"StringLiteral\") {\n\t\t\t\t\t\t\tcontext = attr.value.value;\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tattr.value?.type === \"JSXExpressionContainer\" &&\n\t\t\t\t\t\t\tattr.value.expression.type === \"StringLiteral\"\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext = attr.value.expression.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst parentContextBlockId = getContextBlockIdForJSX(path);\n\n\t\t\t\tconst isDuplicate = collectedStrings.some(\n\t\t\t\t\t(s) =>\n\t\t\t\t\t\ts.text === template &&\n\t\t\t\t\t\ts.context === (context ?? undefined) &&\n\t\t\t\t\t\ts.parentContextBlockId === (parentContextBlockId ?? undefined),\n\t\t\t\t);\n\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tconst entry: TranslatableString = { text: template };\n\t\t\t\t\tif (context) {\n\t\t\t\t\t\tentry.context = context;\n\t\t\t\t\t}\n\t\t\t\t\tif (parentContextBlockId) {\n\t\t\t\t\t\tentry.parentContextBlockId = parentContextBlockId;\n\t\t\t\t\t}\n\t\t\t\t\tcollectedStrings.push(entry);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (name.type === \"JSXIdentifier\" && name.name === \"CTContextBlock\") {\n\t\t\t\tfor (const attr of openingElement.attributes) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tattr.type === \"JSXAttribute\" &&\n\t\t\t\t\t\tattr.name.type === \"JSXIdentifier\" &&\n\t\t\t\t\t\tattr.name.name === \"id\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (attr.value && attr.value.type === \"StringLiteral\") {\n\t\t\t\t\t\t\tconst id = attr.value.value;\n\t\t\t\t\t\t\tconst isDuplicate = collectedContextBlocks.some(\n\t\t\t\t\t\t\t\t(b) => b.id === id,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\t\t\t\tcollectedContextBlocks.push({ id });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`[ciao-tools] Warning: CTContextBlock id must be a string literal at ${formatLocation(state, loc?.start)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function createExtractionPlugin(\n\toptions: ExtractionPluginOptions = {},\n): () => PluginObj {\n\tconst { onComplete } = options;\n\tconst collectedStrings: TranslatableString[] = [];\n\tconst collectedContextBlocks: ContextBlock[] = [];\n\tconst ctVariableNames = new Set<string>();\n\tconst processedLocations = new Set<string>();\n\n\treturn (): PluginObj => ({\n\t\tname: \"@ciao-tools/babel-extraction\",\n\t\tvisitor: createExtractionVisitor(\n\t\t\tcollectedStrings,\n\t\t\tcollectedContextBlocks,\n\t\t\tctVariableNames,\n\t\t\tprocessedLocations,\n\t\t),\n\t\tpost() {\n\t\t\tif (onComplete) {\n\t\t\t\tconst result: ExtractionResult = {\n\t\t\t\t\tstrings: [...collectedStrings],\n\t\t\t\t\tcontextBlocks: [...collectedContextBlocks],\n\t\t\t\t};\n\t\t\t\tonComplete(result);\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport function getCollectedData(\n\tcollectedStrings: TranslatableString[],\n\tcollectedContextBlocks: ContextBlock[],\n): ExtractionResult {\n\treturn {\n\t\tstrings: [...collectedStrings],\n\t\tcontextBlocks: [...collectedContextBlocks],\n\t};\n}\n","import type { PluginObj } from \"@babel/core\";\nimport type {\n\tBuildSchema,\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n} from \"./types\";\nimport { createExtractionVisitor } from \"./visitor\";\n\nexport type {\n\tBuildSchema,\n\tContextBlock,\n\tExtractionPluginOptions,\n\tExtractionResult,\n\tTranslatableString,\n};\nexport { createExtractionPlugin } from \"./visitor\";\n\nexport default function ciaoToolsBabelPlugin(): PluginObj {\n\tconst collectedStrings: TranslatableString[] = [];\n\tconst collectedContextBlocks: ContextBlock[] = [];\n\tconst ctVariableNames = new Set<string>();\n\tconst processedLocations = new Set<string>();\n\n\treturn {\n\t\tname: \"@ciao-tools/babel\",\n\t\tvisitor: createExtractionVisitor(\n\t\t\tcollectedStrings,\n\t\t\tcollectedContextBlocks,\n\t\t\tctVariableNames,\n\t\t\tprocessedLocations,\n\t\t),\n\t};\n}\n\nexport function buildSchema(result: ExtractionResult): BuildSchema {\n\treturn {\n\t\tversion: \"1.0\",\n\t\tstrings: result.strings,\n\t\tcontextBlocks: result.contextBlocks,\n\t\tmetadata: {\n\t\t\tgeneratedAt: new Date().toISOString(),\n\t\t\ttotalStrings: result.strings.length,\n\t\t\ttotalContextBlocks: result.contextBlocks.length,\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "experimental-ciao-babel",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Babel plugin for ciao-tools - extracts translatable strings at build time",
|
|
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
|
+
"babel",
|
|
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/babel"
|
|
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
|
+
"peerDependencies": {
|
|
50
|
+
"@babel/core": "^7.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@babel/core": "^7.24.0",
|
|
54
|
+
"@types/babel__core": "^7.20.5"
|
|
55
|
+
}
|
|
56
|
+
}
|