@intlayer/babel 8.4.3 → 8.4.5
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/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +75 -1
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +306 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/extractContent/babelProcessor.cjs +261 -1
- package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
- package/dist/cjs/extractContent/contentWriter.cjs +134 -1
- package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
- package/dist/cjs/extractContent/extractContent.cjs +184 -1
- package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
- package/dist/cjs/extractContent/index.cjs +26 -1
- package/dist/cjs/extractContent/processTsxFile.cjs +263 -5
- package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/constants.cjs +42 -1
- package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/detectPackageName.cjs +26 -1
- package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs +77 -1
- package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs +29 -1
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/generateKey.cjs +16 -1
- package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getComponentName.cjs +18 -1
- package/dist/cjs/extractContent/utils/getComponentName.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs +50 -1
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs +19 -1
- package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/index.cjs +27 -1
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs +34 -1
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
- package/dist/cjs/extractContent/utils/shouldExtract.cjs +23 -1
- package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs +41 -1
- package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
- package/dist/cjs/getOptimizePluginOptions.cjs +63 -1
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +34 -1
- package/dist/esm/_virtual/_rolldown/runtime.mjs +8 -0
- package/dist/esm/babel-plugin-intlayer-extract.mjs +72 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +304 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/extractContent/babelProcessor.mjs +255 -1
- package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
- package/dist/esm/extractContent/contentWriter.mjs +129 -1
- package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
- package/dist/esm/extractContent/extractContent.mjs +180 -1
- package/dist/esm/extractContent/extractContent.mjs.map +1 -1
- package/dist/esm/extractContent/index.mjs +10 -1
- package/dist/esm/extractContent/processTsxFile.mjs +259 -5
- package/dist/esm/extractContent/processTsxFile.mjs.map +1 -1
- package/dist/esm/extractContent/utils/constants.mjs +38 -1
- package/dist/esm/extractContent/utils/constants.mjs.map +1 -1
- package/dist/esm/extractContent/utils/detectPackageName.mjs +24 -1
- package/dist/esm/extractContent/utils/detectPackageName.mjs.map +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs +72 -1
- package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs +26 -1
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/generateKey.mjs +14 -1
- package/dist/esm/extractContent/utils/generateKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getComponentName.mjs +15 -1
- package/dist/esm/extractContent/utils/getComponentName.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs +47 -1
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
- package/dist/esm/extractContent/utils/getOrGenerateKey.mjs +18 -1
- package/dist/esm/extractContent/utils/getOrGenerateKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/index.mjs +12 -1
- package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs +32 -1
- package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs.map +1 -1
- package/dist/esm/extractContent/utils/shouldExtract.mjs +21 -1
- package/dist/esm/extractContent/utils/shouldExtract.mjs.map +1 -1
- package/dist/esm/getExtractPluginOptions.mjs +38 -1
- package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs +63 -1
- package/dist/esm/getOptimizePluginOptions.mjs.map +1 -0
- package/dist/esm/index.mjs +14 -1
- package/dist/types/babel-plugin-intlayer-extract.d.ts +1 -1
- package/dist/types/extractContent/contentWriter.d.ts +36 -2
- package/dist/types/extractContent/contentWriter.d.ts.map +1 -0
- package/dist/types/extractContent/extractContent.d.ts +37 -2
- package/dist/types/extractContent/extractContent.d.ts.map +1 -0
- package/dist/types/extractContent/index.d.ts +8 -8
- package/dist/types/extractContent/processTsxFile.d.ts +1 -1
- package/dist/types/extractContent/processTsxFile.d.ts.map +1 -1
- package/dist/types/extractContent/utils/constants.d.ts +20 -2
- package/dist/types/extractContent/utils/constants.d.ts.map +1 -0
- package/dist/types/extractContent/utils/detectPackageName.d.ts +10 -2
- package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -0
- package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts +28 -2
- package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts.map +1 -0
- package/dist/types/extractContent/utils/extractDictionaryKey.d.ts +11 -2
- package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/generateKey.d.ts +5 -2
- package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getComponentName.d.ts +10 -2
- package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts +19 -2
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getOrGenerateKey.d.ts +8 -2
- package/dist/types/extractContent/utils/getOrGenerateKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/index.d.ts +10 -10
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts +12 -2
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/shouldExtract.d.ts +14 -2
- package/dist/types/extractContent/utils/shouldExtract.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -8
- package/package.json +9 -9
- package/dist/cjs/chunk-Bmb41Sf3.cjs +0 -1
- package/dist/esm/getOptimizePluginOptions-BAFPfVq5.mjs +0 -2
- package/dist/esm/getOptimizePluginOptions-BAFPfVq5.mjs.map +0 -1
- package/dist/types/constants-BLArAqsA.d.ts +0 -20
- package/dist/types/constants-BLArAqsA.d.ts.map +0 -1
- package/dist/types/contentWriter-I2Ch5yQY.d.ts +0 -36
- package/dist/types/contentWriter-I2Ch5yQY.d.ts.map +0 -1
- package/dist/types/detectPackageName-C0TfbHa3.d.ts +0 -10
- package/dist/types/detectPackageName-C0TfbHa3.d.ts.map +0 -1
- package/dist/types/extractContent-AFk68B7L.d.ts +0 -37
- package/dist/types/extractContent-AFk68B7L.d.ts.map +0 -1
- package/dist/types/extractDictionaryInfo-5GLZsA_I.d.ts +0 -28
- package/dist/types/extractDictionaryInfo-5GLZsA_I.d.ts.map +0 -1
- package/dist/types/extractDictionaryKey-CHgfwRo6.d.ts +0 -11
- package/dist/types/extractDictionaryKey-CHgfwRo6.d.ts.map +0 -1
- package/dist/types/generateKey-Cgdh6seq.d.ts +0 -5
- package/dist/types/generateKey-Cgdh6seq.d.ts.map +0 -1
- package/dist/types/getComponentName-DGlmJa-F.d.ts +0 -10
- package/dist/types/getComponentName-DGlmJa-F.d.ts.map +0 -1
- package/dist/types/getExistingIntlayerInfo-Cy6Vpcfb.d.ts +0 -19
- package/dist/types/getExistingIntlayerInfo-Cy6Vpcfb.d.ts.map +0 -1
- package/dist/types/getOrGenerateKey-DtIR0WeU.d.ts +0 -8
- package/dist/types/getOrGenerateKey-DtIR0WeU.d.ts.map +0 -1
- package/dist/types/index-DK_kKFOF.d.ts +0 -1
- package/dist/types/resolveDictionaryKey-CcbieIfX.d.ts +0 -12
- package/dist/types/resolveDictionaryKey-CcbieIfX.d.ts.map +0 -1
- package/dist/types/shouldExtract-BRaeB9eg.d.ts +0 -14
- package/dist/types/shouldExtract-BRaeB9eg.d.ts.map +0 -1
|
@@ -1,2 +1,181 @@
|
|
|
1
|
-
import{extractDictionaryKey
|
|
1
|
+
import { extractDictionaryKey, extractDictionaryKeyFromPath } from "./utils/extractDictionaryKey.mjs";
|
|
2
|
+
import { writeContentHelper } from "./contentWriter.mjs";
|
|
3
|
+
import { ATTRIBUTES_TO_EXTRACT } from "./utils/constants.mjs";
|
|
4
|
+
import { generateKey } from "./utils/generateKey.mjs";
|
|
5
|
+
import { shouldExtract } from "./utils/shouldExtract.mjs";
|
|
6
|
+
import { extractTsContent } from "./babelProcessor.mjs";
|
|
7
|
+
import { processTsxFile } from "./processTsxFile.mjs";
|
|
8
|
+
import * as ANSIColors from "@intlayer/config/colors";
|
|
9
|
+
import { colorize, colorizePath, getAppLogger } from "@intlayer/config/logger";
|
|
10
|
+
import { getConfiguration } from "@intlayer/config/node";
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { extname, relative } from "node:path";
|
|
13
|
+
import { getProjectRequire } from "@intlayer/config/utils";
|
|
14
|
+
import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
|
|
15
|
+
import { detectFormatCommand } from "@intlayer/chokidar/cli";
|
|
16
|
+
import { execSync } from "node:child_process";
|
|
17
|
+
|
|
18
|
+
//#region src/extractContent/extractContent.ts
|
|
19
|
+
let vueCompiler = null;
|
|
20
|
+
let svelteCompiler = null;
|
|
21
|
+
const formatCompilerResult = (componentKey, res) => {
|
|
22
|
+
if (!res) return void 0;
|
|
23
|
+
return {
|
|
24
|
+
extractedContentMap: { [componentKey]: res.extractedContent },
|
|
25
|
+
transformedCode: res.code
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const processFileInternal = (filePath, packageName, options, dependencies, saveComponent, providedComponentKey) => {
|
|
29
|
+
const fileText = options?.code ?? readFileSync(filePath, "utf-8");
|
|
30
|
+
const componentKey = providedComponentKey ?? extractDictionaryKey(filePath, fileText, dependencies.configuration.compiler.dictionaryKeyPrefix);
|
|
31
|
+
const ext = extname(filePath);
|
|
32
|
+
const { vueCompiler, svelteCompiler, unmergedDictionaries, configuration } = dependencies;
|
|
33
|
+
const compilerCommonOptions = {
|
|
34
|
+
generateKey,
|
|
35
|
+
shouldExtract,
|
|
36
|
+
attributesToExtract: ATTRIBUTES_TO_EXTRACT,
|
|
37
|
+
extractDictionaryKeyFromPath,
|
|
38
|
+
extractTsContent: (ast, code, keys, config, path) => extractTsContent(ast, code, keys, config, path, unmergedDictionaries)
|
|
39
|
+
};
|
|
40
|
+
if (ext === ".vue") {
|
|
41
|
+
if (!vueCompiler) throw new Error(`Please install ${colorizePath("@intlayer/vue-compiler", ANSIColors.YELLOW)} to process Vue files.`);
|
|
42
|
+
const res = vueCompiler.processVueFile(filePath, componentKey, packageName, compilerCommonOptions, saveComponent);
|
|
43
|
+
if (res) return formatCompilerResult(componentKey, res);
|
|
44
|
+
}
|
|
45
|
+
if (ext === ".svelte") {
|
|
46
|
+
if (!svelteCompiler) throw new Error(`Please install ${colorizePath("@intlayer/svelte-compiler", ANSIColors.YELLOW)} to process Svelte files.`);
|
|
47
|
+
const res = svelteCompiler.processSvelteFile(filePath, componentKey, packageName, compilerCommonOptions, saveComponent);
|
|
48
|
+
if (res) return formatCompilerResult(componentKey, res);
|
|
49
|
+
}
|
|
50
|
+
if ([
|
|
51
|
+
".tsx",
|
|
52
|
+
".jsx",
|
|
53
|
+
".ts",
|
|
54
|
+
".js",
|
|
55
|
+
".cjs",
|
|
56
|
+
".mjs"
|
|
57
|
+
].includes(ext)) {
|
|
58
|
+
const result = processTsxFile(filePath, componentKey, packageName, configuration, saveComponent, unmergedDictionaries, fileText);
|
|
59
|
+
if (result) return {
|
|
60
|
+
extractedContentMap: result.extractedContent,
|
|
61
|
+
transformedCode: result.modifiedCode
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const handleExtractionSideEffects = async (extractedContentMap, filePath, options, { configuration, baseDir, appLogger }, saveComponent) => {
|
|
66
|
+
if (options?.onExtract) for (const [key, content] of Object.entries(extractedContentMap)) await options.onExtract({
|
|
67
|
+
key,
|
|
68
|
+
content,
|
|
69
|
+
filePath
|
|
70
|
+
});
|
|
71
|
+
if (!options?.codeOnly && !options?.onExtract) for (const [key, content] of Object.entries(extractedContentMap)) {
|
|
72
|
+
const relativeContentFilePath = relative(baseDir, await writeContentHelper(content, key, filePath, configuration));
|
|
73
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Created content file: ${colorizePath(relativeContentFilePath)}`);
|
|
74
|
+
}
|
|
75
|
+
if (saveComponent) {
|
|
76
|
+
const formatCommand = detectFormatCommand(configuration);
|
|
77
|
+
if (formatCommand) try {
|
|
78
|
+
execSync(formatCommand.replace("{{file}}", filePath), {
|
|
79
|
+
stdio: "inherit",
|
|
80
|
+
cwd: baseDir
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(error);
|
|
84
|
+
}
|
|
85
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Updated component: ${colorizePath(relative(baseDir, filePath))}`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const buildContext = (filePath, options) => {
|
|
89
|
+
const configuration = options?.configuration ?? getConfiguration(options?.configOptions);
|
|
90
|
+
const appLogger = getAppLogger(configuration);
|
|
91
|
+
const { baseDir } = configuration.system;
|
|
92
|
+
return {
|
|
93
|
+
configuration,
|
|
94
|
+
appLogger,
|
|
95
|
+
baseDir,
|
|
96
|
+
unmergedDictionaries: options?.unmergedDictionaries ?? getUnmergedDictionaries(configuration),
|
|
97
|
+
saveComponent: !options?.declarationOnly,
|
|
98
|
+
componentExtension: extname(filePath)
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
const extractContent = async (filePath, packageName, options) => {
|
|
102
|
+
const { configuration, appLogger, baseDir, unmergedDictionaries, saveComponent, componentExtension } = buildContext(filePath, options);
|
|
103
|
+
if (componentExtension === ".vue" && !vueCompiler) try {
|
|
104
|
+
vueCompiler = await import("@intlayer/vue-compiler");
|
|
105
|
+
} catch {
|
|
106
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Install ${colorizePath("@intlayer/vue-compiler", ANSIColors.YELLOW)} to process Vue files.`);
|
|
107
|
+
}
|
|
108
|
+
if (componentExtension === ".svelte" && !svelteCompiler) try {
|
|
109
|
+
svelteCompiler = await import("@intlayer/svelte-compiler");
|
|
110
|
+
} catch {
|
|
111
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Install ${colorizePath("@intlayer/svelte-compiler", ANSIColors.YELLOW)} to process Svelte files.`);
|
|
112
|
+
}
|
|
113
|
+
const dictionaryKey = extractDictionaryKey(filePath, options?.code ?? readFileSync(filePath, "utf-8"), configuration.compiler.dictionaryKeyPrefix);
|
|
114
|
+
const result = processFileInternal(filePath, packageName, options, {
|
|
115
|
+
vueCompiler,
|
|
116
|
+
svelteCompiler,
|
|
117
|
+
unmergedDictionaries,
|
|
118
|
+
configuration
|
|
119
|
+
}, saveComponent, dictionaryKey);
|
|
120
|
+
if (!result || !result.extractedContentMap) {
|
|
121
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`, { isVerbose: true });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await handleExtractionSideEffects(result.extractedContentMap, filePath, options, {
|
|
125
|
+
configuration,
|
|
126
|
+
baseDir,
|
|
127
|
+
appLogger
|
|
128
|
+
}, saveComponent);
|
|
129
|
+
return {
|
|
130
|
+
transformedCode: result.transformedCode,
|
|
131
|
+
extractedContentMap: result.extractedContentMap
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Synchronous variant of `extractContent` — used by the Babel plugin which
|
|
136
|
+
* runs in a sync transform context (e.g. Next.js / Webpack).
|
|
137
|
+
*
|
|
138
|
+
* Differences from `extractContent`:
|
|
139
|
+
* - Loads external compilers (Vue, Svelte) via `require()` instead of `import()`
|
|
140
|
+
* - Fires `onExtract` callbacks as fire-and-forget (cannot await in sync context)
|
|
141
|
+
* - Does NOT write dictionary files or run the code formatter; callers that
|
|
142
|
+
* need persistence should supply an `onExtract` callback
|
|
143
|
+
*/
|
|
144
|
+
const extractContentSync = (filePath, packageName, options) => {
|
|
145
|
+
const { configuration, appLogger, baseDir, unmergedDictionaries, saveComponent, componentExtension } = buildContext(filePath, options);
|
|
146
|
+
const requireFn = getProjectRequire();
|
|
147
|
+
if (componentExtension === ".vue" && !vueCompiler) try {
|
|
148
|
+
vueCompiler = requireFn("@intlayer/vue-compiler");
|
|
149
|
+
} catch {
|
|
150
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Install ${colorizePath("@intlayer/vue-compiler", ANSIColors.YELLOW)} to process Vue files.`);
|
|
151
|
+
}
|
|
152
|
+
if (componentExtension === ".svelte" && !svelteCompiler) try {
|
|
153
|
+
svelteCompiler = requireFn("@intlayer/svelte-compiler");
|
|
154
|
+
} catch {
|
|
155
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} Install ${colorizePath("@intlayer/svelte-compiler", ANSIColors.YELLOW)} to process Svelte files.`);
|
|
156
|
+
}
|
|
157
|
+
const result = processFileInternal(filePath, packageName, options, {
|
|
158
|
+
vueCompiler,
|
|
159
|
+
svelteCompiler,
|
|
160
|
+
unmergedDictionaries,
|
|
161
|
+
configuration
|
|
162
|
+
}, saveComponent);
|
|
163
|
+
if (!result?.extractedContentMap) {
|
|
164
|
+
appLogger(`${colorize("Compiler:", ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`, { isVerbose: true });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const { extractedContentMap, transformedCode } = result;
|
|
168
|
+
if (options?.onExtract) for (const [key, content] of Object.entries(extractedContentMap)) options.onExtract({
|
|
169
|
+
key,
|
|
170
|
+
content,
|
|
171
|
+
filePath
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
transformedCode,
|
|
175
|
+
extractedContentMap
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
export { extractContent, extractContentSync };
|
|
2
181
|
//# sourceMappingURL=extractContent.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractContent.mjs","names":[],"sources":["../../../src/extractContent/extractContent.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { extname, relative } from 'node:path';\nimport type * as t from '@babel/types';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractTsContent } from './babelProcessor';\nimport { writeContentHelper } from './contentWriter';\nimport { processTsxFile } from './processTsxFile';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n type PackageName,\n shouldExtract,\n} from './utils';\nimport { extractDictionaryKey } from './utils/extractDictionaryKey';\nimport { generateKey } from './utils/generateKey';\n\nexport type ExtractIntlayerOptions = {\n configOptions?: GetConfigurationOptions;\n codeOnly?: boolean;\n declarationOnly?: boolean;\n unmergedDictionaries?: Record<string, unknown>;\n configuration?: IntlayerConfig;\n code?: string;\n onExtract?: (result: {\n key: string;\n content: Record<string, string>;\n filePath: string;\n }) => void | Promise<void>;\n};\n\ntype ExternalCompilerResult = {\n extractedContent: Record<string, string>;\n code: string;\n};\n\ntype ExternalCompilerOptions = {\n generateKey: typeof generateKey;\n shouldExtract: typeof shouldExtract;\n attributesToExtract: typeof ATTRIBUTES_TO_EXTRACT;\n extractDictionaryKeyFromPath: typeof extractDictionaryKeyFromPath;\n extractTsContent: (\n ast: unknown,\n code: string,\n keys: Set<string>,\n config: IntlayerConfig,\n path: string\n ) => ReturnType<typeof extractTsContent>;\n};\n\ntype VueCompiler = typeof import('@intlayer/vue-compiler');\ntype SvelteCompiler = typeof import('@intlayer/svelte-compiler');\n\n// Module caches\nlet vueCompiler: VueCompiler | null = null;\nlet svelteCompiler: SvelteCompiler | null = null;\n\ntype InternalExtractResult = {\n extractedContentMap: Record<string, Record<string, string>> | null;\n transformedCode: string | null;\n};\n\nconst formatCompilerResult = (\n componentKey: string,\n res?: ExternalCompilerResult\n): InternalExtractResult | undefined => {\n if (!res) return undefined;\n\n return {\n extractedContentMap: { [componentKey]: res.extractedContent },\n transformedCode: res.code,\n };\n};\n\ntype Dependencies = {\n vueCompiler: VueCompiler | null;\n svelteCompiler: SvelteCompiler | null;\n unmergedDictionaries: Record<string, unknown>;\n configuration: IntlayerConfig;\n};\n\nconst processFileInternal = (\n filePath: string,\n packageName: PackageName,\n options: ExtractIntlayerOptions | undefined,\n dependencies: Dependencies,\n saveComponent: boolean,\n providedComponentKey?: string\n): InternalExtractResult | undefined => {\n const fileText = options?.code ?? readFileSync(filePath, 'utf-8');\n const componentKey =\n providedComponentKey ??\n extractDictionaryKey(\n filePath,\n fileText,\n dependencies.configuration.compiler.dictionaryKeyPrefix\n );\n const ext = extname(filePath);\n\n const { vueCompiler, svelteCompiler, unmergedDictionaries, configuration } =\n dependencies;\n\n const compilerCommonOptions: ExternalCompilerOptions = {\n generateKey,\n shouldExtract,\n attributesToExtract: ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n extractTsContent: (ast, code, keys, config, path) =>\n extractTsContent(\n ast as t.File,\n code,\n keys,\n config,\n path,\n unmergedDictionaries\n ),\n };\n\n if (ext === '.vue') {\n if (!vueCompiler) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n\n const res = vueCompiler.processVueFile(\n filePath,\n componentKey,\n packageName,\n compilerCommonOptions,\n saveComponent\n );\n\n if (res) {\n return formatCompilerResult(componentKey, res);\n }\n }\n\n if (ext === '.svelte') {\n if (!svelteCompiler) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n\n const res = svelteCompiler.processSvelteFile(\n filePath,\n componentKey,\n packageName,\n compilerCommonOptions,\n saveComponent\n );\n\n if (res) {\n return formatCompilerResult(componentKey, res);\n }\n }\n\n if (['.tsx', '.jsx', '.ts', '.js', '.cjs', '.mjs'].includes(ext)) {\n const result = processTsxFile(\n filePath,\n componentKey,\n packageName,\n configuration,\n saveComponent,\n unmergedDictionaries,\n fileText\n );\n\n if (result) {\n return {\n extractedContentMap: result.extractedContent,\n transformedCode: result.modifiedCode,\n };\n }\n }\n\n return undefined;\n};\n\nconst handleExtractionSideEffects = async (\n extractedContentMap: Record<string, Record<string, string>>,\n filePath: string,\n options: ExtractIntlayerOptions | undefined,\n {\n configuration,\n baseDir,\n appLogger,\n }: {\n configuration: IntlayerConfig;\n baseDir: string;\n appLogger: ReturnType<typeof getAppLogger>;\n },\n saveComponent: boolean\n) => {\n if (options?.onExtract) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n await options.onExtract({ key, content, filePath });\n }\n }\n\n const writeContent = !options?.codeOnly && !options?.onExtract;\n\n if (writeContent) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n const contentFilePath = await writeContentHelper(\n content,\n key,\n filePath,\n configuration\n );\n\n const relativeContentFilePath = relative(baseDir, contentFilePath);\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Created content file: ${colorizePath(relativeContentFilePath)}`\n );\n }\n }\n\n if (saveComponent) {\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'inherit',\n cwd: baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\ntype ExtractResult = {\n transformedCode: string | null;\n extractedContentMap: Record<string, Record<string, string>>;\n};\n\ntype ExtractContext = {\n configuration: IntlayerConfig;\n appLogger: ReturnType<typeof getAppLogger>;\n baseDir: string;\n unmergedDictionaries: Record<string, unknown>;\n saveComponent: boolean;\n componentExtension: string;\n};\n\nconst buildContext = (\n filePath: string,\n options: ExtractIntlayerOptions | undefined\n): ExtractContext => {\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n const { baseDir } = configuration.system;\n const unmergedDictionaries =\n options?.unmergedDictionaries ?? getUnmergedDictionaries(configuration);\n const saveComponent = !options?.declarationOnly;\n const componentExtension = extname(filePath);\n\n return {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n };\n};\n\nexport const extractContent = async (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n): Promise<ExtractResult | undefined> => {\n const {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n } = buildContext(filePath, options);\n\n if (componentExtension === '.vue' && !vueCompiler) {\n try {\n vueCompiler = await import('@intlayer/vue-compiler');\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n }\n\n if (componentExtension === '.svelte' && !svelteCompiler) {\n try {\n svelteCompiler = await import('@intlayer/svelte-compiler');\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n }\n\n const fileText = options?.code ?? readFileSync(filePath, 'utf-8');\n const dictionaryKey = extractDictionaryKey(\n filePath,\n fileText,\n configuration.compiler.dictionaryKeyPrefix\n );\n\n const result = processFileInternal(\n filePath,\n packageName,\n options,\n { vueCompiler, svelteCompiler, unmergedDictionaries, configuration },\n saveComponent,\n dictionaryKey\n );\n\n if (!result || !result.extractedContentMap) {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`,\n { isVerbose: true }\n );\n return undefined;\n }\n\n await handleExtractionSideEffects(\n result.extractedContentMap,\n filePath,\n options,\n { configuration, baseDir, appLogger },\n saveComponent\n );\n\n return {\n transformedCode: result.transformedCode,\n extractedContentMap: result.extractedContentMap,\n };\n};\n\n/**\n * Synchronous variant of `extractContent` — used by the Babel plugin which\n * runs in a sync transform context (e.g. Next.js / Webpack).\n *\n * Differences from `extractContent`:\n * - Loads external compilers (Vue, Svelte) via `require()` instead of `import()`\n * - Fires `onExtract` callbacks as fire-and-forget (cannot await in sync context)\n * - Does NOT write dictionary files or run the code formatter; callers that\n * need persistence should supply an `onExtract` callback\n */\nexport const extractContentSync = (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n): ExtractResult | undefined => {\n const {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n } = buildContext(filePath, options);\n\n const requireFn = getProjectRequire();\n\n if (componentExtension === '.vue' && !vueCompiler) {\n try {\n vueCompiler = requireFn('@intlayer/vue-compiler') as VueCompiler;\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n }\n\n if (componentExtension === '.svelte' && !svelteCompiler) {\n try {\n svelteCompiler = requireFn('@intlayer/svelte-compiler') as SvelteCompiler;\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n }\n\n const result = processFileInternal(\n filePath,\n packageName,\n options,\n { vueCompiler, svelteCompiler, unmergedDictionaries, configuration },\n saveComponent\n );\n\n if (!result?.extractedContentMap) {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`,\n { isVerbose: true }\n );\n return undefined;\n }\n\n const { extractedContentMap, transformedCode } = result;\n\n if (options?.onExtract) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n void options.onExtract({ key, content, filePath });\n }\n }\n\n return { transformedCode, extractedContentMap };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extractContent.mjs","names":[],"sources":["../../../src/extractContent/extractContent.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { extname, relative } from 'node:path';\nimport type * as t from '@babel/types';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractTsContent } from './babelProcessor';\nimport { writeContentHelper } from './contentWriter';\nimport { processTsxFile } from './processTsxFile';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n type PackageName,\n shouldExtract,\n} from './utils';\nimport { extractDictionaryKey } from './utils/extractDictionaryKey';\nimport { generateKey } from './utils/generateKey';\n\nexport type ExtractIntlayerOptions = {\n configOptions?: GetConfigurationOptions;\n codeOnly?: boolean;\n declarationOnly?: boolean;\n unmergedDictionaries?: Record<string, unknown>;\n configuration?: IntlayerConfig;\n code?: string;\n onExtract?: (result: {\n key: string;\n content: Record<string, string>;\n filePath: string;\n }) => void | Promise<void>;\n};\n\ntype ExternalCompilerResult = {\n extractedContent: Record<string, string>;\n code: string;\n};\n\ntype ExternalCompilerOptions = {\n generateKey: typeof generateKey;\n shouldExtract: typeof shouldExtract;\n attributesToExtract: typeof ATTRIBUTES_TO_EXTRACT;\n extractDictionaryKeyFromPath: typeof extractDictionaryKeyFromPath;\n extractTsContent: (\n ast: unknown,\n code: string,\n keys: Set<string>,\n config: IntlayerConfig,\n path: string\n ) => ReturnType<typeof extractTsContent>;\n};\n\ntype VueCompiler = typeof import('@intlayer/vue-compiler');\ntype SvelteCompiler = typeof import('@intlayer/svelte-compiler');\n\n// Module caches\nlet vueCompiler: VueCompiler | null = null;\nlet svelteCompiler: SvelteCompiler | null = null;\n\ntype InternalExtractResult = {\n extractedContentMap: Record<string, Record<string, string>> | null;\n transformedCode: string | null;\n};\n\nconst formatCompilerResult = (\n componentKey: string,\n res?: ExternalCompilerResult\n): InternalExtractResult | undefined => {\n if (!res) return undefined;\n\n return {\n extractedContentMap: { [componentKey]: res.extractedContent },\n transformedCode: res.code,\n };\n};\n\ntype Dependencies = {\n vueCompiler: VueCompiler | null;\n svelteCompiler: SvelteCompiler | null;\n unmergedDictionaries: Record<string, unknown>;\n configuration: IntlayerConfig;\n};\n\nconst processFileInternal = (\n filePath: string,\n packageName: PackageName,\n options: ExtractIntlayerOptions | undefined,\n dependencies: Dependencies,\n saveComponent: boolean,\n providedComponentKey?: string\n): InternalExtractResult | undefined => {\n const fileText = options?.code ?? readFileSync(filePath, 'utf-8');\n const componentKey =\n providedComponentKey ??\n extractDictionaryKey(\n filePath,\n fileText,\n dependencies.configuration.compiler.dictionaryKeyPrefix\n );\n const ext = extname(filePath);\n\n const { vueCompiler, svelteCompiler, unmergedDictionaries, configuration } =\n dependencies;\n\n const compilerCommonOptions: ExternalCompilerOptions = {\n generateKey,\n shouldExtract,\n attributesToExtract: ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n extractTsContent: (ast, code, keys, config, path) =>\n extractTsContent(\n ast as t.File,\n code,\n keys,\n config,\n path,\n unmergedDictionaries\n ),\n };\n\n if (ext === '.vue') {\n if (!vueCompiler) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n\n const res = vueCompiler.processVueFile(\n filePath,\n componentKey,\n packageName,\n compilerCommonOptions,\n saveComponent\n );\n\n if (res) {\n return formatCompilerResult(componentKey, res);\n }\n }\n\n if (ext === '.svelte') {\n if (!svelteCompiler) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n\n const res = svelteCompiler.processSvelteFile(\n filePath,\n componentKey,\n packageName,\n compilerCommonOptions,\n saveComponent\n );\n\n if (res) {\n return formatCompilerResult(componentKey, res);\n }\n }\n\n if (['.tsx', '.jsx', '.ts', '.js', '.cjs', '.mjs'].includes(ext)) {\n const result = processTsxFile(\n filePath,\n componentKey,\n packageName,\n configuration,\n saveComponent,\n unmergedDictionaries,\n fileText\n );\n\n if (result) {\n return {\n extractedContentMap: result.extractedContent,\n transformedCode: result.modifiedCode,\n };\n }\n }\n\n return undefined;\n};\n\nconst handleExtractionSideEffects = async (\n extractedContentMap: Record<string, Record<string, string>>,\n filePath: string,\n options: ExtractIntlayerOptions | undefined,\n {\n configuration,\n baseDir,\n appLogger,\n }: {\n configuration: IntlayerConfig;\n baseDir: string;\n appLogger: ReturnType<typeof getAppLogger>;\n },\n saveComponent: boolean\n) => {\n if (options?.onExtract) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n await options.onExtract({ key, content, filePath });\n }\n }\n\n const writeContent = !options?.codeOnly && !options?.onExtract;\n\n if (writeContent) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n const contentFilePath = await writeContentHelper(\n content,\n key,\n filePath,\n configuration\n );\n\n const relativeContentFilePath = relative(baseDir, contentFilePath);\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Created content file: ${colorizePath(relativeContentFilePath)}`\n );\n }\n }\n\n if (saveComponent) {\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'inherit',\n cwd: baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n};\n\ntype ExtractResult = {\n transformedCode: string | null;\n extractedContentMap: Record<string, Record<string, string>>;\n};\n\ntype ExtractContext = {\n configuration: IntlayerConfig;\n appLogger: ReturnType<typeof getAppLogger>;\n baseDir: string;\n unmergedDictionaries: Record<string, unknown>;\n saveComponent: boolean;\n componentExtension: string;\n};\n\nconst buildContext = (\n filePath: string,\n options: ExtractIntlayerOptions | undefined\n): ExtractContext => {\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n const { baseDir } = configuration.system;\n const unmergedDictionaries =\n options?.unmergedDictionaries ?? getUnmergedDictionaries(configuration);\n const saveComponent = !options?.declarationOnly;\n const componentExtension = extname(filePath);\n\n return {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n };\n};\n\nexport const extractContent = async (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n): Promise<ExtractResult | undefined> => {\n const {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n } = buildContext(filePath, options);\n\n if (componentExtension === '.vue' && !vueCompiler) {\n try {\n vueCompiler = await import('@intlayer/vue-compiler');\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n }\n\n if (componentExtension === '.svelte' && !svelteCompiler) {\n try {\n svelteCompiler = await import('@intlayer/svelte-compiler');\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n }\n\n const fileText = options?.code ?? readFileSync(filePath, 'utf-8');\n const dictionaryKey = extractDictionaryKey(\n filePath,\n fileText,\n configuration.compiler.dictionaryKeyPrefix\n );\n\n const result = processFileInternal(\n filePath,\n packageName,\n options,\n { vueCompiler, svelteCompiler, unmergedDictionaries, configuration },\n saveComponent,\n dictionaryKey\n );\n\n if (!result || !result.extractedContentMap) {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`,\n { isVerbose: true }\n );\n return undefined;\n }\n\n await handleExtractionSideEffects(\n result.extractedContentMap,\n filePath,\n options,\n { configuration, baseDir, appLogger },\n saveComponent\n );\n\n return {\n transformedCode: result.transformedCode,\n extractedContentMap: result.extractedContentMap,\n };\n};\n\n/**\n * Synchronous variant of `extractContent` — used by the Babel plugin which\n * runs in a sync transform context (e.g. Next.js / Webpack).\n *\n * Differences from `extractContent`:\n * - Loads external compilers (Vue, Svelte) via `require()` instead of `import()`\n * - Fires `onExtract` callbacks as fire-and-forget (cannot await in sync context)\n * - Does NOT write dictionary files or run the code formatter; callers that\n * need persistence should supply an `onExtract` callback\n */\nexport const extractContentSync = (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n): ExtractResult | undefined => {\n const {\n configuration,\n appLogger,\n baseDir,\n unmergedDictionaries,\n saveComponent,\n componentExtension,\n } = buildContext(filePath, options);\n\n const requireFn = getProjectRequire();\n\n if (componentExtension === '.vue' && !vueCompiler) {\n try {\n vueCompiler = requireFn('@intlayer/vue-compiler') as VueCompiler;\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n }\n\n if (componentExtension === '.svelte' && !svelteCompiler) {\n try {\n svelteCompiler = requireFn('@intlayer/svelte-compiler') as SvelteCompiler;\n } catch {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n }\n\n const result = processFileInternal(\n filePath,\n packageName,\n options,\n { vueCompiler, svelteCompiler, unmergedDictionaries, configuration },\n saveComponent\n );\n\n if (!result?.extractedContentMap) {\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relative(baseDir, filePath))}`,\n { isVerbose: true }\n );\n return undefined;\n }\n\n const { extractedContentMap, transformedCode } = result;\n\n if (options?.onExtract) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n void options.onExtract({ key, content, filePath });\n }\n }\n\n return { transformedCode, extractedContentMap };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { extractDictionaryKey, extractDictionaryKeyFromPath } from "./utils/extractDictionaryKey.mjs";
|
|
2
|
+
import { extractDictionaryInfo, getOutput, resolveContentFilePaths } from "./utils/extractDictionaryInfo.mjs";
|
|
3
|
+
import { mergeWithExistingMultilingualDictionary, mergeWithExistingPerLocaleDictionary, writeContentHelper } from "./contentWriter.mjs";
|
|
4
|
+
import { ATTRIBUTES_TO_EXTRACT, SERVER_CAPABLE_PACKAGES, packageList } from "./utils/constants.mjs";
|
|
5
|
+
import { detectPackageName } from "./utils/detectPackageName.mjs";
|
|
6
|
+
import { generateKey } from "./utils/generateKey.mjs";
|
|
7
|
+
import { getComponentName } from "./utils/getComponentName.mjs";
|
|
8
|
+
import { extractContent, extractContentSync } from "./extractContent.mjs";
|
|
9
|
+
|
|
10
|
+
export { ATTRIBUTES_TO_EXTRACT, SERVER_CAPABLE_PACKAGES, detectPackageName, extractContent, extractContentSync, extractDictionaryInfo, extractDictionaryKey, extractDictionaryKeyFromPath, generateKey, getComponentName, getOutput, mergeWithExistingMultilingualDictionary, mergeWithExistingPerLocaleDictionary, packageList, resolveContentFilePaths, writeContentHelper };
|
|
@@ -1,6 +1,260 @@
|
|
|
1
|
-
import{SERVER_CAPABLE_PACKAGES
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { SERVER_CAPABLE_PACKAGES } from "./utils/constants.mjs";
|
|
2
|
+
import { getExistingIntlayerInfo } from "./utils/getExistingIntlayerInfo.mjs";
|
|
3
|
+
import { extractBabelContentForComponents } from "./babelProcessor.mjs";
|
|
4
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { detectFormatCommand } from "@intlayer/chokidar/cli";
|
|
6
|
+
import { parse } from "@babel/parser";
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
import _traverse from "@babel/traverse";
|
|
9
|
+
import * as t from "@babel/types";
|
|
10
|
+
|
|
11
|
+
//#region src/extractContent/processTsxFile.ts
|
|
12
|
+
const traverse = typeof _traverse === "function" ? _traverse : _traverse.default;
|
|
13
|
+
/**
|
|
14
|
+
* Processes a TSX/JSX/TS/JS file to extract content and inject Intlayer hooks/calls.
|
|
15
|
+
*/
|
|
16
|
+
const processTsxFile = (filePath, componentKey, packageName, configuration, save = true, unmergedDictionaries = {}, providedFileCode) => {
|
|
17
|
+
const fileCode = providedFileCode ?? readFileSync(filePath, "utf-8");
|
|
18
|
+
const ast = parse(fileCode, {
|
|
19
|
+
sourceType: "module",
|
|
20
|
+
plugins: ["jsx", "typescript"]
|
|
21
|
+
});
|
|
22
|
+
const hasUseClient = ast.program.directives.some((directive) => directive.value.value === "use client");
|
|
23
|
+
const effectivePackageName = SERVER_CAPABLE_PACKAGES.has(packageName) && !hasUseClient ? `${packageName}/server` : packageName;
|
|
24
|
+
const isSolid = packageName === "solid-intlayer";
|
|
25
|
+
const { extractedContent, replacements, componentsNeedingHooks, componentKeyMap, componentPaths, hookMap } = extractBabelContentForComponents(ast, fileCode, /* @__PURE__ */ new Set(), componentKey, configuration, filePath, unmergedDictionaries);
|
|
26
|
+
if (Object.keys(extractedContent).length === 0) return null;
|
|
27
|
+
const textEdits = [];
|
|
28
|
+
const componentNodeToPath = /* @__PURE__ */ new Map();
|
|
29
|
+
for (const componentPath of componentPaths) componentNodeToPath.set(componentPath.node, componentPath);
|
|
30
|
+
const existingInfoCache = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const componentPath of componentPaths) existingInfoCache.set(componentPath.node, getExistingIntlayerInfo(componentPath));
|
|
32
|
+
/**
|
|
33
|
+
* Walks up the ancestor chain to find the nearest enclosing component's
|
|
34
|
+
* existing Intlayer info (if any).
|
|
35
|
+
*/
|
|
36
|
+
const getExistingInfoForPath = (path) => {
|
|
37
|
+
let current = path;
|
|
38
|
+
while (current) {
|
|
39
|
+
if (componentNodeToPath.has(current.node)) return existingInfoCache.get(current.node);
|
|
40
|
+
current = current.parentPath;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const getProvidingHookType = (path) => {
|
|
44
|
+
let current = path;
|
|
45
|
+
while (current) {
|
|
46
|
+
const componentPath = componentNodeToPath.get(current.node);
|
|
47
|
+
if (componentPath) {
|
|
48
|
+
const existingInfo = existingInfoCache.get(componentPath.node);
|
|
49
|
+
if (existingInfo) return existingInfo.hook;
|
|
50
|
+
if (componentsNeedingHooks.has(componentPath)) return hookMap.get(componentPath.node) || "useIntlayer";
|
|
51
|
+
}
|
|
52
|
+
current = current.parentPath;
|
|
53
|
+
}
|
|
54
|
+
return "useIntlayer";
|
|
55
|
+
};
|
|
56
|
+
for (const { path, key, type, variables, childrenToReplace } of replacements) {
|
|
57
|
+
const existingInfo = getExistingInfoForPath(path);
|
|
58
|
+
const varName = existingInfo?.variableName ?? "content";
|
|
59
|
+
const contentAccessCode = existingInfo?.isDestructured ? key : isSolid ? `${varName}().${key}` : `${varName}.${key}`;
|
|
60
|
+
const valueSuffix = getProvidingHookType(path) === "getIntlayer" ? "" : ".value";
|
|
61
|
+
if (type === "jsx-text" && path.isJSXText()) textEdits.push({
|
|
62
|
+
start: path.node.start,
|
|
63
|
+
end: path.node.end,
|
|
64
|
+
replacement: `{${contentAccessCode}}`
|
|
65
|
+
});
|
|
66
|
+
else if (type === "jsx-attribute" && path.isJSXAttribute()) {
|
|
67
|
+
const valNode = path.node.value;
|
|
68
|
+
if (valNode) textEdits.push({
|
|
69
|
+
start: valNode.start,
|
|
70
|
+
end: valNode.end,
|
|
71
|
+
replacement: `{${contentAccessCode}${valueSuffix}}`
|
|
72
|
+
});
|
|
73
|
+
} else if (type === "string-literal" && path.isStringLiteral()) textEdits.push({
|
|
74
|
+
start: path.node.start,
|
|
75
|
+
end: path.node.end,
|
|
76
|
+
replacement: `${contentAccessCode}${valueSuffix}`
|
|
77
|
+
});
|
|
78
|
+
else if (type === "jsx-text-combined" && childrenToReplace && childrenToReplace.length > 0) {
|
|
79
|
+
const accessStr = `{${contentAccessCode}}`;
|
|
80
|
+
const start = childrenToReplace[0].start;
|
|
81
|
+
const end = childrenToReplace[childrenToReplace.length - 1].end;
|
|
82
|
+
textEdits.push({
|
|
83
|
+
start,
|
|
84
|
+
end,
|
|
85
|
+
replacement: accessStr
|
|
86
|
+
});
|
|
87
|
+
} else if (type === "jsx-insertion" && variables && childrenToReplace && childrenToReplace.length > 0) {
|
|
88
|
+
const accessStr = `{${contentAccessCode}({ ${variables.map((variableString) => {
|
|
89
|
+
const [key, variableValue] = variableString.split(":").map((part) => part.trim());
|
|
90
|
+
return `${key}: ${variableValue}`;
|
|
91
|
+
}).join(", ")} })}`;
|
|
92
|
+
const start = childrenToReplace[0].start;
|
|
93
|
+
const end = childrenToReplace[childrenToReplace.length - 1].end;
|
|
94
|
+
textEdits.push({
|
|
95
|
+
start,
|
|
96
|
+
end,
|
|
97
|
+
replacement: accessStr
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let needsUseIntlayer = false;
|
|
102
|
+
let needsGetIntlayer = false;
|
|
103
|
+
for (const componentPath of componentsNeedingHooks) {
|
|
104
|
+
const finalKey = componentKeyMap.get(componentPath.node);
|
|
105
|
+
const existingInfo = existingInfoCache.get(componentPath.node);
|
|
106
|
+
if (existingInfo) {
|
|
107
|
+
if (existingInfo.hook === "useIntlayer") needsUseIntlayer = true;
|
|
108
|
+
if (existingInfo.hook === "getIntlayer") needsGetIntlayer = true;
|
|
109
|
+
if (existingInfo.isDestructured && existingInfo.objectPatternNode) {
|
|
110
|
+
const neededKeys = /* @__PURE__ */ new Set();
|
|
111
|
+
for (const { path: rPath, key: rKey } of replacements) {
|
|
112
|
+
let current = rPath;
|
|
113
|
+
while (current) {
|
|
114
|
+
if (current.node === componentPath.node) {
|
|
115
|
+
neededKeys.add(rKey);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
current = current.parentPath;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const missingKeys = [...neededKeys].filter((key) => !existingInfo.existingDestructuredKeys.includes(key));
|
|
122
|
+
if (missingKeys.length > 0) {
|
|
123
|
+
const { objectPatternNode } = existingInfo;
|
|
124
|
+
const lastProp = objectPatternNode.properties[objectPatternNode.properties.length - 1];
|
|
125
|
+
textEdits.push({
|
|
126
|
+
start: lastProp.end,
|
|
127
|
+
end: lastProp.end,
|
|
128
|
+
replacement: `, ${missingKeys.join(", ")}`
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
const hook = hookMap.get(componentPath.node) || "useIntlayer";
|
|
134
|
+
if (hook === "useIntlayer") needsUseIntlayer = true;
|
|
135
|
+
if (hook === "getIntlayer") needsGetIntlayer = true;
|
|
136
|
+
const bodyPath = componentPath.get("body");
|
|
137
|
+
const hookStatementStr = `\n const content = ${hook}('${finalKey}');\n`;
|
|
138
|
+
if (bodyPath.isBlockStatement()) textEdits.push({
|
|
139
|
+
start: bodyPath.node.start + 1,
|
|
140
|
+
end: bodyPath.node.start + 1,
|
|
141
|
+
replacement: hookStatementStr
|
|
142
|
+
});
|
|
143
|
+
else if (bodyPath.isExpression()) {
|
|
144
|
+
const start = bodyPath.node.start;
|
|
145
|
+
const end = bodyPath.node.end;
|
|
146
|
+
let parenStart = -1;
|
|
147
|
+
let parenEnd = -1;
|
|
148
|
+
for (let i = start - 1; i >= 0; i--) {
|
|
149
|
+
const char = fileCode[i];
|
|
150
|
+
if (char === "(") {
|
|
151
|
+
parenStart = i;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if (char !== " " && char !== "\n" && char !== "\r" && char !== " ") break;
|
|
155
|
+
}
|
|
156
|
+
if (parenStart !== -1) for (let i = end; i < fileCode.length; i++) {
|
|
157
|
+
const char = fileCode[i];
|
|
158
|
+
if (char === ")") {
|
|
159
|
+
parenEnd = i;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (char !== " " && char !== "\n" && char !== "\r" && char !== " ") break;
|
|
163
|
+
}
|
|
164
|
+
if (parenStart !== -1 && parenEnd !== -1) {
|
|
165
|
+
textEdits.push({
|
|
166
|
+
start: parenEnd,
|
|
167
|
+
end: parenEnd + 1,
|
|
168
|
+
replacement: `)\n}`
|
|
169
|
+
});
|
|
170
|
+
textEdits.push({
|
|
171
|
+
start: parenStart,
|
|
172
|
+
end: parenStart + 1,
|
|
173
|
+
replacement: `{\n const content = ${hook}('${finalKey}');\n return (`
|
|
174
|
+
});
|
|
175
|
+
} else {
|
|
176
|
+
textEdits.push({
|
|
177
|
+
start: end,
|
|
178
|
+
end,
|
|
179
|
+
replacement: `\n}`
|
|
180
|
+
});
|
|
181
|
+
textEdits.push({
|
|
182
|
+
start,
|
|
183
|
+
end: start,
|
|
184
|
+
replacement: `{\n const content = ${hook}('${finalKey}');\n return `
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const injectImport = (hookName, targetPackage) => {
|
|
191
|
+
let existingImportPath;
|
|
192
|
+
traverse(ast, { ImportDeclaration(path) {
|
|
193
|
+
if (path.node.source.value === targetPackage) {
|
|
194
|
+
existingImportPath = path;
|
|
195
|
+
path.stop();
|
|
196
|
+
}
|
|
197
|
+
} });
|
|
198
|
+
if (!existingImportPath) {
|
|
199
|
+
const newImportStr = `import { ${hookName} } from '${targetPackage}';\n`;
|
|
200
|
+
let insertPos = 0;
|
|
201
|
+
if (ast.program.body.length > 0) insertPos = ast.program.body[0].start;
|
|
202
|
+
else if (ast.program.directives && ast.program.directives.length > 0) {
|
|
203
|
+
insertPos = ast.program.directives[ast.program.directives.length - 1].end;
|
|
204
|
+
if (fileCode[insertPos] === ";") insertPos++;
|
|
205
|
+
textEdits.push({
|
|
206
|
+
start: insertPos,
|
|
207
|
+
end: insertPos,
|
|
208
|
+
replacement: `\n${newImportStr}`
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (insertPos === 0 || ast.program.body.length > 0 && insertPos === ast.program.body[0].start) textEdits.push({
|
|
213
|
+
start: insertPos,
|
|
214
|
+
end: insertPos,
|
|
215
|
+
replacement: newImportStr
|
|
216
|
+
});
|
|
217
|
+
} else if (!existingImportPath.node.specifiers.some((specifier) => t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported) && specifier.imported.name === hookName)) {
|
|
218
|
+
const importCode = fileCode.slice(existingImportPath.node.start, existingImportPath.node.end);
|
|
219
|
+
const closingBraceIndex = importCode.lastIndexOf("}");
|
|
220
|
+
if (closingBraceIndex !== -1) {
|
|
221
|
+
const isCommaNeeded = !importCode.slice(0, closingBraceIndex).trim().endsWith(",");
|
|
222
|
+
const absolutePos = existingImportPath.node.start + closingBraceIndex;
|
|
223
|
+
const prefix = isCommaNeeded ? ", " : " ";
|
|
224
|
+
textEdits.push({
|
|
225
|
+
start: absolutePos,
|
|
226
|
+
end: absolutePos,
|
|
227
|
+
replacement: `${prefix}${hookName} `
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
if (needsUseIntlayer) injectImport("useIntlayer", effectivePackageName);
|
|
233
|
+
if (needsGetIntlayer) injectImport("getIntlayer", "intlayer");
|
|
234
|
+
textEdits.sort((editA, editB) => {
|
|
235
|
+
if (editB.start !== editA.start) return editB.start - editA.start;
|
|
236
|
+
return editB.end - editA.end;
|
|
237
|
+
});
|
|
238
|
+
let formattedCode = fileCode;
|
|
239
|
+
for (const edit of textEdits) formattedCode = formattedCode.slice(0, edit.start) + edit.replacement + formattedCode.slice(edit.end);
|
|
240
|
+
if (save) {
|
|
241
|
+
writeFileSync(filePath, formattedCode);
|
|
242
|
+
const formatCommand = detectFormatCommand(configuration);
|
|
243
|
+
if (formatCommand) try {
|
|
244
|
+
execSync(formatCommand.replace("{{file}}", filePath), {
|
|
245
|
+
stdio: "inherit",
|
|
246
|
+
cwd: configuration.system.baseDir
|
|
247
|
+
});
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
extractedContent,
|
|
254
|
+
modifiedCode: formattedCode
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
//#endregion
|
|
259
|
+
export { processTsxFile };
|
|
6
260
|
//# sourceMappingURL=processTsxFile.mjs.map
|