@intlayer/engine 9.6.0 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/cjs/build.cjs +12 -2
  2. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs +12 -11
  3. package/dist/cjs/buildIntlayerDictionary/buildIntlayerDictionary.cjs.map +1 -1
  4. package/dist/cjs/buildIntlayerDictionary/index.cjs +4 -1
  5. package/dist/cjs/buildIntlayerDictionary/rebuildUnmergedDictionaries.cjs +23 -0
  6. package/dist/cjs/buildIntlayerDictionary/rebuildUnmergedDictionaries.cjs.map +1 -0
  7. package/dist/cjs/cli.cjs +10 -0
  8. package/dist/cjs/fetchDistantDictionaries.cjs.map +1 -1
  9. package/dist/cjs/handleAdditionalContentDeclarationFile.cjs +1 -1
  10. package/dist/cjs/handleContentDeclarationFileChange.cjs +1 -1
  11. package/dist/cjs/handleUnlinkedContentDeclarationFile.cjs +1 -1
  12. package/dist/cjs/init/cms.cjs +18 -0
  13. package/dist/cjs/init/cms.cjs.map +1 -1
  14. package/dist/cjs/init/index.cjs +11 -8
  15. package/dist/cjs/init/index.cjs.map +1 -1
  16. package/dist/cjs/init/utils/configManipulation.cjs +28 -0
  17. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  18. package/dist/cjs/init/utils/contentLayout.cjs +61 -0
  19. package/dist/cjs/init/utils/contentLayout.cjs.map +1 -0
  20. package/dist/cjs/init/utils/index.cjs +1 -0
  21. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  22. package/dist/cjs/listDictionariesPath.cjs +2 -5
  23. package/dist/cjs/listDictionariesPath.cjs.map +1 -1
  24. package/dist/cjs/loadDictionaries/index.cjs +1 -1
  25. package/dist/cjs/loadDictionaries/loadDictionaries.cjs +1 -1
  26. package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
  27. package/dist/cjs/utils/buildComponentFilesList.cjs +18 -30
  28. package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
  29. package/dist/cjs/utils/chunkJSON.cjs +1 -1
  30. package/dist/cjs/utils/chunkJSON.cjs.map +1 -1
  31. package/dist/cjs/utils/index.cjs +2 -0
  32. package/dist/cjs/utils/isDirectoryExcluded.cjs +36 -0
  33. package/dist/cjs/utils/isDirectoryExcluded.cjs.map +1 -0
  34. package/dist/cjs/watcher.cjs +5 -2
  35. package/dist/cjs/watcher.cjs.map +1 -1
  36. package/dist/cjs/writeConfiguration/index.cjs +23 -0
  37. package/dist/cjs/writeConfiguration/index.cjs.map +1 -1
  38. package/dist/cjs/writeContentDeclaration/index.cjs +6 -0
  39. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs +20 -13
  40. package/dist/cjs/writeContentDeclaration/processContentDeclarationContent.cjs.map +1 -1
  41. package/dist/cjs/writeContentDeclaration/renderContentDeclaration.cjs +213 -0
  42. package/dist/cjs/writeContentDeclaration/renderContentDeclaration.cjs.map +1 -0
  43. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs +5 -51
  44. package/dist/cjs/writeContentDeclaration/writeContentDeclaration.cjs.map +1 -1
  45. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -31
  46. package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
  47. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs +2 -8
  48. package/dist/cjs/writeContentDeclaration/writeYamlFile.cjs.map +1 -1
  49. package/dist/esm/build.mjs +7 -5
  50. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs +12 -12
  51. package/dist/esm/buildIntlayerDictionary/buildIntlayerDictionary.mjs.map +1 -1
  52. package/dist/esm/buildIntlayerDictionary/index.mjs +3 -2
  53. package/dist/esm/buildIntlayerDictionary/rebuildUnmergedDictionaries.mjs +22 -0
  54. package/dist/esm/buildIntlayerDictionary/rebuildUnmergedDictionaries.mjs.map +1 -0
  55. package/dist/esm/cli.mjs +3 -1
  56. package/dist/esm/fetchDistantDictionaries.mjs.map +1 -1
  57. package/dist/esm/handleAdditionalContentDeclarationFile.mjs +1 -1
  58. package/dist/esm/handleContentDeclarationFileChange.mjs +1 -1
  59. package/dist/esm/handleUnlinkedContentDeclarationFile.mjs +1 -1
  60. package/dist/esm/init/cms.mjs +19 -2
  61. package/dist/esm/init/cms.mjs.map +1 -1
  62. package/dist/esm/init/index.mjs +12 -9
  63. package/dist/esm/init/index.mjs.map +1 -1
  64. package/dist/esm/init/utils/configManipulation.mjs +28 -1
  65. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  66. package/dist/esm/init/utils/contentLayout.mjs +58 -0
  67. package/dist/esm/init/utils/contentLayout.mjs.map +1 -0
  68. package/dist/esm/init/utils/index.mjs +2 -2
  69. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  70. package/dist/esm/listDictionariesPath.mjs +2 -5
  71. package/dist/esm/listDictionariesPath.mjs.map +1 -1
  72. package/dist/esm/loadDictionaries/index.mjs +1 -1
  73. package/dist/esm/loadDictionaries/loadDictionaries.mjs +1 -1
  74. package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
  75. package/dist/esm/utils/buildComponentFilesList.mjs +19 -31
  76. package/dist/esm/utils/buildComponentFilesList.mjs.map +1 -1
  77. package/dist/esm/utils/chunkJSON.mjs +1 -1
  78. package/dist/esm/utils/chunkJSON.mjs.map +1 -1
  79. package/dist/esm/utils/index.mjs +2 -1
  80. package/dist/esm/utils/isDirectoryExcluded.mjs +35 -0
  81. package/dist/esm/utils/isDirectoryExcluded.mjs.map +1 -0
  82. package/dist/esm/watcher.mjs +5 -2
  83. package/dist/esm/watcher.mjs.map +1 -1
  84. package/dist/esm/writeConfiguration/index.mjs +23 -1
  85. package/dist/esm/writeConfiguration/index.mjs.map +1 -1
  86. package/dist/esm/writeContentDeclaration/index.mjs +2 -1
  87. package/dist/esm/writeContentDeclaration/processContentDeclarationContent.mjs +20 -13
  88. package/dist/esm/writeContentDeclaration/processContentDeclarationContent.mjs.map +1 -1
  89. package/dist/esm/writeContentDeclaration/renderContentDeclaration.mjs +208 -0
  90. package/dist/esm/writeContentDeclaration/renderContentDeclaration.mjs.map +1 -0
  91. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs +5 -51
  92. package/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs.map +1 -1
  93. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -31
  94. package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
  95. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs +2 -8
  96. package/dist/esm/writeContentDeclaration/writeYamlFile.mjs.map +1 -1
  97. package/dist/types/build.d.ts +5 -3
  98. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts +6 -0
  99. package/dist/types/buildIntlayerDictionary/buildIntlayerDictionary.d.ts.map +1 -1
  100. package/dist/types/buildIntlayerDictionary/index.d.ts +3 -2
  101. package/dist/types/buildIntlayerDictionary/rebuildUnmergedDictionaries.d.ts +14 -0
  102. package/dist/types/buildIntlayerDictionary/rebuildUnmergedDictionaries.d.ts.map +1 -0
  103. package/dist/types/cli.d.ts +4 -2
  104. package/dist/types/fetchDistantDictionaries.d.ts +1 -1
  105. package/dist/types/fetchDistantDictionaries.d.ts.map +1 -1
  106. package/dist/types/init/cms.d.ts +6 -0
  107. package/dist/types/init/cms.d.ts.map +1 -1
  108. package/dist/types/init/index.d.ts +15 -14
  109. package/dist/types/init/index.d.ts.map +1 -1
  110. package/dist/types/init/utils/configManipulation.d.ts +8 -0
  111. package/dist/types/init/utils/configManipulation.d.ts.map +1 -1
  112. package/dist/types/init/utils/contentLayout.d.ts +42 -0
  113. package/dist/types/init/utils/contentLayout.d.ts.map +1 -0
  114. package/dist/types/init/utils/index.d.ts +2 -2
  115. package/dist/types/init/utils/packageManager.d.ts +4 -3
  116. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  117. package/dist/types/listDictionariesPath.d.ts +1 -1
  118. package/dist/types/listDictionariesPath.d.ts.map +1 -1
  119. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts +1 -1
  120. package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
  121. package/dist/types/utils/buildComponentFilesList.d.ts +6 -6
  122. package/dist/types/utils/buildComponentFilesList.d.ts.map +1 -1
  123. package/dist/types/utils/chunkJSON.d.ts.map +1 -1
  124. package/dist/types/utils/index.d.ts +2 -1
  125. package/dist/types/utils/isDirectoryExcluded.d.ts +15 -0
  126. package/dist/types/utils/isDirectoryExcluded.d.ts.map +1 -0
  127. package/dist/types/watcher.d.ts.map +1 -1
  128. package/dist/types/writeConfiguration/index.d.ts +13 -0
  129. package/dist/types/writeConfiguration/index.d.ts.map +1 -1
  130. package/dist/types/writeContentDeclaration/index.d.ts +2 -1
  131. package/dist/types/writeContentDeclaration/processContentDeclarationContent.d.ts +8 -2
  132. package/dist/types/writeContentDeclaration/processContentDeclarationContent.d.ts.map +1 -1
  133. package/dist/types/writeContentDeclaration/renderContentDeclaration.d.ts +61 -0
  134. package/dist/types/writeContentDeclaration/renderContentDeclaration.d.ts.map +1 -0
  135. package/dist/types/writeContentDeclaration/writeContentDeclaration.d.ts.map +1 -1
  136. package/dist/types/writeContentDeclaration/writeMarkdownFile.d.ts.map +1 -1
  137. package/dist/types/writeContentDeclaration/writeYamlFile.d.ts.map +1 -1
  138. package/package.json +13 -5
@@ -18,8 +18,31 @@ const writeConfiguration = async (configuration) => {
18
18
  await (0, node_fs_promises.mkdir)(configDir, { recursive: true });
19
19
  await Promise.all([require_writeFileIfChanged.writeFileIfChanged((0, node_path.join)(configDir, "configuration.mjs"), require_writeConfiguration_generateConfigurationContent.generateConfigurationContent(configuration, "esm")), require_writeFileIfChanged.writeFileIfChanged((0, node_path.join)(configDir, "configuration.cjs"), require_writeConfiguration_generateConfigurationContent.generateConfigurationContent(configuration, "cjs"))]);
20
20
  };
21
+ /**
22
+ * Writes the built configuration (`.intlayer/config`) with editor settings
23
+ * overridden, leaving the user configuration file untouched. Lets the visual
24
+ * editor connect to the application when the configuration disables it, or
25
+ * points at another URL. The next configuration build restores the
26
+ * configured values.
27
+ *
28
+ * @returns The overridden keys that differ from the configuration; nothing is
29
+ * written when empty.
30
+ */
31
+ const overrideBuiltEditorConfiguration = async (configuration, editorOverride) => {
32
+ const overriddenKeys = Object.keys(editorOverride).filter((key) => editorOverride[key] !== void 0 && editorOverride[key] !== configuration.editor[key]);
33
+ if (overriddenKeys.length === 0) return [];
34
+ await writeConfiguration({
35
+ ...configuration,
36
+ editor: {
37
+ ...configuration.editor,
38
+ ...editorOverride
39
+ }
40
+ });
41
+ return overriddenKeys;
42
+ };
21
43
 
22
44
  //#endregion
23
45
  exports.isCachedConfigurationUpToDate = isCachedConfigurationUpToDate;
