UNPKG

@intlayer/chokidar

Version:

Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.

332 lines 13.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var writeJSFile_exports = {}; __export(writeJSFile_exports, { writeJSFile: () => writeJSFile }); module.exports = __toCommonJS(writeJSFile_exports); var import_generator = __toESM(require("@babel/generator")); var babelParser = __toESM(require("@babel/parser")); var import_traverse = __toESM(require("@babel/traverse")); var t = __toESM(require("@babel/types")); var import_config = require("@intlayer/config"); var import_built = __toESM(require("@intlayer/config/built")); var import_core = require("@intlayer/core"); var import_fs = require("fs"); var import_promises = require("fs/promises"); var import_path = require("path"); var import_getContentDeclarationFileTemplate = require('../getContentDeclarationFileTemplate/getContentDeclarationFileTemplate.cjs'); var import_formatCode = require('./formatCode.cjs'); const writeJSFile = async (filePath, dictionary) => { const appLogger = (0, import_config.getAppLogger)(import_built.default); const { key: dictionaryIdentifierKey, content: updatesToApply, locale, autoFilled } = dictionary; const isPerLocaleDeclarationFile = typeof locale === "string"; if (!(0, import_fs.existsSync)(filePath)) { const fileExtension = (0, import_path.extname)(filePath); let format = "ts"; if (fileExtension === ".ts" || fileExtension === ".tsx") { format = "ts"; } else if (fileExtension === ".cjs" || fileExtension === ".cjsx") { format = "cjs"; } else { format = "esm"; } appLogger("File does not exist, creating it", { isVerbose: true }); const template = await (0, import_getContentDeclarationFileTemplate.getContentDeclarationFileTemplate)( dictionaryIdentifierKey, format, { locale, autoFilled } ); await (0, import_promises.writeFile)(filePath, template, "utf-8"); } let sourceCode; try { sourceCode = await (0, import_promises.readFile)(filePath, "utf-8"); } catch (error) { const err = error; appLogger(`Failed to read file: ${filePath}`, { level: "error" }); throw new Error(`Failed to read file ${filePath}: ${err.message}`); } const ast = babelParser.parse(sourceCode, { sourceType: "module", plugins: ["typescript", "jsx"], tokens: true }); let dictionaryObjectPath = null; let dictionaryIdentifier = null; (0, import_traverse.default)(ast, { ObjectExpression(path) { if (dictionaryObjectPath) return; const keyProp = path.node.properties.find((prop) => { if (!t.isObjectProperty(prop)) return false; if (!t.isIdentifier(prop.key) && !t.isStringLiteral(prop.key)) return false; const keyName = t.isIdentifier(prop.key) ? prop.key.name : prop.key.value; if (keyName !== "key" || !t.isStringLiteral(prop.value)) return false; const propValue = prop.value.value; return propValue === dictionaryIdentifierKey; }); if (keyProp) { dictionaryObjectPath = path; path.stop(); } } }); if (!dictionaryObjectPath) { appLogger(`Looking for variable declarations`, { isVerbose: true }); const candidateVars = []; (0, import_traverse.default)(ast, { VariableDeclarator(path) { const { node } = path; if (!t.isIdentifier(node.id)) return; let objPath = null; if (node.init && t.isObjectExpression(node.init)) { objPath = path.get("init"); } else if (node.init && (t.isTSAsExpression(node.init) || t.isTSTypeAssertion(node.init)) && t.isObjectExpression(node.init.expression)) { objPath = path.get("init.expression"); } if (objPath) { candidateVars.push({ id: node.id.name, path: objPath }); } } }); appLogger(`Found ${candidateVars.length} candidate variables`, { isVerbose: true }); for (const { id, path } of candidateVars) { const keyProp = path.node.properties.find((prop) => { if (!t.isObjectProperty(prop)) return false; if (!t.isIdentifier(prop.key) && !t.isStringLiteral(prop.key)) return false; const keyName = t.isIdentifier(prop.key) ? prop.key.name : prop.key.value; return keyName === "key" && t.isStringLiteral(prop.value) && prop.value.value === dictionaryIdentifierKey; }); if (keyProp) { appLogger(`Found match in variable: ${id}`); dictionaryObjectPath = path; dictionaryIdentifier = id; break; } } if (!dictionaryObjectPath) { appLogger("Could not find dictionary object. Dumping all objects:", { isVerbose: true }); (0, import_traverse.default)(ast, { ObjectExpression(path) { const props = path.node.properties.map((prop) => { if (!t.isObjectProperty(prop)) return "non-object-property"; if (!t.isIdentifier(prop.key) && !t.isStringLiteral(prop.key)) return "complex-key"; const keyName = t.isIdentifier(prop.key) ? prop.key.name : prop.key.value; let valueDesc = "unknown-value"; if (t.isStringLiteral(prop.value)) { valueDesc = `"${prop.value.value}"`; } return `${keyName}: ${valueDesc}`; }).join(", "); appLogger(`Object: { ${props} }`); } }); } } if (!dictionaryObjectPath) { throw new Error( `Could not find dictionary object with key '${dictionaryIdentifierKey}' in ${filePath}` ); } const contentPropertyPath = dictionaryObjectPath.get("properties").find((propPath) => { if (!propPath.isObjectProperty()) return false; const propNode = propPath.node; const keyName = t.isIdentifier(propNode.key) ? propNode.key.name : t.isStringLiteral(propNode.key) ? propNode.key.value : null; return keyName === "content"; }); if (!contentPropertyPath || !contentPropertyPath.isObjectProperty() || !contentPropertyPath.get("value").isObjectExpression()) { throw new Error( `Could not find 'content' object property, or it's not an object, in dictionary in ${filePath}` ); } const contentObjectPath = contentPropertyPath.get( "value" ); const buildValueNodeFromData = (data) => { if (data?.nodeType === import_core.NodeType.Translation) { const translationContent = data; if (isPerLocaleDeclarationFile && typeof locale === "string" && translationContent?.[import_core.NodeType.Translation]?.[locale] !== void 0) { return buildValueNodeFromData( translationContent[import_core.NodeType.Translation][locale] ); } const translationsObj = t.objectExpression( Object.entries(translationContent?.[import_core.NodeType.Translation] ?? {}).map( ([langKey, langValue]) => { const keyNode = t.isValidIdentifier(langKey) ? t.identifier(langKey) : t.stringLiteral(langKey); return t.objectProperty(keyNode, buildValueNodeFromData(langValue)); } ) ); return t.callExpression(t.identifier("t"), [translationsObj]); } if (Array.isArray(data)) { return t.arrayExpression(data.map((el) => buildValueNodeFromData(el))); } if (data && typeof data === "object") { const props = Object.entries(data).map(([k, v]) => { const key = t.isValidIdentifier(k) ? t.identifier(k) : t.stringLiteral(k); return t.objectProperty(key, buildValueNodeFromData(v)); }); return t.objectExpression(props); } switch (typeof data) { case "string": return t.stringLiteral(data); case "number": return t.numericLiteral(data); case "boolean": return t.booleanLiteral(data); default: return t.nullLiteral(); } }; const ensureObjectProperty = (objPath, key) => { const existing = objPath.get("properties").find((propPath) => { if (!propPath.isObjectProperty()) return false; const propNode = propPath.node; const keyName = t.isIdentifier(propNode.key) ? propNode.key.name : t.isStringLiteral(propNode.key) ? propNode.key.value : null; return keyName === key; }); if (existing) return existing; const keyNode = t.isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key); const newProp = t.objectProperty(keyNode, t.objectExpression([])); objPath.node.properties.push(newProp); const props = objPath.get("properties"); return props[props.length - 1]; }; const mergeValueIntoProperty = (propPath, value, propKeyForLogs) => { const valuePath = propPath.get("value"); if (value?.nodeType === import_core.NodeType.Translation) { const translationContent = value; if (valuePath.isCallExpression() && t.isIdentifier(valuePath.node.callee) && valuePath.node.callee.name === "t") { const translationsObj = t.objectExpression( Object.entries(translationContent?.[import_core.NodeType.Translation] ?? {}).map( ([langKey, langValue]) => t.objectProperty( t.isValidIdentifier(langKey) ? t.identifier(langKey) : t.stringLiteral(langKey), buildValueNodeFromData(langValue) ) ) ); if (isPerLocaleDeclarationFile && typeof locale === "string") { const localized = translationContent?.[import_core.NodeType.Translation]?.[locale]; if (localized !== void 0) { valuePath.replaceWith(buildValueNodeFromData(localized)); return; } } valuePath.node.arguments = [translationsObj]; return; } valuePath.replaceWith(buildValueNodeFromData(value)); return; } if (Array.isArray(value)) { valuePath.replaceWith(buildValueNodeFromData(value)); return; } if (value && typeof value === "object") { if (!valuePath.isObjectExpression()) { valuePath.replaceWith(t.objectExpression([])); } const objPath = valuePath; for (const [k, v] of Object.entries(value)) { const childProp = ensureObjectProperty(objPath, k); mergeValueIntoProperty(childProp, v, `${propKeyForLogs}.${k}`); } return; } valuePath.replaceWith(buildValueNodeFromData(value)); return; }; for (const [entryKeyToUpdate, newEntryData] of Object.entries( updatesToApply )) { let targetPropertyPath = contentObjectPath.get("properties").find((propPath) => { if (!propPath.isObjectProperty()) return false; const propNode = propPath.node; const keyName = t.isIdentifier(propNode.key) ? propNode.key.name : t.isStringLiteral(propNode.key) ? propNode.key.value : null; return keyName === entryKeyToUpdate; }); if (!targetPropertyPath) { const keyNode = t.isValidIdentifier(entryKeyToUpdate) ? t.identifier(entryKeyToUpdate) : t.stringLiteral(entryKeyToUpdate); const newProperty = t.objectProperty(keyNode, t.objectExpression([])); contentObjectPath.node.properties.push(newProperty); const props = contentObjectPath.get("properties"); targetPropertyPath = props[props.length - 1]; } mergeValueIntoProperty(targetPropertyPath, newEntryData, entryKeyToUpdate); } const generatedCode = (0, import_generator.default)(ast, { retainLines: true, comments: true, jsescOption: { minimal: true // This ensures Unicode characters are not escaped } }).code; let finalCode = generatedCode; finalCode = await (0, import_formatCode.formatCode)(filePath, finalCode); try { await (0, import_promises.writeFile)(filePath, finalCode, "utf-8"); (0, import_config.logger)(`Successfully updated ${filePath}`, { level: "info", isVerbose: true }); } catch (error) { const err = error; (0, import_config.logger)(`Failed to write updated file: ${filePath}`, { level: "error" }); throw new Error(`Failed to write updated file ${filePath}: ${err.message}`); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { writeJSFile }); //# sourceMappingURL=writeJSFile.cjs.map