@intlayer/config 9.3.0 → 9.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -2
- package/dist/cjs/bundle/index.cjs.map +1 -1
- package/dist/cjs/callers/base.cjs +0 -1
- package/dist/cjs/callers/base.cjs.map +1 -1
- package/dist/cjs/callers/compat/i18next.cjs +0 -1
- package/dist/cjs/callers/compat/i18next.cjs.map +1 -1
- package/dist/cjs/callers/compat/lingui.cjs +0 -1
- package/dist/cjs/callers/compat/lingui.cjs.map +1 -1
- package/dist/cjs/callers/compat/nextIntl.cjs +0 -1
- package/dist/cjs/callers/compat/nextIntl.cjs.map +1 -1
- package/dist/cjs/callers/compat/reactI18next.cjs +0 -1
- package/dist/cjs/callers/compat/reactI18next.cjs.map +1 -1
- package/dist/cjs/callers/compat/reactIntl.cjs +0 -1
- package/dist/cjs/callers/compat/reactIntl.cjs.map +1 -1
- package/dist/cjs/callers/compat/useIntl.cjs +0 -1
- package/dist/cjs/callers/compat/useIntl.cjs.map +1 -1
- package/dist/cjs/callers/compat/vueI18n.cjs +0 -1
- package/dist/cjs/callers/compat/vueI18n.cjs.map +1 -1
- package/dist/cjs/callers/transform.cjs +0 -1
- package/dist/cjs/callers/transform.cjs.map +1 -1
- package/dist/cjs/colors.cjs +0 -1
- package/dist/cjs/colors.cjs.map +1 -1
- package/dist/cjs/configFile/buildConfigurationFields.cjs.map +1 -1
- package/dist/cjs/configFile/getConfiguration.cjs +3 -2
- package/dist/cjs/configFile/getConfiguration.cjs.map +1 -1
- package/dist/cjs/configFile/searchConfigurationFile.cjs.map +1 -1
- package/dist/cjs/defaultValues/analytics.cjs +0 -1
- package/dist/cjs/defaultValues/analytics.cjs.map +1 -1
- package/dist/cjs/defaultValues/build.cjs +0 -1
- package/dist/cjs/defaultValues/build.cjs.map +1 -1
- package/dist/cjs/defaultValues/compiler.cjs +0 -1
- package/dist/cjs/defaultValues/compiler.cjs.map +1 -1
- package/dist/cjs/defaultValues/content.cjs +0 -1
- package/dist/cjs/defaultValues/content.cjs.map +1 -1
- package/dist/cjs/defaultValues/dictionary.cjs +0 -1
- package/dist/cjs/defaultValues/dictionary.cjs.map +1 -1
- package/dist/cjs/defaultValues/editor.cjs +0 -1
- package/dist/cjs/defaultValues/editor.cjs.map +1 -1
- package/dist/cjs/defaultValues/internationalization.cjs +0 -1
- package/dist/cjs/defaultValues/internationalization.cjs.map +1 -1
- package/dist/cjs/defaultValues/routing.cjs +0 -1
- package/dist/cjs/defaultValues/routing.cjs.map +1 -1
- package/dist/cjs/defaultValues/system.cjs +0 -1
- package/dist/cjs/defaultValues/system.cjs.map +1 -1
- package/dist/cjs/envVars/envVars.cjs +0 -1
- package/dist/cjs/envVars/envVars.cjs.map +1 -1
- package/dist/cjs/extract/constants.cjs +19 -0
- package/dist/cjs/extract/constants.cjs.map +1 -0
- package/dist/cjs/extract/index.cjs +6 -0
- package/dist/cjs/extract/shouldExtract.cjs +38 -0
- package/dist/cjs/extract/shouldExtract.cjs.map +1 -0
- package/dist/cjs/loadEnvFile.cjs +8 -6
- package/dist/cjs/loadEnvFile.cjs.map +1 -1
- package/dist/cjs/loadExternalFile/bundleFile.cjs +4 -2
- package/dist/cjs/loadExternalFile/bundleFile.cjs.map +1 -1
- package/dist/cjs/loadExternalFile/bundleJSFile.cjs.map +1 -1
- package/dist/cjs/loadExternalFile/loadExternalFile.cjs +4 -2
- package/dist/cjs/loadExternalFile/loadExternalFile.cjs.map +1 -1
- package/dist/cjs/loadExternalFile/transpileTSToCJS.cjs +4 -2
- package/dist/cjs/loadExternalFile/transpileTSToCJS.cjs.map +1 -1
- package/dist/cjs/utils/ESMxCJSHelpers.cjs.map +1 -1
- package/dist/cjs/utils/alias.cjs +41 -6
- package/dist/cjs/utils/alias.cjs.map +1 -1
- package/dist/cjs/utils/builtConfigKeys.cjs +0 -1
- package/dist/cjs/utils/builtConfigKeys.cjs.map +1 -1
- package/dist/cjs/utils/cacheDisk.cjs +4 -2
- package/dist/cjs/utils/cacheDisk.cjs.map +1 -1
- package/dist/cjs/utils/cacheMemory.cjs.map +1 -1
- package/dist/cjs/utils/compareVersions.cjs +0 -1
- package/dist/cjs/utils/compareVersions.cjs.map +1 -1
- package/dist/cjs/utils/extractErrorMessage.cjs +0 -1
- package/dist/cjs/utils/extractErrorMessage.cjs.map +1 -1
- package/dist/cjs/utils/getDictionarySelectorUsage.cjs +0 -1
- package/dist/cjs/utils/getDictionarySelectorUsage.cjs.map +1 -1
- package/dist/cjs/utils/getExtension.cjs +0 -1
- package/dist/cjs/utils/getExtension.cjs.map +1 -1
- package/dist/cjs/utils/getPackageJsonPath.cjs.map +1 -1
- package/dist/cjs/utils/getStorageAttributes.cjs +1 -1
- package/dist/cjs/utils/getStorageAttributes.cjs.map +1 -1
- package/dist/cjs/utils/normalizePath.cjs +0 -1
- package/dist/cjs/utils/normalizePath.cjs.map +1 -1
- package/dist/cjs/utils/parseFilePathPattern.cjs +0 -1
- package/dist/cjs/utils/parseFilePathPattern.cjs.map +1 -1
- package/dist/cjs/utils/pathSecurity.cjs.map +1 -1
- package/dist/cjs/utils/setIntlayerIdentifier.cjs +0 -1
- package/dist/cjs/utils/setIntlayerIdentifier.cjs.map +1 -1
- package/dist/cjs/utils/stringFormatter/camelCaseToKebabCase.cjs +0 -1
- package/dist/cjs/utils/stringFormatter/camelCaseToKebabCase.cjs.map +1 -1
- package/dist/cjs/utils/stringFormatter/camelCaseToSentence.cjs +0 -1
- package/dist/cjs/utils/stringFormatter/camelCaseToSentence.cjs.map +1 -1
- package/dist/cjs/utils/stringFormatter/kebabCaseToCamelCase.cjs +0 -1
- package/dist/cjs/utils/stringFormatter/kebabCaseToCamelCase.cjs.map +1 -1
- package/dist/cjs/utils/stringFormatter/toLowerCamelCase.cjs +0 -1
- package/dist/cjs/utils/stringFormatter/toLowerCamelCase.cjs.map +1 -1
- package/dist/esm/configFile/getConfiguration.mjs +3 -2
- package/dist/esm/configFile/getConfiguration.mjs.map +1 -1
- package/dist/esm/extract/constants.mjs +18 -0
- package/dist/esm/extract/constants.mjs.map +1 -0
- package/dist/esm/extract/index.mjs +4 -0
- package/dist/esm/extract/shouldExtract.mjs +37 -0
- package/dist/esm/extract/shouldExtract.mjs.map +1 -0
- package/dist/esm/loadEnvFile.mjs +8 -6
- package/dist/esm/loadEnvFile.mjs.map +1 -1
- package/dist/esm/loadExternalFile/bundleFile.mjs +4 -2
- package/dist/esm/loadExternalFile/bundleFile.mjs.map +1 -1
- package/dist/esm/loadExternalFile/loadExternalFile.mjs +4 -2
- package/dist/esm/loadExternalFile/loadExternalFile.mjs.map +1 -1
- package/dist/esm/loadExternalFile/transpileTSToCJS.mjs +4 -2
- package/dist/esm/loadExternalFile/transpileTSToCJS.mjs.map +1 -1
- package/dist/esm/utils/ESMxCJSHelpers.mjs.map +1 -1
- package/dist/esm/utils/alias.mjs +41 -6
- package/dist/esm/utils/alias.mjs.map +1 -1
- package/dist/esm/utils/cacheDisk.mjs +4 -2
- package/dist/esm/utils/cacheDisk.mjs.map +1 -1
- package/dist/esm/utils/getStorageAttributes.mjs +1 -1
- package/dist/esm/utils/getStorageAttributes.mjs.map +1 -1
- package/dist/types/extract/constants.d.ts +11 -0
- package/dist/types/extract/constants.d.ts.map +1 -0
- package/dist/types/extract/index.d.ts +3 -0
- package/dist/types/extract/shouldExtract.d.ts +15 -0
- package/dist/types/extract/shouldExtract.d.ts.map +1 -0
- package/package.json +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathSecurity.cjs","names":["sep"],"sources":["../../../src/utils/pathSecurity.ts"],"sourcesContent":["import { resolve, sep } from 'node:path';\n\n/**\n * Throws if `resolvedPath` escapes `baseDir`.\n * Use this before any file operation whose path is derived from user-controlled\n * input (e.g. dictionary keys, filePath fields from dictionary data) to prevent\n * path-traversal attacks.\n */\nexport const assertPathWithin = (\n resolvedPath: string,\n baseDir: string\n): void => {\n const normalizedBase = resolve(baseDir);\n const normalizedPath = resolve(resolvedPath);\n if (\n normalizedPath !== normalizedBase &&\n !normalizedPath.startsWith(normalizedBase + sep)\n ) {\n throw new Error(\n `Path traversal detected: \"${resolvedPath}\" escapes the base directory \"${baseDir}\"`\n );\n }\n};\n"],"mappings":";;;;;;;;;;AAQA,MAAa,oBACX,cACA,YACS;CACT,MAAM,
|
|
1
|
+
{"version":3,"file":"pathSecurity.cjs","names":["resolve","sep"],"sources":["../../../src/utils/pathSecurity.ts"],"sourcesContent":["import { resolve, sep } from 'node:path';\n\n/**\n * Throws if `resolvedPath` escapes `baseDir`.\n * Use this before any file operation whose path is derived from user-controlled\n * input (e.g. dictionary keys, filePath fields from dictionary data) to prevent\n * path-traversal attacks.\n */\nexport const assertPathWithin = (\n resolvedPath: string,\n baseDir: string\n): void => {\n const normalizedBase = resolve(baseDir);\n const normalizedPath = resolve(resolvedPath);\n if (\n normalizedPath !== normalizedBase &&\n !normalizedPath.startsWith(normalizedBase + sep)\n ) {\n throw new Error(\n `Path traversal detected: \"${resolvedPath}\" escapes the base directory \"${baseDir}\"`\n );\n }\n};\n"],"mappings":";;;;;;;;;;AAQA,MAAa,oBACX,cACA,YACS;CACT,MAAM,qBAAiBA,mBAAQ,OAAO;CACtC,MAAM,qBAAiBA,mBAAQ,YAAY;CAC3C,IACE,mBAAmB,kBACnB,CAAC,eAAe,WAAW,iBAAiBC,aAAG,GAE/C,MAAM,IAAI,MACR,6BAA6B,aAAa,gCAAgC,QAAQ,EACpF;AAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setIntlayerIdentifier.cjs","names":[],"sources":["../../../src/utils/setIntlayerIdentifier.ts"],"sourcesContent":["type Meta = {\n enabled: true;\n};\n\nexport type WindowsWithIntlayer = typeof window & {\n intlayer?: Meta;\n};\n\n/**\n * Sets the version of Intlayer in the window object.\n * This is used for Intlayer detection in the browser.\n */\nexport const setIntlayerIdentifier = (): void => {\n if (typeof window !== 'undefined') {\n (window as WindowsWithIntlayer).intlayer = {\n enabled: true,\n };\n }\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"setIntlayerIdentifier.cjs","names":[],"sources":["../../../src/utils/setIntlayerIdentifier.ts"],"sourcesContent":["type Meta = {\n enabled: true;\n};\n\nexport type WindowsWithIntlayer = typeof window & {\n intlayer?: Meta;\n};\n\n/**\n * Sets the version of Intlayer in the window object.\n * This is used for Intlayer detection in the browser.\n */\nexport const setIntlayerIdentifier = (): void => {\n if (typeof window !== 'undefined') {\n (window as WindowsWithIntlayer).intlayer = {\n enabled: true,\n };\n }\n};\n"],"mappings":";;;;;;AAYA,MAAa,8BAAoC;CAC/C,IAAI,OAAO,WAAW,aACpB,AAAC,OAA+B,WAAW,EACzC,SAAS,KACX;AAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camelCaseToKebabCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/camelCaseToKebabCase.ts"],"sourcesContent":["/**\n * Convert a string to kebab-case\n * e.g. \"MyNewComponent\" => \"my-new-component\"\n */\nexport const camelCaseToKebabCase = (str: string): string => {\n // Split on transition from lower->upper: \"MyNewComponent\" => [\"My\", \"New\", \"Component\"]\n // Then lowercase each chunk and join by \"-\"\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"camelCaseToKebabCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/camelCaseToKebabCase.ts"],"sourcesContent":["/**\n * Convert a string to kebab-case\n * e.g. \"MyNewComponent\" => \"my-new-component\"\n */\nexport const camelCaseToKebabCase = (str: string): string => {\n // Split on transition from lower->upper: \"MyNewComponent\" => [\"My\", \"New\", \"Component\"]\n // Then lowercase each chunk and join by \"-\"\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n};\n"],"mappings":";;;;;;AAIA,MAAa,wBAAwB,QAAwB;CAG3D,OAAO,IACJ,QAAQ,mBAAmB,OAAO,CAAC,CACnC,QAAQ,wBAAwB,OAAO,CAAC,CACxC,QAAQ,WAAW,GAAG,CAAC,CACvB,YAAY;AACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camelCaseToSentence.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/camelCaseToSentence.ts"],"sourcesContent":["/**\n * Convert a string to sentence case\n * e.g. 'my-new-component' → 'My new component'\n */\nexport const camelCaseToSentence = (value: string): string => {\n if (!value) return '';\n if (typeof value !== 'string') return '';\n\n // Insert space before all caps that follow lowercase letters\n const withSpaces = value\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n // Insert space between sequences like \"XMLParser\" → \"XML Parser\"\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');\n\n // Lowercase everything except the first character\n return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1).toLowerCase();\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"camelCaseToSentence.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/camelCaseToSentence.ts"],"sourcesContent":["/**\n * Convert a string to sentence case\n * e.g. 'my-new-component' → 'My new component'\n */\nexport const camelCaseToSentence = (value: string): string => {\n if (!value) return '';\n if (typeof value !== 'string') return '';\n\n // Insert space before all caps that follow lowercase letters\n const withSpaces = value\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n // Insert space between sequences like \"XMLParser\" → \"XML Parser\"\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');\n\n // Lowercase everything except the first character\n return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1).toLowerCase();\n};\n"],"mappings":";;;;;;AAIA,MAAa,uBAAuB,UAA0B;CAC5D,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,OAAO,UAAU,UAAU,OAAO;CAGtC,MAAM,aAAa,MAChB,QAAQ,mBAAmB,OAAO,CAAC,CAEnC,QAAQ,yBAAyB,OAAO;CAG3C,OAAO,WAAW,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC,YAAY;AAC9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kebabCaseToCamelCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/kebabCaseToCamelCase.ts"],"sourcesContent":["export const kebabCaseToCamelCase = (name: string): string => {\n return name\n .split(/[^a-zA-Z0-9]+/) // Split on any non-alphanumeric character\n .filter(Boolean) // Remove any empty strings\n .map((word) => {\n // Convert the entire word to lowercase first\n const lowerWord = word.toLowerCase();\n\n // Capitalize the first character\n let capitalized = lowerWord.charAt(0).toUpperCase() + lowerWord.slice(1);\n\n // Capitalize any letter that follows a number\n capitalized = capitalized.replace(\n /(\\d)([a-z])/g,\n (_, number, char) => number + char.toUpperCase()\n );\n\n return capitalized;\n })\n .join(''); // Concatenate all parts into a single string\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"kebabCaseToCamelCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/kebabCaseToCamelCase.ts"],"sourcesContent":["export const kebabCaseToCamelCase = (name: string): string => {\n return name\n .split(/[^a-zA-Z0-9]+/) // Split on any non-alphanumeric character\n .filter(Boolean) // Remove any empty strings\n .map((word) => {\n // Convert the entire word to lowercase first\n const lowerWord = word.toLowerCase();\n\n // Capitalize the first character\n let capitalized = lowerWord.charAt(0).toUpperCase() + lowerWord.slice(1);\n\n // Capitalize any letter that follows a number\n capitalized = capitalized.replace(\n /(\\d)([a-z])/g,\n (_, number, char) => number + char.toUpperCase()\n );\n\n return capitalized;\n })\n .join(''); // Concatenate all parts into a single string\n};\n"],"mappings":";;AAAA,MAAa,wBAAwB,SAAyB;CAC5D,OAAO,KACJ,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,KAAK,SAAS;EAEb,MAAM,YAAY,KAAK,YAAY;EAGnC,IAAI,cAAc,UAAU,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,UAAU,MAAM,CAAC;EAGvE,cAAc,YAAY,QACxB,iBACC,GAAG,QAAQ,SAAS,SAAS,KAAK,YAAY,CACjD;EAEA,OAAO;CACT,CAAC,CAAC,CACD,KAAK,EAAE;AACZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toLowerCamelCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/toLowerCamelCase.ts"],"sourcesContent":["/**\n * Convert a string to lowerCamelCase\n * e.g. \"MyComponent\" => \"myComponent\"\n * e.g. \"auth-middleware\" => \"authMiddleware\"\n */\nexport const toLowerCamelCase = (str: string): string => {\n if (!str) {\n return '';\n }\n\n // Handle kebab-case: \"auth-middleware\" => \"authMiddleware\"\n if (str.includes('-')) {\n return str\n .split('-')\n .map((word, index) => {\n if (index === 0) {\n return word.toLowerCase();\n }\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n })\n .join('');\n }\n\n // Handle PascalCase: \"MyComponent\" => \"myComponent\"\n return str.charAt(0).toLowerCase() + str.slice(1);\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"toLowerCamelCase.cjs","names":[],"sources":["../../../../src/utils/stringFormatter/toLowerCamelCase.ts"],"sourcesContent":["/**\n * Convert a string to lowerCamelCase\n * e.g. \"MyComponent\" => \"myComponent\"\n * e.g. \"auth-middleware\" => \"authMiddleware\"\n */\nexport const toLowerCamelCase = (str: string): string => {\n if (!str) {\n return '';\n }\n\n // Handle kebab-case: \"auth-middleware\" => \"authMiddleware\"\n if (str.includes('-')) {\n return str\n .split('-')\n .map((word, index) => {\n if (index === 0) {\n return word.toLowerCase();\n }\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n })\n .join('');\n }\n\n // Handle PascalCase: \"MyComponent\" => \"myComponent\"\n return str.charAt(0).toLowerCase() + str.slice(1);\n};\n"],"mappings":";;;;;;;AAKA,MAAa,oBAAoB,QAAwB;CACvD,IAAI,CAAC,KACH,OAAO;CAIT,IAAI,IAAI,SAAS,GAAG,GAClB,OAAO,IACJ,MAAM,GAAG,CAAC,CACV,KAAK,MAAM,UAAU;EACpB,IAAI,UAAU,GACZ,OAAO,KAAK,YAAY;EAE1B,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY;CAClE,CAAC,CAAC,CACD,KAAK,EAAE;CAIZ,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,MAAM,CAAC;AAClD"}
|
|
@@ -39,10 +39,11 @@ const getConfigurationAndFilePath = (options) => {
|
|
|
39
39
|
});
|
|
40
40
|
storedConfiguration = buildConfigurationFields(customConfiguration, options?.baseDir, options?.logFunctions);
|
|
41
41
|
} else storedConfiguration = buildConfigurationFields({}, options?.baseDir, options?.logFunctions);
|
|
42
|
-
const
|
|
42
|
+
const projectRequireConfig = options?.require ? { build: {
|
|
43
43
|
require: options?.require,
|
|
44
44
|
cache: options?.cache
|
|
45
|
-
} } : {}
|
|
45
|
+
} } : {};
|
|
46
|
+
const configWithProjectRequire = defu(projectRequireConfig, storedConfiguration);
|
|
46
47
|
const configuration = defu(options?.override ?? {}, configWithProjectRequire);
|
|
47
48
|
cacheMemory.set(options, {
|
|
48
49
|
configuration,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getConfiguration.mjs","names":[],"sources":["../../../src/configFile/getConfiguration.ts"],"sourcesContent":["import type {\n CustomIntlayerConfig,\n IntlayerConfig,\n LogFunctions,\n} from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { LoadExternalFileOptions } from '../loadExternalFile/loadExternalFile';\nimport type { SandBoxContextOptions } from '../loadExternalFile/parseFileContent';\nimport { cacheMemory } from '../utils/cacheMemory';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { buildConfigurationFields } from './buildConfigurationFields';\nimport { loadConfigurationFile } from './loadConfigurationFile';\nimport { searchConfigurationFile } from './searchConfigurationFile';\n\nexport type GetConfigurationOptions = {\n baseDir?: string;\n override?: CustomIntlayerConfig;\n // Dotenv options\n env?: string;\n envFile?: string;\n // Log functions\n logFunctions?: LogFunctions;\n // Require function\n require?: NodeJS.Require;\n // cache\n cache?: boolean;\n // Build options for TypeScript transpilation (e.g. custom esbuild instance)\n buildOptions?: LoadExternalFileOptions['buildOptions'];\n} & Omit<SandBoxContextOptions, 'projectRequire'>;\n\nexport type GetConfigurationAndFilePathResult = {\n configuration: IntlayerConfig;\n customConfiguration: CustomIntlayerConfig | undefined;\n numCustomConfiguration: number;\n configurationFilePath: string | undefined;\n};\n\n/**\n * Get the configuration for the intlayer by reading the configuration file (e.g. intlayer.config.js)\n */\nexport const getConfigurationAndFilePath = (\n options?: GetConfigurationOptions\n): GetConfigurationAndFilePathResult => {\n let baseDir: string | undefined;\n\n try {\n // Can fail in some environments (e.g. MCP server, VScode extension)\n baseDir = options?.baseDir ?? getPackageJsonPath().baseDir;\n } catch (_err) {\n // Return default config if the package.json is not found\n return {\n configuration: buildConfigurationFields(\n {},\n options?.baseDir,\n options?.logFunctions\n ),\n customConfiguration: undefined,\n numCustomConfiguration: 0,\n configurationFilePath: undefined,\n };\n }\n\n const cachedConfiguration =\n cacheMemory.get<GetConfigurationAndFilePathResult>(options);\n\n if (cachedConfiguration) return cachedConfiguration;\n\n // Search for configuration files\n const { configurationFilePath, numCustomConfiguration } =\n searchConfigurationFile(baseDir);\n\n let storedConfiguration: IntlayerConfig;\n let customConfiguration: CustomIntlayerConfig | undefined;\n\n if (configurationFilePath) {\n // Load the custom configuration\n customConfiguration = loadConfigurationFile(configurationFilePath, {\n projectRequire: options?.require,\n // Dotenv options\n envVarOptions: {\n env: options?.env,\n envFile: options?.envFile,\n },\n // Sandbox context additional variables\n additionalEnvVars: options?.additionalEnvVars,\n aliases: options?.aliases,\n // Build options for TypeScript transpilation (e.g. custom esbuild instance)\n buildOptions: options?.buildOptions,\n });\n\n // Save the configuration to avoid reading the file again\n storedConfiguration = buildConfigurationFields(\n customConfiguration,\n options?.baseDir,\n options?.logFunctions\n );\n } else {\n // No configuration file found, use default configuration\n storedConfiguration = buildConfigurationFields(\n {},\n options?.baseDir,\n options?.logFunctions\n );\n }\n\n // Log warning if multiple configuration files are found\n const projectRequireConfig: CustomIntlayerConfig = options?.require\n ? {\n build: {\n require: options?.require,\n cache: options?.cache,\n },\n }\n : {};\n\n const configWithProjectRequire = defu(\n projectRequireConfig,\n storedConfiguration\n ) as IntlayerConfig;\n\n const configuration = defu(\n options?.override ?? {},\n configWithProjectRequire\n ) as IntlayerConfig;\n\n cacheMemory.set(options, {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n });\n\n return {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n };\n};\n\n/**\n * Get the configuration for the intlayer by reading the configuration file (e.g. intlayer.config.js)\n */\nexport const getConfiguration = (\n options?: GetConfigurationOptions\n): IntlayerConfig => getConfigurationAndFilePath(options).configuration;\n"],"mappings":";;;;;;;;;;;AAwCA,MAAa,+BACX,YACsC;CACtC,IAAI;CAEJ,IAAI;EAEF,UAAU,SAAS,WAAW,mBAAmB,CAAC,CAAC;CACrD,SAAS,MAAM;EAEb,OAAO;GACL,eAAe,yBACb,CAAC,GACD,SAAS,SACT,SAAS,YACX;GACA,qBAAqB;GACrB,wBAAwB;GACxB,uBAAuB;EACzB;CACF;CAEA,MAAM,sBACJ,YAAY,IAAuC,OAAO;CAE5D,IAAI,qBAAqB,OAAO;CAGhC,MAAM,EAAE,uBAAuB,2BAC7B,wBAAwB,OAAO;CAEjC,IAAI;CACJ,IAAI;CAEJ,IAAI,uBAAuB;EAEzB,sBAAsB,sBAAsB,uBAAuB;GACjE,gBAAgB,SAAS;GAEzB,eAAe;IACb,KAAK,SAAS;IACd,SAAS,SAAS;GACpB;GAEA,mBAAmB,SAAS;GAC5B,SAAS,SAAS;GAElB,cAAc,SAAS;EACzB,CAAC;EAGD,sBAAsB,yBACpB,qBACA,SAAS,SACT,SAAS,YACX;CACF,OAEE,sBAAsB,yBACpB,CAAC,GACD,SAAS,SACT,SAAS,YACX;
|
|
1
|
+
{"version":3,"file":"getConfiguration.mjs","names":[],"sources":["../../../src/configFile/getConfiguration.ts"],"sourcesContent":["import type {\n CustomIntlayerConfig,\n IntlayerConfig,\n LogFunctions,\n} from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { LoadExternalFileOptions } from '../loadExternalFile/loadExternalFile';\nimport type { SandBoxContextOptions } from '../loadExternalFile/parseFileContent';\nimport { cacheMemory } from '../utils/cacheMemory';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { buildConfigurationFields } from './buildConfigurationFields';\nimport { loadConfigurationFile } from './loadConfigurationFile';\nimport { searchConfigurationFile } from './searchConfigurationFile';\n\nexport type GetConfigurationOptions = {\n baseDir?: string;\n override?: CustomIntlayerConfig;\n // Dotenv options\n env?: string;\n envFile?: string;\n // Log functions\n logFunctions?: LogFunctions;\n // Require function\n require?: NodeJS.Require;\n // cache\n cache?: boolean;\n // Build options for TypeScript transpilation (e.g. custom esbuild instance)\n buildOptions?: LoadExternalFileOptions['buildOptions'];\n} & Omit<SandBoxContextOptions, 'projectRequire'>;\n\nexport type GetConfigurationAndFilePathResult = {\n configuration: IntlayerConfig;\n customConfiguration: CustomIntlayerConfig | undefined;\n numCustomConfiguration: number;\n configurationFilePath: string | undefined;\n};\n\n/**\n * Get the configuration for the intlayer by reading the configuration file (e.g. intlayer.config.js)\n */\nexport const getConfigurationAndFilePath = (\n options?: GetConfigurationOptions\n): GetConfigurationAndFilePathResult => {\n let baseDir: string | undefined;\n\n try {\n // Can fail in some environments (e.g. MCP server, VScode extension)\n baseDir = options?.baseDir ?? getPackageJsonPath().baseDir;\n } catch (_err) {\n // Return default config if the package.json is not found\n return {\n configuration: buildConfigurationFields(\n {},\n options?.baseDir,\n options?.logFunctions\n ),\n customConfiguration: undefined,\n numCustomConfiguration: 0,\n configurationFilePath: undefined,\n };\n }\n\n const cachedConfiguration =\n cacheMemory.get<GetConfigurationAndFilePathResult>(options);\n\n if (cachedConfiguration) return cachedConfiguration;\n\n // Search for configuration files\n const { configurationFilePath, numCustomConfiguration } =\n searchConfigurationFile(baseDir);\n\n let storedConfiguration: IntlayerConfig;\n let customConfiguration: CustomIntlayerConfig | undefined;\n\n if (configurationFilePath) {\n // Load the custom configuration\n customConfiguration = loadConfigurationFile(configurationFilePath, {\n projectRequire: options?.require,\n // Dotenv options\n envVarOptions: {\n env: options?.env,\n envFile: options?.envFile,\n },\n // Sandbox context additional variables\n additionalEnvVars: options?.additionalEnvVars,\n aliases: options?.aliases,\n // Build options for TypeScript transpilation (e.g. custom esbuild instance)\n buildOptions: options?.buildOptions,\n });\n\n // Save the configuration to avoid reading the file again\n storedConfiguration = buildConfigurationFields(\n customConfiguration,\n options?.baseDir,\n options?.logFunctions\n );\n } else {\n // No configuration file found, use default configuration\n storedConfiguration = buildConfigurationFields(\n {},\n options?.baseDir,\n options?.logFunctions\n );\n }\n\n // Log warning if multiple configuration files are found\n const projectRequireConfig: CustomIntlayerConfig = options?.require\n ? {\n build: {\n require: options?.require,\n cache: options?.cache,\n },\n }\n : {};\n\n const configWithProjectRequire = defu(\n projectRequireConfig,\n storedConfiguration\n ) as IntlayerConfig;\n\n const configuration = defu(\n options?.override ?? {},\n configWithProjectRequire\n ) as IntlayerConfig;\n\n cacheMemory.set(options, {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n });\n\n return {\n configuration,\n customConfiguration,\n numCustomConfiguration,\n configurationFilePath,\n };\n};\n\n/**\n * Get the configuration for the intlayer by reading the configuration file (e.g. intlayer.config.js)\n */\nexport const getConfiguration = (\n options?: GetConfigurationOptions\n): IntlayerConfig => getConfigurationAndFilePath(options).configuration;\n"],"mappings":";;;;;;;;;;;AAwCA,MAAa,+BACX,YACsC;CACtC,IAAI;CAEJ,IAAI;EAEF,UAAU,SAAS,WAAW,mBAAmB,CAAC,CAAC;CACrD,SAAS,MAAM;EAEb,OAAO;GACL,eAAe,yBACb,CAAC,GACD,SAAS,SACT,SAAS,YACX;GACA,qBAAqB;GACrB,wBAAwB;GACxB,uBAAuB;EACzB;CACF;CAEA,MAAM,sBACJ,YAAY,IAAuC,OAAO;CAE5D,IAAI,qBAAqB,OAAO;CAGhC,MAAM,EAAE,uBAAuB,2BAC7B,wBAAwB,OAAO;CAEjC,IAAI;CACJ,IAAI;CAEJ,IAAI,uBAAuB;EAEzB,sBAAsB,sBAAsB,uBAAuB;GACjE,gBAAgB,SAAS;GAEzB,eAAe;IACb,KAAK,SAAS;IACd,SAAS,SAAS;GACpB;GAEA,mBAAmB,SAAS;GAC5B,SAAS,SAAS;GAElB,cAAc,SAAS;EACzB,CAAC;EAGD,sBAAsB,yBACpB,qBACA,SAAS,SACT,SAAS,YACX;CACF,OAEE,sBAAsB,yBACpB,CAAC,GACD,SAAS,SACT,SAAS,YACX;CAIF,MAAM,uBAA6C,SAAS,UACxD,EACE,OAAO;EACL,SAAS,SAAS;EAClB,OAAO,SAAS;CAClB,EACF,IACA,CAAC;CAEL,MAAM,2BAA2B,KAC/B,sBACA,mBACF;CAEA,MAAM,gBAAgB,KACpB,SAAS,YAAY,CAAC,GACtB,wBACF;CAEA,YAAY,IAAI,SAAS;EACvB;EACA;EACA;EACA;CACF,CAAC;CAED,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;;;;AAKA,MAAa,oBACX,YACmB,4BAA4B,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/extract/constants.ts
|
|
2
|
+
/**
|
|
3
|
+
* Attributes that should be extracted as translatable strings from JSX/HTML elements.
|
|
4
|
+
* This is the single source of truth shared across all Intlayer compiler packages
|
|
5
|
+
* (@intlayer/babel, @intlayer/vue-compiler, @intlayer/svelte-compiler, @intlayer/engine)
|
|
6
|
+
* and the `eslint-plugin-intlayer` `no-raw-text` rule.
|
|
7
|
+
*/
|
|
8
|
+
const ATTRIBUTES_TO_EXTRACT = [
|
|
9
|
+
"title",
|
|
10
|
+
"placeholder",
|
|
11
|
+
"alt",
|
|
12
|
+
"aria-label",
|
|
13
|
+
"label"
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ATTRIBUTES_TO_EXTRACT };
|
|
18
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.mjs","names":[],"sources":["../../../src/extract/constants.ts"],"sourcesContent":["/**\n * Attributes that should be extracted as translatable strings from JSX/HTML elements.\n * This is the single source of truth shared across all Intlayer compiler packages\n * (@intlayer/babel, @intlayer/vue-compiler, @intlayer/svelte-compiler, @intlayer/engine)\n * and the `eslint-plugin-intlayer` `no-raw-text` rule.\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n] as const;\n"],"mappings":";;;;;;;AAMA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;AACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/extract/shouldExtract.ts
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the given text should be extracted as a translatable string.
|
|
4
|
+
*
|
|
5
|
+
* Filters out:
|
|
6
|
+
* - Empty strings
|
|
7
|
+
* - Emails
|
|
8
|
+
* - Single capitalized words (likely brand/proper nouns, e.g. "Intlayer")
|
|
9
|
+
* - Uncapitalized strings of 2 words or fewer (likely technical terms)
|
|
10
|
+
* - Dynamic content patterns like Vue bindings (`v-`) or object patterns (`{`)
|
|
11
|
+
*/
|
|
12
|
+
const shouldExtract = (text) => {
|
|
13
|
+
const trimmed = text.trim();
|
|
14
|
+
if (!trimmed) return false;
|
|
15
|
+
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) return false;
|
|
16
|
+
if (trimmed.startsWith("{") && !trimmed.startsWith("{{") || trimmed.startsWith("v-")) return false;
|
|
17
|
+
if (trimmed.includes("=>") || trimmed.includes(");") || trimmed.includes("(){") || trimmed.includes("==") || trimmed.includes("window.") || trimmed.startsWith("(function") || trimmed.startsWith("function(")) return false;
|
|
18
|
+
if ((trimmed.match(/[^\p{L}\p{N}\s.,!?;:'"()[\]{}–—/«»„“\p{Sc}%&*+#@^_+=<>/~]/gu) || []).length > 5) return false;
|
|
19
|
+
const wordCount = trimmed.split(/\s+/).length;
|
|
20
|
+
const cssClassTokenRegex = /^!?([a-z][a-z0-9-]*:)*[a-z][a-z0-9]*(-[a-z0-9[\].,%#/]+)*(\/[a-z0-9]+)?$/;
|
|
21
|
+
if (wordCount > 1) {
|
|
22
|
+
const tokens = trimmed.split(/\s+/);
|
|
23
|
+
if (tokens.every((token) => cssClassTokenRegex.test(token)) && tokens.some((token) => token.includes("-"))) return false;
|
|
24
|
+
}
|
|
25
|
+
const isCapitalized = /^['"([]*\p{Lu}/u.test(trimmed);
|
|
26
|
+
if (wordCount === 1 && isCapitalized) return false;
|
|
27
|
+
if (wordCount === 1) {
|
|
28
|
+
if (/[a-z]\p{Lu}/u.test(trimmed)) return false;
|
|
29
|
+
if (trimmed.includes("-") || trimmed.includes("_")) return false;
|
|
30
|
+
}
|
|
31
|
+
if (!isCapitalized && wordCount <= 2) return false;
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { shouldExtract };
|
|
37
|
+
//# sourceMappingURL=shouldExtract.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shouldExtract.mjs","names":[],"sources":["../../../src/extract/shouldExtract.ts"],"sourcesContent":["/**\n * Checks whether the given text should be extracted as a translatable string.\n *\n * Filters out:\n * - Empty strings\n * - Emails\n * - Single capitalized words (likely brand/proper nouns, e.g. \"Intlayer\")\n * - Uncapitalized strings of 2 words or fewer (likely technical terms)\n * - Dynamic content patterns like Vue bindings (`v-`) or object patterns (`{`)\n */\nexport const shouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n\n if (!trimmed) return false;\n\n // Ignore emails\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return false;\n\n // Ignore dynamic content patterns, but allow {{placeholder}} which is intlayer's insertion format\n if (\n (trimmed.startsWith('{') && !trimmed.startsWith('{{')) ||\n trimmed.startsWith('v-')\n )\n return false;\n\n // Ignore explicit code patterns (markers)\n if (\n trimmed.includes('=>') ||\n trimmed.includes(');') ||\n trimmed.includes('(){') ||\n trimmed.includes('==') ||\n trimmed.includes('window.') ||\n trimmed.startsWith('(function') ||\n trimmed.startsWith('function(')\n ) {\n return false;\n }\n\n // Heuristic: check for characters that are common in code but rare in natural text.\n // Whitelist: letters, numbers, spaces, and frequent text symbols (including punctuation, braces, and technical symbols)\n const nonTextualRegex =\n /[^\\p{L}\\p{N}\\s.,!?;:'\"()[\\]{}–—/«»„“\\p{Sc}%&*+#@^_+=<>/~]/gu;\n const nonTextualMatches = trimmed.match(nonTextualRegex) || [];\n\n // If a string contains a high density of truly exceptional symbols (like |, \\, etc.),\n // it is highly likely to be code or complex technical data.\n if (nonTextualMatches.length > 5) return false;\n\n const wordCount = trimmed.split(/\\s+/).length;\n\n // Ignore CSS/Tailwind utility class strings. A string whose tokens all look\n // like CSS utility classes (lowercase, optional responsive/state prefix like\n // \"sm:\" or \"hover:\", optional hyphenated suffix like \"-4\" or \"-full\") and\n // where at least one token contains a hyphen is almost certainly a className\n // value, not translatable text.\n const cssClassTokenRegex =\n /^!?([a-z][a-z0-9-]*:)*[a-z][a-z0-9]*(-[a-z0-9[\\].,%#/]+)*(\\/[a-z0-9]+)?$/;\n if (wordCount > 1) {\n const tokens = trimmed.split(/\\s+/);\n if (\n tokens.every((token) => cssClassTokenRegex.test(token)) &&\n tokens.some((token) => token.includes('-'))\n ) {\n return false;\n }\n }\n\n // Check if starts with a capital letter (including after an opening parenthesis/quote)\n const isCapitalized = /^['\"([]*\\p{Lu}/u.test(trimmed);\n\n // Ignore single capitalized words (e.g. brand or proper nouns like \"Intlayer\").\n // A lone word starting with a capital is almost always a name/identifier rather\n // than a translatable sentence or label.\n if (wordCount === 1 && isCapitalized) return false;\n\n // Ignore technical identifiers (one word strings with camelCase, kebab-case, snake_case etc.)\n if (wordCount === 1) {\n // CamelCase or internal capitals (like camelCaseProperty or CamelCaseProperty)\n if (/[a-z]\\p{Lu}/u.test(trimmed)) return false;\n // kebab-case or snake_case\n if (trimmed.includes('-') || trimmed.includes('_')) return false;\n }\n\n // We usually want to extract full sentences or labels, not single/short technical words.\n // Extract if capitalized, or if it contains more than 2 words.\n if (!isCapitalized && wordCount <= 2) return false;\n\n return true;\n};\n"],"mappings":";;;;;;;;;;;AAUA,MAAa,iBAAiB,SAA0B;CACtD,MAAM,UAAU,KAAK,KAAK;CAE1B,IAAI,CAAC,SAAS,OAAO;CAGrB,IAAI,6BAA6B,KAAK,OAAO,GAAG,OAAO;CAGvD,IACG,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,IAAI,KACpD,QAAQ,WAAW,IAAI,GAEvB,OAAO;CAGT,IACE,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,KAAK,KACtB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,WAAW,WAAW,KAC9B,QAAQ,WAAW,WAAW,GAE9B,OAAO;CAWT,KAJ0B,QAAQ,MAAM,6DAAe,KAAK,CAAC,EAIxC,CAAC,SAAS,GAAG,OAAO;CAEzC,MAAM,YAAY,QAAQ,MAAM,KAAK,CAAC,CAAC;CAOvC,MAAM,qBACJ;CACF,IAAI,YAAY,GAAG;EACjB,MAAM,SAAS,QAAQ,MAAM,KAAK;EAClC,IACE,OAAO,OAAO,UAAU,mBAAmB,KAAK,KAAK,CAAC,KACtD,OAAO,MAAM,UAAU,MAAM,SAAS,GAAG,CAAC,GAE1C,OAAO;CAEX;CAGA,MAAM,gBAAgB,kBAAkB,KAAK,OAAO;CAKpD,IAAI,cAAc,KAAK,eAAe,OAAO;CAG7C,IAAI,cAAc,GAAG;EAEnB,IAAI,eAAe,KAAK,OAAO,GAAG,OAAO;EAEzC,IAAI,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG,OAAO;CAC7D;CAIA,IAAI,CAAC,iBAAiB,aAAa,GAAG,OAAO;CAE7C,OAAO;AACT"}
|
package/dist/esm/loadEnvFile.mjs
CHANGED
|
@@ -31,12 +31,14 @@ const loadEnvFile = (options) => {
|
|
|
31
31
|
const env = options?.env ?? DEFAULT_ENV;
|
|
32
32
|
const cacheKey = `${process.cwd()}|${env}|${options?.envFile ?? ""}`;
|
|
33
33
|
const cachedEntry = envFileCache.get(cacheKey);
|
|
34
|
-
if (cachedEntry)
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
if (cachedEntry) {
|
|
35
|
+
if (cachedEntry.envFilePath === void 0) {
|
|
36
|
+
if (!getEnvFilePath(env, options?.envFile)) return cachedEntry.parsedEnv;
|
|
37
|
+
} else try {
|
|
38
|
+
const stats = statSync(cachedEntry.envFilePath);
|
|
39
|
+
if (stats.mtimeMs === cachedEntry.mtimeMs && stats.size === cachedEntry.size) return cachedEntry.parsedEnv;
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
40
42
|
const envFilePath = getEnvFilePath(env, options?.envFile);
|
|
41
43
|
if (!envFilePath) {
|
|
42
44
|
envFileCache.set(cacheKey, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadEnvFile.mjs","names":[],"sources":["../../src/loadEnvFile.ts"],"sourcesContent":["import { existsSync, statSync } from 'node:fs';\nimport dotenv from 'dotenv';\n\nconst DEFAULT_ENV = process.env.NODE_ENV ?? 'development';\n\nexport type LoadEnvFileOptions = {\n env?: string;\n envFile?: string;\n};\n\nexport const getEnvFilePath = (\n env: string = process.env.NODE_ENV ?? 'development',\n envFile?: string\n): string | undefined => {\n const envFiles = envFile\n ? [envFile]\n : [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'];\n\n return envFiles.find(existsSync); // Returns the first existing env file\n};\n\ntype EnvFileCacheEntry = {\n /** The env file that was resolved and parsed (undefined if none exists). */\n envFilePath: string | undefined;\n /** Fingerprint of the parsed file, used to detect edits. */\n mtimeMs: number;\n size: number;\n /** The parsed env variables. */\n parsedEnv: Record<string, string>;\n};\n\n/**\n * Cache of parsed env files keyed by `cwd|env|envFile`. Loading content\n * declarations calls `loadEnvFile` once per file; without this every call pays\n * up to 4 `existsSync` probes plus a dotenv read+parse. A cached hit is\n * validated with a single `stat` so edits to the env file are still picked up.\n */\nconst envFileCache = new Map<string, EnvFileCacheEntry>();\n\nconst parseEnvFile = (envFilePath: string): Record<string, string> => {\n const parsedEnv: Record<string, string> = {};\n\n dotenv.config({\n path: envFilePath,\n processEnv: parsedEnv,\n quiet: true,\n });\n\n return parsedEnv;\n};\n\nexport const loadEnvFile = (\n options?: Partial<LoadEnvFileOptions>\n): Record<string, string> => {\n const env = options?.env ?? DEFAULT_ENV;\n\n // Env file candidates are resolved relative to the working directory\n const cacheKey = `${process.cwd()}|${env}|${options?.envFile ?? ''}`;\n\n const cachedEntry = envFileCache.get(cacheKey);\n\n if (cachedEntry) {\n if (cachedEntry.envFilePath === undefined) {\n // No env file existed. Re-probe cheaply in case one was created since.\n const envFilePath = getEnvFilePath(env, options?.envFile);\n if (!envFilePath) return cachedEntry.parsedEnv;\n } else {\n try {\n const stats = statSync(cachedEntry.envFilePath);\n if (\n stats.mtimeMs === cachedEntry.mtimeMs &&\n stats.size === cachedEntry.size\n ) {\n return cachedEntry.parsedEnv;\n }\n } catch {\n // File was removed — fall through and re-resolve\n }\n }\n }\n\n const envFilePath = getEnvFilePath(env, options?.envFile);\n\n if (!envFilePath) {\n envFileCache.set(cacheKey, {\n envFilePath: undefined,\n mtimeMs: 0,\n size: 0,\n parsedEnv: {},\n });\n return {};\n }\n\n const parsedEnv = parseEnvFile(envFilePath);\n\n try {\n const stats = statSync(envFilePath);\n envFileCache.set(cacheKey, {\n envFilePath,\n mtimeMs: stats.mtimeMs,\n size: stats.size,\n parsedEnv,\n });\n } catch {\n // Race: file removed between parse and stat — skip caching this round\n }\n\n return parsedEnv; // Return the parsed env object\n};\n"],"mappings":";;;;AAGA,MAAM;AAON,MAAa,kBACX,qBACA,YACuB;CAKvB,QAJiB,UACb,CAAC,OAAO,IACR;EAAC,QAAQ,IAAI;EAAS,QAAQ;EAAO;EAAc;CAAM,EAE9C,CAAC,KAAK,UAAU;AACjC;;;;;;;AAkBA,MAAM,+BAAe,IAAI,IAA+B;AAExD,MAAM,gBAAgB,gBAAgD;CACpE,MAAM,YAAoC,CAAC;CAE3C,OAAO,OAAO;EACZ,MAAM;EACN,YAAY;EACZ,OAAO;CACT,CAAC;CAED,OAAO;AACT;AAEA,MAAa,eACX,YAC2B;CAC3B,MAAM,MAAM,SAAS,OAAO;CAG5B,MAAM,WAAW,GAAG,QAAQ,IAAI,EAAE,GAAG,IAAI,GAAG,SAAS,WAAW;CAEhE,MAAM,cAAc,aAAa,IAAI,QAAQ;CAE7C,IAAI,
|
|
1
|
+
{"version":3,"file":"loadEnvFile.mjs","names":[],"sources":["../../src/loadEnvFile.ts"],"sourcesContent":["import { existsSync, statSync } from 'node:fs';\nimport dotenv from 'dotenv';\n\nconst DEFAULT_ENV = process.env.NODE_ENV ?? 'development';\n\nexport type LoadEnvFileOptions = {\n env?: string;\n envFile?: string;\n};\n\nexport const getEnvFilePath = (\n env: string = process.env.NODE_ENV ?? 'development',\n envFile?: string\n): string | undefined => {\n const envFiles = envFile\n ? [envFile]\n : [`.env.${env}.local`, `.env.${env}`, '.env.local', '.env'];\n\n return envFiles.find(existsSync); // Returns the first existing env file\n};\n\ntype EnvFileCacheEntry = {\n /** The env file that was resolved and parsed (undefined if none exists). */\n envFilePath: string | undefined;\n /** Fingerprint of the parsed file, used to detect edits. */\n mtimeMs: number;\n size: number;\n /** The parsed env variables. */\n parsedEnv: Record<string, string>;\n};\n\n/**\n * Cache of parsed env files keyed by `cwd|env|envFile`. Loading content\n * declarations calls `loadEnvFile` once per file; without this every call pays\n * up to 4 `existsSync` probes plus a dotenv read+parse. A cached hit is\n * validated with a single `stat` so edits to the env file are still picked up.\n */\nconst envFileCache = new Map<string, EnvFileCacheEntry>();\n\nconst parseEnvFile = (envFilePath: string): Record<string, string> => {\n const parsedEnv: Record<string, string> = {};\n\n dotenv.config({\n path: envFilePath,\n processEnv: parsedEnv,\n quiet: true,\n });\n\n return parsedEnv;\n};\n\nexport const loadEnvFile = (\n options?: Partial<LoadEnvFileOptions>\n): Record<string, string> => {\n const env = options?.env ?? DEFAULT_ENV;\n\n // Env file candidates are resolved relative to the working directory\n const cacheKey = `${process.cwd()}|${env}|${options?.envFile ?? ''}`;\n\n const cachedEntry = envFileCache.get(cacheKey);\n\n if (cachedEntry) {\n if (cachedEntry.envFilePath === undefined) {\n // No env file existed. Re-probe cheaply in case one was created since.\n const envFilePath = getEnvFilePath(env, options?.envFile);\n if (!envFilePath) return cachedEntry.parsedEnv;\n } else {\n try {\n const stats = statSync(cachedEntry.envFilePath);\n if (\n stats.mtimeMs === cachedEntry.mtimeMs &&\n stats.size === cachedEntry.size\n ) {\n return cachedEntry.parsedEnv;\n }\n } catch {\n // File was removed — fall through and re-resolve\n }\n }\n }\n\n const envFilePath = getEnvFilePath(env, options?.envFile);\n\n if (!envFilePath) {\n envFileCache.set(cacheKey, {\n envFilePath: undefined,\n mtimeMs: 0,\n size: 0,\n parsedEnv: {},\n });\n return {};\n }\n\n const parsedEnv = parseEnvFile(envFilePath);\n\n try {\n const stats = statSync(envFilePath);\n envFileCache.set(cacheKey, {\n envFilePath,\n mtimeMs: stats.mtimeMs,\n size: stats.size,\n parsedEnv,\n });\n } catch {\n // Race: file removed between parse and stat — skip caching this round\n }\n\n return parsedEnv; // Return the parsed env object\n};\n"],"mappings":";;;;AAGA,MAAM;AAON,MAAa,kBACX,qBACA,YACuB;CAKvB,QAJiB,UACb,CAAC,OAAO,IACR;EAAC,QAAQ,IAAI;EAAS,QAAQ;EAAO;EAAc;CAAM,EAE9C,CAAC,KAAK,UAAU;AACjC;;;;;;;AAkBA,MAAM,+BAAe,IAAI,IAA+B;AAExD,MAAM,gBAAgB,gBAAgD;CACpE,MAAM,YAAoC,CAAC;CAE3C,OAAO,OAAO;EACZ,MAAM;EACN,YAAY;EACZ,OAAO;CACT,CAAC;CAED,OAAO;AACT;AAEA,MAAa,eACX,YAC2B;CAC3B,MAAM,MAAM,SAAS,OAAO;CAG5B,MAAM,WAAW,GAAG,QAAQ,IAAI,EAAE,GAAG,IAAI,GAAG,SAAS,WAAW;CAEhE,MAAM,cAAc,aAAa,IAAI,QAAQ;CAE7C,IAAI,aAAa;EACf,IAAI,YAAY,gBAAgB,QAG9B;OAAI,CADgB,eAAe,KAAK,SAAS,OAClC,GAAG,OAAO,YAAY;EAAS,OAE9C,IAAI;GACF,MAAM,QAAQ,SAAS,YAAY,WAAW;GAC9C,IACE,MAAM,YAAY,YAAY,WAC9B,MAAM,SAAS,YAAY,MAE3B,OAAO,YAAY;EAEvB,QAAQ,CAER;CAEJ;CAEA,MAAM,cAAc,eAAe,KAAK,SAAS,OAAO;CAExD,IAAI,CAAC,aAAa;EAChB,aAAa,IAAI,UAAU;GACzB,aAAa;GACb,SAAS;GACT,MAAM;GACN,WAAW,CAAC;EACd,CAAC;EACD,OAAO,CAAC;CACV;CAEA,MAAM,YAAY,aAAa,WAAW;CAE1C,IAAI;EACF,MAAM,QAAQ,SAAS,WAAW;EAClC,aAAa,IAAI,UAAU;GACzB;GACA,SAAS,MAAM;GACf,MAAM,MAAM;GACZ;EACF,CAAC;CACH,QAAQ,CAER;CAEA,OAAO;AACT"}
|
|
@@ -40,10 +40,11 @@ const getTransformationOptions = (filePath) => ({
|
|
|
40
40
|
});
|
|
41
41
|
const bundleFileSync = (code, filePath, options) => {
|
|
42
42
|
const extension = extname(filePath);
|
|
43
|
+
const loader = getLoader(extension);
|
|
43
44
|
return buildSync({
|
|
44
45
|
stdin: {
|
|
45
46
|
contents: code,
|
|
46
|
-
loader
|
|
47
|
+
loader,
|
|
47
48
|
resolveDir: dirname(filePath),
|
|
48
49
|
sourcefile: filePath
|
|
49
50
|
},
|
|
@@ -53,10 +54,11 @@ const bundleFileSync = (code, filePath, options) => {
|
|
|
53
54
|
};
|
|
54
55
|
const bundleFile = async (code, filePath, options) => {
|
|
55
56
|
const extension = extname(filePath);
|
|
57
|
+
const loader = getLoader(extension);
|
|
56
58
|
return (await build({
|
|
57
59
|
stdin: {
|
|
58
60
|
contents: code,
|
|
59
|
-
loader
|
|
61
|
+
loader,
|
|
60
62
|
resolveDir: dirname(filePath),
|
|
61
63
|
sourcefile: filePath
|
|
62
64
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundleFile.mjs","names":[],"sources":["../../../src/loadExternalFile/bundleFile.ts"],"sourcesContent":["import { dirname, extname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n build,\n buildSync,\n type Loader,\n type Plugin,\n} from 'esbuild';\n\nexport type ESBuildPlugin = Plugin;\n\nexport const getLoader = (extension: string): Loader => {\n switch (extension) {\n case '.js':\n return 'js';\n case '.jsx':\n return 'jsx';\n case '.mjs':\n return 'js';\n case '.ts':\n return 'ts';\n case '.tsx':\n return 'tsx';\n case '.cjs':\n return 'js';\n case '.json':\n return 'json';\n case '.md':\n return 'text';\n case '.mdx':\n return 'text';\n default:\n return 'js';\n }\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node16',\n platform: 'neutral',\n write: false,\n packages: 'bundle',\n external: ['esbuild'],\n bundle: true,\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n },\n});\n\nexport const bundleFileSync = (\n code: string,\n filePath: string,\n options?: BuildOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const moduleResult: BuildResult = buildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...options,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const bundleFile = async (\n code: string,\n filePath: string,\n options?: BuildOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const moduleResult: BuildResult = await build({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...options,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n"],"mappings":";;;;;AAaA,MAAa,aAAa,cAA8B;CACtD,QAAQ,WAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,UAAU,CAAC,SAAS;CACpB,QAAQ;CACR,QAAQ,EACN,mBAAmB,KAAK,UAAU,cAAc,QAAQ,CAAC,CAAC,IAAI,EAChE;AACF;AAEA,MAAa,kBACX,MACA,UACA,YACuB;CACvB,MAAM,YAAY,QAAQ,QAAQ;
|
|
1
|
+
{"version":3,"file":"bundleFile.mjs","names":[],"sources":["../../../src/loadExternalFile/bundleFile.ts"],"sourcesContent":["import { dirname, extname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n build,\n buildSync,\n type Loader,\n type Plugin,\n} from 'esbuild';\n\nexport type ESBuildPlugin = Plugin;\n\nexport const getLoader = (extension: string): Loader => {\n switch (extension) {\n case '.js':\n return 'js';\n case '.jsx':\n return 'jsx';\n case '.mjs':\n return 'js';\n case '.ts':\n return 'ts';\n case '.tsx':\n return 'tsx';\n case '.cjs':\n return 'js';\n case '.json':\n return 'json';\n case '.md':\n return 'text';\n case '.mdx':\n return 'text';\n default:\n return 'js';\n }\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node16',\n platform: 'neutral',\n write: false,\n packages: 'bundle',\n external: ['esbuild'],\n bundle: true,\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n },\n});\n\nexport const bundleFileSync = (\n code: string,\n filePath: string,\n options?: BuildOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const moduleResult: BuildResult = buildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...options,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n\nexport const bundleFile = async (\n code: string,\n filePath: string,\n options?: BuildOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const moduleResult: BuildResult = await build({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...options,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0].text;\n\n return moduleResultString;\n};\n"],"mappings":";;;;;AAaA,MAAa,aAAa,cAA8B;CACtD,QAAQ,WAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,4BAA4B,cAAoC;CACpE,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,OAAO;CACP,UAAU;CACV,UAAU,CAAC,SAAS;CACpB,QAAQ;CACR,QAAQ,EACN,mBAAmB,KAAK,UAAU,cAAc,QAAQ,CAAC,CAAC,IAAI,EAChE;AACF;AAEA,MAAa,kBACX,MACA,UACA,YACuB;CACvB,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,SAAS,UAAU,SAAS;CAelC,OAbkC,UAAU;EAC1C,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,QAAQ;GAC5B,YAAY;EACd;EACA,GAAG,yBAAyB,QAAQ;EACpC,GAAG;CACL,CAEsC,CAAC,CAAC,cAAc,EAAE,CAAC;AAG3D;AAEA,MAAa,aAAa,OACxB,MACA,UACA,YACgC;CAChC,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,SAAS,UAAU,SAAS;CAelC,QAF2B,MAXa,MAAM;EAC5C,OAAO;GACL,UAAU;GACV;GACA,YAAY,QAAQ,QAAQ;GAC5B,YAAY;EACd;EACA,GAAG,yBAAyB,QAAQ;EACpC,GAAG;CACL,CAAC,EAEsC,CAAC,cAAc,EAAE,CAAC;AAG3D"}
|
|
@@ -17,7 +17,8 @@ const loadExternalFileSync = (filePath, options) => {
|
|
|
17
17
|
const fileExtension = extname(filePath) || ".json";
|
|
18
18
|
try {
|
|
19
19
|
if (fileExtension === ".json" || fileExtension === ".json5" || fileExtension === ".jsonc") return parseJSON5(readFileSync(filePath, "utf-8"));
|
|
20
|
-
const
|
|
20
|
+
const code = readFileSync(filePath, "utf-8");
|
|
21
|
+
const moduleResultString = transpileTSToCJSSync(code, filePath, options?.buildOptions);
|
|
21
22
|
if (!moduleResultString) {
|
|
22
23
|
logger("File could not be loaded.", { level: "error" });
|
|
23
24
|
return;
|
|
@@ -67,7 +68,8 @@ const loadExternalFile = async (filePath, options) => {
|
|
|
67
68
|
const fileContent = await readFile(filePath, "utf-8");
|
|
68
69
|
return parseJSON5(fileContent);
|
|
69
70
|
}
|
|
70
|
-
const
|
|
71
|
+
const code = await readFile(filePath, "utf-8");
|
|
72
|
+
const moduleResultString = await transpileTSToCJS(code, filePath, options?.buildOptions);
|
|
71
73
|
if (!moduleResultString) {
|
|
72
74
|
logger("File could not be loaded.", { level: "error" });
|
|
73
75
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadExternalFile.mjs","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n /**\n * Key-value pairs to temporarily set on the main Node.js `globalThis` for the\n * synchronous duration of `parseFileContent` / `runInNewContext`. External modules\n * loaded via `require()` inside the VM (e.g. `@intlayer/core`'s `file()` helper)\n * run in the main context and read from the real `globalThis`, not the VM sandbox.\n * Values are restored (or deleted) after `runInNewContext` returns.\n */\n preloadGlobals?: Record<string, unknown>;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // fully restores the globals before returning.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\nconst withPreloadedGlobals = <T>(\n globals: Record<string, unknown> | undefined,\n fn: () => T\n): T => {\n if (!globals) return fn();\n\n const globalVars = globalThis as Record<string, unknown>;\n const previousValues: Record<string, unknown> = {};\n const previouslyPresent: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(globals)) {\n previouslyPresent[key] = key in globalVars;\n previousValues[key] = globalVars[key];\n globalVars[key] = value;\n }\n\n try {\n return fn();\n } finally {\n for (const key of Object.keys(globals)) {\n // `in` check (not `!== undefined`) so a global that legitimately held\n // `undefined` is restored rather than deleted.\n if (previouslyPresent[key]) {\n globalVars[key] = previousValues[key];\n } else {\n delete globalVars[key];\n }\n }\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // has no interleaving risk even when multiple files are processed concurrently.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;AAiBA,MAAM,aAAa,MAAM,SAAU,MAAc,SAAS;;;;;;AAqB1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,gBAAgB,QAAQ,QAAQ,KAAK;CAE3C,IAAI;EACF,IACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,UAGlB,OAAO,WAAW,aAAa,UAAU,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"loadExternalFile.mjs","names":[],"sources":["../../../src/loadExternalFile/loadExternalFile.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport JSON5 from 'json5';\nimport { colorizePath, logger } from '../logger';\nimport {\n parseFileContent,\n type SandBoxContextOptions,\n} from './parseFileContent';\nimport {\n type TranspileOptions,\n transpileTSToCJS,\n transpileTSToCJSSync,\n} from './transpileTSToCJS';\n\n// CJS MJS cross usage\nconst parseJSON5 = JSON5.parse || (JSON5 as any).default?.parse;\n\nexport type LoadExternalFileOptions = {\n configuration?: IntlayerConfig;\n buildOptions?: TranspileOptions;\n logError?: boolean;\n /**\n * Key-value pairs to temporarily set on the main Node.js `globalThis` for the\n * synchronous duration of `parseFileContent` / `runInNewContext`. External modules\n * loaded via `require()` inside the VM (e.g. `@intlayer/core`'s `file()` helper)\n * run in the main context and read from the real `globalThis`, not the VM sandbox.\n * Values are restored (or deleted) after `runInNewContext` returns.\n */\n preloadGlobals?: Record<string, unknown>;\n} & SandBoxContextOptions;\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFileSync = (\n filePath: string,\n options?: LoadExternalFileOptions\n): any | undefined => {\n const fileExtension = extname(filePath) || '.json';\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Assume JSON\n return parseJSON5(readFileSync(filePath, 'utf-8'));\n }\n\n // Rest is JS, MJS or TS\n const code = readFileSync(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = transpileTSToCJSSync(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // fully restores the globals before returning.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${filePath}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n};\n\nconst withPreloadedGlobals = <T>(\n globals: Record<string, unknown> | undefined,\n fn: () => T\n): T => {\n if (!globals) return fn();\n\n const globalVars = globalThis as Record<string, unknown>;\n const previousValues: Record<string, unknown> = {};\n const previouslyPresent: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(globals)) {\n previouslyPresent[key] = key in globalVars;\n previousValues[key] = globalVars[key];\n globalVars[key] = value;\n }\n\n try {\n return fn();\n } finally {\n for (const key of Object.keys(globals)) {\n // `in` check (not `!== undefined`) so a global that legitimately held\n // `undefined` is restored rather than deleted.\n if (previouslyPresent[key]) {\n globalVars[key] = previousValues[key];\n } else {\n delete globalVars[key];\n }\n }\n }\n};\n\n/**\n * Load the content declaration from the given path\n *\n * Accepts JSON, JS, MJS and TS files as configuration\n */\nexport const loadExternalFile = async (\n filePath: string,\n options?: LoadExternalFileOptions\n): Promise<any | undefined> => {\n const fileExtension = extname(filePath);\n\n try {\n if (\n fileExtension === '.json' ||\n fileExtension === '.json5' ||\n fileExtension === '.jsonc'\n ) {\n // Remove cache to force getting fresh content\n const fileContent = await readFile(filePath, 'utf-8');\n return parseJSON5(fileContent);\n }\n\n // Rest is JS, MJS or TS\n const code = await readFile(filePath, 'utf-8');\n\n const moduleResultString: string | undefined = await transpileTSToCJS(\n code,\n filePath,\n options?.buildOptions\n );\n\n if (!moduleResultString) {\n logger('File could not be loaded.', { level: 'error' });\n return undefined;\n }\n\n // parseFileContent/runInNewContext is synchronous, so withPreloadedGlobals\n // has no interleaving risk even when multiple files are processed concurrently.\n const fileContent = withPreloadedGlobals(options?.preloadGlobals, () =>\n parseFileContent(moduleResultString, {\n projectRequire: options?.projectRequire,\n envVarOptions: options?.envVarOptions,\n additionalEnvVars: options?.additionalEnvVars,\n mocks: options?.mocks,\n aliases: options?.aliases,\n })\n );\n\n if (typeof fileContent === 'undefined') {\n logger(`File could not be loaded. Path : ${colorizePath(filePath)}`);\n return undefined;\n }\n\n return fileContent;\n } catch (error) {\n if (options?.logError ?? true) {\n logger(\n [\n `Error: ${(error as Error).message} - `,\n JSON.stringify((error as Error).stack, null, 2),\n ],\n {\n level: 'error',\n }\n );\n }\n }\n};\n"],"mappings":";;;;;;;;;AAiBA,MAAM,aAAa,MAAM,SAAU,MAAc,SAAS;;;;;;AAqB1D,MAAa,wBACX,UACA,YACoB;CACpB,MAAM,gBAAgB,QAAQ,QAAQ,KAAK;CAE3C,IAAI;EACF,IACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,UAGlB,OAAO,WAAW,aAAa,UAAU,OAAO,CAAC;EAInD,MAAM,OAAO,aAAa,UAAU,OAAO;EAE3C,MAAM,qBAAyC,qBAC7C,MACA,UACA,SAAS,YACX;EAEA,IAAI,CAAC,oBAAoB;GACvB,OAAO,6BAA6B,EAAE,OAAO,QAAQ,CAAC;GACtD;EACF;EAIA,MAAM,cAAc,qBAAqB,SAAS,sBAChD,iBAAiB,oBAAoB;GACnC,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;EACpB,CAAC,CACH;EAEA,IAAI,OAAO,gBAAgB,aAAa;GACtC,OAAO,oCAAoC,UAAU;GACrD;EACF;EAEA,OAAO;CACT,SAAS,OAAO;EACd,OACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,CAAC,CAChD,GACA,EACE,OAAO,QACT,CACF;CACF;AACF;AAEA,MAAM,wBACJ,SACA,OACM;CACN,IAAI,CAAC,SAAS,OAAO,GAAG;CAExB,MAAM,aAAa;CACnB,MAAM,iBAA0C,CAAC;CACjD,MAAM,oBAA6C,CAAC;CAEpD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAAG;EAClD,kBAAkB,OAAO,OAAO;EAChC,eAAe,OAAO,WAAW;EACjC,WAAW,OAAO;CACpB;CAEA,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,GAGnC,IAAI,kBAAkB,MACpB,WAAW,OAAO,eAAe;OAEjC,OAAO,WAAW;CAGxB;AACF;;;;;;AAOA,MAAa,mBAAmB,OAC9B,UACA,YAC6B;CAC7B,MAAM,gBAAgB,QAAQ,QAAQ;CAEtC,IAAI;EACF,IACE,kBAAkB,WAClB,kBAAkB,YAClB,kBAAkB,UAClB;GAEA,MAAM,cAAc,MAAM,SAAS,UAAU,OAAO;GACpD,OAAO,WAAW,WAAW;EAC/B;EAGA,MAAM,OAAO,MAAM,SAAS,UAAU,OAAO;EAE7C,MAAM,qBAAyC,MAAM,iBACnD,MACA,UACA,SAAS,YACX;EAEA,IAAI,CAAC,oBAAoB;GACvB,OAAO,6BAA6B,EAAE,OAAO,QAAQ,CAAC;GACtD;EACF;EAIA,MAAM,cAAc,qBAAqB,SAAS,sBAChD,iBAAiB,oBAAoB;GACnC,gBAAgB,SAAS;GACzB,eAAe,SAAS;GACxB,mBAAmB,SAAS;GAC5B,OAAO,SAAS;GAChB,SAAS,SAAS;EACpB,CAAC,CACH;EAEA,IAAI,OAAO,gBAAgB,aAAa;GACtC,OAAO,oCAAoC,aAAa,QAAQ,GAAG;GACnE;EACF;EAEA,OAAO;CACT,SAAS,OAAO;EACd,IAAI,SAAS,YAAY,MACvB,OACE,CACE,UAAW,MAAgB,QAAQ,MACnC,KAAK,UAAW,MAAgB,OAAO,MAAM,CAAC,CAChD,GACA,EACE,OAAO,QACT,CACF;CAEJ;AACF"}
|
|
@@ -117,7 +117,8 @@ const clearTranspileCache = () => {
|
|
|
117
117
|
tsConfigPathCache.clear();
|
|
118
118
|
};
|
|
119
119
|
const transpileTSToCJSSync = (code, filePath, options) => {
|
|
120
|
-
const
|
|
120
|
+
const extension = extname(filePath);
|
|
121
|
+
const loader = getLoader(extension);
|
|
121
122
|
const { esbuildInstance, ...buildOptions } = options ?? {};
|
|
122
123
|
const codeHash = computeKeyId([code]);
|
|
123
124
|
const optionsKey = computeKeyId([buildOptions]);
|
|
@@ -158,7 +159,8 @@ const transpileTSToCJSSync = (code, filePath, options) => {
|
|
|
158
159
|
return moduleResultString;
|
|
159
160
|
};
|
|
160
161
|
const transpileTSToCJS = async (code, filePath, options) => {
|
|
161
|
-
const
|
|
162
|
+
const extension = extname(filePath);
|
|
163
|
+
const loader = getLoader(extension);
|
|
162
164
|
const { esbuildInstance, ...buildOptions } = options ?? {};
|
|
163
165
|
const codeHash = computeKeyId([code]);
|
|
164
166
|
const optionsKey = computeKeyId([buildOptions]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transpileTSToCJS.mjs","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync, statSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, extname, isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n build,\n buildSync,\n type Metafile,\n} from 'esbuild';\nimport { computeKeyId } from '../utils/cacheMemory';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\n/**\n * Cache of resolved tsconfig paths keyed by the file's directory.\n * Avoids re-walking to package.json + existsSync on every transpilation.\n */\nconst tsConfigPathCache = new Map<string, string | undefined>();\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const fileDirectory = dirname(filePath);\n\n if (tsConfigPathCache.has(fileDirectory)) {\n return tsConfigPathCache.get(fileDirectory);\n }\n\n let resolvedPath: string | undefined;\n try {\n const tsconfigPath = join(\n getPackageJsonPath(fileDirectory).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n resolvedPath = existsSync(tsconfigPath) ? tsconfigPath : undefined;\n } catch {\n // No package.json found up the tree — transpile without a tsconfig\n resolvedPath = undefined;\n }\n\n tsConfigPathCache.set(fileDirectory, resolvedPath);\n\n return resolvedPath;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n // The metafile lists every bundled input, which the transpile cache uses to\n // invalidate when an imported file changes (the entry itself is keyed by hash).\n metafile: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\n/** Fingerprint of a bundled input file, used to detect changes without re-reading it. */\ntype TranspileCacheInput = {\n path: string;\n mtimeMs: number;\n size: number;\n};\n\ntype TranspileCacheEntry = {\n /** Hash of the entry file's source code. */\n codeHash: string;\n /** Hash of the build options, so different option sets don't collide. */\n optionsKey: string;\n /** The transpiled CJS output. */\n output: string;\n /** Fingerprints of every non-entry input bundled into the output. */\n inputs: TranspileCacheInput[];\n};\n\n/**\n * In-memory cache of transpiled outputs keyed by entry file path (one entry\n * per file, so re-transpilations replace rather than accumulate).\n * The entry file is validated by content hash; bundled relative imports are\n * validated by mtime + size so an edited dependency invalidates the cache.\n */\nconst transpileCache = new Map<string, TranspileCacheEntry>();\n\nconst isInputUnchanged = (input: TranspileCacheInput): boolean => {\n try {\n const stats = statSync(input.path);\n return stats.mtimeMs === input.mtimeMs && stats.size === input.size;\n } catch {\n // File removed or unreadable — treat as changed\n return false;\n }\n};\n\nconst getCachedTranspilation = (\n filePath: string,\n codeHash: string,\n optionsKey: string\n): string | undefined => {\n const cacheEntry = transpileCache.get(filePath);\n\n if (!cacheEntry) return undefined;\n if (cacheEntry.codeHash !== codeHash) return undefined;\n if (cacheEntry.optionsKey !== optionsKey) return undefined;\n if (!cacheEntry.inputs.every(isInputUnchanged)) return undefined;\n\n return cacheEntry.output;\n};\n\n/**\n * Extracts the fingerprints of every bundled input from the esbuild metafile.\n * Returns `undefined` when an input cannot be fingerprinted (the result should\n * then not be cached, as invalidation would be unreliable).\n */\nconst getInputFingerprints = (\n metafile: Metafile | undefined,\n entryFilePath: string\n): TranspileCacheInput[] | undefined => {\n if (!metafile) return undefined;\n\n const resolvedEntryFilePath = resolve(entryFilePath);\n const inputs: TranspileCacheInput[] = [];\n\n for (const inputPath of Object.keys(metafile.inputs)) {\n // The entry itself is provided via stdin and validated by content hash.\n // esbuild labels it \"<stdin>\", or with the sourcefile path when set.\n if (inputPath === '<stdin>') continue;\n // Virtual modules from plugins (e.g. \"plugin:...\") cannot be fingerprinted\n if (inputPath.includes(':') && !isAbsolute(inputPath)) return undefined;\n\n const absoluteInputPath = isAbsolute(inputPath)\n ? inputPath\n : resolve(process.cwd(), inputPath);\n\n if (absoluteInputPath === resolvedEntryFilePath) continue;\n\n try {\n const stats = statSync(absoluteInputPath);\n inputs.push({\n path: absoluteInputPath,\n mtimeMs: stats.mtimeMs,\n size: stats.size,\n });\n } catch {\n return undefined;\n }\n }\n\n return inputs;\n};\n\nconst setCachedTranspilation = (\n filePath: string,\n codeHash: string,\n optionsKey: string,\n moduleResult: BuildResult,\n output: string\n): void => {\n const inputs = getInputFingerprints(moduleResult.metafile, filePath);\n\n // Without a usable metafile the cache cannot be invalidated reliably — skip\n if (!inputs) return;\n\n transpileCache.set(filePath, { codeHash, optionsKey, output, inputs });\n};\n\n/** Clears the in-memory transpilation cache (mainly for tests). */\nexport const clearTranspileCache = (): void => {\n transpileCache.clear();\n tsConfigPathCache.clear();\n};\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n\n const codeHash = computeKeyId([code]);\n const optionsKey = computeKeyId([buildOptions]);\n\n const cachedOutput = getCachedTranspilation(filePath, codeHash, optionsKey);\n if (typeof cachedOutput === 'string') return cachedOutput;\n\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n // esbuild's worker thread service calls `new Worker(__filename, …)` on first use.\n // In Vite's SSR module runner the SSR-optimised chunk is ESM and __filename is\n // never declared (confirmed: accessing it throws ReferenceError, not undefined).\n // Because there is no local declaration the bare `__filename` lookup falls\n // through to globalThis, so we set it there to esbuild's own CJS entry-point –\n // the exact path esbuild would use if it were loaded in a normal CJS context.\n //\n // IMPORTANT: We save/restore the globals so this temporary shim does not leak\n // to other Vite plugins (e.g. `@vitejs/plugin-react-swc`) that check\n // `typeof __dirname !== \"undefined\"` to locate their own assets.\n const g = globalThis as Record<string, unknown>;\n const hadFilename = typeof g.__filename === 'string';\n const prevFilename = g.__filename;\n const prevDirname = g.__dirname;\n\n if (!hadFilename) {\n try {\n const _require = createRequire(import.meta.url);\n const esbuildEntry = _require.resolve('esbuild');\n g.__filename = esbuildEntry;\n g.__dirname = dirname(esbuildEntry);\n } catch {\n // Best-effort: if esbuild can't be resolved the caller's catch handles it\n }\n }\n\n let moduleResult: BuildResult;\n try {\n moduleResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n } finally {\n // Always restore the previous values so the globals don't linger.\n if (!hadFilename) {\n if (prevFilename === undefined) {\n // biome-ignore lint/performance/noDelete: the global must be truly absent — assigning undefined would leave the key present and break `typeof __filename` checks in other tools\n delete g.__filename;\n } else {\n g.__filename = prevFilename;\n }\n if (prevDirname === undefined) {\n // biome-ignore lint/performance/noDelete: same as __filename above\n delete g.__dirname;\n } else {\n g.__dirname = prevDirname;\n }\n }\n }\n\n const moduleResultString = moduleResult!.outputFiles?.[0]?.text;\n\n if (typeof moduleResultString === 'string') {\n setCachedTranspilation(\n filePath,\n codeHash,\n optionsKey,\n moduleResult!,\n moduleResultString\n );\n }\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n\n const codeHash = computeKeyId([code]);\n const optionsKey = computeKeyId([buildOptions]);\n\n const cachedOutput = getCachedTranspilation(filePath, codeHash, optionsKey);\n if (typeof cachedOutput === 'string') return cachedOutput;\n\n // A one-shot build() releases its Go-side resources on completion and costs a\n // single service round-trip (context()+rebuild()+dispose() costs three).\n const esbuildBuild = esbuildInstance?.build ?? build;\n\n const moduleResult = await esbuildBuild({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath),\n sourcefile: filePath,\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0]?.text;\n\n if (typeof moduleResultString === 'string') {\n setCachedTranspilation(\n filePath,\n codeHash,\n optionsKey,\n moduleResult,\n moduleResultString\n );\n }\n\n return moduleResultString;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transpileTSToCJS.mjs","names":[],"sources":["../../../src/loadExternalFile/transpileTSToCJS.ts"],"sourcesContent":["import { existsSync, statSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, extname, isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n type BuildOptions,\n type BuildResult,\n build,\n buildSync,\n type Metafile,\n} from 'esbuild';\nimport { computeKeyId } from '../utils/cacheMemory';\nimport { getPackageJsonPath } from '../utils/getPackageJsonPath';\nimport { getLoader } from './bundleFile';\n\nexport type TranspileOptions = BuildOptions & {\n /**\n * Optional custom esbuild instance to use for transpilation.\n * Useful in environments (e.g. VS Code extensions) where the bundled\n * esbuild binary may not match the host platform.\n * When provided, its `buildSync`/`build` methods are used instead of\n * the ones imported from the `esbuild` package.\n */\n esbuildInstance?: typeof import('esbuild');\n};\n\n/**\n * Cache of resolved tsconfig paths keyed by the file's directory.\n * Avoids re-walking to package.json + existsSync on every transpilation.\n */\nconst tsConfigPathCache = new Map<string, string | undefined>();\n\nconst getTsConfigPath = (filePath: string): string | undefined => {\n const fileDirectory = dirname(filePath);\n\n if (tsConfigPathCache.has(fileDirectory)) {\n return tsConfigPathCache.get(fileDirectory);\n }\n\n let resolvedPath: string | undefined;\n try {\n const tsconfigPath = join(\n getPackageJsonPath(fileDirectory).baseDir,\n 'tsconfig.json'\n );\n\n // Only return the tsconfig path if it exists\n resolvedPath = existsSync(tsconfigPath) ? tsconfigPath : undefined;\n } catch {\n // No package.json found up the tree — transpile without a tsconfig\n resolvedPath = undefined;\n }\n\n tsConfigPathCache.set(fileDirectory, resolvedPath);\n\n return resolvedPath;\n};\n\nconst getTransformationOptions = (filePath: string): BuildOptions => ({\n loader: {\n '.js': 'js',\n '.jsx': 'jsx',\n '.mjs': 'js',\n '.ts': 'ts',\n '.tsx': 'tsx',\n '.cjs': 'js',\n '.json': 'json',\n '.md': 'text',\n '.mdx': 'text',\n },\n format: 'cjs',\n target: 'node20',\n platform: 'node',\n write: false,\n packages: 'external',\n bundle: true,\n // The metafile lists every bundled input, which the transpile cache uses to\n // invalidate when an imported file changes (the entry itself is keyed by hash).\n metafile: true,\n tsconfig: getTsConfigPath(filePath),\n define: {\n 'import.meta.url': JSON.stringify(pathToFileURL(filePath).href),\n 'import.meta.env': 'process.env',\n },\n});\n\n/** Fingerprint of a bundled input file, used to detect changes without re-reading it. */\ntype TranspileCacheInput = {\n path: string;\n mtimeMs: number;\n size: number;\n};\n\ntype TranspileCacheEntry = {\n /** Hash of the entry file's source code. */\n codeHash: string;\n /** Hash of the build options, so different option sets don't collide. */\n optionsKey: string;\n /** The transpiled CJS output. */\n output: string;\n /** Fingerprints of every non-entry input bundled into the output. */\n inputs: TranspileCacheInput[];\n};\n\n/**\n * In-memory cache of transpiled outputs keyed by entry file path (one entry\n * per file, so re-transpilations replace rather than accumulate).\n * The entry file is validated by content hash; bundled relative imports are\n * validated by mtime + size so an edited dependency invalidates the cache.\n */\nconst transpileCache = new Map<string, TranspileCacheEntry>();\n\nconst isInputUnchanged = (input: TranspileCacheInput): boolean => {\n try {\n const stats = statSync(input.path);\n return stats.mtimeMs === input.mtimeMs && stats.size === input.size;\n } catch {\n // File removed or unreadable — treat as changed\n return false;\n }\n};\n\nconst getCachedTranspilation = (\n filePath: string,\n codeHash: string,\n optionsKey: string\n): string | undefined => {\n const cacheEntry = transpileCache.get(filePath);\n\n if (!cacheEntry) return undefined;\n if (cacheEntry.codeHash !== codeHash) return undefined;\n if (cacheEntry.optionsKey !== optionsKey) return undefined;\n if (!cacheEntry.inputs.every(isInputUnchanged)) return undefined;\n\n return cacheEntry.output;\n};\n\n/**\n * Extracts the fingerprints of every bundled input from the esbuild metafile.\n * Returns `undefined` when an input cannot be fingerprinted (the result should\n * then not be cached, as invalidation would be unreliable).\n */\nconst getInputFingerprints = (\n metafile: Metafile | undefined,\n entryFilePath: string\n): TranspileCacheInput[] | undefined => {\n if (!metafile) return undefined;\n\n const resolvedEntryFilePath = resolve(entryFilePath);\n const inputs: TranspileCacheInput[] = [];\n\n for (const inputPath of Object.keys(metafile.inputs)) {\n // The entry itself is provided via stdin and validated by content hash.\n // esbuild labels it \"<stdin>\", or with the sourcefile path when set.\n if (inputPath === '<stdin>') continue;\n // Virtual modules from plugins (e.g. \"plugin:...\") cannot be fingerprinted\n if (inputPath.includes(':') && !isAbsolute(inputPath)) return undefined;\n\n const absoluteInputPath = isAbsolute(inputPath)\n ? inputPath\n : resolve(process.cwd(), inputPath);\n\n if (absoluteInputPath === resolvedEntryFilePath) continue;\n\n try {\n const stats = statSync(absoluteInputPath);\n inputs.push({\n path: absoluteInputPath,\n mtimeMs: stats.mtimeMs,\n size: stats.size,\n });\n } catch {\n return undefined;\n }\n }\n\n return inputs;\n};\n\nconst setCachedTranspilation = (\n filePath: string,\n codeHash: string,\n optionsKey: string,\n moduleResult: BuildResult,\n output: string\n): void => {\n const inputs = getInputFingerprints(moduleResult.metafile, filePath);\n\n // Without a usable metafile the cache cannot be invalidated reliably — skip\n if (!inputs) return;\n\n transpileCache.set(filePath, { codeHash, optionsKey, output, inputs });\n};\n\n/** Clears the in-memory transpilation cache (mainly for tests). */\nexport const clearTranspileCache = (): void => {\n transpileCache.clear();\n tsConfigPathCache.clear();\n};\n\nexport const transpileTSToCJSSync = (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): string | undefined => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n\n const codeHash = computeKeyId([code]);\n const optionsKey = computeKeyId([buildOptions]);\n\n const cachedOutput = getCachedTranspilation(filePath, codeHash, optionsKey);\n if (typeof cachedOutput === 'string') return cachedOutput;\n\n const esbuildBuildSync = esbuildInstance?.buildSync ?? buildSync;\n\n // esbuild's worker thread service calls `new Worker(__filename, …)` on first use.\n // In Vite's SSR module runner the SSR-optimised chunk is ESM and __filename is\n // never declared (confirmed: accessing it throws ReferenceError, not undefined).\n // Because there is no local declaration the bare `__filename` lookup falls\n // through to globalThis, so we set it there to esbuild's own CJS entry-point –\n // the exact path esbuild would use if it were loaded in a normal CJS context.\n //\n // IMPORTANT: We save/restore the globals so this temporary shim does not leak\n // to other Vite plugins (e.g. `@vitejs/plugin-react-swc`) that check\n // `typeof __dirname !== \"undefined\"` to locate their own assets.\n const g = globalThis as Record<string, unknown>;\n const hadFilename = typeof g.__filename === 'string';\n const prevFilename = g.__filename;\n const prevDirname = g.__dirname;\n\n if (!hadFilename) {\n try {\n const _require = createRequire(import.meta.url);\n const esbuildEntry = _require.resolve('esbuild');\n g.__filename = esbuildEntry;\n g.__dirname = dirname(esbuildEntry);\n } catch {\n // Best-effort: if esbuild can't be resolved the caller's catch handles it\n }\n }\n\n let moduleResult: BuildResult;\n try {\n moduleResult = esbuildBuildSync({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath), // Add resolveDir to resolve imports relative to the file's location\n sourcefile: filePath, // Add sourcefile for better error messages\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n } finally {\n // Always restore the previous values so the globals don't linger.\n if (!hadFilename) {\n if (prevFilename === undefined) {\n // biome-ignore lint/performance/noDelete: the global must be truly absent — assigning undefined would leave the key present and break `typeof __filename` checks in other tools\n delete g.__filename;\n } else {\n g.__filename = prevFilename;\n }\n if (prevDirname === undefined) {\n // biome-ignore lint/performance/noDelete: same as __filename above\n delete g.__dirname;\n } else {\n g.__dirname = prevDirname;\n }\n }\n }\n\n const moduleResultString = moduleResult!.outputFiles?.[0]?.text;\n\n if (typeof moduleResultString === 'string') {\n setCachedTranspilation(\n filePath,\n codeHash,\n optionsKey,\n moduleResult!,\n moduleResultString\n );\n }\n\n return moduleResultString;\n};\n\nexport const transpileTSToCJS = async (\n code: string,\n filePath: string,\n options?: TranspileOptions\n): Promise<string | undefined> => {\n const extension = extname(filePath);\n const loader = getLoader(extension);\n\n const { esbuildInstance, ...buildOptions } = options ?? {};\n\n const codeHash = computeKeyId([code]);\n const optionsKey = computeKeyId([buildOptions]);\n\n const cachedOutput = getCachedTranspilation(filePath, codeHash, optionsKey);\n if (typeof cachedOutput === 'string') return cachedOutput;\n\n // A one-shot build() releases its Go-side resources on completion and costs a\n // single service round-trip (context()+rebuild()+dispose() costs three).\n const esbuildBuild = esbuildInstance?.build ?? build;\n\n const moduleResult = await esbuildBuild({\n stdin: {\n contents: code,\n loader,\n resolveDir: dirname(filePath),\n sourcefile: filePath,\n },\n ...getTransformationOptions(filePath),\n ...buildOptions,\n });\n\n const moduleResultString = moduleResult.outputFiles?.[0]?.text;\n\n if (typeof moduleResultString === 'string') {\n setCachedTranspilation(\n filePath,\n codeHash,\n optionsKey,\n moduleResult,\n moduleResultString\n );\n }\n\n return moduleResultString;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ESMxCJSHelpers.mjs","names":[],"sources":["../../../src/utils/ESMxCJSHelpers.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { getPackageJsonPath } from './getPackageJsonPath';\n\nexport const isESModule = typeof import.meta.url === 'string';\n\n/**\n * Require relative to the user project\n *\n * Note: Can resolve package that are installed in the user project, ex `'intlayer'`\n */\nexport const getProjectRequire = (startDir?: string): NodeJS.Require => {\n // Can fail on VSCode extensions\n const { packageJsonPath } = getPackageJsonPath(startDir);\n\n return createRequire(packageJsonPath);\n};\n\n/**\n * Require relative to the @intlayer/config package\n *\n * Note: Can resolve package that are installed in the config package, ex `'@intlayer/types'`\n */\nexport const configESMxCJSRequire: NodeJS.Require = isESModule\n ? createRequire(import.meta.url)\n : require;\n"],"mappings":";;;;;AAGA,MAAa,aAAa,OAAO,
|
|
1
|
+
{"version":3,"file":"ESMxCJSHelpers.mjs","names":[],"sources":["../../../src/utils/ESMxCJSHelpers.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { getPackageJsonPath } from './getPackageJsonPath';\n\nexport const isESModule = typeof import.meta.url === 'string';\n\n/**\n * Require relative to the user project\n *\n * Note: Can resolve package that are installed in the user project, ex `'intlayer'`\n */\nexport const getProjectRequire = (startDir?: string): NodeJS.Require => {\n // Can fail on VSCode extensions\n const { packageJsonPath } = getPackageJsonPath(startDir);\n\n return createRequire(packageJsonPath);\n};\n\n/**\n * Require relative to the @intlayer/config package\n *\n * Note: Can resolve package that are installed in the config package, ex `'@intlayer/types'`\n */\nexport const configESMxCJSRequire: NodeJS.Require = isESModule\n ? createRequire(import.meta.url)\n : require;\n"],"mappings":";;;;;AAGA,MAAa,aAAa,OAAO,YAAY,QAAQ;;;;;;AAOrD,MAAa,qBAAqB,aAAsC;CAEtE,MAAM,EAAE,oBAAoB,mBAAmB,QAAQ;CAEvD,OAAO,cAAc,eAAe;AACtC;;;;;;AAOA,MAAa,uBAAuC,aAChD,cAAc,YAAY,GAAG"}
|
package/dist/esm/utils/alias.mjs
CHANGED
|
@@ -7,13 +7,48 @@ const getAlias = ({ configuration, format, formatter = (value) => value }) => {
|
|
|
7
7
|
const extension = getExtension(configuration, format ?? configuration.build.outputFormat[0] ?? "esm");
|
|
8
8
|
const { baseDir } = configuration.system;
|
|
9
9
|
const { mainDir, configDir } = configuration.system;
|
|
10
|
+
/**
|
|
11
|
+
* Dictionaries
|
|
12
|
+
*/
|
|
13
|
+
const dictionariesPath = join(mainDir, `dictionaries.${extension}`);
|
|
14
|
+
const relativeDictionariesPath = relative(baseDir, dictionariesPath);
|
|
15
|
+
const fixedDictionariesPath = formatter(normalizePath(relativeDictionariesPath));
|
|
16
|
+
/**
|
|
17
|
+
* Unmerged dictionaries
|
|
18
|
+
*/
|
|
19
|
+
const unmergedDictionariesPath = join(mainDir, `unmerged_dictionaries.${extension}`);
|
|
20
|
+
const relativeUnmergedDictionariesPath = relative(baseDir, unmergedDictionariesPath);
|
|
21
|
+
const fixedUnmergedDictionariesPath = formatter(normalizePath(relativeUnmergedDictionariesPath));
|
|
22
|
+
/**
|
|
23
|
+
* Remote dictionaries
|
|
24
|
+
*/
|
|
25
|
+
const remoteDictionariesPath = join(mainDir, `remote_dictionaries.${extension}`);
|
|
26
|
+
const relativeRemoteDictionariesPath = relative(baseDir, remoteDictionariesPath);
|
|
27
|
+
const fixedRemoteDictionariesPath = formatter(normalizePath(relativeRemoteDictionariesPath));
|
|
28
|
+
/**
|
|
29
|
+
* Dynamic dictionaries
|
|
30
|
+
*/
|
|
31
|
+
const dynamicDictionariesPath = join(mainDir, `dynamic_dictionaries.${extension}`);
|
|
32
|
+
const relativeDynamicDictionariesPath = relative(baseDir, dynamicDictionariesPath);
|
|
33
|
+
const fixedDynamicDictionariesPath = formatter(normalizePath(relativeDynamicDictionariesPath));
|
|
34
|
+
/**
|
|
35
|
+
* Fetch dictionaries
|
|
36
|
+
*/
|
|
37
|
+
const fetchDictionariesPath = join(mainDir, `fetch_dictionaries.${extension}`);
|
|
38
|
+
const relativeFetchDictionariesPath = relative(baseDir, fetchDictionariesPath);
|
|
39
|
+
const fixedFetchDictionariesPath = formatter(normalizePath(relativeFetchDictionariesPath));
|
|
40
|
+
/**
|
|
41
|
+
* Configuration
|
|
42
|
+
*/
|
|
43
|
+
const configurationPath = join(configDir, `configuration.${extension}`);
|
|
44
|
+
const relativeConfigurationPath = relative(baseDir, configurationPath);
|
|
10
45
|
return {
|
|
11
|
-
"@intlayer/dictionaries-entry":
|
|
12
|
-
"@intlayer/unmerged-dictionaries-entry":
|
|
13
|
-
"@intlayer/remote-dictionaries-entry":
|
|
14
|
-
"@intlayer/dynamic-dictionaries-entry":
|
|
15
|
-
"@intlayer/fetch-dictionaries-entry":
|
|
16
|
-
"@intlayer/config/built": formatter(normalizePath(
|
|
46
|
+
"@intlayer/dictionaries-entry": fixedDictionariesPath,
|
|
47
|
+
"@intlayer/unmerged-dictionaries-entry": fixedUnmergedDictionariesPath,
|
|
48
|
+
"@intlayer/remote-dictionaries-entry": fixedRemoteDictionariesPath,
|
|
49
|
+
"@intlayer/dynamic-dictionaries-entry": fixedDynamicDictionariesPath,
|
|
50
|
+
"@intlayer/fetch-dictionaries-entry": fixedFetchDictionariesPath,
|
|
51
|
+
"@intlayer/config/built": formatter(normalizePath(relativeConfigurationPath))
|
|
17
52
|
};
|
|
18
53
|
};
|
|
19
54
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alias.mjs","names":[],"sources":["../../../src/utils/alias.ts"],"sourcesContent":["import { join, relative } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { getExtension } from './getExtension';\nimport { normalizePath } from './normalizePath';\n\nexport type GetAliasOptions = {\n configuration: IntlayerConfig;\n format?: 'esm' | 'cjs';\n formatter?: (value: string) => string;\n};\n\nexport const getAlias = ({\n configuration,\n format,\n formatter = (value: string) => value,\n}: GetAliasOptions) => {\n const extension = getExtension(\n configuration,\n format ?? configuration.build.outputFormat[0] ?? 'esm'\n );\n\n const { baseDir } = configuration.system;\n const { mainDir, configDir } = configuration.system;\n\n /**\n * Dictionaries\n */\n const dictionariesPath = join(mainDir, `dictionaries.${extension}`);\n const relativeDictionariesPath = relative(baseDir, dictionariesPath);\n const fixedDictionariesPath = formatter(\n normalizePath(relativeDictionariesPath)\n );\n\n /**\n * Unmerged dictionaries\n */\n const unmergedDictionariesPath = join(\n mainDir,\n `unmerged_dictionaries.${extension}`\n );\n const relativeUnmergedDictionariesPath = relative(\n baseDir,\n unmergedDictionariesPath\n );\n const fixedUnmergedDictionariesPath = formatter(\n normalizePath(relativeUnmergedDictionariesPath)\n );\n\n /**\n * Remote dictionaries\n */\n const remoteDictionariesPath = join(\n mainDir,\n `remote_dictionaries.${extension}`\n );\n const relativeRemoteDictionariesPath = relative(\n baseDir,\n remoteDictionariesPath\n );\n const fixedRemoteDictionariesPath = formatter(\n normalizePath(relativeRemoteDictionariesPath)\n );\n\n /**\n * Dynamic dictionaries\n */\n const dynamicDictionariesPath = join(\n mainDir,\n `dynamic_dictionaries.${extension}`\n );\n const relativeDynamicDictionariesPath = relative(\n baseDir,\n dynamicDictionariesPath\n );\n const fixedDynamicDictionariesPath = formatter(\n normalizePath(relativeDynamicDictionariesPath)\n );\n\n /**\n * Fetch dictionaries\n */\n const fetchDictionariesPath = join(\n mainDir,\n `fetch_dictionaries.${extension}`\n );\n const relativeFetchDictionariesPath = relative(\n baseDir,\n fetchDictionariesPath\n );\n const fixedFetchDictionariesPath = formatter(\n normalizePath(relativeFetchDictionariesPath)\n );\n\n /**\n * Configuration\n */\n const configurationPath = join(configDir, `configuration.${extension}`);\n const relativeConfigurationPath = relative(baseDir, configurationPath);\n const fixedConfigurationPath = formatter(\n normalizePath(relativeConfigurationPath)\n );\n\n return {\n '@intlayer/dictionaries-entry': fixedDictionariesPath,\n '@intlayer/unmerged-dictionaries-entry': fixedUnmergedDictionariesPath,\n '@intlayer/remote-dictionaries-entry': fixedRemoteDictionariesPath,\n '@intlayer/dynamic-dictionaries-entry': fixedDynamicDictionariesPath,\n '@intlayer/fetch-dictionaries-entry': fixedFetchDictionariesPath,\n '@intlayer/config/built': fixedConfigurationPath,\n } as const;\n};\n"],"mappings":";;;;;AAWA,MAAa,YAAY,EACvB,eACA,QACA,aAAa,UAAkB,YACV;CACrB,MAAM,YAAY,aAChB,eACA,UAAU,cAAc,MAAM,aAAa,MAAM,KACnD;CAEA,MAAM,EAAE,YAAY,cAAc;CAClC,MAAM,EAAE,SAAS,cAAc,cAAc
|
|
1
|
+
{"version":3,"file":"alias.mjs","names":[],"sources":["../../../src/utils/alias.ts"],"sourcesContent":["import { join, relative } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { getExtension } from './getExtension';\nimport { normalizePath } from './normalizePath';\n\nexport type GetAliasOptions = {\n configuration: IntlayerConfig;\n format?: 'esm' | 'cjs';\n formatter?: (value: string) => string;\n};\n\nexport const getAlias = ({\n configuration,\n format,\n formatter = (value: string) => value,\n}: GetAliasOptions) => {\n const extension = getExtension(\n configuration,\n format ?? configuration.build.outputFormat[0] ?? 'esm'\n );\n\n const { baseDir } = configuration.system;\n const { mainDir, configDir } = configuration.system;\n\n /**\n * Dictionaries\n */\n const dictionariesPath = join(mainDir, `dictionaries.${extension}`);\n const relativeDictionariesPath = relative(baseDir, dictionariesPath);\n const fixedDictionariesPath = formatter(\n normalizePath(relativeDictionariesPath)\n );\n\n /**\n * Unmerged dictionaries\n */\n const unmergedDictionariesPath = join(\n mainDir,\n `unmerged_dictionaries.${extension}`\n );\n const relativeUnmergedDictionariesPath = relative(\n baseDir,\n unmergedDictionariesPath\n );\n const fixedUnmergedDictionariesPath = formatter(\n normalizePath(relativeUnmergedDictionariesPath)\n );\n\n /**\n * Remote dictionaries\n */\n const remoteDictionariesPath = join(\n mainDir,\n `remote_dictionaries.${extension}`\n );\n const relativeRemoteDictionariesPath = relative(\n baseDir,\n remoteDictionariesPath\n );\n const fixedRemoteDictionariesPath = formatter(\n normalizePath(relativeRemoteDictionariesPath)\n );\n\n /**\n * Dynamic dictionaries\n */\n const dynamicDictionariesPath = join(\n mainDir,\n `dynamic_dictionaries.${extension}`\n );\n const relativeDynamicDictionariesPath = relative(\n baseDir,\n dynamicDictionariesPath\n );\n const fixedDynamicDictionariesPath = formatter(\n normalizePath(relativeDynamicDictionariesPath)\n );\n\n /**\n * Fetch dictionaries\n */\n const fetchDictionariesPath = join(\n mainDir,\n `fetch_dictionaries.${extension}`\n );\n const relativeFetchDictionariesPath = relative(\n baseDir,\n fetchDictionariesPath\n );\n const fixedFetchDictionariesPath = formatter(\n normalizePath(relativeFetchDictionariesPath)\n );\n\n /**\n * Configuration\n */\n const configurationPath = join(configDir, `configuration.${extension}`);\n const relativeConfigurationPath = relative(baseDir, configurationPath);\n const fixedConfigurationPath = formatter(\n normalizePath(relativeConfigurationPath)\n );\n\n return {\n '@intlayer/dictionaries-entry': fixedDictionariesPath,\n '@intlayer/unmerged-dictionaries-entry': fixedUnmergedDictionariesPath,\n '@intlayer/remote-dictionaries-entry': fixedRemoteDictionariesPath,\n '@intlayer/dynamic-dictionaries-entry': fixedDynamicDictionariesPath,\n '@intlayer/fetch-dictionaries-entry': fixedFetchDictionariesPath,\n '@intlayer/config/built': fixedConfigurationPath,\n } as const;\n};\n"],"mappings":";;;;;AAWA,MAAa,YAAY,EACvB,eACA,QACA,aAAa,UAAkB,YACV;CACrB,MAAM,YAAY,aAChB,eACA,UAAU,cAAc,MAAM,aAAa,MAAM,KACnD;CAEA,MAAM,EAAE,YAAY,cAAc;CAClC,MAAM,EAAE,SAAS,cAAc,cAAc;;;;CAK7C,MAAM,mBAAmB,KAAK,SAAS,gBAAgB,WAAW;CAClE,MAAM,2BAA2B,SAAS,SAAS,gBAAgB;CACnE,MAAM,wBAAwB,UAC5B,cAAc,wBAAwB,CACxC;;;;CAKA,MAAM,2BAA2B,KAC/B,SACA,yBAAyB,WAC3B;CACA,MAAM,mCAAmC,SACvC,SACA,wBACF;CACA,MAAM,gCAAgC,UACpC,cAAc,gCAAgC,CAChD;;;;CAKA,MAAM,yBAAyB,KAC7B,SACA,uBAAuB,WACzB;CACA,MAAM,iCAAiC,SACrC,SACA,sBACF;CACA,MAAM,8BAA8B,UAClC,cAAc,8BAA8B,CAC9C;;;;CAKA,MAAM,0BAA0B,KAC9B,SACA,wBAAwB,WAC1B;CACA,MAAM,kCAAkC,SACtC,SACA,uBACF;CACA,MAAM,+BAA+B,UACnC,cAAc,+BAA+B,CAC/C;;;;CAKA,MAAM,wBAAwB,KAC5B,SACA,sBAAsB,WACxB;CACA,MAAM,gCAAgC,SACpC,SACA,qBACF;CACA,MAAM,6BAA6B,UACjC,cAAc,6BAA6B,CAC7C;;;;CAKA,MAAM,oBAAoB,KAAK,WAAW,iBAAiB,WAAW;CACtE,MAAM,4BAA4B,SAAS,SAAS,iBAAiB;CAKrE,OAAO;EACL,gCAAgC;EAChC,yCAAyC;EACzC,uCAAuC;EACvC,wCAAwC;EACxC,sCAAsC;EACtC,0BAV6B,UAC7B,cAAc,yBAAyB,CASQ;CACjD;AACF"}
|
|
@@ -55,7 +55,8 @@ const cacheDisk = (intlayerConfig, keys, options) => {
|
|
|
55
55
|
let raw = await readFile(filePath);
|
|
56
56
|
const flag = raw[0];
|
|
57
57
|
raw = raw.subarray(1);
|
|
58
|
-
const
|
|
58
|
+
const payload = flag === 1 ? gunzipSync(raw) : raw;
|
|
59
|
+
const deserialized = deserialize(payload);
|
|
59
60
|
let value;
|
|
60
61
|
const maybeObj = deserialized;
|
|
61
62
|
if (!!maybeObj && typeof maybeObj === "object" && typeof maybeObj.version === "string" && typeof maybeObj.timestamp === "number" && Object.hasOwn(maybeObj, "data")) {
|
|
@@ -154,7 +155,8 @@ const cacheDisk = (intlayerConfig, keys, options) => {
|
|
|
154
155
|
let raw = await readFile(filePath);
|
|
155
156
|
const flag = raw[0];
|
|
156
157
|
raw = raw.subarray(1);
|
|
157
|
-
const
|
|
158
|
+
const payload = flag === 1 ? gunzipSync(raw) : raw;
|
|
159
|
+
const maybeObj = deserialize(payload);
|
|
158
160
|
if (!!maybeObj && typeof maybeObj === "object" && typeof maybeObj.version === "string" && typeof maybeObj.timestamp === "number" && Object.hasOwn(maybeObj, "data")) {
|
|
159
161
|
const entry = maybeObj;
|
|
160
162
|
if (entry.version !== configPackageJson.version) return false;
|