46
+ exports.overrideBuiltEditorConfiguration = overrideBuiltEditorConfiguration;
24
47
  exports.writeConfiguration = writeConfiguration;
25
48
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["join","readFile","generateConfigurationContent","mkdir","writeFileIfChanged"],"sources":["../../../src/writeConfiguration/index.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { generateConfigurationContent } from './generateConfigurationContent';\n\nexport const isCachedConfigurationUpToDate = async (\n configuration: IntlayerConfig\n): Promise<boolean | null> => {\n try {\n const mjsPath = join(configuration.system.configDir, 'configuration.mjs');\n const existingContent = await readFile(mjsPath, 'utf8');\n const expectedContent = generateConfigurationContent(configuration, 'esm');\n return existingContent === expectedContent;\n } catch {\n return null; // Can crash if file doesn't exist yet or config is not defined\n }\n};\n\nexport const writeConfiguration = async (configuration: IntlayerConfig) => {\n const { configDir } = configuration.system;\n\n await mkdir(configDir, { recursive: true });\n\n await Promise.all([\n writeFileIfChanged(\n join(configDir, 'configuration.mjs'),\n generateConfigurationContent(configuration, 'esm')\n ),\n writeFileIfChanged(\n join(configDir, 'configuration.cjs'),\n generateConfigurationContent(configuration, 'cjs')\n ),\n ]);\n};\n"],"mappings":";;;;;;;AAMA,MAAa,gCAAgC,OAC3C,kBAC4B;CAC5B,IAAI;EACF,MAAM,cAAUA,gBAAK,cAAc,OAAO,WAAW,mBAAmB;EAGxE,OAAO,UAFuBC,2BAAS,SAAS,MAAM,MAC9BC,qFAA6B,eAAe,KAC3B;CAC3C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,qBAAqB,OAAO,kBAAkC;CACzE,MAAM,EAAE,cAAc,cAAc;CAEpC,UAAMC,wBAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,MAAM,QAAQ,IAAI,CAChBC,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,GACAE,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.cjs","names":["join","readFile","generateConfigurationContent","mkdir","writeFileIfChanged"],"sources":["../../../src/writeConfiguration/index.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { writeFileIfChanged } from '../writeFileIfChanged';\nimport { generateConfigurationContent } from './generateConfigurationContent';\n\nexport const isCachedConfigurationUpToDate = async (\n configuration: IntlayerConfig\n): Promise<boolean | null> => {\n try {\n const mjsPath = join(configuration.system.configDir, 'configuration.mjs');\n const existingContent = await readFile(mjsPath, 'utf8');\n const expectedContent = generateConfigurationContent(configuration, 'esm');\n return existingContent === expectedContent;\n } catch {\n return null; // Can crash if file doesn't exist yet or config is not defined\n }\n};\n\nexport const writeConfiguration = async (configuration: IntlayerConfig) => {\n const { configDir } = configuration.system;\n\n await mkdir(configDir, { recursive: true });\n\n await Promise.all([\n writeFileIfChanged(\n join(configDir, 'configuration.mjs'),\n generateConfigurationContent(configuration, 'esm')\n ),\n writeFileIfChanged(\n join(configDir, 'configuration.cjs'),\n generateConfigurationContent(configuration, 'cjs')\n ),\n ]);\n};\n\n/** Editor settings the built configuration can be overridden with. */\nexport type BuiltEditorOverride = Partial<\n Pick<IntlayerConfig['editor'], 'enabled' | 'editorURL'>\n>;\n\n/**\n * Writes the built configuration (`.intlayer/config`) with editor settings\n * overridden, leaving the user configuration file untouched. Lets the visual\n * editor connect to the application when the configuration disables it, or\n * points at another URL. The next configuration build restores the\n * configured values.\n *\n * @returns The overridden keys that differ from the configuration; nothing is\n * written when empty.\n */\nexport const overrideBuiltEditorConfiguration = async (\n configuration: IntlayerConfig,\n editorOverride: BuiltEditorOverride\n): Promise<(keyof BuiltEditorOverride)[]> => {\n const overriddenKeys = (\n Object.keys(editorOverride) as (keyof BuiltEditorOverride)[]\n ).filter(\n (key) =>\n editorOverride[key] !== undefined &&\n editorOverride[key] !== configuration.editor[key]\n );\n\n if (overriddenKeys.length === 0) return [];\n\n await writeConfiguration({\n ...configuration,\n editor: { ...configuration.editor, ...editorOverride },\n });\n\n return overriddenKeys;\n};\n"],"mappings":";;;;;;;AAMA,MAAa,gCAAgC,OAC3C,kBAC4B;CAC5B,IAAI;EACF,MAAM,cAAUA,gBAAK,cAAc,OAAO,WAAW,mBAAmB;EAGxE,OAAO,UAFuBC,2BAAS,SAAS,MAAM,MAC9BC,qFAA6B,eAAe,KAC3B;CAC3C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,qBAAqB,OAAO,kBAAkC;CACzE,MAAM,EAAE,cAAc,cAAc;CAEpC,UAAMC,wBAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,MAAM,QAAQ,IAAI,CAChBC,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,GACAE,kDACEJ,gBAAK,WAAW,mBAAmB,GACnCE,qFAA6B,eAAe,KAAK,CACnD,CACF,CAAC;AACH;;;;;;;;;;;AAiBA,MAAa,mCAAmC,OAC9C,eACA,mBAC2C;CAC3C,MAAM,iBACJ,OAAO,KAAK,cAAc,CAAC,CAC3B,QACC,QACC,eAAe,SAAS,UACxB,eAAe,SAAS,cAAc,OAAO,IACjD;CAEA,IAAI,eAAe,WAAW,GAAG,OAAO,CAAC;CAEzC,MAAM,mBAAmB;EACvB,GAAG;EACH,QAAQ;GAAE,GAAG,cAAc;GAAQ,GAAG;EAAe;CACvD,CAAC;CAED,OAAO;AACT"}
@@ -1,10 +1,16 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_writeContentDeclaration_detectExportedComponentName = require('./detectExportedComponentName.cjs');
3
3
  const require_writeContentDeclaration_transformJSFile = require('./transformJSFile.cjs');
4
+ const require_writeContentDeclaration_renderContentDeclaration = require('./renderContentDeclaration.cjs');
4
5
  const require_writeContentDeclaration_writeJSFile = require('./writeJSFile.cjs');
5
6
  const require_writeContentDeclaration_writeContentDeclaration = require('./writeContentDeclaration.cjs');
6
7
 
7
8
  exports.detectExportedComponentName = require_writeContentDeclaration_detectExportedComponentName.detectExportedComponentName;
9
+ exports.formatContentDeclaration = require_writeContentDeclaration_renderContentDeclaration.formatContentDeclaration;
10
+ exports.isRenderableContentDeclarationPath = require_writeContentDeclaration_renderContentDeclaration.isRenderableContentDeclarationPath;
11
+ exports.renderContentDeclaration = require_writeContentDeclaration_renderContentDeclaration.renderContentDeclaration;
12
+ exports.renderMarkdownContentDeclaration = require_writeContentDeclaration_renderContentDeclaration.renderMarkdownContentDeclaration;
13
+ exports.renderYamlContentDeclaration = require_writeContentDeclaration_renderContentDeclaration.renderYamlContentDeclaration;
8
14
  exports.transformJSFile = require_writeContentDeclaration_transformJSFile.transformJSFile;
9
15
  exports.writeContentDeclaration = require_writeContentDeclaration_writeContentDeclaration.writeContentDeclaration;
10
16
  exports.writeJSFile = require_writeContentDeclaration_writeJSFile.writeJSFile;
@@ -9,9 +9,22 @@ let _intlayer_core_interpreter = require("@intlayer/core/interpreter");
9
9
 
10
10
  //#region src/writeContentDeclaration/processContentDeclarationContent.ts
11
11
  /**
12
+ * Writes the content of a `file()` node to disk.
13
+ */
14
+ const writeExternalFileToDisk = (filePath, fileContent) => {
15
+ try {
16
+ const absoluteFilePath = (0, node_path.join)(process.cwd(), filePath);
17
+ const fileDirectory = (0, node_path.dirname)(absoluteFilePath);
18
+ if (!(0, node_fs.existsSync)(fileDirectory)) (0, node_fs.mkdirSync)(fileDirectory, { recursive: true });
19
+ (0, node_fs.writeFileSync)(absoluteFilePath, fileContent);
20
+ } catch (error) {
21
+ throw new Error(`${_intlayer_config_logger.x} Error writing file to ${(0, _intlayer_config_logger.colorizePath)(filePath)}: ${error}`);
22
+ }
23
+ };
24
+ /**
12
25
  * Write file plugin
13
26
  */
