@intlayer/babel 8.1.1 → 8.1.3-canary.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/dist/cjs/babel-plugin-intlayer-extract.cjs +1 -189
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +1 -298
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs +1 -79
- package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
- package/dist/cjs/getOptimizePluginOptions.cjs +1 -63
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -10
- package/dist/esm/_virtual/_rolldown/runtime.mjs +1 -8
- package/dist/esm/babel-plugin-intlayer-extract.mjs +1 -188
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +1 -297
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/getExtractPluginOptions.mjs +1 -78
- package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs +1 -63
- package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -6
- package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
- package/dist/types/getOptimizePluginOptions.d.ts +1 -1
- package/package.json +7 -7
|
@@ -1,190 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,
|
|
2
|
-
let node_path = require("node:path");
|
|
3
|
-
let _intlayer_chokidar = require("@intlayer/chokidar");
|
|
4
|
-
|
|
5
|
-
//#region src/babel-plugin-intlayer-extract.ts
|
|
6
|
-
const extractDictionaryKeyFromPath = (filePath) => {
|
|
7
|
-
let baseName = (0, node_path.basename)(filePath, (0, node_path.extname)(filePath));
|
|
8
|
-
if (baseName === "index") baseName = (0, node_path.basename)((0, node_path.dirname)(filePath));
|
|
9
|
-
return `comp-${baseName.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase()}`;
|
|
10
|
-
};
|
|
11
|
-
const unwrapParentheses = (node, t) => {
|
|
12
|
-
let current = node;
|
|
13
|
-
while (t.isParenthesizedExpression(current)) current = current.expression;
|
|
14
|
-
return current;
|
|
15
|
-
};
|
|
16
|
-
const intlayerExtractBabelPlugin = (babel) => {
|
|
17
|
-
const { types: t } = babel;
|
|
18
|
-
return {
|
|
19
|
-
name: "babel-plugin-intlayer-extract",
|
|
20
|
-
pre() {
|
|
21
|
-
this._extractedContent = {};
|
|
22
|
-
this._existingKeys = /* @__PURE__ */ new Set();
|
|
23
|
-
this._isIncluded = true;
|
|
24
|
-
this._hasJSX = false;
|
|
25
|
-
this._hasUseIntlayerImport = false;
|
|
26
|
-
this._useIntlayerLocalName = "useIntlayer";
|
|
27
|
-
this._hasGetIntlayerImport = false;
|
|
28
|
-
this._getIntlayerLocalName = "getIntlayer";
|
|
29
|
-
this._contentVarName = "content";
|
|
30
|
-
const filename = this.file.opts.filename;
|
|
31
|
-
if (this.opts.filesList && filename) {
|
|
32
|
-
const normalizedFilename = filename.replace(/\\/g, "/");
|
|
33
|
-
this._isIncluded = this.opts.filesList.some((f) => f.replace(/\\/g, "/") === normalizedFilename);
|
|
34
|
-
}
|
|
35
|
-
if (filename) this._dictionaryKey = extractDictionaryKeyFromPath(filename);
|
|
36
|
-
},
|
|
37
|
-
visitor: {
|
|
38
|
-
ImportDeclaration(path, state) {
|
|
39
|
-
if (!state._isIncluded) return;
|
|
40
|
-
for (const spec of path.node.specifiers) {
|
|
41
|
-
if (!t.isImportSpecifier(spec)) continue;
|
|
42
|
-
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
43
|
-
if (importedName === "useIntlayer") {
|
|
44
|
-
state._hasUseIntlayerImport = true;
|
|
45
|
-
state._useIntlayerLocalName = spec.local.name;
|
|
46
|
-
}
|
|
47
|
-
if (importedName === "getIntlayer") {
|
|
48
|
-
state._hasGetIntlayerImport = true;
|
|
49
|
-
state._getIntlayerLocalName = spec.local.name;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
JSXElement(_path, state) {
|
|
54
|
-
if (!state._isIncluded) return;
|
|
55
|
-
state._hasJSX = true;
|
|
56
|
-
},
|
|
57
|
-
Program: {
|
|
58
|
-
enter(programPath, state) {
|
|
59
|
-
if (!state._isIncluded) return;
|
|
60
|
-
let contentVarUsed = false;
|
|
61
|
-
programPath.traverse({ VariableDeclarator(varPath) {
|
|
62
|
-
if (t.isIdentifier(varPath.node.id) && varPath.node.id.name === "content") contentVarUsed = true;
|
|
63
|
-
} });
|
|
64
|
-
state._contentVarName = contentVarUsed ? "_compContent" : "content";
|
|
65
|
-
},
|
|
66
|
-
exit(programPath, state) {
|
|
67
|
-
if (!state._isIncluded || !state._hasJSX) return;
|
|
68
|
-
const extractionTargets = [];
|
|
69
|
-
const functionsToInject = /* @__PURE__ */ new Set();
|
|
70
|
-
const shouldExtract = state.opts.shouldExtract ?? _intlayer_chokidar.shouldExtract;
|
|
71
|
-
programPath.traverse({
|
|
72
|
-
JSXText(path) {
|
|
73
|
-
const text = path.node.value;
|
|
74
|
-
if (shouldExtract(text)) {
|
|
75
|
-
const key = (0, _intlayer_chokidar.generateKey)(text, state._existingKeys);
|
|
76
|
-
state._existingKeys.add(key);
|
|
77
|
-
state._extractedContent[key] = text.replace(/\s+/g, " ").trim();
|
|
78
|
-
extractionTargets.push({
|
|
79
|
-
path,
|
|
80
|
-
key,
|
|
81
|
-
isAttribute: false
|
|
82
|
-
});
|
|
83
|
-
const func = path.getFunctionParent();
|
|
84
|
-
if (func) functionsToInject.add(func);
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
JSXAttribute(path) {
|
|
88
|
-
const attrName = path.node.name;
|
|
89
|
-
if (!t.isJSXIdentifier(attrName)) return;
|
|
90
|
-
const isKey = attrName.name === "key";
|
|
91
|
-
if (!_intlayer_chokidar.ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey) return;
|
|
92
|
-
const value = path.node.value;
|
|
93
|
-
let text = null;
|
|
94
|
-
if (t.isStringLiteral(value)) text = value.value;
|
|
95
|
-
else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) text = value.expression.value;
|
|
96
|
-
if (text && shouldExtract(text)) {
|
|
97
|
-
const key = (0, _intlayer_chokidar.generateKey)(text, state._existingKeys);
|
|
98
|
-
state._existingKeys.add(key);
|
|
99
|
-
state._extractedContent[key] = text.trim();
|
|
100
|
-
extractionTargets.push({
|
|
101
|
-
path,
|
|
102
|
-
key,
|
|
103
|
-
isAttribute: true
|
|
104
|
-
});
|
|
105
|
-
const func = path.getFunctionParent();
|
|
106
|
-
if (func) functionsToInject.add(func);
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
StringLiteral(path) {
|
|
110
|
-
const parent = path.parentPath;
|
|
111
|
-
if (parent.isJSXAttribute() || parent.isImportDeclaration() || parent.isExportDeclaration() || parent.isImportSpecifier()) return;
|
|
112
|
-
if (parent.isObjectProperty() && path.key === "key") return;
|
|
113
|
-
if (parent.isCallExpression()) {
|
|
114
|
-
const callee = parent.node.callee;
|
|
115
|
-
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object) && callee.object.name === "console" || t.isIdentifier(callee) && (callee.name === state._useIntlayerLocalName || callee.name === state._getIntlayerLocalName || callee.name === "require") || callee.type === "Import") return;
|
|
116
|
-
}
|
|
117
|
-
const text = path.node.value;
|
|
118
|
-
if (shouldExtract(text)) {
|
|
119
|
-
const key = (0, _intlayer_chokidar.generateKey)(text, state._existingKeys);
|
|
120
|
-
state._existingKeys.add(key);
|
|
121
|
-
state._extractedContent[key] = text.trim();
|
|
122
|
-
extractionTargets.push({
|
|
123
|
-
path,
|
|
124
|
-
key,
|
|
125
|
-
isAttribute: false
|
|
126
|
-
});
|
|
127
|
-
const func = path.getFunctionParent();
|
|
128
|
-
if (func) functionsToInject.add(func);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
if (extractionTargets.length === 0) return;
|
|
133
|
-
for (const { path, key, isAttribute } of extractionTargets) if (isAttribute) {
|
|
134
|
-
const member = t.memberExpression(t.identifier(state._contentVarName), t.identifier(key));
|
|
135
|
-
path.node.value = t.jsxExpressionContainer(t.memberExpression(member, t.identifier("value")));
|
|
136
|
-
} else if (path.isJSXText()) path.replaceWith(t.jsxExpressionContainer(t.memberExpression(t.identifier(state._contentVarName), t.identifier(key))));
|
|
137
|
-
else path.replaceWith(t.memberExpression(t.identifier(state._contentVarName), t.identifier(key)));
|
|
138
|
-
if (state.opts.onExtract && state._dictionaryKey) state.opts.onExtract({
|
|
139
|
-
dictionaryKey: state._dictionaryKey,
|
|
140
|
-
filePath: state.file.opts.filename,
|
|
141
|
-
content: { ...state._extractedContent },
|
|
142
|
-
locale: state.opts.defaultLocale
|
|
143
|
-
});
|
|
144
|
-
let needsUseIntlayer = false;
|
|
145
|
-
let needsGetIntlayer = false;
|
|
146
|
-
for (const funcPath of functionsToInject) {
|
|
147
|
-
const type = injectHook(funcPath, state, t);
|
|
148
|
-
if (type === "hook") needsUseIntlayer = true;
|
|
149
|
-
if (type === "core") needsGetIntlayer = true;
|
|
150
|
-
}
|
|
151
|
-
if (needsUseIntlayer || needsGetIntlayer) {
|
|
152
|
-
const pkg = state.opts.packageName;
|
|
153
|
-
let pos = 0;
|
|
154
|
-
const body = programPath.node.body;
|
|
155
|
-
while (pos < body.length && t.isExpressionStatement(body[pos]) && t.isStringLiteral(body[pos].expression)) pos++;
|
|
156
|
-
if (needsUseIntlayer && !state._hasUseIntlayerImport) body.splice(pos++, 0, t.importDeclaration([t.importSpecifier(t.identifier("useIntlayer"), t.identifier("useIntlayer"))], t.stringLiteral(pkg)));
|
|
157
|
-
if (needsGetIntlayer && !state._hasGetIntlayerImport) body.splice(pos, 0, t.importDeclaration([t.importSpecifier(t.identifier("getIntlayer"), t.identifier("getIntlayer"))], t.stringLiteral(pkg)));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
};
|
|
164
|
-
const injectHook = (path, state, t) => {
|
|
165
|
-
const node = path.node;
|
|
166
|
-
const contentVarName = state._contentVarName;
|
|
167
|
-
const dictionaryKey = state._dictionaryKey;
|
|
168
|
-
if (!t.isBlockStatement(node.body)) {
|
|
169
|
-
const unwrapped = unwrapParentheses(node.body, t);
|
|
170
|
-
const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);
|
|
171
|
-
const hookName = isJSX ? state._useIntlayerLocalName : state._getIntlayerLocalName;
|
|
172
|
-
const hookCall = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName), [t.stringLiteral(dictionaryKey)]))]);
|
|
173
|
-
node.body = t.blockStatement([hookCall, t.returnStatement(node.body)]);
|
|
174
|
-
return isJSX ? "hook" : "core";
|
|
175
|
-
}
|
|
176
|
-
let returnsJSX = false;
|
|
177
|
-
path.traverse({ ReturnStatement(p) {
|
|
178
|
-
if (p.node.argument) {
|
|
179
|
-
const unwrapped = unwrapParentheses(p.node.argument, t);
|
|
180
|
-
if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) returnsJSX = true;
|
|
181
|
-
}
|
|
182
|
-
} });
|
|
183
|
-
const hookName = returnsJSX ? state._useIntlayerLocalName : state._getIntlayerLocalName;
|
|
184
|
-
if (!node.body.body.some((s) => t.isVariableDeclaration(s) && s.declarations.some((d) => t.isIdentifier(d.id) && d.id.name === contentVarName))) node.body.body.unshift(t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName), [t.stringLiteral(dictionaryKey)]))]));
|
|
185
|
-
return returnsJSX ? "hook" : "core";
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
//#endregion
|
|
189
|
-
exports.intlayerExtractBabelPlugin = intlayerExtractBabelPlugin;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:path`),t=require(`@intlayer/chokidar/cli`);const n=t=>{let n=(0,e.basename)(t,(0,e.extname)(t));return n===`index`&&(n=(0,e.basename)((0,e.dirname)(t))),`comp-${n.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}`},r=(e,t)=>{let n=e;for(;t.isParenthesizedExpression(n);)n=n.expression;return n},i=e=>{let{types:r}=e;return{name:`babel-plugin-intlayer-extract`,pre(){this._extractedContent={},this._existingKeys=new Set,this._isIncluded=!0,this._hasJSX=!1,this._hasUseIntlayerImport=!1,this._useIntlayerLocalName=`useIntlayer`,this._hasGetIntlayerImport=!1,this._getIntlayerLocalName=`getIntlayer`,this._contentVarName=`content`;let e=this.file.opts.filename;if(this.opts.filesList&&e){let t=e.replace(/\\/g,`/`);this._isIncluded=this.opts.filesList.some(e=>e.replace(/\\/g,`/`)===t)}e&&(this._dictionaryKey=n(e))},visitor:{ImportDeclaration(e,t){if(t._isIncluded)for(let n of e.node.specifiers){if(!r.isImportSpecifier(n))continue;let e=r.isIdentifier(n.imported)?n.imported.name:n.imported.value;e===`useIntlayer`&&(t._hasUseIntlayerImport=!0,t._useIntlayerLocalName=n.local.name),e===`getIntlayer`&&(t._hasGetIntlayerImport=!0,t._getIntlayerLocalName=n.local.name)}},JSXElement(e,t){t._isIncluded&&(t._hasJSX=!0)},Program:{enter(e,t){if(!t._isIncluded)return;let n=!1;e.traverse({VariableDeclarator(e){r.isIdentifier(e.node.id)&&e.node.id.name===`content`&&(n=!0)}}),t._contentVarName=n?`_compContent`:`content`},exit(e,n){if(!n._isIncluded||!n._hasJSX)return;let i=[],o=new Set,s=n.opts.shouldExtract??t.shouldExtract;if(e.traverse({JSXText(e){let r=e.node.value;if(s(r)){let a=(0,t.generateKey)(r,n._existingKeys);n._existingKeys.add(a),n._extractedContent[a]=r.replace(/\s+/g,` `).trim(),i.push({path:e,key:a,isAttribute:!1});let s=e.getFunctionParent();s&&o.add(s)}},JSXAttribute(e){let a=e.node.name;if(!r.isJSXIdentifier(a))return;let c=a.name===`key`;if(!t.ATTRIBUTES_TO_EXTRACT.includes(a.name)&&!c)return;let l=e.node.value,u=null;if(r.isStringLiteral(l)?u=l.value:r.isJSXExpressionContainer(l)&&r.isStringLiteral(l.expression)&&(u=l.expression.value),u&&s(u)){let r=(0,t.generateKey)(u,n._existingKeys);n._existingKeys.add(r),n._extractedContent[r]=u.trim(),i.push({path:e,key:r,isAttribute:!0});let a=e.getFunctionParent();a&&o.add(a)}},StringLiteral(e){let a=e.parentPath;if(a.isJSXAttribute()||a.isImportDeclaration()||a.isExportDeclaration()||a.isImportSpecifier()||a.isObjectProperty()&&e.key===`key`)return;if(a.isCallExpression()){let e=a.node.callee;if(r.isMemberExpression(e)&&r.isIdentifier(e.object)&&e.object.name===`console`||r.isIdentifier(e)&&(e.name===n._useIntlayerLocalName||e.name===n._getIntlayerLocalName||e.name===`require`)||e.type===`Import`)return}let c=e.node.value;if(s(c)){let r=(0,t.generateKey)(c,n._existingKeys);n._existingKeys.add(r),n._extractedContent[r]=c.trim(),i.push({path:e,key:r,isAttribute:!1});let a=e.getFunctionParent();a&&o.add(a)}}}),i.length===0)return;for(let{path:e,key:t,isAttribute:a}of i)if(a){let i=r.memberExpression(r.identifier(n._contentVarName),r.identifier(t));e.node.value=r.jsxExpressionContainer(r.memberExpression(i,r.identifier(`value`)))}else e.isJSXText()?e.replaceWith(r.jsxExpressionContainer(r.memberExpression(r.identifier(n._contentVarName),r.identifier(t)))):e.replaceWith(r.memberExpression(r.identifier(n._contentVarName),r.identifier(t)));n.opts.onExtract&&n._dictionaryKey&&n.opts.onExtract({dictionaryKey:n._dictionaryKey,filePath:n.file.opts.filename,content:{...n._extractedContent},locale:n.opts.defaultLocale});let c=!1,l=!1;for(let e of o){let t=a(e,n,r);t===`hook`&&(c=!0),t===`core`&&(l=!0)}if(c||l){let t=n.opts.packageName,i=0,a=e.node.body;for(;i<a.length&&r.isExpressionStatement(a[i])&&r.isStringLiteral(a[i].expression);)i++;c&&!n._hasUseIntlayerImport&&a.splice(i++,0,r.importDeclaration([r.importSpecifier(r.identifier(`useIntlayer`),r.identifier(`useIntlayer`))],r.stringLiteral(t))),l&&!n._hasGetIntlayerImport&&a.splice(i,0,r.importDeclaration([r.importSpecifier(r.identifier(`getIntlayer`),r.identifier(`getIntlayer`))],r.stringLiteral(t)))}}}}}},a=(e,t,n)=>{let i=e.node,a=t._contentVarName,o=t._dictionaryKey;if(!n.isBlockStatement(i.body)){let e=r(i.body,n),s=n.isJSXElement(e)||n.isJSXFragment(e),c=s?t._useIntlayerLocalName:t._getIntlayerLocalName,l=n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(a),n.callExpression(n.identifier(c),[n.stringLiteral(o)]))]);return i.body=n.blockStatement([l,n.returnStatement(i.body)]),s?`hook`:`core`}let s=!1;e.traverse({ReturnStatement(e){if(e.node.argument){let t=r(e.node.argument,n);(n.isJSXElement(t)||n.isJSXFragment(t))&&(s=!0)}}});let c=s?t._useIntlayerLocalName:t._getIntlayerLocalName;return i.body.body.some(e=>n.isVariableDeclaration(e)&&e.declarations.some(e=>n.isIdentifier(e.id)&&e.id.name===a))||i.body.body.unshift(n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(a),n.callExpression(n.identifier(c),[n.stringLiteral(o)]))])),s?`hook`:`core`};exports.intlayerExtractBabelPlugin=i;
|
|
190
2
|
//# sourceMappingURL=babel-plugin-intlayer-extract.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["defaultShouldExtract","ATTRIBUTES_TO_EXTRACT"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar';\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._hasJSX) return;\n\n const extractionTargets: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[] = [];\n const functionsToInject = new Set<NodePath<BabelTypes.Function>>();\n const shouldExtract =\n state.opts.shouldExtract ?? defaultShouldExtract;\n\n // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey)\n return;\n\n const value = path.node.value;\n let text: string | null = null;\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n });\n\n if (extractionTargets.length === 0) return;\n\n // Pass 2: Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(pkg)\n )\n );\n }\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(pkg)\n )\n );\n }\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n return isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\n });\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["defaultShouldExtract","ATTRIBUTES_TO_EXTRACT"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar/cli';\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._hasJSX) return;\n\n const extractionTargets: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[] = [];\n const functionsToInject = new Set<NodePath<BabelTypes.Function>>();\n const shouldExtract =\n state.opts.shouldExtract ?? defaultShouldExtract;\n\n // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey)\n return;\n\n const value = path.node.value;\n let text: string | null = null;\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n });\n\n if (extractionTargets.length === 0) return;\n\n // Pass 2: Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(pkg)\n )\n );\n }\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(pkg)\n )\n );\n }\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n return isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\n });\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
|
|
@@ -1,299 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,
|
|
2
|
-
let node_path = require("node:path");
|
|
3
|
-
let _intlayer_chokidar = require("@intlayer/chokidar");
|
|
4
|
-
let _intlayer_config = require("@intlayer/config");
|
|
5
|
-
|
|
6
|
-
//#region src/babel-plugin-intlayer-optimize.ts
|
|
7
|
-
const PACKAGE_LIST = [
|
|
8
|
-
"intlayer",
|
|
9
|
-
"@intlayer/core",
|
|
10
|
-
"react-intlayer",
|
|
11
|
-
"react-intlayer/client",
|
|
12
|
-
"react-intlayer/server",
|
|
13
|
-
"next-intlayer",
|
|
14
|
-
"next-intlayer/client",
|
|
15
|
-
"next-intlayer/server",
|
|
16
|
-
"svelte-intlayer",
|
|
17
|
-
"vue-intlayer",
|
|
18
|
-
"angular-intlayer",
|
|
19
|
-
"preact-intlayer",
|
|
20
|
-
"solid-intlayer"
|
|
21
|
-
];
|
|
22
|
-
const CALLER_LIST = ["useIntlayer", "getIntlayer"];
|
|
23
|
-
/**
|
|
24
|
-
* Packages that support dynamic import
|
|
25
|
-
*/
|
|
26
|
-
const PACKAGE_LIST_DYNAMIC = [
|
|
27
|
-
"react-intlayer",
|
|
28
|
-
"react-intlayer/client",
|
|
29
|
-
"react-intlayer/server",
|
|
30
|
-
"next-intlayer",
|
|
31
|
-
"next-intlayer/client",
|
|
32
|
-
"next-intlayer/server",
|
|
33
|
-
"preact-intlayer",
|
|
34
|
-
"vue-intlayer",
|
|
35
|
-
"solid-intlayer",
|
|
36
|
-
"svelte-intlayer",
|
|
37
|
-
"angular-intlayer"
|
|
38
|
-
];
|
|
39
|
-
const STATIC_IMPORT_FUNCTION = {
|
|
40
|
-
getIntlayer: "getDictionary",
|
|
41
|
-
useIntlayer: "useDictionary"
|
|
42
|
-
};
|
|
43
|
-
const DYNAMIC_IMPORT_FUNCTION = { useIntlayer: "useDictionaryDynamic" };
|
|
44
|
-
/**
|
|
45
|
-
* Replicates the xxHash64 → Base-62 algorithm used by the SWC version
|
|
46
|
-
* and prefixes an underscore so the generated identifiers never collide
|
|
47
|
-
* with user-defined ones.
|
|
48
|
-
*/
|
|
49
|
-
const makeIdent = (key, t) => {
|
|
50
|
-
const hash = (0, _intlayer_chokidar.getFileHash)(key);
|
|
51
|
-
return t.identifier(`_${hash}`);
|
|
52
|
-
};
|
|
53
|
-
const computeImport = (fromFile, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, importMode) => {
|
|
54
|
-
let relativePath = (0, node_path.join)(dictionariesDir, `${key}.json`);
|
|
55
|
-
if (importMode === "fetch") relativePath = (0, node_path.join)(fetchDictionariesDir, `${key}.mjs`);
|
|
56
|
-
if (importMode === "dynamic") relativePath = (0, node_path.join)(dynamicDictionariesDir, `${key}.mjs`);
|
|
57
|
-
let rel = (0, node_path.relative)((0, node_path.dirname)(fromFile), relativePath);
|
|
58
|
-
rel = (0, _intlayer_config.normalizePath)(rel);
|
|
59
|
-
if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
|
|
60
|
-
return rel;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.
|
|
64
|
-
*
|
|
65
|
-
* This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer
|
|
66
|
-
* packages into optimized dictionary access patterns, automatically importing the required
|
|
67
|
-
* dictionary files based on the configured import mode.
|
|
68
|
-
*
|
|
69
|
-
* ## Supported Input Patterns
|
|
70
|
-
*
|
|
71
|
-
* The plugin recognizes these function calls:
|
|
72
|
-
*
|
|
73
|
-
* ```ts
|
|
74
|
-
* // useIntlayer
|
|
75
|
-
* import { useIntlayer } from 'react-intlayer';
|
|
76
|
-
* import { useIntlayer } from 'next-intlayer';
|
|
77
|
-
*
|
|
78
|
-
* // getIntlayer
|
|
79
|
-
* import { getIntlayer } from 'intlayer';
|
|
80
|
-
*
|
|
81
|
-
* // Usage
|
|
82
|
-
* const content = useIntlayer('app');
|
|
83
|
-
* const content = getIntlayer('app');
|
|
84
|
-
* ```
|
|
85
|
-
*
|
|
86
|
-
* ## Transformation Modes
|
|
87
|
-
*
|
|
88
|
-
* ### Static Mode (default: `importMode = "static"`)
|
|
89
|
-
*
|
|
90
|
-
* Imports JSON dictionaries directly and replaces function calls with dictionary access:
|
|
91
|
-
*
|
|
92
|
-
* **Output:**
|
|
93
|
-
* ```ts
|
|
94
|
-
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
95
|
-
* import { useDictionary as useIntlayer } from 'react-intlayer';
|
|
96
|
-
* import { getDictionary as getIntlayer } from 'intlayer';
|
|
97
|
-
*
|
|
98
|
-
* const content1 = useIntlayer(_dicHash);
|
|
99
|
-
* const content2 = getIntlayer(_dicHash);
|
|
100
|
-
* ```
|
|
101
|
-
*
|
|
102
|
-
* ### Dynamic Mode (`importMode = "dynamic"`)
|
|
103
|
-
*
|
|
104
|
-
* Uses dynamic dictionary loading with Suspense support:
|
|
105
|
-
*
|
|
106
|
-
* **Output:**
|
|
107
|
-
* ```ts
|
|
108
|
-
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
109
|
-
* import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';
|
|
110
|
-
* import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';
|
|
111
|
-
* import { getDictionary as getIntlayer } from 'intlayer';
|
|
112
|
-
*
|
|
113
|
-
* const content1 = useIntlayer(_dicHash_dyn, 'app');
|
|
114
|
-
* const content2 = getIntlayer(_dicHash);
|
|
115
|
-
* ```
|
|
116
|
-
*
|
|
117
|
-
* ### Live Mode (`importMode = "live"`)
|
|
118
|
-
*
|
|
119
|
-
* Uses live-based dictionary loading for remote dictionaries:
|
|
120
|
-
*
|
|
121
|
-
* **Output if `dictionaryModeMap` includes the key with "live" value:**
|
|
122
|
-
* ```ts
|
|
123
|
-
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
124
|
-
* import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';
|
|
125
|
-
* import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';
|
|
126
|
-
* import { getDictionary as getIntlayer } from 'intlayer';
|
|
127
|
-
*
|
|
128
|
-
* const content1 = useIntlayer(_dicHash_fetch, "app");
|
|
129
|
-
* const content2 = getIntlayer(_dicHash);
|
|
130
|
-
* ```
|
|
131
|
-
*
|
|
132
|
-
* > If `dictionaryModeMap` does not include the key with "live" value, the plugin will fallback to the dynamic impor
|
|
133
|
-
*
|
|
134
|
-
* ```ts
|
|
135
|
-
* import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };
|
|
136
|
-
* import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';
|
|
137
|
-
* import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';
|
|
138
|
-
* import { getDictionary as getIntlayer } from 'intlayer';
|
|
139
|
-
*
|
|
140
|
-
* const content1 = useIntlayer(_dicHash_dyn, 'app');
|
|
141
|
-
* const content2 = getIntlayer(_dicHash);
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
const intlayerOptimizeBabelPlugin = (babel) => {
|
|
145
|
-
const { types: t } = babel;
|
|
146
|
-
return {
|
|
147
|
-
name: "babel-plugin-intlayer-transform",
|
|
148
|
-
pre() {
|
|
149
|
-
this._newStaticImports = /* @__PURE__ */ new Map();
|
|
150
|
-
this._newDynamicImports = /* @__PURE__ */ new Map();
|
|
151
|
-
this._isIncluded = true;
|
|
152
|
-
this._hasValidImport = false;
|
|
153
|
-
this._isDictEntry = false;
|
|
154
|
-
this._useDynamicHelpers = false;
|
|
155
|
-
if (this.opts.optimize === false) {
|
|
156
|
-
this._isIncluded = false;
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const filename = this.file.opts.filename;
|
|
160
|
-
if (this.opts.filesList && filename) {
|
|
161
|
-
if (!this.opts.filesList.includes(filename)) {
|
|
162
|
-
this._isIncluded = false;
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
visitor: { Program: {
|
|
168
|
-
enter(programPath, state) {
|
|
169
|
-
const filename = state.file.opts.filename;
|
|
170
|
-
if (state.opts.replaceDictionaryEntry && filename === state.opts.dictionariesEntryPath) {
|
|
171
|
-
state._isDictEntry = true;
|
|
172
|
-
programPath.traverse({
|
|
173
|
-
ImportDeclaration(path) {
|
|
174
|
-
path.remove();
|
|
175
|
-
},
|
|
176
|
-
VariableDeclarator(path) {
|
|
177
|
-
if (t.isObjectExpression(path.node.init)) path.node.init.properties = [];
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
exit(programPath, state) {
|
|
183
|
-
if (state._isDictEntry) return;
|
|
184
|
-
if (!state._isIncluded) return;
|
|
185
|
-
let fileHasDynamicCall = false;
|
|
186
|
-
programPath.traverse({ CallExpression(path) {
|
|
187
|
-
const callee = path.node.callee;
|
|
188
|
-
if (!t.isIdentifier(callee)) return;
|
|
189
|
-
if (callee.name !== "useIntlayer") return;
|
|
190
|
-
const arg = path.node.arguments[0];
|
|
191
|
-
if (!arg || !t.isStringLiteral(arg)) return;
|
|
192
|
-
const key = arg.value;
|
|
193
|
-
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
194
|
-
if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") fileHasDynamicCall = true;
|
|
195
|
-
} });
|
|
196
|
-
programPath.traverse({
|
|
197
|
-
ImportDeclaration(path) {
|
|
198
|
-
const src = path.node.source.value;
|
|
199
|
-
if (!PACKAGE_LIST.includes(src)) return;
|
|
200
|
-
state._hasValidImport = true;
|
|
201
|
-
for (const spec of path.node.specifiers) {
|
|
202
|
-
if (!t.isImportSpecifier(spec)) continue;
|
|
203
|
-
const importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
204
|
-
const importMode = state.opts.importMode;
|
|
205
|
-
const shouldUseDynamicHelpers = (importMode === "dynamic" || importMode === "fetch" || fileHasDynamicCall) && PACKAGE_LIST_DYNAMIC.includes(src);
|
|
206
|
-
if (shouldUseDynamicHelpers) state._useDynamicHelpers = true;
|
|
207
|
-
let helperMap;
|
|
208
|
-
if (shouldUseDynamicHelpers) helperMap = {
|
|
209
|
-
...STATIC_IMPORT_FUNCTION,
|
|
210
|
-
...DYNAMIC_IMPORT_FUNCTION
|
|
211
|
-
};
|
|
212
|
-
else helperMap = STATIC_IMPORT_FUNCTION;
|
|
213
|
-
const newIdentifier = helperMap[importedName];
|
|
214
|
-
if (newIdentifier) spec.imported = t.identifier(newIdentifier);
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
CallExpression(path) {
|
|
218
|
-
const callee = path.node.callee;
|
|
219
|
-
if (!t.isIdentifier(callee)) return;
|
|
220
|
-
if (!CALLER_LIST.includes(callee.name)) return;
|
|
221
|
-
state._hasValidImport = true;
|
|
222
|
-
const arg = path.node.arguments[0];
|
|
223
|
-
if (!arg || !t.isStringLiteral(arg)) return;
|
|
224
|
-
const key = arg.value;
|
|
225
|
-
const importMode = state.opts.importMode;
|
|
226
|
-
const isUseIntlayer = callee.name === "useIntlayer";
|
|
227
|
-
const useDynamicHelpers = Boolean(state._useDynamicHelpers);
|
|
228
|
-
let perCallMode = "static";
|
|
229
|
-
const dictionaryOverrideMode = state.opts.dictionaryModeMap?.[key];
|
|
230
|
-
if (isUseIntlayer && useDynamicHelpers) {
|
|
231
|
-
if (dictionaryOverrideMode) perCallMode = dictionaryOverrideMode;
|
|
232
|
-
else if (importMode === "dynamic") perCallMode = "dynamic";
|
|
233
|
-
else if (importMode === "fetch") perCallMode = "fetch";
|
|
234
|
-
} else if (isUseIntlayer && !useDynamicHelpers) {
|
|
235
|
-
if (dictionaryOverrideMode === "dynamic" || dictionaryOverrideMode === "fetch") perCallMode = dictionaryOverrideMode;
|
|
236
|
-
}
|
|
237
|
-
let ident;
|
|
238
|
-
if (perCallMode === "fetch") {
|
|
239
|
-
let dynamicIdent = state._newDynamicImports?.get(key);
|
|
240
|
-
if (!dynamicIdent) {
|
|
241
|
-
const hash = (0, _intlayer_chokidar.getFileHash)(key);
|
|
242
|
-
dynamicIdent = t.identifier(`_${hash}_fetch`);
|
|
243
|
-
state._newDynamicImports?.set(key, dynamicIdent);
|
|
244
|
-
}
|
|
245
|
-
ident = dynamicIdent;
|
|
246
|
-
path.node.arguments = [t.identifier(ident.name), ...path.node.arguments];
|
|
247
|
-
} else if (perCallMode === "dynamic") {
|
|
248
|
-
let dynamicIdent = state._newDynamicImports?.get(key);
|
|
249
|
-
if (!dynamicIdent) {
|
|
250
|
-
const hash = (0, _intlayer_chokidar.getFileHash)(key);
|
|
251
|
-
dynamicIdent = t.identifier(`_${hash}_dyn`);
|
|
252
|
-
state._newDynamicImports?.set(key, dynamicIdent);
|
|
253
|
-
}
|
|
254
|
-
ident = dynamicIdent;
|
|
255
|
-
path.node.arguments = [t.identifier(ident.name), ...path.node.arguments];
|
|
256
|
-
} else {
|
|
257
|
-
let staticIdent = state._newStaticImports?.get(key);
|
|
258
|
-
if (!staticIdent) {
|
|
259
|
-
staticIdent = makeIdent(key, t);
|
|
260
|
-
state._newStaticImports?.set(key, staticIdent);
|
|
261
|
-
}
|
|
262
|
-
ident = staticIdent;
|
|
263
|
-
path.node.arguments[0] = t.identifier(ident.name);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
if (!state._hasValidImport) return;
|
|
268
|
-
const file = state.file.opts.filename;
|
|
269
|
-
const dictionariesDir = state.opts.dictionariesDir;
|
|
270
|
-
const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;
|
|
271
|
-
const fetchDictionariesDir = state.opts.fetchDictionariesDir;
|
|
272
|
-
const imports = [];
|
|
273
|
-
for (const [key, ident] of state._newStaticImports) {
|
|
274
|
-
const rel = computeImport(file, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, "static");
|
|
275
|
-
const importDeclarationNode = t.importDeclaration([t.importDefaultSpecifier(t.identifier(ident.name))], t.stringLiteral(rel));
|
|
276
|
-
importDeclarationNode.attributes = [t.importAttribute(t.identifier("type"), t.stringLiteral("json"))];
|
|
277
|
-
imports.push(importDeclarationNode);
|
|
278
|
-
}
|
|
279
|
-
for (const [key, ident] of state._newDynamicImports) {
|
|
280
|
-
const rel = computeImport(file, dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, key, ident.name.endsWith("_fetch") ? "fetch" : "dynamic");
|
|
281
|
-
imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(ident.name))], t.stringLiteral(rel)));
|
|
282
|
-
}
|
|
283
|
-
if (!imports.length) return;
|
|
284
|
-
const bodyPaths = programPath.get("body");
|
|
285
|
-
let insertPos = 0;
|
|
286
|
-
for (const stmtPath of bodyPaths) {
|
|
287
|
-
const stmt = stmtPath.node;
|
|
288
|
-
if (t.isExpressionStatement(stmt) && t.isStringLiteral(stmt.expression) && !stmt.expression.value.startsWith("import") && !stmt.expression.value.startsWith("require")) insertPos += 1;
|
|
289
|
-
else break;
|
|
290
|
-
}
|
|
291
|
-
programPath.node.body.splice(insertPos, 0, ...imports);
|
|
292
|
-
}
|
|
293
|
-
} }
|
|
294
|
-
};
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
//#endregion
|
|
298
|
-
exports.intlayerOptimizeBabelPlugin = intlayerOptimizeBabelPlugin;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:path`),t=require(`@intlayer/chokidar/utils`),n=require(`@intlayer/config/utils`);const r=[`intlayer`,`@intlayer/core`,`react-intlayer`,`react-intlayer/client`,`react-intlayer/server`,`next-intlayer`,`next-intlayer/client`,`next-intlayer/server`,`svelte-intlayer`,`vue-intlayer`,`angular-intlayer`,`preact-intlayer`,`solid-intlayer`],i=[`useIntlayer`,`getIntlayer`],a=[`react-intlayer`,`react-intlayer/client`,`react-intlayer/server`,`next-intlayer`,`next-intlayer/client`,`next-intlayer/server`,`preact-intlayer`,`vue-intlayer`,`solid-intlayer`,`svelte-intlayer`,`angular-intlayer`],o={getIntlayer:`getDictionary`,useIntlayer:`useDictionary`},s={useIntlayer:`useDictionaryDynamic`},c=(e,n)=>{let r=(0,t.getFileHash)(e);return n.identifier(`_${r}`)},l=(t,r,i,a,o,s)=>{let c=(0,e.join)(r,`${o}.json`);s===`fetch`&&(c=(0,e.join)(a,`${o}.mjs`)),s===`dynamic`&&(c=(0,e.join)(i,`${o}.mjs`));let l=(0,e.relative)((0,e.dirname)(t),c);return l=(0,n.normalizePath)(l),!l.startsWith(`./`)&&!l.startsWith(`../`)&&(l=`./${l}`),l},u=e=>{let{types:n}=e;return{name:`babel-plugin-intlayer-transform`,pre(){if(this._newStaticImports=new Map,this._newDynamicImports=new Map,this._isIncluded=!0,this._hasValidImport=!1,this._isDictEntry=!1,this._useDynamicHelpers=!1,this.opts.optimize===!1){this._isIncluded=!1;return}let e=this.file.opts.filename;if(this.opts.filesList&&e&&!this.opts.filesList.includes(e)){this._isIncluded=!1;return}},visitor:{Program:{enter(e,t){let r=t.file.opts.filename;t.opts.replaceDictionaryEntry&&r===t.opts.dictionariesEntryPath&&(t._isDictEntry=!0,e.traverse({ImportDeclaration(e){e.remove()},VariableDeclarator(e){n.isObjectExpression(e.node.init)&&(e.node.init.properties=[])}}))},exit(e,u){if(u._isDictEntry||!u._isIncluded)return;let d=!1;if(e.traverse({CallExpression(e){let t=e.node.callee;if(!n.isIdentifier(t)||t.name!==`useIntlayer`)return;let r=e.node.arguments[0];if(!r||!n.isStringLiteral(r))return;let i=r.value,a=u.opts.dictionaryModeMap?.[i];(a===`dynamic`||a===`fetch`)&&(d=!0)}}),e.traverse({ImportDeclaration(e){let t=e.node.source.value;if(r.includes(t)){u._hasValidImport=!0;for(let r of e.node.specifiers){if(!n.isImportSpecifier(r))continue;let e=n.isIdentifier(r.imported)?r.imported.name:r.imported.value,i=u.opts.importMode,c=(i===`dynamic`||i===`fetch`||d)&&a.includes(t);c&&(u._useDynamicHelpers=!0);let l;l=c?{...o,...s}:o;let f=l[e];f&&(r.imported=n.identifier(f))}}},CallExpression(e){let r=e.node.callee;if(!n.isIdentifier(r)||!i.includes(r.name))return;u._hasValidImport=!0;let a=e.node.arguments[0];if(!a||!n.isStringLiteral(a))return;let o=a.value,s=u.opts.importMode,l=r.name===`useIntlayer`,d=!!u._useDynamicHelpers,f=`static`,p=u.opts.dictionaryModeMap?.[o];l&&d?p?f=p:s===`dynamic`?f=`dynamic`:s===`fetch`&&(f=`fetch`):l&&!d&&(p===`dynamic`||p===`fetch`)&&(f=p);let m;if(f===`fetch`){let r=u._newDynamicImports?.get(o);if(!r){let e=(0,t.getFileHash)(o);r=n.identifier(`_${e}_fetch`),u._newDynamicImports?.set(o,r)}m=r,e.node.arguments=[n.identifier(m.name),...e.node.arguments]}else if(f===`dynamic`){let r=u._newDynamicImports?.get(o);if(!r){let e=(0,t.getFileHash)(o);r=n.identifier(`_${e}_dyn`),u._newDynamicImports?.set(o,r)}m=r,e.node.arguments=[n.identifier(m.name),...e.node.arguments]}else{let t=u._newStaticImports?.get(o);t||(t=c(o,n),u._newStaticImports?.set(o,t)),m=t,e.node.arguments[0]=n.identifier(m.name)}}}),!u._hasValidImport)return;let f=u.file.opts.filename,p=u.opts.dictionariesDir,m=u.opts.dynamicDictionariesDir,h=u.opts.fetchDictionariesDir,g=[];for(let[e,t]of u._newStaticImports){let r=l(f,p,m,h,e,`static`),i=n.importDeclaration([n.importDefaultSpecifier(n.identifier(t.name))],n.stringLiteral(r));i.attributes=[n.importAttribute(n.identifier(`type`),n.stringLiteral(`json`))],g.push(i)}for(let[e,t]of u._newDynamicImports){let r=l(f,p,m,h,e,t.name.endsWith(`_fetch`)?`fetch`:`dynamic`);g.push(n.importDeclaration([n.importDefaultSpecifier(n.identifier(t.name))],n.stringLiteral(r)))}if(!g.length)return;let _=e.get(`body`),v=0;for(let e of _){let t=e.node;if(n.isExpressionStatement(t)&&n.isStringLiteral(t.expression)&&!t.expression.value.startsWith(`import`)&&!t.expression.value.startsWith(`require`))v+=1;else break}e.node.body.splice(v,0,...g)}}}}};exports.intlayerOptimizeBabelPlugin=u;
|
|
299
2
|
//# sourceMappingURL=babel-plugin-intlayer-optimize.cjs.map
|