14
- const writeFilePlugin = {
27
+ const getWriteFilePlugin = (onExternalFile) => ({
15
28
  id: "write-file-plugin",
16
29
  canHandle: (node) => typeof node === "object" && node?.nodeType === _intlayer_types_nodeType.FILE,
17
30
  transform: (node) => {
@@ -19,20 +32,13 @@ const writeFilePlugin = {
19
32
  const filePath = node.fixedPath;
20
33
  if (typeof fileContent !== "string") throw new Error("File content must be a string");
21
34
  if (typeof filePath !== "string") throw new Error("File path must be a string");
22
- try {
23
- const absoluteFilePath = (0, node_path.join)(process.cwd(), filePath);
24
- const fileDirectory = (0, node_path.dirname)(absoluteFilePath);
25
- if (!(0, node_fs.existsSync)(fileDirectory)) (0, node_fs.mkdirSync)(fileDirectory, { recursive: true });
26
- (0, node_fs.writeFileSync)(absoluteFilePath, fileContent);
27
- } catch (error) {
28
- throw new Error(`${_intlayer_config_logger.x} Error writing file to ${(0, _intlayer_config_logger.colorizePath)(filePath)}: ${error}`);
29
- }
35
+ onExternalFile(filePath, fileContent);
30
36
  return {
31
37
  nodeType: _intlayer_types_nodeType.FILE,
32
38
  [_intlayer_types_nodeType.FILE]: node[_intlayer_types_nodeType.FILE]
33
39
  };
34
40
  }
35
- };
41
+ });
36
42
  /**
37
43
  * Markdown file plugin
38
44
  */
@@ -77,13 +83,14 @@ const htmlFilePlugin = {
77
83
  *
78
84
  * It filter node that are autogenerated by intlayer to do not rewrite them in the content declaration file.
79
85
  *
80
- * And write external sources as file content if necessary.
86
+ * And write external sources as file content if necessary. Pass
87
+ * `onExternalFile` to collect them instead of writing them to disk.
81
88
  */
82
- const processContentDeclarationContent = async (dictionary) => (0, _intlayer_core_interpreter.deepTransformNode)(dictionary, {
89
+ const processContentDeclarationContent = async (dictionary, onExternalFile = writeExternalFileToDisk) => (0, _intlayer_core_interpreter.deepTransformNode)(dictionary, {
83
90
  dictionaryKey: dictionary.key,
84
91
  keyPath: [],
85
92
  plugins: [
86
- writeFilePlugin,
93
+ getWriteFilePlugin(onExternalFile),
87
94
  markdownFilePlugin,
88
95
  insertionFilePlugin,
89
96
  htmlFilePlugin
@@ -1 +1 @@
1
- {"version":3,"file":"processContentDeclarationContent.cjs","names":["NodeTypes","join","dirname","existsSync","x","colorizePath","deepTransformNode"],"sources":["../../../src/writeContentDeclaration/processContentDeclarationContent.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { colorizePath, x } from '@intlayer/config/logger';\nimport { deepTransformNode, type Plugins } from '@intlayer/core/interpreter';\nimport type {\n FileContent,\n FileContentConstructor,\n HTMLContent,\n HTMLContentConstructor,\n InsertionContent,\n InsertionContentConstructor,\n MarkdownContent,\n MarkdownContentConstructor,\n} from '@intlayer/core/transpiler';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Write file plugin\n */\n\nconst writeFilePlugin: Plugins = {\n id: 'write-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent) => {\n const fileContent = node.content;\n const filePath = node.fixedPath;\n\n if (typeof fileContent !== 'string') {\n throw new Error('File content must be a string');\n }\n\n if (typeof filePath !== 'string') {\n throw new Error('File path must be a string');\n }\n\n // Write the file to the file system\n try {\n const absoluteFilePath = join(process.cwd(), filePath);\n\n // Create the file directory if it doesn't exist\n const fileDirectory = dirname(absoluteFilePath);\n\n if (!existsSync(fileDirectory)) {\n mkdirSync(fileDirectory, { recursive: true });\n }\n\n // Write the file\n writeFileSync(absoluteFilePath, fileContent);\n } catch (error) {\n throw new Error(\n `${x} Error writing file to ${colorizePath(filePath)}: ${error}`\n );\n }\n\n const transformedFileContent: FileContentConstructor = {\n nodeType: NodeTypes.FILE,\n [NodeTypes.FILE]: node[NodeTypes.FILE],\n };\n\n return transformedFileContent;\n },\n};\n\n/**\n * Markdown file plugin\n */\n\nconst markdownFilePlugin: Plugins = {\n id: 'markdown-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.MARKDOWN,\n transform: (node: MarkdownContent, props, deepTransformNode) => {\n const simplifiedMarkdownNode: MarkdownContentConstructor = {\n nodeType: NodeTypes.MARKDOWN,\n [NodeTypes.MARKDOWN]: deepTransformNode(node[NodeTypes.MARKDOWN], props),\n };\n\n return simplifiedMarkdownNode;\n },\n};\n\n/**\n * Insertion file plugin\n */\n\nconst insertionFilePlugin: Plugins = {\n id: 'insertion-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const simplifiedInsertionNode: InsertionContentConstructor = {\n nodeType: NodeTypes.INSERTION,\n [NodeTypes.INSERTION]: deepTransformNode(\n node[NodeTypes.INSERTION],\n props\n ),\n };\n\n return simplifiedInsertionNode;\n },\n};\n\n/**\n * HTML file plugin\n */\n\nconst htmlFilePlugin: Plugins = {\n id: 'html-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.HTML,\n transform: (node: HTMLContent, props, deepTransformNode) => {\n const simplifiedHTMLNode: HTMLContentConstructor = {\n nodeType: NodeTypes.HTML,\n [NodeTypes.HTML]: deepTransformNode(node[NodeTypes.HTML], props),\n };\n\n return simplifiedHTMLNode;\n },\n};\n\n/**\n * Process content declaration content\n *\n * It filter node that are autogenerated by intlayer to do not rewrite them in the content declaration file.\n *\n * And write external sources as file content if necessary.\n */\nexport const processContentDeclarationContent = async (\n dictionary: Dictionary\n) =>\n deepTransformNode(dictionary, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [\n writeFilePlugin,\n markdownFilePlugin,\n insertionFilePlugin,\n htmlFilePlugin,\n ],\n });\n"],"mappings":";;;;;;;;;;;;;AAqBA,MAAM,kBAA2B;CAC/B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,SAAsB;EAChC,MAAM,cAAc,KAAK;EACzB,MAAM,WAAW,KAAK;EAEtB,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MAAM,+BAA+B;EAGjD,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,MAAM,4BAA4B;EAI9C,IAAI;GACF,MAAM,uBAAmBC,gBAAK,QAAQ,IAAI,GAAG,QAAQ;GAGrD,MAAM,oBAAgBC,mBAAQ,gBAAgB;GAE9C,IAAI,KAACC,oBAAW,aAAa,GAC3B,uBAAU,eAAe,EAAE,WAAW,KAAK,CAAC;GAI9C,2BAAc,kBAAkB,WAAW;EAC7C,SAAS,OAAO;GACd,MAAM,IAAI,MACR,GAAGC,0BAAE,6BAAyBC,sCAAa,QAAQ,EAAE,IAAI,OAC3D;EACF;EAOA,OAAO;GAJL,UAAUL,yBAAU;IACnBA,yBAAU,OAAO,KAAKA,yBAAU;EAGP;CAC9B;AACF;;;;AAMA,MAAM,qBAA8B;CAClC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAuB,OAAO,sBAAsB;EAM9D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,WAAW,kBAAkB,KAAKA,yBAAU,WAAW,KAAK;EAG7C;CAC9B;AACF;;;;AAMA,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAS/D,OAAO;GAPL,UAAUA,yBAAU;IACnBA,yBAAU,YAAY,kBACrB,KAAKA,yBAAU,YACf,KACF;EAG2B;CAC/B;AACF;;;;AAMA,MAAM,iBAA0B;CAC9B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAmB,OAAO,sBAAsB;EAM1D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,OAAO,kBAAkB,KAAKA,yBAAU,OAAO,KAAK;EAGzC;CAC1B;AACF;;;;;;;;AASA,MAAa,mCAAmC,OAC9C,mBAEAM,8CAAkB,YAAY;CAC5B,eAAe,WAAW;CAC1B,SAAS,CAAC;CACV,SAAS;EACP;EACA;EACA;EACA;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"processContentDeclarationContent.cjs","names":["join","dirname","existsSync","x","colorizePath","NodeTypes","deepTransformNode"],"sources":["../../../src/writeContentDeclaration/processContentDeclarationContent.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { colorizePath, x } from '@intlayer/config/logger';\nimport { deepTransformNode, type Plugins } from '@intlayer/core/interpreter';\nimport type {\n FileContent,\n FileContentConstructor,\n HTMLContent,\n HTMLContentConstructor,\n InsertionContent,\n InsertionContentConstructor,\n MarkdownContent,\n MarkdownContentConstructor,\n} from '@intlayer/core/transpiler';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\n\n/**\n * Receives the content of a `file()` node instead of writing it to disk.\n * `filePath` is relative to the project base directory.\n */\nexport type ExternalFileHandler = (filePath: string, content: string) => void;\n\n/**\n * Writes the content of a `file()` node to disk.\n */\nconst writeExternalFileToDisk: ExternalFileHandler = (\n filePath,\n fileContent\n) => {\n try {\n const absoluteFilePath = join(process.cwd(), filePath);\n\n // Create the file directory if it doesn't exist\n const fileDirectory = dirname(absoluteFilePath);\n\n if (!existsSync(fileDirectory)) {\n mkdirSync(fileDirectory, { recursive: true });\n }\n\n // Write the file\n writeFileSync(absoluteFilePath, fileContent);\n } catch (error) {\n throw new Error(\n `${x} Error writing file to ${colorizePath(filePath)}: ${error}`\n );\n }\n};\n\n/**\n * Write file plugin\n */\n\nconst getWriteFilePlugin = (onExternalFile: ExternalFileHandler): Plugins => ({\n id: 'write-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent) => {\n const fileContent = node.content;\n const filePath = node.fixedPath;\n\n if (typeof fileContent !== 'string') {\n throw new Error('File content must be a string');\n }\n\n if (typeof filePath !== 'string') {\n throw new Error('File path must be a string');\n }\n\n onExternalFile(filePath, fileContent);\n\n const transformedFileContent: FileContentConstructor = {\n nodeType: NodeTypes.FILE,\n [NodeTypes.FILE]: node[NodeTypes.FILE],\n };\n\n return transformedFileContent;\n },\n});\n\n/**\n * Markdown file plugin\n */\n\nconst markdownFilePlugin: Plugins = {\n id: 'markdown-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.MARKDOWN,\n transform: (node: MarkdownContent, props, deepTransformNode) => {\n const simplifiedMarkdownNode: MarkdownContentConstructor = {\n nodeType: NodeTypes.MARKDOWN,\n [NodeTypes.MARKDOWN]: deepTransformNode(node[NodeTypes.MARKDOWN], props),\n };\n\n return simplifiedMarkdownNode;\n },\n};\n\n/**\n * Insertion file plugin\n */\n\nconst insertionFilePlugin: Plugins = {\n id: 'insertion-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const simplifiedInsertionNode: InsertionContentConstructor = {\n nodeType: NodeTypes.INSERTION,\n [NodeTypes.INSERTION]: deepTransformNode(\n node[NodeTypes.INSERTION],\n props\n ),\n };\n\n return simplifiedInsertionNode;\n },\n};\n\n/**\n * HTML file plugin\n */\n\nconst htmlFilePlugin: Plugins = {\n id: 'html-file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.HTML,\n transform: (node: HTMLContent, props, deepTransformNode) => {\n const simplifiedHTMLNode: HTMLContentConstructor = {\n nodeType: NodeTypes.HTML,\n [NodeTypes.HTML]: deepTransformNode(node[NodeTypes.HTML], props),\n };\n\n return simplifiedHTMLNode;\n },\n};\n\n/**\n * Process content declaration content\n *\n * It filter node that are autogenerated by intlayer to do not rewrite them in the content declaration file.\n *\n * And write external sources as file content if necessary. Pass\n * `onExternalFile` to collect them instead of writing them to disk.\n */\nexport const processContentDeclarationContent = async (\n dictionary: Dictionary,\n onExternalFile: ExternalFileHandler = writeExternalFileToDisk\n) =>\n deepTransformNode(dictionary, {\n dictionaryKey: dictionary.key,\n keyPath: [],\n plugins: [\n getWriteFilePlugin(onExternalFile),\n markdownFilePlugin,\n insertionFilePlugin,\n htmlFilePlugin,\n ],\n });\n"],"mappings":";;;;;;;;;;;;;AA0BA,MAAM,2BACJ,UACA,gBACG;CACH,IAAI;EACF,MAAM,uBAAmBA,gBAAK,QAAQ,IAAI,GAAG,QAAQ;EAGrD,MAAM,oBAAgBC,mBAAQ,gBAAgB;EAE9C,IAAI,KAACC,oBAAW,aAAa,GAC3B,uBAAU,eAAe,EAAE,WAAW,KAAK,CAAC;EAI9C,2BAAc,kBAAkB,WAAW;CAC7C,SAAS,OAAO;EACd,MAAM,IAAI,MACR,GAAGC,0BAAE,6BAAyBC,sCAAa,QAAQ,EAAE,IAAI,OAC3D;CACF;AACF;;;;AAMA,MAAM,sBAAsB,oBAAkD;CAC5E,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaC,yBAAU;CAC3D,YAAY,SAAsB;EAChC,MAAM,cAAc,KAAK;EACzB,MAAM,WAAW,KAAK;EAEtB,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MAAM,+BAA+B;EAGjD,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,MAAM,4BAA4B;EAG9C,eAAe,UAAU,WAAW;EAOpC,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,OAAO,KAAKA,yBAAU;EAGP;CAC9B;AACF;;;;AAMA,MAAM,qBAA8B;CAClC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAuB,OAAO,sBAAsB;EAM9D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,WAAW,kBAAkB,KAAKA,yBAAU,WAAW,KAAK;EAG7C;CAC9B;AACF;;;;AAMA,MAAM,sBAA+B;CACnC,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAS/D,OAAO;GAPL,UAAUA,yBAAU;IACnBA,yBAAU,YAAY,kBACrB,KAAKA,yBAAU,YACf,KACF;EAG2B;CAC/B;AACF;;;;AAMA,MAAM,iBAA0B;CAC9B,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAmB,OAAO,sBAAsB;EAM1D,OAAO;GAJL,UAAUA,yBAAU;IACnBA,yBAAU,OAAO,kBAAkB,KAAKA,yBAAU,OAAO,KAAK;EAGzC;CAC1B;AACF;;;;;;;;;AAUA,MAAa,mCAAmC,OAC9C,YACA,iBAAsC,gCAEtCC,8CAAkB,YAAY;CAC5B,eAAe,WAAW;CAC1B,SAAS,CAAC;CACV,SAAS;EACP,mBAAmB,cAAc;EACjC;EACA;EACA;CACF;AACF,CAAC"}
@@ -0,0 +1,213 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_utils_getFormatFromExtension = require('../utils/getFormatFromExtension.cjs');
3
+ const require_writeContentDeclaration_processContentDeclarationContent = require('./processContentDeclarationContent.cjs');
4
+ const require_writeContentDeclaration_transformJSFile = require('./transformJSFile.cjs');
5
+ const require_writeContentDeclaration_transformJSONFile = require('./transformJSONFile.cjs');
6
+ let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
7
+ let _intlayer_core_plugins = require("@intlayer/core/plugins");
8
+ let _intlayer_core_utils = require("@intlayer/core/utils");
9
+
10
+ //#region src/writeContentDeclaration/renderContentDeclaration.ts
11
+ /**
12
+ * Fields that are internal to the build and must never be persisted in a
13
+ * content declaration file.
14
+ */
15
+ const INTERNAL_FIELDS = /* @__PURE__ */ new Set([
16
+ "$schema",
17
+ "filePath",
18
+ "localId",
19
+ "localIds",
20
+ "projectIds"
21
+ ]);
22
+ /** Fields that are auto-generated or runtime-only, not persisted in YAML. */
23
+ const EXCLUDED_YAML_KEYS = /* @__PURE__ */ new Set([
24
+ "$schema",
25
+ "id",
26
+ "filePath"
27
+ ]);
28
+ /** Fields that must not appear in a markdown frontmatter. */
29
+ const EXCLUDED_FRONTMATTER_KEYS = /* @__PURE__ */ new Set([...INTERNAL_FIELDS, "content"]);
30
+ const JS_EXTENSIONS = /* @__PURE__ */ new Set([
31
+ ".ts",
32
+ ".tsx",
33
+ ".js",
34
+ ".jsx",
35
+ ".mjs",
36
+ ".cjs"
37
+ ]);
38
+ const JSON_EXTENSIONS = /* @__PURE__ */ new Set([
39
+ ".json",
40
+ ".jsonc",
41
+ ".json5"
42
+ ]);
43
+ const MARKDOWN_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx"]);
44
+ const YAML_EXTENSIONS = /* @__PURE__ */ new Set([".yaml", ".yml"]);
45
+ const getExtension = (filePath) => {
46
+ const fileName = filePath.split(/[\\/]/).pop() ?? "";
47
+ const dotIndex = fileName.lastIndexOf(".");
48
+ return dotIndex === -1 ? "" : fileName.slice(dotIndex).toLowerCase();
49
+ };
50
+ const omitFields = (record, excludedFields) => Object.fromEntries(Object.entries(record).filter(([fieldName, value]) => !excludedFields.has(fieldName) && value !== void 0));
51
+ /**
52
+ * Whether a content declaration file can be rewritten from a dictionary.
53
+ * Other extensions (e.g. `.po`) are owned by plugins.
54
+ */
55
+ const isRenderableContentDeclarationPath = (filePath) => {
56
+ const extension = getExtension(filePath);
57
+ return JS_EXTENSIONS.has(extension) || JSON_EXTENSIONS.has(extension) || MARKDOWN_EXTENSIONS.has(extension) || YAML_EXTENSIONS.has(extension);
58
+ };
59
+ /**
60
+ * Cleans a dictionary before persisting it: strips auto-generated node
61
+ * metadata, filters locales, and applies the plugins `formatOutput` hooks.
62
+ */
63
+ const formatContentDeclaration = async (dictionary, options = {}) => {
64
+ const { configuration, localeList, onExternalFile } = options;
65
+ const processedDictionary = await require_writeContentDeclaration_processContentDeclarationContent.processContentDeclarationContent(dictionary, onExternalFile);
66
+ let content = processedDictionary.content;
67
+ if (dictionary.locale) content = (0, _intlayer_core_plugins.getPerLocaleDictionary)(processedDictionary, dictionary.locale).content;
68
+ else if (localeList) content = (0, _intlayer_core_plugins.getFilteredLocalesDictionary)(processedDictionary, localeList).content;
69
+ let pluginFormatResult = {
70
+ ...dictionary,
71
+ content
72
+ };
73
+ for await (const plugin of configuration?.plugins ?? []) if (plugin.formatOutput && configuration) {
74
+ const formattedResult = await plugin.formatOutput({
75
+ dictionary: pluginFormatResult,
76
+ configuration
77
+ });
78
+ if (formattedResult) pluginFormatResult = formattedResult;
79
+ }
80
+ if (!(pluginFormatResult.content && pluginFormatResult.key)) return pluginFormatResult;
81
+ let result = {
82
+ ...omitFields(dictionary, INTERNAL_FIELDS),
83
+ content
84
+ };
85
+ const extension = dictionary.filePath ? getExtension(dictionary.filePath) : ".json";
86
+ if (require_utils_getFormatFromExtension.getFormatFromExtension(extension) === "json") result = {
87
+ $schema: "https://intlayer.org/schema.json",
88
+ ...result
89
+ };
90
+ return result;
91
+ };
92
+ const stringifyYamlFrontmatter = (fields) => Object.entries(fields).filter(([, value]) => value !== void 0 && value !== null).map(([fieldName, value]) => {
93
+ if (Array.isArray(value)) return `${fieldName}:\n${value.map((item) => ` - ${JSON.stringify(item)}`).join("\n")}`;
94
+ if (typeof value === "string" && (value.includes(":") || value.includes("\n") || value.includes("#"))) return `${fieldName}: ${JSON.stringify(value)}`;
95
+ return `${fieldName}: ${value}`;
96
+ }).join("\n");
97
+ /**
98
+ * Splits a markdown string into its YAML frontmatter and its body.
99
+ */
100
+ const splitMarkdown = (markdown) => {
101
+ const lines = markdown.split(/\r?\n/);
102
+ const firstNonEmptyIndex = lines.findIndex((line) => line.trim() !== "");
103
+ if (firstNonEmptyIndex === -1 || lines[firstNonEmptyIndex]?.trim() !== "---") return {
104
+ frontmatter: void 0,
105
+ body: markdown
106
+ };
107
+ const endIndex = lines.findIndex((line, index) => index > firstNonEmptyIndex && line.trim() === "---");
108
+ if (endIndex === -1) return {
109
+ frontmatter: void 0,
110
+ body: markdown
111
+ };
112
+ return {
113
+ frontmatter: lines.slice(firstNonEmptyIndex + 1, endIndex).join("\n"),
114
+ body: lines.slice(endIndex + 1).join("\n").trimStart()
115
+ };
116
+ };
117
+ /**
118
+ * Renders a `.content.md` file. When the current file is provided, its
119
+ * frontmatter fields are kept and only overridden by the dictionary ones; the
120
+ * original frontmatter text is reused verbatim when nothing changed.
121
+ */
122
+ const renderMarkdownContentDeclaration = (dictionary, existingFileContent) => {
123
+ const content = dictionary.content;
124
+ const markdownRaw = typeof content === "object" && content?.nodeType === _intlayer_types_nodeType.MARKDOWN ? String(content[_intlayer_types_nodeType.MARKDOWN] ?? "") : "";
125
+ const { body } = splitMarkdown(markdownRaw);
126
+ const dictionaryFields = omitFields(dictionary, EXCLUDED_FRONTMATTER_KEYS);
127
+ const existingFrontmatter = existingFileContent === void 0 ? void 0 : splitMarkdown(existingFileContent).frontmatter;
128
+ if (existingFrontmatter === void 0) return `---\n${stringifyYamlFrontmatter(dictionaryFields)}\n---\n\n${body}`;
129
+ const existingFields = (0, _intlayer_core_utils.parseYaml)(existingFrontmatter) ?? {};
130
+ const mergedFields = {
131
+ ...existingFields,
132
+ ...dictionaryFields
133
+ };
134
+ const mergedFrontmatter = stringifyYamlFrontmatter(mergedFields);
135
+ return `---\n${stringifyYamlFrontmatter(existingFields) === mergedFrontmatter ? existingFrontmatter : mergedFrontmatter}\n---\n\n${body}`;
136
+ };
137
+ /**
138
+ * Renders a `.content.yaml` file. When the current file is provided, its
139
+ * fields are kept and only overridden by the dictionary ones; the original
140
+ * text is returned untouched when nothing changed.
141
+ */
142
+ const renderYamlContentDeclaration = (dictionary, existingFileContent) => {
143
+ const dictionaryFields = omitFields(dictionary, EXCLUDED_YAML_KEYS);
144
+ if (existingFileContent === void 0) return (0, _intlayer_core_utils.stringifyYaml)(dictionaryFields);
145
+ const existingFields = (0, _intlayer_core_utils.parseYaml)(existingFileContent) ?? {};
146
+ const mergedFields = {
147
+ ...existingFields,
148
+ ...dictionaryFields
149
+ };
150
+ if ((0, _intlayer_core_utils.stringifyYaml)(existingFields) === (0, _intlayer_core_utils.stringifyYaml)(mergedFields)) return existingFileContent;
151
+ return (0, _intlayer_core_utils.stringifyYaml)(mergedFields);
152
+ };
153
+ /**
154
+ * Whether a content declaration source declares only the content (compiler
155
+ * `noMetadata` mode) rather than a `{ key, content }` dictionary.
156
+ */
157
+ const isContentOnlyDeclaration = (fileContent, extension) => {
158
+ if (JSON_EXTENSIONS.has(extension)) try {
159
+ const parsed = JSON.parse(fileContent);
160
+ return !("content" in parsed) && !("key" in parsed);
161
+ } catch {
162
+ return false;
163
+ }
164
+ return !/(^|[\s{,])['"]?content['"]?\s*:/m.test(fileContent);
165
+ };
166
+ /**
167
+ * Renders the new source of an existing content declaration file from a
168
+ * dictionary, without touching the file system. JS/TS and JSON sources are
169
+ * updated through their AST so untouched code keeps its formatting.
170
+ *
171
+ * Returns `undefined` for formats owned by plugins (e.g. `.po`).
172
+ */
173
+ const renderContentDeclaration = async (dictionary, options) => {
174
+ const { filePath, fileContent, configuration, localeList } = options;
175
+ const extension = getExtension(filePath);
176
+ if (!isRenderableContentDeclarationPath(filePath)) return void 0;
177
+ const externalFiles = {};
178
+ const formattedDictionary = await formatContentDeclaration({
179
+ ...dictionary,
180
+ filePath
181
+ }, {
182
+ configuration,
183
+ localeList,
184
+ onExternalFile: (externalFilePath, externalFileContent) => {
185
+ externalFiles[externalFilePath] = externalFileContent;
186
+ }
187
+ });
188
+ if (MARKDOWN_EXTENSIONS.has(extension)) return {
189
+ fileContent: renderMarkdownContentDeclaration(formattedDictionary, fileContent),
190
+ externalFiles
191
+ };
192
+ if (YAML_EXTENSIONS.has(extension)) return {
193
+ fileContent: renderYamlContentDeclaration(formattedDictionary, fileContent),
194
+ externalFiles
195
+ };
196
+ const noMetadata = options.noMetadata ?? isContentOnlyDeclaration(fileContent, extension);
197
+ if (JSON_EXTENSIONS.has(extension)) return {
198
+ fileContent: require_writeContentDeclaration_transformJSONFile.transformJSONFile(fileContent, formattedDictionary, noMetadata),
199
+ externalFiles
200
+ };
201
+ return {
202
+ fileContent: await require_writeContentDeclaration_transformJSFile.transformJSFile(fileContent, formattedDictionary, dictionary.locale, noMetadata),
203
+ externalFiles
204
+ };
205
+ };
206
+
207
+ //#endregion
208
+ exports.formatContentDeclaration = formatContentDeclaration;
209
+ exports.isRenderableContentDeclarationPath = isRenderableContentDeclarationPath;
210
+ exports.renderContentDeclaration = renderContentDeclaration;
211
+ exports.renderMarkdownContentDeclaration = renderMarkdownContentDeclaration;
212
+ exports.renderYamlContentDeclaration = renderYamlContentDeclaration;
213
+ //# sourceMappingURL=renderContentDeclaration.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderContentDeclaration.cjs","names":["processContentDeclarationContent","getPerLocaleDictionary","getFilteredLocalesDictionary","getFormatFromExtension","MARKDOWN","parseYaml","stringifyYaml","transformJSONFile","transformJSFile"],"sources":["../../../src/writeContentDeclaration/renderContentDeclaration.ts"],"sourcesContent":["import {\n getFilteredLocalesDictionary,\n getPerLocaleDictionary,\n} from '@intlayer/core/plugins';\nimport { parseYaml, stringifyYaml } from '@intlayer/core/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { MARKDOWN } from '@intlayer/types/nodeType';\nimport {\n type Extension,\n getFormatFromExtension,\n} from '../utils/getFormatFromExtension';\nimport {\n type ExternalFileHandler,\n processContentDeclarationContent,\n} from './processContentDeclarationContent';\nimport { transformJSFile } from './transformJSFile';\nimport { transformJSONFile } from './transformJSONFile';\n\n/**\n * Fields that are internal to the build and must never be persisted in a\n * content declaration file.\n */\nconst INTERNAL_FIELDS = new Set<string>([\n '$schema',\n 'filePath',\n 'localId',\n 'localIds',\n 'projectIds',\n]);\n\n/** Fields that are auto-generated or runtime-only, not persisted in YAML. */\nconst EXCLUDED_YAML_KEYS = new Set<string>(['$schema', 'id', 'filePath']);\n\n/** Fields that must not appear in a markdown frontmatter. */\nconst EXCLUDED_FRONTMATTER_KEYS = new Set<string>([\n ...INTERNAL_FIELDS,\n 'content',\n]);\n\nconst JS_EXTENSIONS = new Set<string>([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n]);\n\nconst JSON_EXTENSIONS = new Set<string>(['.json', '.jsonc', '.json5']);\n\nconst MARKDOWN_EXTENSIONS = new Set<string>(['.md', '.mdx']);\n\nconst YAML_EXTENSIONS = new Set<string>(['.yaml', '.yml']);\n\nconst getExtension = (filePath: string): string => {\n const fileName = filePath.split(/[\\\\/]/).pop() ?? '';\n const dotIndex = fileName.lastIndexOf('.');\n\n return dotIndex === -1 ? '' : fileName.slice(dotIndex).toLowerCase();\n};\n\nconst omitFields = (\n record: Record<string, unknown>,\n excludedFields: Set<string>\n): Record<string, unknown> =>\n Object.fromEntries(\n Object.entries(record).filter(\n ([fieldName, value]) =>\n !excludedFields.has(fieldName) && value !== undefined\n )\n );\n\n/**\n * Whether a content declaration file can be rewritten from a dictionary.\n * Other extensions (e.g. `.po`) are owned by plugins.\n */\nexport const isRenderableContentDeclarationPath = (\n filePath: string\n): boolean => {\n const extension = getExtension(filePath);\n\n return (\n JS_EXTENSIONS.has(extension) ||\n JSON_EXTENSIONS.has(extension) ||\n MARKDOWN_EXTENSIONS.has(extension) ||\n YAML_EXTENSIONS.has(extension)\n );\n};\n\ntype FormatContentDeclarationOptions = {\n /** Plugins `formatOutput` hooks are applied when provided. */\n configuration?: IntlayerConfig;\n localeList?: LocalesValues[];\n /** Collects `file()` node contents instead of writing them to disk. */\n onExternalFile?: ExternalFileHandler;\n};\n\n/**\n * Cleans a dictionary before persisting it: strips auto-generated node\n * metadata, filters locales, and applies the plugins `formatOutput` hooks.\n */\nexport const formatContentDeclaration = async (\n dictionary: Dictionary,\n options: FormatContentDeclarationOptions = {}\n): Promise<Dictionary> => {\n const { configuration, localeList, onExternalFile } = options;\n\n const processedDictionary = await processContentDeclarationContent(\n dictionary,\n onExternalFile\n );\n\n let content = processedDictionary.content;\n\n if (dictionary.locale) {\n content = getPerLocaleDictionary(\n processedDictionary,\n dictionary.locale\n ).content;\n } else if (localeList) {\n content = getFilteredLocalesDictionary(\n processedDictionary,\n localeList\n ).content;\n }\n\n let pluginFormatResult: any = {\n ...dictionary,\n content,\n } satisfies Dictionary;\n\n for await (const plugin of configuration?.plugins ?? []) {\n if (plugin.formatOutput && configuration) {\n const formattedResult = await plugin.formatOutput({\n dictionary: pluginFormatResult,\n configuration,\n });\n\n if (formattedResult) {\n pluginFormatResult = formattedResult;\n }\n }\n }\n\n const isDictionaryFormat =\n pluginFormatResult.content && pluginFormatResult.key;\n\n if (!isDictionaryFormat) return pluginFormatResult;\n\n // Build result from the original dictionary so that extra user-defined\n // fields (e.g. custom frontmatter in markdown files) are preserved.\n let result = {\n ...omitFields(dictionary as Record<string, unknown>, INTERNAL_FIELDS),\n content,\n } as Dictionary;\n\n const extension = (\n dictionary.filePath ? getExtension(dictionary.filePath) : '.json'\n ) as Extension;\n\n if (getFormatFromExtension(extension) === 'json') {\n result = {\n $schema: 'https://intlayer.org/schema.json',\n ...result,\n } as Dictionary;\n }\n\n return result;\n};\n\nconst stringifyYamlFrontmatter = (fields: Record<string, unknown>): string =>\n Object.entries(fields)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([fieldName, value]) => {\n if (Array.isArray(value)) {\n return `${fieldName}:\\n${value.map((item) => ` - ${JSON.stringify(item)}`).join('\\n')}`;\n }\n if (\n typeof value === 'string' &&\n (value.includes(':') || value.includes('\\n') || value.includes('#'))\n ) {\n return `${fieldName}: ${JSON.stringify(value)}`;\n }\n return `${fieldName}: ${value}`;\n })\n .join('\\n');\n\ntype SplitMarkdown = {\n /** Raw frontmatter text, without the `---` fences. */\n frontmatter: string | undefined;\n body: string;\n};\n\n/**\n * Splits a markdown string into its YAML frontmatter and its body.\n */\nconst splitMarkdown = (markdown: string): SplitMarkdown => {\n const lines = markdown.split(/\\r?\\n/);\n const firstNonEmptyIndex = lines.findIndex((line) => line.trim() !== '');\n\n if (\n firstNonEmptyIndex === -1 ||\n lines[firstNonEmptyIndex]?.trim() !== '---'\n ) {\n return { frontmatter: undefined, body: markdown };\n }\n\n const endIndex = lines.findIndex(\n (line, index) => index > firstNonEmptyIndex && line.trim() === '---'\n );\n\n if (endIndex === -1) return { frontmatter: undefined, body: markdown };\n\n return {\n frontmatter: lines.slice(firstNonEmptyIndex + 1, endIndex).join('\\n'),\n body: lines\n .slice(endIndex + 1)\n .join('\\n')\n .trimStart(),\n };\n};\n\n/**\n * Renders a `.content.md` file. When the current file is provided, its\n * frontmatter fields are kept and only overridden by the dictionary ones; the\n * original frontmatter text is reused verbatim when nothing changed.\n */\nexport const renderMarkdownContentDeclaration = (\n dictionary: Dictionary,\n existingFileContent?: string\n): string => {\n const content = dictionary.content as Record<string, unknown> | undefined;\n const markdownRaw =\n typeof content === 'object' && content?.nodeType === MARKDOWN\n ? String(content[MARKDOWN] ?? '')\n : '';\n // content.markdown stores the full file (frontmatter + body)\n const { body } = splitMarkdown(markdownRaw);\n\n const dictionaryFields = omitFields(\n dictionary as Record<string, unknown>,\n EXCLUDED_FRONTMATTER_KEYS\n );\n\n const existingFrontmatter =\n existingFileContent === undefined\n ? undefined\n : splitMarkdown(existingFileContent).frontmatter;\n\n if (existingFrontmatter === undefined) {\n return `---\\n${stringifyYamlFrontmatter(dictionaryFields)}\\n---\\n\\n${body}`;\n }\n\n const existingFields =\n parseYaml<Record<string, unknown>>(existingFrontmatter) ?? {};\n const mergedFields = { ...existingFields, ...dictionaryFields };\n\n const mergedFrontmatter = stringifyYamlFrontmatter(mergedFields);\n const frontmatter =\n stringifyYamlFrontmatter(existingFields) === mergedFrontmatter\n ? existingFrontmatter\n : mergedFrontmatter;\n\n return `---\\n${frontmatter}\\n---\\n\\n${body}`;\n};\n\n/**\n * Renders a `.content.yaml` file. When the current file is provided, its\n * fields are kept and only overridden by the dictionary ones; the original\n * text is returned untouched when nothing changed.\n */\nexport const renderYamlContentDeclaration = (\n dictionary: Dictionary,\n existingFileContent?: string\n): string => {\n const dictionaryFields = omitFields(\n dictionary as Record<string, unknown>,\n EXCLUDED_YAML_KEYS\n );\n\n if (existingFileContent === undefined) {\n return stringifyYaml(dictionaryFields);\n }\n\n const existingFields =\n parseYaml<Record<string, unknown>>(existingFileContent) ?? {};\n const mergedFields = { ...existingFields, ...dictionaryFields };\n\n if (stringifyYaml(existingFields) === stringifyYaml(mergedFields)) {\n return existingFileContent;\n }\n\n return stringifyYaml(mergedFields);\n};\n\n/**\n * Whether a content declaration source declares only the content (compiler\n * `noMetadata` mode) rather than a `{ key, content }` dictionary.\n */\nconst isContentOnlyDeclaration = (\n fileContent: string,\n extension: string\n): boolean => {\n if (JSON_EXTENSIONS.has(extension)) {\n try {\n const parsed = JSON.parse(fileContent) as Record<string, unknown>;\n\n return !('content' in parsed) && !('key' in parsed);\n } catch {\n return false;\n }\n }\n\n return !/(^|[\\s{,])['\"]?content['\"]?\\s*:/m.test(fileContent);\n};\n\nexport type RenderContentDeclarationOptions = {\n /** Path of the content declaration file, used to pick its format. */\n filePath: string;\n /** Current source of the file. */\n fileContent: string;\n /** Applies the plugins `formatOutput` hooks when provided. */\n configuration?: IntlayerConfig;\n localeList?: LocalesValues[];\n /** Forces the `noMetadata` mode; detected from the source when omitted. */\n noMetadata?: boolean;\n};\n\nexport type RenderedContentDeclaration = {\n /** New source of the content declaration file. */\n fileContent: string;\n /** Content of the `file()` nodes, keyed by path relative to the base dir. */\n externalFiles: Record<string, string>;\n};\n\n/**\n * Renders the new source of an existing content declaration file from a\n * dictionary, without touching the file system. JS/TS and JSON sources are\n * updated through their AST so untouched code keeps its formatting.\n *\n * Returns `undefined` for formats owned by plugins (e.g. `.po`).\n */\nexport const renderContentDeclaration = async (\n dictionary: Dictionary,\n options: RenderContentDeclarationOptions\n): Promise<RenderedContentDeclaration | undefined> => {\n const { filePath, fileContent, configuration, localeList } = options;\n const extension = getExtension(filePath);\n\n if (!isRenderableContentDeclarationPath(filePath)) return undefined;\n\n const externalFiles: Record<string, string> = {};\n\n const formattedDictionary = await formatContentDeclaration(\n { ...dictionary, filePath },\n {\n configuration,\n localeList,\n onExternalFile: (externalFilePath, externalFileContent) => {\n externalFiles[externalFilePath] = externalFileContent;\n },\n }\n );\n\n if (MARKDOWN_EXTENSIONS.has(extension)) {\n return {\n fileContent: renderMarkdownContentDeclaration(\n formattedDictionary,\n fileContent\n ),\n externalFiles,\n };\n }\n\n if (YAML_EXTENSIONS.has(extension)) {\n return {\n fileContent: renderYamlContentDeclaration(\n formattedDictionary,\n fileContent\n ),\n externalFiles,\n };\n }\n\n const noMetadata =\n options.noMetadata ?? isContentOnlyDeclaration(fileContent, extension);\n\n if (JSON_EXTENSIONS.has(extension)) {\n return {\n fileContent: transformJSONFile(\n fileContent,\n formattedDictionary,\n noMetadata\n ),\n externalFiles,\n };\n }\n\n return {\n fileContent: await transformJSFile(\n fileContent,\n formattedDictionary,\n dictionary.locale as Locale | undefined,\n noMetadata\n ),\n externalFiles,\n };\n};\n"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_utils_getFormatFromExtension = require('../utils/getFormatFromExtension.cjs');
3
2
  const require_detectFormatCommand = require('../detectFormatCommand.cjs');
4
3
  const require_utils_readDictionariesFromDisk = require('../utils/readDictionariesFromDisk.cjs');
5
- const require_writeContentDeclaration_processContentDeclarationContent = require('./processContentDeclarationContent.cjs');
6
4
  const require_writeContentDeclaration_transformJSONFile = require('./transformJSONFile.cjs');
5
+ const require_writeContentDeclaration_renderContentDeclaration = require('./renderContentDeclaration.cjs');
7
6
  const require_writeContentDeclaration_writeJSFile = require('./writeJSFile.cjs');
8
7
  const require_writeContentDeclaration_writeMarkdownFile = require('./writeMarkdownFile.cjs');
9
8
  const require_writeContentDeclaration_writeYamlFile = require('./writeYamlFile.cjs');
@@ -12,57 +11,9 @@ let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
12
11
  let node_fs = require("node:fs");
13
12
  let node_fs_promises = require("node:fs/promises");
14
13
  let node_child_process = require("node:child_process");
15
- let _intlayer_core_plugins = require("@intlayer/core/plugins");
16
14
  let node_util = require("node:util");
17
15
 
18
16
  //#region src/writeContentDeclaration/writeContentDeclaration.ts
19
- const formatContentDeclaration = async (dictionary, configuration, localeList) => {
20
- /**
21
- * Clean Markdown, Insertion, File, etc. node metadata
22
- */
23
- const processedDictionary = await require_writeContentDeclaration_processContentDeclarationContent.processContentDeclarationContent(dictionary);
24
- let content = processedDictionary.content;
25
- /**
26
- * Filter locales content
27
- */
28
- if (dictionary.locale) content = (0, _intlayer_core_plugins.getPerLocaleDictionary)(processedDictionary, dictionary.locale).content;
29
- else if (localeList) content = (0, _intlayer_core_plugins.getFilteredLocalesDictionary)(processedDictionary, localeList).content;
30
- let pluginFormatResult = {
31
- ...dictionary,
32
- content
33
- };
34
- /**
35
- * Format the dictionary with the plugins
36
- */
37
- for await (const plugin of configuration.plugins ?? []) if (plugin.formatOutput) {
38
- const formattedResult = await plugin.formatOutput?.({
39
- dictionary: pluginFormatResult,
40
- configuration
41
- });
42
- if (formattedResult) pluginFormatResult = formattedResult;
43
- }
44
- if (!(pluginFormatResult.content && pluginFormatResult.key)) return pluginFormatResult;
45
- const INTERNAL_FIELDS = /* @__PURE__ */ new Set([
46
- "$schema",
47
- "filePath",
48
- "localId",
49
- "localIds",
50
- "projectIds"
51
- ]);
52
- let result = {
53
- ...Object.fromEntries(Object.entries(dictionary).filter(([k]) => !INTERNAL_FIELDS.has(k))),
54
- content
55
- };
56
- /**
57
- * Add $schema to JSON dictionaries
58
- */
59
- const extension = dictionary.filePath ? (0, node_path.extname)(dictionary.filePath) : ".json";
60
- if (require_utils_getFormatFromExtension.getFormatFromExtension(extension) === "json" && pluginFormatResult.content && pluginFormatResult.key) result = {
61
- $schema: "https://intlayer.org/schema.json",
62
- ...result
63
- };
64
- return result;
65
- };
66
17
  const defaultOptions = { newDictionariesPath: "intlayer-dictionaries" };
67
18
  const writeContentDeclaration = async (dictionary, configuration, options) => {
68
19
  const { system, compiler } = configuration;
@@ -74,7 +25,10 @@ const writeContentDeclaration = async (dictionary, configuration, options) => {
74
25
  };
75
26
  const newDictionaryLocationPath = (0, node_path.join)(baseDir, newDictionariesPath);
76
27
  const existingDictionary = require_utils_readDictionariesFromDisk.readDictionariesFromDisk(configuration.system.unmergedDictionariesDir)[dictionary.key]?.find((el) => el.localId === dictionary.localId);
77
- const formattedContentDeclaration = await formatContentDeclaration(dictionary, configuration, localeList);
28
+ const formattedContentDeclaration = await require_writeContentDeclaration_renderContentDeclaration.formatContentDeclaration(dictionary, {
29
+ configuration,
30
+ localeList
31
+ });
78
32
  if (existingDictionary?.filePath) {
79
33
  const isSameContent = (0, node_util.isDeepStrictEqual)(existingDictionary, dictionary);
80
34
  const filePath = (0, node_path.resolve)(configuration.system.baseDir, existingDictionary.filePath);
@@ -1 +1 @@
1
- {"version":3,"file":"writeContentDeclaration.cjs","names":["processContentDeclarationContent","getPerLocaleDictionary","getFilteredLocalesDictionary","extname","getFormatFromExtension","COMPILER_NO_METADATA","join","readDictionariesFromDisk","isDeepStrictEqual","resolve","dirname","mkdir","writeMarkdownFile","writeYamlFile","existsSync","readFile","transformJSONFile","basename","writeFile","rename","rm","detectFormatCommand","writeJSFile"],"sources":["../../../src/writeContentDeclaration/writeContentDeclaration.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { basename, dirname, extname, join, resolve } from 'node:path';\nimport { isDeepStrictEqual } from 'node:util';\nimport { COMPILER_NO_METADATA } from '@intlayer/config/defaultValues';\nimport {\n getFilteredLocalesDictionary,\n getPerLocaleDictionary,\n} from '@intlayer/core/plugins';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { detectFormatCommand } from '../detectFormatCommand';\nimport {\n type Extension,\n getFormatFromExtension,\n} from '../utils/getFormatFromExtension';\nimport { readDictionariesFromDisk } from '../utils/readDictionariesFromDisk';\nimport type { DictionaryStatus } from './dictionaryStatus';\nimport { processContentDeclarationContent } from './processContentDeclarationContent';\nimport { transformJSONFile } from './transformJSONFile';\nimport { writeJSFile } from './writeJSFile';\nimport { writeMarkdownFile } from './writeMarkdownFile';\nimport { writeYamlFile } from './writeYamlFile';\n\nconst formatContentDeclaration = async (\n dictionary: Dictionary,\n configuration: IntlayerConfig,\n localeList?: LocalesValues[]\n) => {\n /**\n * Clean Markdown, Insertion, File, etc. node metadata\n */\n const processedDictionary =\n await processContentDeclarationContent(dictionary);\n\n let content = processedDictionary.content;\n\n /**\n * Filter locales content\n */\n\n if (dictionary.locale) {\n content = getPerLocaleDictionary(\n processedDictionary,\n dictionary.locale\n ).content;\n } else if (localeList) {\n content = getFilteredLocalesDictionary(\n processedDictionary,\n localeList\n ).content;\n }\n\n let pluginFormatResult: any = {\n ...dictionary,\n content,\n } satisfies Dictionary;\n\n /**\n * Format the dictionary with the plugins\n */\n\n for await (const plugin of configuration.plugins ?? []) {\n if (plugin.formatOutput) {\n const formattedResult = await plugin.formatOutput?.({\n dictionary: pluginFormatResult,\n configuration,\n });\n\n if (formattedResult) {\n pluginFormatResult = formattedResult;\n }\n }\n }\n\n const isDictionaryFormat =\n pluginFormatResult.content && pluginFormatResult.key;\n\n if (!isDictionaryFormat) return pluginFormatResult;\n\n // Build result from the original dictionary so that extra user-defined fields\n // (e.g. custom frontmatter in markdown files) are preserved.\n // Strip internal-only fields that must never appear in persisted output.\n const INTERNAL_FIELDS = new Set([\n '$schema',\n 'filePath',\n 'localId',\n 'localIds',\n 'projectIds',\n ]);\n\n const preservedFields = Object.fromEntries(\n Object.entries(dictionary as Record<string, unknown>).filter(\n ([k]) => !INTERNAL_FIELDS.has(k)\n )\n );\n\n let result: Dictionary = {\n ...preservedFields,\n content,\n } as Dictionary;\n\n /**\n * Add $schema to JSON dictionaries\n */\n const extension = (\n dictionary.filePath ? extname(dictionary.filePath) : '.json'\n ) as Extension;\n const format = getFormatFromExtension(extension);\n\n if (\n format === 'json' &&\n pluginFormatResult.content &&\n pluginFormatResult.key\n ) {\n result = {\n $schema: 'https://intlayer.org/schema.json',\n ...result,\n };\n }\n\n return result;\n};\n\ntype WriteContentDeclarationOptions = {\n newDictionariesPath?: string;\n localeList?: LocalesValues[];\n fallbackLocale?: Locale;\n};\n\nconst defaultOptions = {\n newDictionariesPath: 'intlayer-dictionaries',\n} satisfies WriteContentDeclarationOptions;\n\nexport const writeContentDeclaration = async (\n dictionary: Dictionary,\n configuration: IntlayerConfig,\n options?: WriteContentDeclarationOptions\n): Promise<{ status: DictionaryStatus; path: string }> => {\n const { system, compiler } = configuration;\n const { baseDir } = system;\n\n const noMetadata = compiler?.noMetadata ?? COMPILER_NO_METADATA;\n const { newDictionariesPath, localeList } = {\n ...defaultOptions,\n ...options,\n };\n\n const newDictionaryLocationPath = join(baseDir, newDictionariesPath);\n\n const unmergedDictionariesRecord = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n const unmergedDictionaries = unmergedDictionariesRecord[\n dictionary.key\n ] as Dictionary[];\n\n const existingDictionary = unmergedDictionaries?.find(\n (el) => el.localId === dictionary.localId\n );\n\n const formattedContentDeclaration = await formatContentDeclaration(\n dictionary,\n configuration,\n localeList\n );\n\n if (existingDictionary?.filePath) {\n // Compare existing dictionary content with new dictionary content\n const isSameContent = isDeepStrictEqual(existingDictionary, dictionary);\n\n const filePath = resolve(\n configuration.system.baseDir,\n existingDictionary.filePath\n );\n\n // Up to date, nothing to do\n if (isSameContent) {\n return {\n status: 'up-to-date',\n path: filePath,\n };\n }\n\n await writeFileWithDirectories(\n filePath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return { status: 'updated', path: filePath };\n }\n\n if (dictionary.filePath) {\n const filePath = resolve(configuration.system.baseDir, dictionary.filePath);\n\n await writeFileWithDirectories(\n filePath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return { status: 'created', path: filePath };\n }\n\n // No existing dictionary, write to new location\n const contentDeclarationPath = join(\n newDictionaryLocationPath,\n `${dictionary.key}.content.json`\n );\n\n await writeFileWithDirectories(\n contentDeclarationPath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return {\n status: 'imported',\n path: contentDeclarationPath,\n };\n};\n\nconst writeFileWithDirectories = async (\n absoluteFilePath: string,\n dictionary: Dictionary,\n configuration: IntlayerConfig,\n noMetadata?: boolean\n): Promise<void> => {\n // Extract the directory from the file path\n const dir = dirname(absoluteFilePath);\n\n // Create the directory recursively\n await mkdir(dir, { recursive: true });\n\n const extension = extname(absoluteFilePath);\n\n if (extension === '.md' || extension === '.mdx') {\n await writeMarkdownFile(absoluteFilePath, dictionary, configuration);\n return;\n }\n\n if (extension === '.yaml' || extension === '.yml') {\n await writeYamlFile(absoluteFilePath, dictionary, configuration);\n return;\n }\n\n // Handle JSON, JSONC, and JSON5 via the AST transformer\n if (['.json', '.jsonc', '.json5'].includes(extension)) {\n let fileContent = '{}';\n\n if (existsSync(absoluteFilePath)) {\n try {\n fileContent = await readFile(absoluteFilePath, 'utf-8');\n } catch {\n // ignore read errors, start with empty object\n }\n }\n\n const transformedContent = transformJSONFile(\n fileContent,\n dictionary,\n noMetadata\n );\n\n // We use standard writeFile because transformedContent is already a string\n const tempDir = configuration.system?.tempDir;\n if (tempDir) {\n await mkdir(tempDir, { recursive: true });\n }\n\n const tempFileName = `${basename(absoluteFilePath)}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;\n const tempPath = tempDir\n ? join(tempDir, tempFileName)\n : `${absoluteFilePath}.${tempFileName}`;\n try {\n await writeFile(tempPath, transformedContent, 'utf-8');\n await rename(tempPath, absoluteFilePath);\n } catch (error) {\n try {\n await rm(tempPath, { force: true });\n } catch {\n // Ignore\n }\n throw error;\n }\n\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', absoluteFilePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n return;\n }\n\n const knownJsExtensions = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n ]);\n\n if (!knownJsExtensions.has(extension)) {\n // Unknown extension (e.g. .po managed by a plugin) — skip; the plugin\n // owns this file format and writeJSFile / prettier would corrupt it.\n return;\n }\n\n await writeJSFile(absoluteFilePath, dictionary, configuration, noMetadata);\n\n // remove the cache as content has changed\n // Will force a new preparation of the intlayer on next build\n try {\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n await rm(sentinelPath, { recursive: true });\n } catch {}\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"writeContentDeclaration.cjs","names":["COMPILER_NO_METADATA","join","readDictionariesFromDisk","formatContentDeclaration","isDeepStrictEqual","resolve","dirname","mkdir","extname","writeMarkdownFile","writeYamlFile","existsSync","readFile","transformJSONFile","basename","writeFile","rename","rm","detectFormatCommand","writeJSFile"],"sources":["../../../src/writeContentDeclaration/writeContentDeclaration.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { basename, dirname, extname, join, resolve } from 'node:path';\nimport { isDeepStrictEqual } from 'node:util';\nimport { COMPILER_NO_METADATA } from '@intlayer/config/defaultValues';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { detectFormatCommand } from '../detectFormatCommand';\nimport { readDictionariesFromDisk } from '../utils/readDictionariesFromDisk';\nimport type { DictionaryStatus } from './dictionaryStatus';\nimport { formatContentDeclaration } from './renderContentDeclaration';\nimport { transformJSONFile } from './transformJSONFile';\nimport { writeJSFile } from './writeJSFile';\nimport { writeMarkdownFile } from './writeMarkdownFile';\nimport { writeYamlFile } from './writeYamlFile';\n\ntype WriteContentDeclarationOptions = {\n newDictionariesPath?: string;\n localeList?: LocalesValues[];\n fallbackLocale?: Locale;\n};\n\nconst defaultOptions = {\n newDictionariesPath: 'intlayer-dictionaries',\n} satisfies WriteContentDeclarationOptions;\n\nexport const writeContentDeclaration = async (\n dictionary: Dictionary,\n configuration: IntlayerConfig,\n options?: WriteContentDeclarationOptions\n): Promise<{ status: DictionaryStatus; path: string }> => {\n const { system, compiler } = configuration;\n const { baseDir } = system;\n\n const noMetadata = compiler?.noMetadata ?? COMPILER_NO_METADATA;\n const { newDictionariesPath, localeList } = {\n ...defaultOptions,\n ...options,\n };\n\n const newDictionaryLocationPath = join(baseDir, newDictionariesPath);\n\n const unmergedDictionariesRecord = readDictionariesFromDisk<\n Record<string, Dictionary[]>\n >(configuration.system.unmergedDictionariesDir);\n const unmergedDictionaries = unmergedDictionariesRecord[\n dictionary.key\n ] as Dictionary[];\n\n const existingDictionary = unmergedDictionaries?.find(\n (el) => el.localId === dictionary.localId\n );\n\n const formattedContentDeclaration = await formatContentDeclaration(\n dictionary,\n { configuration, localeList }\n );\n\n if (existingDictionary?.filePath) {\n // Compare existing dictionary content with new dictionary content\n const isSameContent = isDeepStrictEqual(existingDictionary, dictionary);\n\n const filePath = resolve(\n configuration.system.baseDir,\n existingDictionary.filePath\n );\n\n // Up to date, nothing to do\n if (isSameContent) {\n return {\n status: 'up-to-date',\n path: filePath,\n };\n }\n\n await writeFileWithDirectories(\n filePath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return { status: 'updated', path: filePath };\n }\n\n if (dictionary.filePath) {\n const filePath = resolve(configuration.system.baseDir, dictionary.filePath);\n\n await writeFileWithDirectories(\n filePath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return { status: 'created', path: filePath };\n }\n\n // No existing dictionary, write to new location\n const contentDeclarationPath = join(\n newDictionaryLocationPath,\n `${dictionary.key}.content.json`\n );\n\n await writeFileWithDirectories(\n contentDeclarationPath,\n formattedContentDeclaration,\n configuration,\n noMetadata\n );\n\n return {\n status: 'imported',\n path: contentDeclarationPath,\n };\n};\n\nconst writeFileWithDirectories = async (\n absoluteFilePath: string,\n dictionary: Dictionary,\n configuration: IntlayerConfig,\n noMetadata?: boolean\n): Promise<void> => {\n // Extract the directory from the file path\n const dir = dirname(absoluteFilePath);\n\n // Create the directory recursively\n await mkdir(dir, { recursive: true });\n\n const extension = extname(absoluteFilePath);\n\n if (extension === '.md' || extension === '.mdx') {\n await writeMarkdownFile(absoluteFilePath, dictionary, configuration);\n return;\n }\n\n if (extension === '.yaml' || extension === '.yml') {\n await writeYamlFile(absoluteFilePath, dictionary, configuration);\n return;\n }\n\n // Handle JSON, JSONC, and JSON5 via the AST transformer\n if (['.json', '.jsonc', '.json5'].includes(extension)) {\n let fileContent = '{}';\n\n if (existsSync(absoluteFilePath)) {\n try {\n fileContent = await readFile(absoluteFilePath, 'utf-8');\n } catch {\n // ignore read errors, start with empty object\n }\n }\n\n const transformedContent = transformJSONFile(\n fileContent,\n dictionary,\n noMetadata\n );\n\n // We use standard writeFile because transformedContent is already a string\n const tempDir = configuration.system?.tempDir;\n if (tempDir) {\n await mkdir(tempDir, { recursive: true });\n }\n\n const tempFileName = `${basename(absoluteFilePath)}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;\n const tempPath = tempDir\n ? join(tempDir, tempFileName)\n : `${absoluteFilePath}.${tempFileName}`;\n try {\n await writeFile(tempPath, transformedContent, 'utf-8');\n await rename(tempPath, absoluteFilePath);\n } catch (error) {\n try {\n await rm(tempPath, { force: true });\n } catch {\n // Ignore\n }\n throw error;\n }\n\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', absoluteFilePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n return;\n }\n\n const knownJsExtensions = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n ]);\n\n if (!knownJsExtensions.has(extension)) {\n // Unknown extension (e.g. .po managed by a plugin) — skip; the plugin\n // owns this file format and writeJSFile / prettier would corrupt it.\n return;\n }\n\n await writeJSFile(absoluteFilePath, dictionary, configuration, noMetadata);\n\n // remove the cache as content has changed\n // Will force a new preparation of the intlayer on next build\n try {\n const sentinelPath = join(\n configuration.system.cacheDir,\n 'intlayer-prepared.lock'\n );\n await rm(sentinelPath, { recursive: true });\n } catch {}\n};\n"],"mappings":"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"}
@@ -1,42 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_detectFormatCommand = require('../detectFormatCommand.cjs');
3
+ const require_writeContentDeclaration_renderContentDeclaration = require('./renderContentDeclaration.cjs');
3
4
  let node_path = require("node:path");
4
- let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
5
5
  let node_fs_promises = require("node:fs/promises");
6
6
  let node_child_process = require("node:child_process");
7
7
 
8
8
  //#region src/writeContentDeclaration/writeMarkdownFile.ts
9
- const stringifyYamlFrontmatter = (fields) => Object.entries(fields).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => {
10
- if (Array.isArray(value)) return `${key}:\n${value.map((item) => ` - ${JSON.stringify(item)}`).join("\n")}`;
11
- if (typeof value === "string" && (value.includes(":") || value.includes("\n") || value.includes("#"))) return `${key}: ${JSON.stringify(value)}`;
12
- return `${key}: ${value}`;
13
- }).join("\n");
14
- const getMarkdownBody = (content) => {
15
- const lines = content.split(/\r?\n/);
16
- const firstNonEmptyIndex = lines.findIndex((line) => line.trim() !== "");
17
- if (firstNonEmptyIndex === -1 || lines[firstNonEmptyIndex]?.trim() !== "---") return content;
18
- let endIndex = -1;
19
- for (let i = firstNonEmptyIndex + 1; i < lines.length; i++) if (lines[i]?.trim() === "---") {
20
- endIndex = i;
21
- break;
22
- }
23
- if (endIndex === -1) return content;
24
- return lines.slice(endIndex + 1).join("\n").trimStart();
25
- };
26
- const EXCLUDED_FRONTMATTER_KEYS = /* @__PURE__ */ new Set([
27
- "content",
28
- "$schema",
29
- "filePath",
30
- "localId",
31
- "localIds",
32
- "projectIds"
33
- ]);
34
9
  const writeMarkdownFile = async (absoluteFilePath, dictionary, configuration) => {
35
- const content = dictionary.content;
36
- const markdownRaw = typeof content === "object" && content?.nodeType === _intlayer_types_nodeType.MARKDOWN ? content[_intlayer_types_nodeType.MARKDOWN] ?? "" : "";
37
- const markdownBody = getMarkdownBody(markdownRaw);
38
- const frontmatterFields = Object.fromEntries(Object.entries(dictionary).filter(([k, v]) => !EXCLUDED_FRONTMATTER_KEYS.has(k) && v !== void 0));
39
- const fileContent = `---\n${stringifyYamlFrontmatter(frontmatterFields)}\n---\n\n${markdownBody}`;
10
+ const fileContent = require_writeContentDeclaration_renderContentDeclaration.renderMarkdownContentDeclaration(dictionary);
40
11
  const dir = (0, node_path.dirname)(absoluteFilePath);
41
12
  await (0, node_fs_promises.mkdir)(dir, { recursive: true });
42
13
  const tempDir = configuration.system?.tempDir;
@@ -1 +1 @@
1
- {"version":3,"file":"writeMarkdownFile.cjs","names":["MARKDOWN","dirname","mkdir","basename","join","writeFile","rename","rm","detectFormatCommand"],"sources":["../../../src/writeContentDeclaration/writeMarkdownFile.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { mkdir, rename, rm, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { MARKDOWN } from '@intlayer/types/nodeType';\nimport { detectFormatCommand } from '../detectFormatCommand';\n\nconst stringifyYamlFrontmatter = (fields: Record<string, any>): string =>\n Object.entries(fields)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return `${key}:\\n${value.map((item) => ` - ${JSON.stringify(item)}`).join('\\n')}`;\n }\n if (\n typeof value === 'string' &&\n (value.includes(':') || value.includes('\\n') || value.includes('#'))\n ) {\n return `${key}: ${JSON.stringify(value)}`;\n }\n return `${key}: ${value}`;\n })\n .join('\\n');\n\n// Strips YAML frontmatter from a markdown string, returning only the body\nconst getMarkdownBody = (content: string): string => {\n const lines = content.split(/\\r?\\n/);\n const firstNonEmptyIndex = lines.findIndex((line) => line.trim() !== '');\n\n if (\n firstNonEmptyIndex === -1 ||\n lines[firstNonEmptyIndex]?.trim() !== '---'\n ) {\n return content;\n }\n\n let endIndex = -1;\n for (let i = firstNonEmptyIndex + 1; i < lines.length; i++) {\n if (lines[i]?.trim() === '---') {\n endIndex = i;\n break;\n }\n }\n\n if (endIndex === -1) return content;\n\n return lines\n .slice(endIndex + 1)\n .join('\\n')\n .trimStart();\n};\n\n// Fields that are auto-generated / internal and must not appear in frontmatter\nconst EXCLUDED_FRONTMATTER_KEYS = new Set<string>([\n 'content',\n '$schema',\n 'filePath',\n 'localId',\n 'localIds',\n 'projectIds',\n]);\n\nexport const writeMarkdownFile = async (\n absoluteFilePath: string,\n dictionary: Dictionary,\n configuration: IntlayerConfig\n): Promise<void> => {\n const content = dictionary.content as any;\n const markdownRaw =\n typeof content === 'object' && content?.nodeType === MARKDOWN\n ? (content[MARKDOWN] ?? '')\n : '';\n // content.markdown now stores the full file (frontmatter + body); extract only the body\n const markdownBody = getMarkdownBody(markdownRaw);\n\n const frontmatterFields = Object.fromEntries(\n Object.entries(dictionary).filter(\n ([k, v]) => !EXCLUDED_FRONTMATTER_KEYS.has(k) && v !== undefined\n )\n );\n\n const frontmatterStr = stringifyYamlFrontmatter(frontmatterFields);\n const fileContent = `---\\n${frontmatterStr}\\n---\\n\\n${markdownBody}`;\n\n const dir = dirname(absoluteFilePath);\n await mkdir(dir, { recursive: true });\n\n const tempDir = configuration.system?.tempDir;\n if (tempDir) await mkdir(tempDir, { recursive: true });\n\n const tempFileName = `${basename(absoluteFilePath)}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;\n const tempPath = tempDir\n ? join(tempDir, tempFileName)\n : `${absoluteFilePath}.${tempFileName}`;\n\n try {\n await writeFile(tempPath, fileContent, 'utf-8');\n await rename(tempPath, absoluteFilePath);\n } catch (error) {\n try {\n await rm(tempPath, { force: true });\n } catch {\n // ignore\n }\n throw error;\n }\n\n const formatCommand = detectFormatCommand(configuration);\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', absoluteFilePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n};\n"],"mappings":";;;;;;;;AAQA,MAAM,4BAA4B,WAChC,OAAO,QAAQ,MAAM,CAAC,CACnB,QAAQ,GAAG,WAAW,UAAU,UAAa,UAAU,IAAI,CAAC,CAC5D,KAAK,CAAC,KAAK,WAAW;CACrB,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,GAAG,IAAI,KAAK,MAAM,KAAK,SAAS,OAAO,KAAK,UAAU,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;CAEjF,IACE,OAAO,UAAU,aAChB,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,GAAG,IAElE,OAAO,GAAG,IAAI,IAAI,KAAK,UAAU,KAAK;CAExC,OAAO,GAAG,IAAI,IAAI;AACpB,CAAC,CAAC,CACD,KAAK,IAAI;AAGd,MAAM,mBAAmB,YAA4B;CACnD,MAAM,QAAQ,QAAQ,MAAM,OAAO;CACnC,MAAM,qBAAqB,MAAM,WAAW,SAAS,KAAK,KAAK,MAAM,EAAE;CAEvE,IACE,uBAAuB,MACvB,MAAM,mBAAmB,EAAE,KAAK,MAAM,OAEtC,OAAO;CAGT,IAAI,WAAW;CACf,KAAK,IAAI,IAAI,qBAAqB,GAAG,IAAI,MAAM,QAAQ,KACrD,IAAI,MAAM,EAAE,EAAE,KAAK,MAAM,OAAO;EAC9B,WAAW;EACX;CACF;CAGF,IAAI,aAAa,IAAI,OAAO;CAE5B,OAAO,MACJ,MAAM,WAAW,CAAC,CAAC,CACnB,KAAK,IAAI,CAAC,CACV,UAAU;AACf;AAGA,MAAM,4CAA4B,IAAI,IAAY;CAChD;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAa,oBAAoB,OAC/B,kBACA,YACA,kBACkB;CAClB,MAAM,UAAU,WAAW;CAC3B,MAAM,cACJ,OAAO,YAAY,YAAY,SAAS,aAAaA,oCAChD,QAAQA,sCAAa,KACtB;CAEN,MAAM,eAAe,gBAAgB,WAAW;CAEhD,MAAM,oBAAoB,OAAO,YAC/B,OAAO,QAAQ,UAAU,CAAC,CAAC,QACxB,CAAC,GAAG,OAAO,CAAC,0BAA0B,IAAI,CAAC,KAAK,MAAM,MACzD,CACF;CAGA,MAAM,cAAc,QADG,yBAAyB,iBACP,EAAE,WAAW;CAEtD,MAAM,UAAMC,mBAAQ,gBAAgB;CACpC,UAAMC,wBAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CAEpC,MAAM,UAAU,cAAc,QAAQ;CACtC,IAAI,SAAS,UAAMA,wBAAM,SAAS,EAAE,WAAW,KAAK,CAAC;CAErD,MAAM,eAAe,OAAGC,oBAAS,gBAAgB,EAAE,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;CACxG,MAAM,WAAW,cACbC,gBAAK,SAAS,YAAY,IAC1B,GAAG,iBAAiB,GAAG;CAE3B,IAAI;EACF,UAAMC,4BAAU,UAAU,aAAa,OAAO;EAC9C,UAAMC,yBAAO,UAAU,gBAAgB;CACzC,SAAS,OAAO;EACd,IAAI;GACF,UAAMC,qBAAG,UAAU,EAAE,OAAO,KAAK,CAAC;EACpC,QAAQ,CAER;EACA,MAAM;CACR;CAEA,MAAM,gBAAgBC,gDAAoB,aAAa;CACvD,IAAI,eACF,IAAI;EACF,iCAAS,cAAc,QAAQ,YAAY,gBAAgB,GAAG;GAC5D,OAAO;GACP,KAAK,cAAc,OAAO;EAC5B,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;CACrB;AAEJ"}
1
+ {"version":3,"file":"writeMarkdownFile.cjs","names":["renderMarkdownContentDeclaration","dirname","mkdir","basename","join","writeFile","rename","rm","detectFormatCommand"],"sources":["../../../src/writeContentDeclaration/writeMarkdownFile.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { mkdir, rename, rm, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { detectFormatCommand } from '../detectFormatCommand';\nimport { renderMarkdownContentDeclaration } from './renderContentDeclaration';\n\nexport const writeMarkdownFile = async (\n absoluteFilePath: string,\n dictionary: Dictionary,\n configuration: IntlayerConfig\n): Promise<void> => {\n const fileContent = renderMarkdownContentDeclaration(dictionary);\n\n const dir = dirname(absoluteFilePath);\n await mkdir(dir, { recursive: true });\n\n const tempDir = configuration.system?.tempDir;\n if (tempDir) await mkdir(tempDir, { recursive: true });\n\n const tempFileName = `${basename(absoluteFilePath)}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;\n const tempPath = tempDir\n ? join(tempDir, tempFileName)\n : `${absoluteFilePath}.${tempFileName}`;\n\n try {\n await writeFile(tempPath, fileContent, 'utf-8');\n await rename(tempPath, absoluteFilePath);\n } catch (error) {\n try {\n await rm(tempPath, { force: true });\n } catch {\n // ignore\n }\n throw error;\n }\n\n const formatCommand = detectFormatCommand(configuration);\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', absoluteFilePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n};\n"],"mappings":";;;;;;;;AAQA,MAAa,oBAAoB,OAC/B,kBACA,YACA,kBACkB;CAClB,MAAM,cAAcA,0FAAiC,UAAU;CAE/D,MAAM,UAAMC,mBAAQ,gBAAgB;CACpC,UAAMC,wBAAM,KAAK,EAAE,WAAW,KAAK,CAAC;CAEpC,MAAM,UAAU,cAAc,QAAQ;CACtC,IAAI,SAAS,UAAMA,wBAAM,SAAS,EAAE,WAAW,KAAK,CAAC;CAErD,MAAM,eAAe,OAAGC,oBAAS,gBAAgB,EAAE,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;CACxG,MAAM,WAAW,cACbC,gBAAK,SAAS,YAAY,IAC1B,GAAG,iBAAiB,GAAG;CAE3B,IAAI;EACF,UAAMC,4BAAU,UAAU,aAAa,OAAO;EAC9C,UAAMC,yBAAO,UAAU,gBAAgB;CACzC,SAAS,OAAO;EACd,IAAI;GACF,UAAMC,qBAAG,UAAU,EAAE,OAAO,KAAK,CAAC;EACpC,QAAQ,CAER;EACA,MAAM;CACR;CAEA,MAAM,gBAAgBC,gDAAoB,aAAa;CACvD,IAAI,eACF,IAAI;EACF,iCAAS,cAAc,QAAQ,YAAY,gBAAgB,GAAG;GAC5D,OAAO;GACP,KAAK,cAAc,OAAO;EAC5B,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;CACrB;AAEJ"}