@arkebcacy/beacon-cli-temp 0.1.9 → 0.1.11

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.
@@ -11,6 +11,9 @@ export default function planPush(cs, fs) {
11
11
  };
12
12
  }
13
13
  function warning(ui, itemPath) {
14
+ if (!ui.options.verbose) {
15
+ return;
16
+ }
14
17
  const msg1 = 'Skipping asset which exists in the file system,';
15
18
  const msg2 = 'but is not included by filters:';
16
19
  const msg3 = styleText('yellowBright', itemPath);
@@ -1 +1 @@
1
- {"version":3,"file":"planPush.js","sourceRoot":"","sources":["../../../../src/schema/assets/lib/planPush.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,MAAM,uBAAuB,CAAC;AAG1C,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC/B,EAAkC,EAClC,EAAkC;IAElC,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEnD,OAAO;QACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzD,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC3B,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,EAAa,EAAE,QAAgB;IAC/C,MAAM,IAAI,GAAG,iDAAiD,CAAC;IAC/D,MAAM,IAAI,GAAG,iCAAiC,CAAC;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACjD,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,cAAc,CACtB,EAAkC,EAClC,EAAkC;IAElC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE9C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEhC,IAAI,MAAM,EAAE,CAAC;YACZ,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;oBACvC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBACP,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAChC,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACtB,CAAC;QACF,CAAC;aAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,cAAc,CACtB,EAAkC,EAClC,SAA8B;IAE9B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjC,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACrC,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,SAAS;QACV,CAAC;QAED,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["import type MergePlan from '#cli/schema/xfer/lib/MergePlan.js';\nimport type UiContext from '#cli/ui/UiContext.js';\nimport { isDeepStrictEqual, styleText } from 'node:util';\nimport getUi from '../../lib/SchemaUi.js';\nimport type AssetMeta from '../AssetMeta.js';\n\nexport default function planPush(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tfs: ReadonlyMap<string, AssetMeta>,\n): MergePlan<AssetMeta> {\n\tconst fsResult = processFsItems(cs, fs);\n\tconst csResult = processCsItems(cs, fsResult.seen);\n\n\treturn {\n\t\ttoCreate: fsResult.toCreate,\n\t\ttoRemove: csResult.toRemove,\n\t\ttoSkip: new Set([...fsResult.toSkip, ...csResult.toSkip]),\n\t\ttoUpdate: fsResult.toUpdate,\n\t};\n}\n\nfunction warning(ui: UiContext, itemPath: string) {\n\tconst msg1 = 'Skipping asset which exists in the file system,';\n\tconst msg2 = 'but is not included by filters:';\n\tconst msg3 = styleText('yellowBright', itemPath);\n\tui.warn(msg1, msg2, msg3);\n}\n\nfunction processFsItems(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tfs: ReadonlyMap<string, AssetMeta>,\n) {\n\tconst seen = new Set<string>();\n\tconst ui = getUi();\n\tconst { isIncluded } = ui.options.schema.assets;\n\tconst toCreate = new Map<string, AssetMeta>();\n\tconst toSkip = new Set<string>();\n\tconst toUpdate = new Map<string, AssetMeta>();\n\n\tfor (const [itemPath, fsMeta] of fs) {\n\t\tseen.add(itemPath);\n\t\tconst csMeta = cs.get(itemPath);\n\n\t\tif (csMeta) {\n\t\t\tif (isIncluded(itemPath)) {\n\t\t\t\tif (isDeepStrictEqual(csMeta, fsMeta)) {\n\t\t\t\t\ttoSkip.add(itemPath);\n\t\t\t\t} else {\n\t\t\t\t\ttoUpdate.set(itemPath, fsMeta);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarning(ui, itemPath);\n\t\t\t\ttoSkip.add(itemPath);\n\t\t\t}\n\t\t} else if (isIncluded(itemPath)) {\n\t\t\ttoCreate.set(itemPath, fsMeta);\n\t\t} else {\n\t\t\twarning(ui, itemPath);\n\t\t\ttoSkip.add(itemPath);\n\t\t}\n\t}\n\n\treturn { seen, toCreate, toSkip, toUpdate };\n}\n\nfunction processCsItems(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tseenItems: ReadonlySet<string>,\n) {\n\tconst ui = getUi();\n\tconst { isIncluded } = ui.options.schema.assets;\n\tconst toRemove = new Map<string, AssetMeta>();\n\tconst toSkip = new Set<string>();\n\n\tfor (const [itemPath, csMeta] of cs) {\n\t\tif (seenItems.has(itemPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isIncluded(itemPath)) {\n\t\t\ttoRemove.set(itemPath, csMeta);\n\t\t} else {\n\t\t\ttoSkip.add(itemPath);\n\t\t}\n\t}\n\n\treturn { toRemove, toSkip };\n}\n"]}
1
+ {"version":3,"file":"planPush.js","sourceRoot":"","sources":["../../../../src/schema/assets/lib/planPush.ts"],"names":[],"mappings":"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","sourcesContent":["import type MergePlan from '#cli/schema/xfer/lib/MergePlan.js';\nimport type UiContext from '#cli/ui/UiContext.js';\nimport { isDeepStrictEqual, styleText } from 'node:util';\nimport getUi from '../../lib/SchemaUi.js';\nimport type AssetMeta from '../AssetMeta.js';\n\nexport default function planPush(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tfs: ReadonlyMap<string, AssetMeta>,\n): MergePlan<AssetMeta> {\n\tconst fsResult = processFsItems(cs, fs);\n\tconst csResult = processCsItems(cs, fsResult.seen);\n\n\treturn {\n\t\ttoCreate: fsResult.toCreate,\n\t\ttoRemove: csResult.toRemove,\n\t\ttoSkip: new Set([...fsResult.toSkip, ...csResult.toSkip]),\n\t\ttoUpdate: fsResult.toUpdate,\n\t};\n}\n\nfunction warning(ui: UiContext, itemPath: string) {\n\tif (!ui.options.verbose) {\n\t\treturn;\n\t}\n\tconst msg1 = 'Skipping asset which exists in the file system,';\n\tconst msg2 = 'but is not included by filters:';\n\tconst msg3 = styleText('yellowBright', itemPath);\n\tui.warn(msg1, msg2, msg3);\n}\n\nfunction processFsItems(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tfs: ReadonlyMap<string, AssetMeta>,\n) {\n\tconst seen = new Set<string>();\n\tconst ui = getUi();\n\tconst { isIncluded } = ui.options.schema.assets;\n\tconst toCreate = new Map<string, AssetMeta>();\n\tconst toSkip = new Set<string>();\n\tconst toUpdate = new Map<string, AssetMeta>();\n\n\tfor (const [itemPath, fsMeta] of fs) {\n\t\tseen.add(itemPath);\n\t\tconst csMeta = cs.get(itemPath);\n\n\t\tif (csMeta) {\n\t\t\tif (isIncluded(itemPath)) {\n\t\t\t\tif (isDeepStrictEqual(csMeta, fsMeta)) {\n\t\t\t\t\ttoSkip.add(itemPath);\n\t\t\t\t} else {\n\t\t\t\t\ttoUpdate.set(itemPath, fsMeta);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarning(ui, itemPath);\n\t\t\t\ttoSkip.add(itemPath);\n\t\t\t}\n\t\t} else if (isIncluded(itemPath)) {\n\t\t\ttoCreate.set(itemPath, fsMeta);\n\t\t} else {\n\t\t\twarning(ui, itemPath);\n\t\t\ttoSkip.add(itemPath);\n\t\t}\n\t}\n\n\treturn { seen, toCreate, toSkip, toUpdate };\n}\n\nfunction processCsItems(\n\tcs: ReadonlyMap<string, AssetMeta>,\n\tseenItems: ReadonlySet<string>,\n) {\n\tconst ui = getUi();\n\tconst { isIncluded } = ui.options.schema.assets;\n\tconst toRemove = new Map<string, AssetMeta>();\n\tconst toSkip = new Set<string>();\n\n\tfor (const [itemPath, csMeta] of cs) {\n\t\tif (seenItems.has(itemPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isIncluded(itemPath)) {\n\t\t\ttoRemove.set(itemPath, csMeta);\n\t\t} else {\n\t\t\ttoSkip.add(itemPath);\n\t\t}\n\t}\n\n\treturn { toRemove, toSkip };\n}\n"]}
@@ -25,9 +25,14 @@ async function loadContentTypeEntries(contentType) {
25
25
  for (const [entryTitle, localeMap] of entriesByTitle.entries()) {
26
26
  const preferredEntry = selectPreferredLocale(localeMap);
27
27
  if (preferredEntry) {
28
+ // Preserve Contentstack UIDs (starting with 'blt'), otherwise use synthetic UID
29
+ const entryUid = preferredEntry.uid;
30
+ const uid = typeof entryUid === 'string' && entryUid.startsWith('blt')
31
+ ? entryUid
32
+ : `file: ${preferredEntry.title}`;
28
33
  entriesSet.add({
29
34
  ...preferredEntry,
30
- uid: `file: ${preferredEntry.title}`,
35
+ uid,
31
36
  });
32
37
  }
33
38
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"indexAllFsEntries.js","sourceRoot":"","sources":["../../../src/schema/entries/indexAllFsEntries.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentType } from '#cli/cs/content-types/Types.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport { isEntry } from '#cli/cs/entries/Types.js';\nimport readYaml from '#cli/fs/readYaml.js';\nimport type OmitIndex from '#cli/util/OmitIndex.js';\nimport { readdir } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport indexContentTypes from '../content-types/indexFromFilesystem.js';\nimport getUi from '../lib/SchemaUi.js';\nimport schemaDirectory from './schemaDirectory.js';\n\nexport default async function indexAllFsEntries(): Promise<\n\tReadonlyMap<ContentType, ReadonlySet<Entry>>\n> {\n\tconst contentTypes = await indexContentTypes();\n\tconst entries = new Map<ContentType, ReadonlySet<Entry>>();\n\n\tfor (const contentType of contentTypes.values()) {\n\t\tconst contentTypeEntries = await loadContentTypeEntries(contentType);\n\t\tentries.set(contentType, contentTypeEntries);\n\t}\n\n\treturn entries;\n}\n\nasync function loadContentTypeEntries(\n\tcontentType: ContentType,\n): Promise<ReadonlySet<Entry>> {\n\tconst dir = schemaDirectory(contentType.uid);\n\tconst entriesSet = new Set<Entry>();\n\n\ttry {\n\t\tconst files = await readdir(dir);\n\t\tconst yamlFiles = files.filter((f) => f.endsWith('.yaml'));\n\t\tconst entriesByTitle = await groupEntriesByTitle(dir, yamlFiles);\n\n\t\t// For each entry title, pick one locale version to represent it\n\t\tfor (const [entryTitle, localeMap] of entriesByTitle.entries()) {\n\t\t\tconst preferredEntry = selectPreferredLocale(localeMap);\n\t\t\tif (preferredEntry) {\n\t\t\t\tentriesSet.add({\n\t\t\t\t\t...preferredEntry,\n\t\t\t\t\tuid: `file: ${preferredEntry.title}`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Log warning if entry has files but no valid locale versions\n\t\t\t\tgetUi().warn(\n\t\t\t\t\t`Warning: Entry \"${entryTitle}\" in ${contentType.uid} has files but no valid locale versions could be selected`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (\n\t\t\terror &&\n\t\t\ttypeof error === 'object' &&\n\t\t\t'code' in error &&\n\t\t\terror.code === 'ENOENT'\n\t\t) {\n\t\t\t// Directory doesn't exist, which is fine\n\t\t\treturn entriesSet;\n\t\t}\n\t\tthrow error;\n\t}\n\n\treturn entriesSet;\n}\n\nasync function groupEntriesByTitle(\n\tdir: string,\n\tyamlFiles: readonly string[],\n): Promise<Map<string, Map<string, FsEntry>>> {\n\tconst entriesByTitle = new Map<string, Map<string, FsEntry>>();\n\n\tfor (const file of yamlFiles) {\n\t\t// Try to match multi-locale pattern first: title.locale.yaml\n\t\tconst multiLocaleMatch = /^(?<title>.+)\\.(?<locale>[^.]+)\\.yaml$/u.exec(\n\t\t\tfile,\n\t\t);\n\n\t\tlet entryTitle: string;\n\t\tlet locale: string;\n\n\t\tif (\n\t\t\tmultiLocaleMatch?.groups?.title &&\n\t\t\tmultiLocaleMatch.groups.locale &&\n\t\t\tisValidLocaleCode(multiLocaleMatch.groups.locale)\n\t\t) {\n\t\t\t// Multi-locale file with valid locale code\n\t\t\tconst { title, locale: localeCode } = multiLocaleMatch.groups;\n\t\t\tentryTitle = title;\n\t\t\tlocale = localeCode;\n\t\t} else {\n\t\t\t// Try single-locale pattern: title.yaml\n\t\t\tconst singleLocaleMatch = /^(?<title>.+)\\.yaml$/u.exec(file);\n\t\t\tif (!singleLocaleMatch?.groups?.title) {\n\t\t\t\t// Skip files that don't match either pattern\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tentryTitle = singleLocaleMatch.groups.title;\n\t\t\tlocale = 'default'; // Use 'default' as locale for backward compatibility\n\t\t}\n\n\t\tconst filePath = resolve(dir, file);\n\t\tconst data = (await readYaml(filePath)) as Record<string, unknown>;\n\n\t\tif (!isFsEntry(data)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet localeMap = entriesByTitle.get(entryTitle);\n\t\tif (!localeMap) {\n\t\t\tlocaleMap = new Map();\n\t\t\tentriesByTitle.set(entryTitle, localeMap);\n\t\t}\n\n\t\tlocaleMap.set(locale, data);\n\t}\n\n\treturn entriesByTitle;\n}\n\nfunction selectPreferredLocale(\n\tlocaleMap: Map<string, FsEntry>,\n): FsEntry | undefined {\n\t// Prefer 'default' (single-locale file), then en-us, then the first available locale\n\treturn (\n\t\tlocaleMap.get('default') ??\n\t\tlocaleMap.get('en-us') ??\n\t\t[...localeMap.values()][0]\n\t);\n}\n\ntype FsEntry = Omit<OmitIndex<Entry>, 'uid'> & Record<string, unknown>;\n\nfunction isFsEntry(o: Record<string, unknown>): o is FsEntry {\n\treturn isEntry({ ...o, uid: 'uid' });\n}\n\n/**\n * Validates if a string is a valid locale code.\n * Valid locale codes contain only letters (case-insensitive), hyphens, and underscores.\n * Examples: en-us, fr, de-DE, zh_CN\n * This prevents misidentifying filenames like \"Entry.Title.yaml\" as \"Entry\" with locale \"Title\"\n */\nfunction isValidLocaleCode(code: string): boolean {\n\t// Locale codes: 2-3 letter language code, optionally followed by separator and 2-4 letter region code\n\t// Pattern matches: en, en-us, en-US, fr-CA, zh_CN, etc.\n\treturn /^[a-z]{2,3}(?:[_-][a-z]{2,4})?$/iu.test(code);\n}\n"]}
1
+ {"version":3,"file":"indexAllFsEntries.js","sourceRoot":"","sources":["../../../src/schema/entries/indexAllFsEntries.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentType } from '#cli/cs/content-types/Types.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport { isEntry } from '#cli/cs/entries/Types.js';\nimport readYaml from '#cli/fs/readYaml.js';\nimport type OmitIndex from '#cli/util/OmitIndex.js';\nimport { readdir } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport indexContentTypes from '../content-types/indexFromFilesystem.js';\nimport getUi from '../lib/SchemaUi.js';\nimport schemaDirectory from './schemaDirectory.js';\n\nexport default async function indexAllFsEntries(): Promise<\n\tReadonlyMap<ContentType, ReadonlySet<Entry>>\n> {\n\tconst contentTypes = await indexContentTypes();\n\tconst entries = new Map<ContentType, ReadonlySet<Entry>>();\n\n\tfor (const contentType of contentTypes.values()) {\n\t\tconst contentTypeEntries = await loadContentTypeEntries(contentType);\n\t\tentries.set(contentType, contentTypeEntries);\n\t}\n\n\treturn entries;\n}\n\nasync function loadContentTypeEntries(\n\tcontentType: ContentType,\n): Promise<ReadonlySet<Entry>> {\n\tconst dir = schemaDirectory(contentType.uid);\n\tconst entriesSet = new Set<Entry>();\n\n\ttry {\n\t\tconst files = await readdir(dir);\n\t\tconst yamlFiles = files.filter((f) => f.endsWith('.yaml'));\n\t\tconst entriesByTitle = await groupEntriesByTitle(dir, yamlFiles);\n\n\t\t// For each entry title, pick one locale version to represent it\n\t\tfor (const [entryTitle, localeMap] of entriesByTitle.entries()) {\n\t\t\tconst preferredEntry = selectPreferredLocale(localeMap);\n\t\t\tif (preferredEntry) {\n\t\t\t\t// Preserve Contentstack UIDs (starting with 'blt'), otherwise use synthetic UID\n\t\t\t\tconst entryUid = preferredEntry.uid;\n\t\t\t\tconst uid =\n\t\t\t\t\ttypeof entryUid === 'string' && entryUid.startsWith('blt')\n\t\t\t\t\t\t? entryUid\n\t\t\t\t\t\t: `file: ${preferredEntry.title}`;\n\t\t\t\tentriesSet.add({\n\t\t\t\t\t...preferredEntry,\n\t\t\t\t\tuid,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Log warning if entry has files but no valid locale versions\n\t\t\t\tgetUi().warn(\n\t\t\t\t\t`Warning: Entry \"${entryTitle}\" in ${contentType.uid} has files but no valid locale versions could be selected`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (\n\t\t\terror &&\n\t\t\ttypeof error === 'object' &&\n\t\t\t'code' in error &&\n\t\t\terror.code === 'ENOENT'\n\t\t) {\n\t\t\t// Directory doesn't exist, which is fine\n\t\t\treturn entriesSet;\n\t\t}\n\t\tthrow error;\n\t}\n\n\treturn entriesSet;\n}\n\nasync function groupEntriesByTitle(\n\tdir: string,\n\tyamlFiles: readonly string[],\n): Promise<Map<string, Map<string, FsEntry>>> {\n\tconst entriesByTitle = new Map<string, Map<string, FsEntry>>();\n\n\tfor (const file of yamlFiles) {\n\t\t// Try to match multi-locale pattern first: title.locale.yaml\n\t\tconst multiLocaleMatch = /^(?<title>.+)\\.(?<locale>[^.]+)\\.yaml$/u.exec(\n\t\t\tfile,\n\t\t);\n\n\t\tlet entryTitle: string;\n\t\tlet locale: string;\n\n\t\tif (\n\t\t\tmultiLocaleMatch?.groups?.title &&\n\t\t\tmultiLocaleMatch.groups.locale &&\n\t\t\tisValidLocaleCode(multiLocaleMatch.groups.locale)\n\t\t) {\n\t\t\t// Multi-locale file with valid locale code\n\t\t\tconst { title, locale: localeCode } = multiLocaleMatch.groups;\n\t\t\tentryTitle = title;\n\t\t\tlocale = localeCode;\n\t\t} else {\n\t\t\t// Try single-locale pattern: title.yaml\n\t\t\tconst singleLocaleMatch = /^(?<title>.+)\\.yaml$/u.exec(file);\n\t\t\tif (!singleLocaleMatch?.groups?.title) {\n\t\t\t\t// Skip files that don't match either pattern\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tentryTitle = singleLocaleMatch.groups.title;\n\t\t\tlocale = 'default'; // Use 'default' as locale for backward compatibility\n\t\t}\n\n\t\tconst filePath = resolve(dir, file);\n\t\tconst data = (await readYaml(filePath)) as Record<string, unknown>;\n\n\t\tif (!isFsEntry(data)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet localeMap = entriesByTitle.get(entryTitle);\n\t\tif (!localeMap) {\n\t\t\tlocaleMap = new Map();\n\t\t\tentriesByTitle.set(entryTitle, localeMap);\n\t\t}\n\n\t\tlocaleMap.set(locale, data);\n\t}\n\n\treturn entriesByTitle;\n}\n\nfunction selectPreferredLocale(\n\tlocaleMap: Map<string, FsEntry>,\n): FsEntry | undefined {\n\t// Prefer 'default' (single-locale file), then en-us, then the first available locale\n\treturn (\n\t\tlocaleMap.get('default') ??\n\t\tlocaleMap.get('en-us') ??\n\t\t[...localeMap.values()][0]\n\t);\n}\n\ntype FsEntry = Omit<OmitIndex<Entry>, 'uid'> & Record<string, unknown>;\n\nfunction isFsEntry(o: Record<string, unknown>): o is FsEntry {\n\treturn isEntry({ ...o, uid: 'uid' });\n}\n\n/**\n * Validates if a string is a valid locale code.\n * Valid locale codes contain only letters (case-insensitive), hyphens, and underscores.\n * Examples: en-us, fr, de-DE, zh_CN\n * This prevents misidentifying filenames like \"Entry.Title.yaml\" as \"Entry\" with locale \"Title\"\n */\nfunction isValidLocaleCode(code: string): boolean {\n\t// Locale codes: 2-3 letter language code, optionally followed by separator and 2-4 letter region code\n\t// Pattern matches: en, en-us, en-US, fr-CA, zh_CN, etc.\n\treturn /^[a-z]{2,3}(?:[_-][a-z]{2,4})?$/iu.test(code);\n}\n"]}
@@ -19,19 +19,65 @@ export default function buildCreator(ctx, transformer, contentType) {
19
19
  };
20
20
  }
21
21
  async function loadLocaleVersions(entry, contentTypeUid) {
22
+ const directory = schemaDirectory(contentTypeUid);
23
+ // For entries with real Contentstack UIDs, try to find locale files by UID first
24
+ if (entry.uid.startsWith('blt')) {
25
+ const localesByUid = await findLocaleFilesByUid(directory, entry.uid);
26
+ if (localesByUid.length > 0) {
27
+ return localesByUid;
28
+ }
29
+ }
30
+ // Fall back to filename-based lookup using the entry title
22
31
  const filenamesByTitle = generateFilenames(new Map([[entry.title, entry]]));
23
32
  const filename = filenamesByTitle.get(entry.title);
24
33
  if (!filename) {
25
34
  throw new Error(`No filename found for entry ${entry.title}.`);
26
35
  }
27
36
  const baseFilename = filename.replace(/\.yaml$/u, '');
28
- const directory = schemaDirectory(contentTypeUid);
29
37
  const fsLocaleVersions = await loadEntryLocales(directory, entry.title, baseFilename);
30
38
  if (fsLocaleVersions.length === 0) {
31
39
  throw new Error(`No locale versions found for entry ${entry.title}.`);
32
40
  }
33
41
  return fsLocaleVersions;
34
42
  }
43
+ /**
44
+ * Find locale files by searching for files containing the given UID.
45
+ * This helps handle cases where the entry title doesn't match the filename.
46
+ */
47
+ async function findLocaleFilesByUid(directory, uid) {
48
+ try {
49
+ const fs = await import('node:fs/promises');
50
+ const readYaml = (await import('#cli/fs/readYaml.js')).default;
51
+ const path = await import('node:path');
52
+ const files = await fs.readdir(directory);
53
+ const yamlFiles = files.filter((f) => f.endsWith('.yaml'));
54
+ const results = [];
55
+ // Read all YAML files and find those with matching UID
56
+ for (const file of yamlFiles) {
57
+ const filePath = path.resolve(directory, file);
58
+ try {
59
+ const data = (await readYaml(filePath));
60
+ if (data.uid === uid) {
61
+ // Extract locale from filename if present
62
+ const localeMatch = /\.(?<locale>[a-z]{2,3}(?:[_-][a-z]{2,4})?)\\.yaml$/iu.exec(file);
63
+ const locale = localeMatch?.groups?.locale ?? 'default';
64
+ results.push({
65
+ entry: { ...data, uid },
66
+ locale,
67
+ });
68
+ }
69
+ }
70
+ catch {
71
+ // Skip files that can't be read
72
+ continue;
73
+ }
74
+ }
75
+ return results;
76
+ }
77
+ catch {
78
+ return [];
79
+ }
80
+ }
35
81
  async function createFirstLocale(ctx, transformer, contentType, fsLocaleVersions) {
36
82
  const [firstLocale] = fsLocaleVersions;
37
83
  if (!firstLocale) {
@@ -73,7 +119,16 @@ async function importAdditionalLocales(ctx, transformer, contentType, fsLocaleVe
73
119
  return;
74
120
  }
75
121
  const localeTransformed = transformer.process(localeVersion.entry);
76
- return importEntry(ctx.cs.client, contentType.uid, { ...localeTransformed, uid: created.uid }, false, localeVersion.locale);
122
+ try {
123
+ return await importEntry(ctx.cs.client, contentType.uid, { ...localeTransformed, uid: created.uid }, false, localeVersion.locale);
124
+ }
125
+ catch (ex) {
126
+ // If we get error 201 (localized version already exists), retry with update=true
127
+ if (isDuplicateKeyError(ex)) {
128
+ return await importEntry(ctx.cs.client, contentType.uid, { ...localeTransformed, uid: created.uid }, true, localeVersion.locale);
129
+ }
130
+ throw ex;
131
+ }
77
132
  });
78
133
  await Promise.all(importPromises);
79
134
  }
@@ -81,11 +136,17 @@ function isDuplicateKeyError(ex) {
81
136
  if (!(ex instanceof ContentstackError)) {
82
137
  return false;
83
138
  }
139
+ // Error code 119: title is not unique
84
140
  const invalidDataCode = 119;
85
- if (ex.code !== invalidDataCode) {
86
- return false;
141
+ if (ex.code === invalidDataCode) {
142
+ return isDeepStrictEqual(ex.details, { title: ['is not unique.'] });
143
+ }
144
+ // Error code 201: entry already exists (localized version)
145
+ const alreadyExistsCode = 201;
146
+ if (ex.code === alreadyExistsCode) {
147
+ return true;
87
148
  }
88
- return isDeepStrictEqual(ex.details, { title: ['is not unique.'] });
149
+ return false;
89
150
  }
90
151
  async function getUidByTitle(client, globalFieldsByUid, contentType, title) {
91
152
  const entries = await indexEntries(client, globalFieldsByUid, contentType);
@@ -1 +1 @@
1
- {"version":3,"file":"buildCreator.js","sourceRoot":"","sources":["../../../../src/schema/entries/lib/buildCreator.ts"],"names":[],"mappings":"AAEA,OAAO,iBAAiB,MAAM,kCAAkC,CAAC;AAGjE,OAAO,WAAW,MAAM,2BAA2B,CAAC;AACpD,OAAO,YAAY,MAAM,0BAA0B,CAAC;AAGpD,OAAO,KAAK,MAAM,6BAA6B,CAAC;AAChD,OAAO,YAAY,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,eAAe,MAAM,uBAAuB,CAAC;AACpD,OAAO,iBAAiB,MAAM,wBAAwB,CAAC;AACvD,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AAErD,MAAM,CAAC,OAAO,UAAU,YAAY,CACnC,GAAQ,EACR,WAA2B,EAC3B,WAAwB;IAExB,OAAO,KAAK,EAAE,KAAY,EAAE,EAAE;QAC7B,MAAM,gBAAgB,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAG,MAAM,iBAAiB,CACtC,GAAG,EACH,WAAW,EACX,WAAW,EACX,gBAAgB,CAChB,CAAC;QAEF,MAAM,uBAAuB,CAC5B,GAAG,EACH,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,OAAO,CACP,CAAC;QAEF,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,WAAW,CAAC,GAAG,EAAE;YACxD,GAAG,KAAK;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;SAChB,CAAC,CAAC;IACJ,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,KAAY,EAAE,cAAsB;IACrE,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAC9C,SAAS,EACT,KAAK,CAAC,KAAK,EACX,YAAY,CACZ,CAAC;IAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,gBAAgB,CAAC;AACzB,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC/B,GAAQ,EACR,WAA2B,EAC3B,WAAwB,EACxB,gBAAgE;IAEhE,MAAM,CAAC,WAAW,CAAC,GAAG,gBAAgB,CAAC;IAEvC,IAAI,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAE3D,sEAAsE;IACtE,MAAM,MAAM,GACX,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;IAEnE,IAAI,CAAC;QACJ,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,WAAW,EACX,KAAK,EACL,MAAM,CACN,CAAC;IACH,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACb,OAAO,MAAM,uBAAuB,CACnC,EAAE,EACF,GAAG,EACH,WAAW,EACX,WAAW,EACX,MAAM,CACN,CAAC;IACH,CAAC;AACF,CAAC;AAED,KAAK,UAAU,uBAAuB,CACrC,EAAW,EACX,GAAQ,EACR,WAAwB,EACxB,WAAkD,EAClD,MAA0B;IAE1B,IAAI,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,aAAa,CAC9B,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,GAAG,CAAC,EAAE,CAAC,YAAY,EACnB,WAAW,EACX,WAAW,CAAC,KAAK,CACjB,CAAC;QAEF,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,eAAe,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,QAAQ,GAAG,IAAI,KAAK,CACzB,0BAA0B,WAAW,CAAC,KAAK,yFAAyF,CACpI,CAAC;YACF,2CAA2C;YAC3C,IAAI,EAAE,YAAY,KAAK,EAAE,CAAC;gBACzB,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,CAAC;YACD,MAAM,QAAQ,CAAC;QAChB,CAAC;QAED,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,EAAE,GAAG,WAAW,EAAE,GAAG,EAAE,EACvB,IAAI,EACJ,MAAM,CACN,CAAC;IACH,CAAC;IAED,MAAM,EAAE,CAAC;AACV,CAAC;AAED,KAAK,UAAU,uBAAuB,CACrC,GAAQ,EACR,WAA2B,EAC3B,WAAwB,EACxB,gBAAgE,EAChE,OAAc;IAEd,2EAA2E;IAC3E,MAAM,cAAc,GAAG,gBAAgB;SACrC,KAAK,CAAC,CAAC,CAAC;SACR,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QAC5B,IAAI,aAAa,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACxC,0DAA0D;YAC1D,OAAO;QACR,CAAC;QAED,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAEnE,OAAO,WAAW,CACjB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,EAAE,GAAG,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAC1C,KAAK,EACL,aAAa,CAAC,MAAM,CACpB,CAAC;IACH,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAW;IACvC,IAAI,CAAC,CAAC,EAAE,YAAY,iBAAiB,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,eAAe,GAAG,GAAG,CAAC;IAC5B,IAAI,EAAE,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,aAAa,CAC3B,MAAc,EACd,iBAAqD,EACrD,WAAwB,EACxB,KAAa;IAEb,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;AAChC,CAAC;AAED,SAAS,eAAe,CAAC,gBAAwB,EAAE,UAAkB;IACpE,MAAM,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,CAAC,CAAA,mBAAmB,gBAAgB,UAAU,UAAU,GAAG,CAAC;IACzE,MAAM,IAAI,GAAG,0DAA0D,CAAC;IACxE,MAAM,IAAI,GAAG,qDAAqD,CAAC;IACnE,MAAM,IAAI,GAAG,cAAc,CAAC;IAC5B,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC","sourcesContent":["import type { Schema } from '#cli/cs/Types.js';\nimport type Client from '#cli/cs/api/Client.js';\nimport ContentstackError from '#cli/cs/api/ContentstackError.js';\nimport type { ContentType } from '#cli/cs/content-types/Types.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport importEntry from '#cli/cs/entries/import.js';\nimport indexEntries from '#cli/cs/entries/index.js';\nimport type BeaconReplacer from '#cli/dto/entry/BeaconReplacer.js';\nimport type Ctx from '#cli/schema/ctx/Ctx.js';\nimport getUi from '#cli/schema/lib/SchemaUi.js';\nimport createStylus from '#cli/ui/createStylus.js';\nimport { isDeepStrictEqual } from 'node:util';\nimport schemaDirectory from '../schemaDirectory.js';\nimport generateFilenames from './generateFilenames.js';\nimport loadEntryLocales from './loadEntryLocales.js';\n\nexport default function buildCreator(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n) {\n\treturn async (entry: Entry) => {\n\t\tconst fsLocaleVersions = await loadLocaleVersions(entry, contentType.uid);\n\n\t\tconst created = await createFirstLocale(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t);\n\n\t\tawait importAdditionalLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tcreated,\n\t\t);\n\n\t\tctx.references.recordEntryForReferences(contentType.uid, {\n\t\t\t...entry,\n\t\t\tuid: created.uid,\n\t\t});\n\t};\n}\n\nasync function loadLocaleVersions(entry: Entry, contentTypeUid: string) {\n\tconst filenamesByTitle = generateFilenames(new Map([[entry.title, entry]]));\n\tconst filename = filenamesByTitle.get(entry.title);\n\tif (!filename) {\n\t\tthrow new Error(`No filename found for entry ${entry.title}.`);\n\t}\n\n\tconst baseFilename = filename.replace(/\\.yaml$/u, '');\n\tconst directory = schemaDirectory(contentTypeUid);\n\tconst fsLocaleVersions = await loadEntryLocales(\n\t\tdirectory,\n\t\tentry.title,\n\t\tbaseFilename,\n\t);\n\n\tif (fsLocaleVersions.length === 0) {\n\t\tthrow new Error(`No locale versions found for entry ${entry.title}.`);\n\t}\n\n\treturn fsLocaleVersions;\n}\n\nasync function createFirstLocale(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadLocaleVersions>>,\n): Promise<Entry> {\n\tconst [firstLocale] = fsLocaleVersions;\n\n\tif (!firstLocale) {\n\t\tthrow new Error('No locale versions found');\n\t}\n\n\tconst transformed = transformer.process(firstLocale.entry);\n\n\t// Pass undefined for 'default' locale (single-locale backward compat)\n\tconst locale =\n\t\tfirstLocale.locale === 'default' ? undefined : firstLocale.locale;\n\n\ttry {\n\t\treturn await importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\ttransformed,\n\t\t\tfalse,\n\t\t\tlocale,\n\t\t);\n\t} catch (ex) {\n\t\treturn await handleDuplicateKeyError(\n\t\t\tex,\n\t\t\tctx,\n\t\t\tcontentType,\n\t\t\ttransformed,\n\t\t\tlocale,\n\t\t);\n\t}\n}\n\nasync function handleDuplicateKeyError(\n\tex: unknown,\n\tctx: Ctx,\n\tcontentType: ContentType,\n\ttransformed: ReturnType<BeaconReplacer['process']>,\n\tlocale: string | undefined,\n): Promise<Entry> {\n\tif (isDuplicateKeyError(ex)) {\n\t\tconst uid = await getUidByTitle(\n\t\t\tctx.cs.client,\n\t\t\tctx.cs.globalFields,\n\t\t\tcontentType,\n\t\t\ttransformed.title,\n\t\t);\n\n\t\tif (!uid) {\n\t\t\tlogInvalidState(contentType.title, transformed.title);\n\t\t\tconst newError = new Error(\n\t\t\t\t`Failed to create entry ${transformed.title}: Contentstack reported a duplicate title but the entry was not found after re-indexing`,\n\t\t\t);\n\t\t\t// Preserve the original error as the cause\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tnewError.cause = ex;\n\t\t\t}\n\t\t\tthrow newError;\n\t\t}\n\n\t\treturn await importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\t{ ...transformed, uid },\n\t\t\ttrue,\n\t\t\tlocale,\n\t\t);\n\t}\n\n\tthrow ex;\n}\n\nasync function importAdditionalLocales(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadLocaleVersions>>,\n\tcreated: Entry,\n) {\n\t// Import all additional locale versions in parallel for better performance\n\tconst importPromises = fsLocaleVersions\n\t\t.slice(1)\n\t\t.map(async (localeVersion) => {\n\t\t\tif (localeVersion.locale === 'default') {\n\t\t\t\t// Skip 'default' locale (already handled by first locale)\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst localeTransformed = transformer.process(localeVersion.entry);\n\n\t\t\treturn importEntry(\n\t\t\t\tctx.cs.client,\n\t\t\t\tcontentType.uid,\n\t\t\t\t{ ...localeTransformed, uid: created.uid },\n\t\t\t\tfalse,\n\t\t\t\tlocaleVersion.locale,\n\t\t\t);\n\t\t});\n\n\tawait Promise.all(importPromises);\n}\n\nfunction isDuplicateKeyError(ex: unknown) {\n\tif (!(ex instanceof ContentstackError)) {\n\t\treturn false;\n\t}\n\n\tconst invalidDataCode = 119;\n\tif (ex.code !== invalidDataCode) {\n\t\treturn false;\n\t}\n\n\treturn isDeepStrictEqual(ex.details, { title: ['is not unique.'] });\n}\n\nasync function getUidByTitle(\n\tclient: Client,\n\tglobalFieldsByUid: ReadonlyMap<Schema['uid'], Schema>,\n\tcontentType: ContentType,\n\ttitle: string,\n) {\n\tconst entries = await indexEntries(client, globalFieldsByUid, contentType);\n\treturn entries.get(title)?.uid;\n}\n\nfunction logInvalidState(contentTypeTitle: string, entryTitle: string) {\n\tconst y = createStylus('yellowBright');\n\tconst ui = getUi();\n\tconst msg1 = y`While importing ${contentTypeTitle} entry ${entryTitle},`;\n\tconst msg2 = 'Contentstack reported a duplicate key error based on the';\n\tconst msg3 = 'title, but no entry with that title was found after';\n\tconst msg4 = 're-indexing.';\n\tconst msg = [msg1, msg2, msg3, msg4].join(' ');\n\tui.warn(msg);\n}\n"]}
1
+ {"version":3,"file":"buildCreator.js","sourceRoot":"","sources":["../../../../src/schema/entries/lib/buildCreator.ts"],"names":[],"mappings":"AAEA,OAAO,iBAAiB,MAAM,kCAAkC,CAAC;AAGjE,OAAO,WAAW,MAAM,2BAA2B,CAAC;AACpD,OAAO,YAAY,MAAM,0BAA0B,CAAC;AAGpD,OAAO,KAAK,MAAM,6BAA6B,CAAC;AAChD,OAAO,YAAY,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,eAAe,MAAM,uBAAuB,CAAC;AACpD,OAAO,iBAAiB,MAAM,wBAAwB,CAAC;AACvD,OAAO,gBAA0C,MAAM,uBAAuB,CAAC;AAE/E,MAAM,CAAC,OAAO,UAAU,YAAY,CACnC,GAAQ,EACR,WAA2B,EAC3B,WAAwB;IAExB,OAAO,KAAK,EAAE,KAAY,EAAE,EAAE;QAC7B,MAAM,gBAAgB,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAG,MAAM,iBAAiB,CACtC,GAAG,EACH,WAAW,EACX,WAAW,EACX,gBAAgB,CAChB,CAAC;QAEF,MAAM,uBAAuB,CAC5B,GAAG,EACH,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,OAAO,CACP,CAAC;QAEF,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,WAAW,CAAC,GAAG,EAAE;YACxD,GAAG,KAAK;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;SAChB,CAAC,CAAC;IACJ,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,KAAY,EAAE,cAAsB;IACrE,MAAM,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;IAElD,iFAAiF;IACjF,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACtE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,YAAY,CAAC;QACrB,CAAC;IACF,CAAC;IAED,2DAA2D;IAC3D,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAC9C,SAAS,EACT,KAAK,CAAC,KAAK,EACX,YAAY,CACZ,CAAC;IAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,gBAAgB,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,oBAAoB,CAClC,SAAiB,EACjB,GAAW;IAEX,IAAI,CAAC;QACJ,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAEvC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAsB,EAAE,CAAC;QAEtC,uDAAuD;QACvD,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC;gBACJ,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAA4B,CAAC;gBACnE,IAAI,IAAI,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;oBACtB,0CAA0C;oBAC1C,MAAM,WAAW,GAChB,sDAAsD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACnE,MAAM,MAAM,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,IAAI,SAAS,CAAC;oBAExD,OAAO,CAAC,IAAI,CAAC;wBACZ,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,EAAW;wBAChC,MAAM;qBACN,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAAC,MAAM,CAAC;gBACR,gCAAgC;gBAChC,SAAS;YACV,CAAC;QACF,CAAC;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC/B,GAAQ,EACR,WAA2B,EAC3B,WAAwB,EACxB,gBAAgE;IAEhE,MAAM,CAAC,WAAW,CAAC,GAAG,gBAAgB,CAAC;IAEvC,IAAI,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAE3D,sEAAsE;IACtE,MAAM,MAAM,GACX,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;IAEnE,IAAI,CAAC;QACJ,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,WAAW,EACX,KAAK,EACL,MAAM,CACN,CAAC;IACH,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACb,OAAO,MAAM,uBAAuB,CACnC,EAAE,EACF,GAAG,EACH,WAAW,EACX,WAAW,EACX,MAAM,CACN,CAAC;IACH,CAAC;AACF,CAAC;AAED,KAAK,UAAU,uBAAuB,CACrC,EAAW,EACX,GAAQ,EACR,WAAwB,EACxB,WAAkD,EAClD,MAA0B;IAE1B,IAAI,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,aAAa,CAC9B,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,GAAG,CAAC,EAAE,CAAC,YAAY,EACnB,WAAW,EACX,WAAW,CAAC,KAAK,CACjB,CAAC;QAEF,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,eAAe,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,QAAQ,GAAG,IAAI,KAAK,CACzB,0BAA0B,WAAW,CAAC,KAAK,yFAAyF,CACpI,CAAC;YACF,2CAA2C;YAC3C,IAAI,EAAE,YAAY,KAAK,EAAE,CAAC;gBACzB,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,CAAC;YACD,MAAM,QAAQ,CAAC;QAChB,CAAC;QAED,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,EAAE,GAAG,WAAW,EAAE,GAAG,EAAE,EACvB,IAAI,EACJ,MAAM,CACN,CAAC;IACH,CAAC;IAED,MAAM,EAAE,CAAC;AACV,CAAC;AAED,KAAK,UAAU,uBAAuB,CACrC,GAAQ,EACR,WAA2B,EAC3B,WAAwB,EACxB,gBAAgE,EAChE,OAAc;IAEd,2EAA2E;IAC3E,MAAM,cAAc,GAAG,gBAAgB;SACrC,KAAK,CAAC,CAAC,CAAC;SACR,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QAC5B,IAAI,aAAa,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACxC,0DAA0D;YAC1D,OAAO;QACR,CAAC;QAED,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAEnE,IAAI,CAAC;YACJ,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,EAAE,GAAG,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAC1C,KAAK,EACL,aAAa,CAAC,MAAM,CACpB,CAAC;QACH,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACb,iFAAiF;YACjF,IAAI,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC7B,OAAO,MAAM,WAAW,CACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EACb,WAAW,CAAC,GAAG,EACf,EAAE,GAAG,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAC1C,IAAI,EACJ,aAAa,CAAC,MAAM,CACpB,CAAC;YACH,CAAC;YACD,MAAM,EAAE,CAAC;QACV,CAAC;IACF,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAW;IACvC,IAAI,CAAC,CAAC,EAAE,YAAY,iBAAiB,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,sCAAsC;IACtC,MAAM,eAAe,GAAG,GAAG,CAAC;IAC5B,IAAI,EAAE,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACjC,OAAO,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,2DAA2D;IAC3D,MAAM,iBAAiB,GAAG,GAAG,CAAC;IAC9B,IAAI,EAAE,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,aAAa,CAC3B,MAAc,EACd,iBAAqD,EACrD,WAAwB,EACxB,KAAa;IAEb,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;AAChC,CAAC;AAED,SAAS,eAAe,CAAC,gBAAwB,EAAE,UAAkB;IACpE,MAAM,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,CAAC,CAAA,mBAAmB,gBAAgB,UAAU,UAAU,GAAG,CAAC;IACzE,MAAM,IAAI,GAAG,0DAA0D,CAAC;IACxE,MAAM,IAAI,GAAG,qDAAqD,CAAC;IACnE,MAAM,IAAI,GAAG,cAAc,CAAC;IAC5B,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC","sourcesContent":["import type { Schema } from '#cli/cs/Types.js';\nimport type Client from '#cli/cs/api/Client.js';\nimport ContentstackError from '#cli/cs/api/ContentstackError.js';\nimport type { ContentType } from '#cli/cs/content-types/Types.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport importEntry from '#cli/cs/entries/import.js';\nimport indexEntries from '#cli/cs/entries/index.js';\nimport type BeaconReplacer from '#cli/dto/entry/BeaconReplacer.js';\nimport type Ctx from '#cli/schema/ctx/Ctx.js';\nimport getUi from '#cli/schema/lib/SchemaUi.js';\nimport createStylus from '#cli/ui/createStylus.js';\nimport { isDeepStrictEqual } from 'node:util';\nimport schemaDirectory from '../schemaDirectory.js';\nimport generateFilenames from './generateFilenames.js';\nimport loadEntryLocales, { type EntryWithLocale } from './loadEntryLocales.js';\n\nexport default function buildCreator(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n) {\n\treturn async (entry: Entry) => {\n\t\tconst fsLocaleVersions = await loadLocaleVersions(entry, contentType.uid);\n\n\t\tconst created = await createFirstLocale(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t);\n\n\t\tawait importAdditionalLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tcreated,\n\t\t);\n\n\t\tctx.references.recordEntryForReferences(contentType.uid, {\n\t\t\t...entry,\n\t\t\tuid: created.uid,\n\t\t});\n\t};\n}\n\nasync function loadLocaleVersions(entry: Entry, contentTypeUid: string) {\n\tconst directory = schemaDirectory(contentTypeUid);\n\n\t// For entries with real Contentstack UIDs, try to find locale files by UID first\n\tif (entry.uid.startsWith('blt')) {\n\t\tconst localesByUid = await findLocaleFilesByUid(directory, entry.uid);\n\t\tif (localesByUid.length > 0) {\n\t\t\treturn localesByUid;\n\t\t}\n\t}\n\n\t// Fall back to filename-based lookup using the entry title\n\tconst filenamesByTitle = generateFilenames(new Map([[entry.title, entry]]));\n\tconst filename = filenamesByTitle.get(entry.title);\n\tif (!filename) {\n\t\tthrow new Error(`No filename found for entry ${entry.title}.`);\n\t}\n\n\tconst baseFilename = filename.replace(/\\.yaml$/u, '');\n\tconst fsLocaleVersions = await loadEntryLocales(\n\t\tdirectory,\n\t\tentry.title,\n\t\tbaseFilename,\n\t);\n\n\tif (fsLocaleVersions.length === 0) {\n\t\tthrow new Error(`No locale versions found for entry ${entry.title}.`);\n\t}\n\n\treturn fsLocaleVersions;\n}\n\n/**\n * Find locale files by searching for files containing the given UID.\n * This helps handle cases where the entry title doesn't match the filename.\n */\nasync function findLocaleFilesByUid(\n\tdirectory: string,\n\tuid: string,\n): Promise<readonly EntryWithLocale[]> {\n\ttry {\n\t\tconst fs = await import('node:fs/promises');\n\t\tconst readYaml = (await import('#cli/fs/readYaml.js')).default;\n\t\tconst path = await import('node:path');\n\n\t\tconst files = await fs.readdir(directory);\n\t\tconst yamlFiles = files.filter((f) => f.endsWith('.yaml'));\n\t\tconst results: EntryWithLocale[] = [];\n\n\t\t// Read all YAML files and find those with matching UID\n\t\tfor (const file of yamlFiles) {\n\t\t\tconst filePath = path.resolve(directory, file);\n\t\t\ttry {\n\t\t\t\tconst data = (await readYaml(filePath)) as Record<string, unknown>;\n\t\t\t\tif (data.uid === uid) {\n\t\t\t\t\t// Extract locale from filename if present\n\t\t\t\t\tconst localeMatch =\n\t\t\t\t\t\t/\\.(?<locale>[a-z]{2,3}(?:[_-][a-z]{2,4})?)\\\\.yaml$/iu.exec(file);\n\t\t\t\t\tconst locale = localeMatch?.groups?.locale ?? 'default';\n\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tentry: { ...data, uid } as Entry,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip files that can't be read\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function createFirstLocale(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadLocaleVersions>>,\n): Promise<Entry> {\n\tconst [firstLocale] = fsLocaleVersions;\n\n\tif (!firstLocale) {\n\t\tthrow new Error('No locale versions found');\n\t}\n\n\tconst transformed = transformer.process(firstLocale.entry);\n\n\t// Pass undefined for 'default' locale (single-locale backward compat)\n\tconst locale =\n\t\tfirstLocale.locale === 'default' ? undefined : firstLocale.locale;\n\n\ttry {\n\t\treturn await importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\ttransformed,\n\t\t\tfalse,\n\t\t\tlocale,\n\t\t);\n\t} catch (ex) {\n\t\treturn await handleDuplicateKeyError(\n\t\t\tex,\n\t\t\tctx,\n\t\t\tcontentType,\n\t\t\ttransformed,\n\t\t\tlocale,\n\t\t);\n\t}\n}\n\nasync function handleDuplicateKeyError(\n\tex: unknown,\n\tctx: Ctx,\n\tcontentType: ContentType,\n\ttransformed: ReturnType<BeaconReplacer['process']>,\n\tlocale: string | undefined,\n): Promise<Entry> {\n\tif (isDuplicateKeyError(ex)) {\n\t\tconst uid = await getUidByTitle(\n\t\t\tctx.cs.client,\n\t\t\tctx.cs.globalFields,\n\t\t\tcontentType,\n\t\t\ttransformed.title,\n\t\t);\n\n\t\tif (!uid) {\n\t\t\tlogInvalidState(contentType.title, transformed.title);\n\t\t\tconst newError = new Error(\n\t\t\t\t`Failed to create entry ${transformed.title}: Contentstack reported a duplicate title but the entry was not found after re-indexing`,\n\t\t\t);\n\t\t\t// Preserve the original error as the cause\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tnewError.cause = ex;\n\t\t\t}\n\t\t\tthrow newError;\n\t\t}\n\n\t\treturn await importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\t{ ...transformed, uid },\n\t\t\ttrue,\n\t\t\tlocale,\n\t\t);\n\t}\n\n\tthrow ex;\n}\n\nasync function importAdditionalLocales(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadLocaleVersions>>,\n\tcreated: Entry,\n) {\n\t// Import all additional locale versions in parallel for better performance\n\tconst importPromises = fsLocaleVersions\n\t\t.slice(1)\n\t\t.map(async (localeVersion) => {\n\t\t\tif (localeVersion.locale === 'default') {\n\t\t\t\t// Skip 'default' locale (already handled by first locale)\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst localeTransformed = transformer.process(localeVersion.entry);\n\n\t\t\ttry {\n\t\t\t\treturn await importEntry(\n\t\t\t\t\tctx.cs.client,\n\t\t\t\t\tcontentType.uid,\n\t\t\t\t\t{ ...localeTransformed, uid: created.uid },\n\t\t\t\t\tfalse,\n\t\t\t\t\tlocaleVersion.locale,\n\t\t\t\t);\n\t\t\t} catch (ex) {\n\t\t\t\t// If we get error 201 (localized version already exists), retry with update=true\n\t\t\t\tif (isDuplicateKeyError(ex)) {\n\t\t\t\t\treturn await importEntry(\n\t\t\t\t\t\tctx.cs.client,\n\t\t\t\t\t\tcontentType.uid,\n\t\t\t\t\t\t{ ...localeTransformed, uid: created.uid },\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tlocaleVersion.locale,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t});\n\n\tawait Promise.all(importPromises);\n}\n\nfunction isDuplicateKeyError(ex: unknown) {\n\tif (!(ex instanceof ContentstackError)) {\n\t\treturn false;\n\t}\n\n\t// Error code 119: title is not unique\n\tconst invalidDataCode = 119;\n\tif (ex.code === invalidDataCode) {\n\t\treturn isDeepStrictEqual(ex.details, { title: ['is not unique.'] });\n\t}\n\n\t// Error code 201: entry already exists (localized version)\n\tconst alreadyExistsCode = 201;\n\tif (ex.code === alreadyExistsCode) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nasync function getUidByTitle(\n\tclient: Client,\n\tglobalFieldsByUid: ReadonlyMap<Schema['uid'], Schema>,\n\tcontentType: ContentType,\n\ttitle: string,\n) {\n\tconst entries = await indexEntries(client, globalFieldsByUid, contentType);\n\treturn entries.get(title)?.uid;\n}\n\nfunction logInvalidState(contentTypeTitle: string, entryTitle: string) {\n\tconst y = createStylus('yellowBright');\n\tconst ui = getUi();\n\tconst msg1 = y`While importing ${contentTypeTitle} entry ${entryTitle},`;\n\tconst msg2 = 'Contentstack reported a duplicate key error based on the';\n\tconst msg3 = 'title, but no entry with that title was found after';\n\tconst msg4 = 're-indexing.';\n\tconst msg = [msg1, msg2, msg3, msg4].join(' ');\n\tui.warn(msg);\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { Entry } from '#cli/cs/entries/Types.js';
2
+ import type MergePlan from '../../xfer/lib/MergePlan.js';
3
+ /**
4
+ * Custom planning function for entries that matches by UID when available,
5
+ * falling back to title-based matching. This handles cases where entries
6
+ * have Contentstack UIDs but different titles (e.g., localized titles).
7
+ */
8
+ export default function planEntryMerge(equalityFn: (a: Entry, b: Entry) => boolean, fsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>, csEntriesByTitle: ReadonlyMap<Entry['title'], Entry>): MergePlan<Entry>;
9
+ //# sourceMappingURL=planEntryMerge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planEntryMerge.d.ts","sourceRoot":"","sources":["../../../../src/schema/entries/lib/planEntryMerge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,SAAS,MAAM,6BAA6B,CAAC;AA6EzD;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CACrC,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,KAAK,OAAO,EAC3C,gBAAgB,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EACpD,gBAAgB,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,GAClD,SAAS,CAAC,KAAK,CAAC,CAkBlB"}
@@ -0,0 +1,78 @@
1
+ import getUi from '../../lib/SchemaUi.js';
2
+ /**
3
+ * Build a UID-based index for CS entries
4
+ */
5
+ function buildUidIndex(csEntriesByTitle) {
6
+ const csEntriesByUid = new Map();
7
+ for (const csEntry of csEntriesByTitle.values()) {
8
+ if (csEntry.uid.startsWith('blt')) {
9
+ csEntriesByUid.set(csEntry.uid, csEntry);
10
+ }
11
+ }
12
+ return csEntriesByUid;
13
+ }
14
+ /**
15
+ * Match entries by UID and title
16
+ */
17
+ function matchEntries(equalityFn, fsEntriesByTitle, csEntriesByTitle, csEntriesByUid) {
18
+ const ui = getUi();
19
+ const toCreate = new Map();
20
+ const toUpdate = new Map();
21
+ const toSkip = new Set();
22
+ const matched = new Set();
23
+ // First pass: match by UID for entries that have real Contentstack UIDs
24
+ for (const [fsTitle, fsEntry] of fsEntriesByTitle) {
25
+ if (fsEntry.uid.startsWith('blt')) {
26
+ const csEntry = csEntriesByUid.get(fsEntry.uid);
27
+ if (csEntry) {
28
+ // Found a match by UID
29
+ matched.add(csEntry.title);
30
+ if (equalityFn(fsEntry, csEntry)) {
31
+ toSkip.add(fsTitle);
32
+ }
33
+ else {
34
+ toUpdate.set(fsTitle, fsEntry);
35
+ }
36
+ continue;
37
+ }
38
+ else if (ui.options.verbose) {
39
+ // Entry has a Contentstack UID but wasn't found in CS
40
+ // This might mean it was deleted from CS, treat as new creation
41
+ ui.warn(`Entry "${fsTitle}" has UID ${fsEntry.uid} but was not found in Contentstack. It will be created.`);
42
+ }
43
+ }
44
+ // Second pass: fall back to title-based matching
45
+ const csEntry = csEntriesByTitle.get(fsTitle);
46
+ if (csEntry) {
47
+ matched.add(csEntry.title);
48
+ if (equalityFn(fsEntry, csEntry)) {
49
+ toSkip.add(fsTitle);
50
+ }
51
+ else {
52
+ toUpdate.set(fsTitle, fsEntry);
53
+ }
54
+ }
55
+ else {
56
+ toCreate.set(fsTitle, fsEntry);
57
+ }
58
+ }
59
+ return { matched, toCreate, toSkip, toUpdate };
60
+ }
61
+ /**
62
+ * Custom planning function for entries that matches by UID when available,
63
+ * falling back to title-based matching. This handles cases where entries
64
+ * have Contentstack UIDs but different titles (e.g., localized titles).
65
+ */
66
+ export default function planEntryMerge(equalityFn, fsEntriesByTitle, csEntriesByTitle) {
67
+ const csEntriesByUid = buildUidIndex(csEntriesByTitle);
68
+ const { matched, toCreate, toSkip, toUpdate } = matchEntries(equalityFn, fsEntriesByTitle, csEntriesByTitle, csEntriesByUid);
69
+ // Find entries to remove (in CS but not matched with any FS entry)
70
+ const toRemove = new Map();
71
+ for (const [csTitle, csEntry] of csEntriesByTitle) {
72
+ if (!matched.has(csTitle)) {
73
+ toRemove.set(csTitle, csEntry);
74
+ }
75
+ }
76
+ return { toCreate, toRemove, toSkip, toUpdate };
77
+ }
78
+ //# sourceMappingURL=planEntryMerge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planEntryMerge.js","sourceRoot":"","sources":["../../../../src/schema/entries/lib/planEntryMerge.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Entry } from '#cli/cs/entries/Types.js';\nimport type MergePlan from '../../xfer/lib/MergePlan.js';\nimport getUi from '../../lib/SchemaUi.js';\n\n/**\n * Build a UID-based index for CS entries\n */\nfunction buildUidIndex(\n\tcsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>,\n): Map<Entry['uid'], Entry> {\n\tconst csEntriesByUid = new Map<Entry['uid'], Entry>();\n\tfor (const csEntry of csEntriesByTitle.values()) {\n\t\tif (csEntry.uid.startsWith('blt')) {\n\t\t\tcsEntriesByUid.set(csEntry.uid, csEntry);\n\t\t}\n\t}\n\treturn csEntriesByUid;\n}\n\n/**\n * Match entries by UID and title\n */\nfunction matchEntries(\n\tequalityFn: (a: Entry, b: Entry) => boolean,\n\tfsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>,\n\tcsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>,\n\tcsEntriesByUid: Map<Entry['uid'], Entry>,\n): {\n\ttoCreate: Map<Entry['title'], Entry>;\n\ttoUpdate: Map<Entry['title'], Entry>;\n\ttoSkip: Set<Entry['title']>;\n\tmatched: Set<Entry['title']>;\n} {\n\tconst ui = getUi();\n\tconst toCreate = new Map<Entry['title'], Entry>();\n\tconst toUpdate = new Map<Entry['title'], Entry>();\n\tconst toSkip = new Set<Entry['title']>();\n\tconst matched = new Set<Entry['title']>();\n\n\t// First pass: match by UID for entries that have real Contentstack UIDs\n\tfor (const [fsTitle, fsEntry] of fsEntriesByTitle) {\n\t\tif (fsEntry.uid.startsWith('blt')) {\n\t\t\tconst csEntry = csEntriesByUid.get(fsEntry.uid);\n\t\t\tif (csEntry) {\n\t\t\t\t// Found a match by UID\n\t\t\t\tmatched.add(csEntry.title);\n\t\t\t\tif (equalityFn(fsEntry, csEntry)) {\n\t\t\t\t\ttoSkip.add(fsTitle);\n\t\t\t\t} else {\n\t\t\t\t\ttoUpdate.set(fsTitle, fsEntry);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t} else if (ui.options.verbose) {\n\t\t\t\t// Entry has a Contentstack UID but wasn't found in CS\n\t\t\t\t// This might mean it was deleted from CS, treat as new creation\n\t\t\t\tui.warn(\n\t\t\t\t\t`Entry \"${fsTitle}\" has UID ${fsEntry.uid} but was not found in Contentstack. It will be created.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Second pass: fall back to title-based matching\n\t\tconst csEntry = csEntriesByTitle.get(fsTitle);\n\t\tif (csEntry) {\n\t\t\tmatched.add(csEntry.title);\n\t\t\tif (equalityFn(fsEntry, csEntry)) {\n\t\t\t\ttoSkip.add(fsTitle);\n\t\t\t} else {\n\t\t\t\ttoUpdate.set(fsTitle, fsEntry);\n\t\t\t}\n\t\t} else {\n\t\t\ttoCreate.set(fsTitle, fsEntry);\n\t\t}\n\t}\n\n\treturn { matched, toCreate, toSkip, toUpdate };\n}\n\n/**\n * Custom planning function for entries that matches by UID when available,\n * falling back to title-based matching. This handles cases where entries\n * have Contentstack UIDs but different titles (e.g., localized titles).\n */\nexport default function planEntryMerge(\n\tequalityFn: (a: Entry, b: Entry) => boolean,\n\tfsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>,\n\tcsEntriesByTitle: ReadonlyMap<Entry['title'], Entry>,\n): MergePlan<Entry> {\n\tconst csEntriesByUid = buildUidIndex(csEntriesByTitle);\n\tconst { matched, toCreate, toSkip, toUpdate } = matchEntries(\n\t\tequalityFn,\n\t\tfsEntriesByTitle,\n\t\tcsEntriesByTitle,\n\t\tcsEntriesByUid,\n\t);\n\n\t// Find entries to remove (in CS but not matched with any FS entry)\n\tconst toRemove = new Map<Entry['title'], Entry>();\n\tfor (const [csTitle, csEntry] of csEntriesByTitle) {\n\t\tif (!matched.has(csTitle)) {\n\t\t\ttoRemove.set(csTitle, csEntry);\n\t\t}\n\t}\n\n\treturn { toCreate, toRemove, toSkip, toUpdate };\n}\n"]}
@@ -4,12 +4,12 @@ import importEntry from '#cli/cs/entries/import.js';
4
4
  import { ensureLocaleExists } from '#cli/cs/locales/ensureLocaleExists.js';
5
5
  import BeaconReplacer from '#cli/dto/entry/BeaconReplacer.js';
6
6
  import getUi from '../lib/SchemaUi.js';
7
- import planMerge from '../xfer/lib/planMerge.js';
8
7
  import processPlan from '../xfer/lib/processPlan.js';
9
8
  import equality from './equality.js';
10
9
  import buildCreator from './lib/buildCreator.js';
11
10
  import generateFilenames from './lib/generateFilenames.js';
12
11
  import loadEntryLocales from './lib/loadEntryLocales.js';
12
+ import planEntryMerge from './lib/planEntryMerge.js';
13
13
  import schemaDirectory from './schemaDirectory.js';
14
14
  export default async function toContentstack(ctx, contentType, bar) {
15
15
  const ui = getUi();
@@ -22,7 +22,7 @@ export default async function toContentstack(ctx, contentType, bar) {
22
22
  const result = await processPlan({
23
23
  create,
24
24
  deletionStrategy: ui.options.schema.deletionStrategy,
25
- plan: planMerge(equality, fsEntriesByTitle, csEntriesByTitle),
25
+ plan: planEntryMerge(equality, fsEntriesByTitle, csEntriesByTitle),
26
26
  progress: bar,
27
27
  remove: async (entry) => deleteEntry(ctx.cs.client, contentType.uid, entry.uid),
28
28
  update,
@@ -1 +1 @@
1
- {"version":3,"file":"toContentstack.js","sourceRoot":"","sources":["../../../src/schema/entries/toContentstack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentType } from '#cli/cs/content-types/Types.js';\nimport deleteEntry from '#cli/cs/entries/delete.js';\nimport getEntryLocales from '#cli/cs/entries/getEntryLocales.js';\nimport importEntry from '#cli/cs/entries/import.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport { ensureLocaleExists } from '#cli/cs/locales/ensureLocaleExists.js';\nimport BeaconReplacer from '#cli/dto/entry/BeaconReplacer.js';\nimport type ProgressBar from '#cli/ui/progress/ProgressBar.js';\nimport type Ctx from '../ctx/Ctx.js';\nimport getUi from '../lib/SchemaUi.js';\nimport planMerge from '../xfer/lib/planMerge.js';\nimport processPlan from '../xfer/lib/processPlan.js';\nimport equality from './equality.js';\nimport buildCreator from './lib/buildCreator.js';\nimport generateFilenames from './lib/generateFilenames.js';\nimport loadEntryLocales from './lib/loadEntryLocales.js';\nimport schemaDirectory from './schemaDirectory.js';\n\nexport default async function toContentstack(\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tbar: ProgressBar,\n) {\n\tconst ui = getUi();\n\n\tconst fsEntriesByTitle = ctx.fs.entries.byTitleFor(contentType.uid);\n\tconst csEntriesByTitle = ctx.cs.entries.byTitleFor(contentType.uid);\n\tconst transformer = new BeaconReplacer(ctx, contentType);\n\tconst filenamesByTitle = generateFilenames(fsEntriesByTitle);\n\tconst create = buildCreator(ctx, transformer, contentType);\n\tconst update = buildUpdateFn(\n\t\tctx,\n\t\tcsEntriesByTitle,\n\t\ttransformer,\n\t\tcontentType,\n\t\tfilenamesByTitle,\n\t);\n\n\tconst result = await processPlan<Entry>({\n\t\tcreate,\n\t\tdeletionStrategy: ui.options.schema.deletionStrategy,\n\t\tplan: planMerge(equality, fsEntriesByTitle, csEntriesByTitle),\n\t\tprogress: bar,\n\t\tremove: async (entry) =>\n\t\t\tdeleteEntry(ctx.cs.client, contentType.uid, entry.uid),\n\t\tupdate,\n\t});\n\n\t// Process unmodified entries to ensure all locale versions are synced\n\tawait processUnmodifiedEntries(\n\t\tresult.unmodified,\n\t\tctx,\n\t\tcontentType,\n\t\tcsEntriesByTitle,\n\t\tfsEntriesByTitle,\n\t\ttransformer,\n\t\tfilenamesByTitle,\n\t);\n\n\treturn result;\n}\n\nfunction shouldSyncLocales(\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadFsLocaleVersions>>,\n\tcsLocaleSet: Set<string>,\n): boolean {\n\t// Check if we have new locale versions that don't exist in Contentstack\n\tconst fsLocaleSet = new Set(\n\t\tfsLocaleVersions.map((lv) => (lv.locale === 'default' ? null : lv.locale)),\n\t);\n\treturn Array.from(fsLocaleSet).some(\n\t\t(locale) => locale !== null && !csLocaleSet.has(locale),\n\t);\n}\n\nasync function processUnmodifiedEntries(\n\tunmodified: Iterable<string>,\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tcsEntriesByTitle: ReadonlyMap<string, Entry>,\n\tfsEntriesByTitle: ReadonlyMap<string, Entry>,\n\ttransformer: BeaconReplacer,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\tconst ui = getUi();\n\n\tfor (const title of unmodified) {\n\t\tconst cs = csEntriesByTitle.get(title);\n\t\tconst fs = fsEntriesByTitle.get(title);\n\n\t\tif (cs && !fs && ui.options.schema.deletionStrategy !== 'delete') {\n\t\t\t// The entry was deleted from the file system, but the user has chosen\n\t\t\t// to ignore deletions in Contentstack. The item is invalid as a\n\t\t\t// reference, but does not represent an error state.\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!cs || !fs) {\n\t\t\tthrow new Error(`No matching entry found for ${title}.`);\n\t\t}\n\n\t\t// Load all locale versions from filesystem\n\t\tconst fsLocaleVersions = await loadFsLocaleVersions(\n\t\t\tfs,\n\t\t\tcontentType.uid,\n\t\t\tfilenamesByTitle,\n\t\t);\n\n\t\tconst csLocaleSet = await getExistingLocales(ctx, contentType, cs.uid);\n\n\t\t// Only push if there are new locale versions to sync\n\t\tif (!shouldSyncLocales(fsLocaleVersions, csLocaleSet)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Push all locale versions (including new locales like zh-cn)\n\t\tawait updateAllLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tcs.uid,\n\t\t\tcsLocaleSet,\n\t\t);\n\n\t\tconst entry = { ...fs, uid: cs.uid };\n\t\tctx.references.recordEntryForReferences(contentType.uid, entry);\n\t}\n}\n\nfunction buildUpdateFn(\n\tctx: Ctx,\n\tcsEntriesByTitle: ReadonlyMap<string, Entry>,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\treturn async (entry: Entry) => {\n\t\tconst match = csEntriesByTitle.get(entry.title);\n\t\tif (!match) {\n\t\t\tthrow new Error(`No matching entry found for ${entry.title}.`);\n\t\t}\n\n\t\tconst fsLocaleVersions = await loadFsLocaleVersions(\n\t\t\tentry,\n\t\t\tcontentType.uid,\n\t\t\tfilenamesByTitle,\n\t\t);\n\n\t\tconst csLocaleSet = await getExistingLocales(ctx, contentType, match.uid);\n\n\t\tawait updateAllLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tmatch.uid,\n\t\t\tcsLocaleSet,\n\t\t);\n\n\t\tctx.references.recordEntryForReferences(contentType.uid, {\n\t\t\t...entry,\n\t\t\tuid: match.uid,\n\t\t});\n\t};\n}\n\nasync function loadFsLocaleVersions(\n\tentry: Entry,\n\tcontentTypeUid: string,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\tconst filename = filenamesByTitle.get(entry.title);\n\tif (!filename) {\n\t\tthrow new Error(`No filename found for entry ${entry.title}.`);\n\t}\n\n\tconst baseFilename = filename.replace(/\\.yaml$/u, '');\n\tconst directory = schemaDirectory(contentTypeUid);\n\n\treturn loadEntryLocales(directory, entry.title, baseFilename);\n}\n\nasync function getExistingLocales(\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tentryUid: string,\n) {\n\tconst csLocales = await getEntryLocales(\n\t\tctx.cs.client,\n\t\tcontentType.uid,\n\t\tentryUid,\n\t);\n\treturn new Set(csLocales.map((l) => l.code));\n}\n\nasync function updateAllLocales(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadFsLocaleVersions>>,\n\tentryUid: string,\n\tcsLocaleSet: Set<string>,\n) {\n\t// Ensure all required locales exist in the target stack before pushing entries\n\tconst localeEnsurePromises = fsLocaleVersions\n\t\t.filter((lv) => lv.locale !== 'default')\n\t\t.map(async (lv) => ensureLocaleExists(ctx.cs.client, lv.locale));\n\n\tawait Promise.all(localeEnsurePromises);\n\n\t// Import all locale versions in parallel for better performance\n\tconst importPromises = fsLocaleVersions.map(async (localeVersion) => {\n\t\tconst transformed = transformer.process(localeVersion.entry);\n\n\t\t// Pass undefined for 'default' locale (single-locale backward compat)\n\t\tconst locale =\n\t\t\tlocaleVersion.locale === 'default' ? undefined : localeVersion.locale;\n\n\t\t// Always use overwrite=true for locale-specific versions since the entry exists.\n\t\t// For 'default' locale (single-locale backward compat), only overwrite if entry has locales.\n\t\tconst overwrite = locale ? true : csLocaleSet.size > 0;\n\n\t\treturn importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\t{ ...transformed, uid: entryUid },\n\t\t\toverwrite,\n\t\t\tlocale,\n\t\t);\n\t});\n\n\tawait Promise.all(importPromises);\n}\n"]}
1
+ {"version":3,"file":"toContentstack.js","sourceRoot":"","sources":["../../../src/schema/entries/toContentstack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentType } from '#cli/cs/content-types/Types.js';\nimport deleteEntry from '#cli/cs/entries/delete.js';\nimport getEntryLocales from '#cli/cs/entries/getEntryLocales.js';\nimport importEntry from '#cli/cs/entries/import.js';\nimport type { Entry } from '#cli/cs/entries/Types.js';\nimport { ensureLocaleExists } from '#cli/cs/locales/ensureLocaleExists.js';\nimport BeaconReplacer from '#cli/dto/entry/BeaconReplacer.js';\nimport type ProgressBar from '#cli/ui/progress/ProgressBar.js';\nimport type Ctx from '../ctx/Ctx.js';\nimport getUi from '../lib/SchemaUi.js';\nimport processPlan from '../xfer/lib/processPlan.js';\nimport equality from './equality.js';\nimport buildCreator from './lib/buildCreator.js';\nimport generateFilenames from './lib/generateFilenames.js';\nimport loadEntryLocales from './lib/loadEntryLocales.js';\nimport planEntryMerge from './lib/planEntryMerge.js';\nimport schemaDirectory from './schemaDirectory.js';\n\nexport default async function toContentstack(\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tbar: ProgressBar,\n) {\n\tconst ui = getUi();\n\n\tconst fsEntriesByTitle = ctx.fs.entries.byTitleFor(contentType.uid);\n\tconst csEntriesByTitle = ctx.cs.entries.byTitleFor(contentType.uid);\n\tconst transformer = new BeaconReplacer(ctx, contentType);\n\tconst filenamesByTitle = generateFilenames(fsEntriesByTitle);\n\tconst create = buildCreator(ctx, transformer, contentType);\n\tconst update = buildUpdateFn(\n\t\tctx,\n\t\tcsEntriesByTitle,\n\t\ttransformer,\n\t\tcontentType,\n\t\tfilenamesByTitle,\n\t);\n\n\tconst result = await processPlan<Entry>({\n\t\tcreate,\n\t\tdeletionStrategy: ui.options.schema.deletionStrategy,\n\t\tplan: planEntryMerge(equality, fsEntriesByTitle, csEntriesByTitle),\n\t\tprogress: bar,\n\t\tremove: async (entry) =>\n\t\t\tdeleteEntry(ctx.cs.client, contentType.uid, entry.uid),\n\t\tupdate,\n\t});\n\n\t// Process unmodified entries to ensure all locale versions are synced\n\tawait processUnmodifiedEntries(\n\t\tresult.unmodified,\n\t\tctx,\n\t\tcontentType,\n\t\tcsEntriesByTitle,\n\t\tfsEntriesByTitle,\n\t\ttransformer,\n\t\tfilenamesByTitle,\n\t);\n\n\treturn result;\n}\n\nfunction shouldSyncLocales(\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadFsLocaleVersions>>,\n\tcsLocaleSet: Set<string>,\n): boolean {\n\t// Check if we have new locale versions that don't exist in Contentstack\n\tconst fsLocaleSet = new Set(\n\t\tfsLocaleVersions.map((lv) => (lv.locale === 'default' ? null : lv.locale)),\n\t);\n\treturn Array.from(fsLocaleSet).some(\n\t\t(locale) => locale !== null && !csLocaleSet.has(locale),\n\t);\n}\n\nasync function processUnmodifiedEntries(\n\tunmodified: Iterable<string>,\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tcsEntriesByTitle: ReadonlyMap<string, Entry>,\n\tfsEntriesByTitle: ReadonlyMap<string, Entry>,\n\ttransformer: BeaconReplacer,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\tconst ui = getUi();\n\n\tfor (const title of unmodified) {\n\t\tconst cs = csEntriesByTitle.get(title);\n\t\tconst fs = fsEntriesByTitle.get(title);\n\n\t\tif (cs && !fs && ui.options.schema.deletionStrategy !== 'delete') {\n\t\t\t// The entry was deleted from the file system, but the user has chosen\n\t\t\t// to ignore deletions in Contentstack. The item is invalid as a\n\t\t\t// reference, but does not represent an error state.\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!cs || !fs) {\n\t\t\tthrow new Error(`No matching entry found for ${title}.`);\n\t\t}\n\n\t\t// Load all locale versions from filesystem\n\t\tconst fsLocaleVersions = await loadFsLocaleVersions(\n\t\t\tfs,\n\t\t\tcontentType.uid,\n\t\t\tfilenamesByTitle,\n\t\t);\n\n\t\tconst csLocaleSet = await getExistingLocales(ctx, contentType, cs.uid);\n\n\t\t// Only push if there are new locale versions to sync\n\t\tif (!shouldSyncLocales(fsLocaleVersions, csLocaleSet)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Push all locale versions (including new locales like zh-cn)\n\t\tawait updateAllLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tcs.uid,\n\t\t\tcsLocaleSet,\n\t\t);\n\n\t\tconst entry = { ...fs, uid: cs.uid };\n\t\tctx.references.recordEntryForReferences(contentType.uid, entry);\n\t}\n}\n\nfunction buildUpdateFn(\n\tctx: Ctx,\n\tcsEntriesByTitle: ReadonlyMap<string, Entry>,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\treturn async (entry: Entry) => {\n\t\tconst match = csEntriesByTitle.get(entry.title);\n\t\tif (!match) {\n\t\t\tthrow new Error(`No matching entry found for ${entry.title}.`);\n\t\t}\n\n\t\tconst fsLocaleVersions = await loadFsLocaleVersions(\n\t\t\tentry,\n\t\t\tcontentType.uid,\n\t\t\tfilenamesByTitle,\n\t\t);\n\n\t\tconst csLocaleSet = await getExistingLocales(ctx, contentType, match.uid);\n\n\t\tawait updateAllLocales(\n\t\t\tctx,\n\t\t\ttransformer,\n\t\t\tcontentType,\n\t\t\tfsLocaleVersions,\n\t\t\tmatch.uid,\n\t\t\tcsLocaleSet,\n\t\t);\n\n\t\tctx.references.recordEntryForReferences(contentType.uid, {\n\t\t\t...entry,\n\t\t\tuid: match.uid,\n\t\t});\n\t};\n}\n\nasync function loadFsLocaleVersions(\n\tentry: Entry,\n\tcontentTypeUid: string,\n\tfilenamesByTitle: ReadonlyMap<Entry['uid'], string>,\n) {\n\tconst filename = filenamesByTitle.get(entry.title);\n\tif (!filename) {\n\t\tthrow new Error(`No filename found for entry ${entry.title}.`);\n\t}\n\n\tconst baseFilename = filename.replace(/\\.yaml$/u, '');\n\tconst directory = schemaDirectory(contentTypeUid);\n\n\treturn loadEntryLocales(directory, entry.title, baseFilename);\n}\n\nasync function getExistingLocales(\n\tctx: Ctx,\n\tcontentType: ContentType,\n\tentryUid: string,\n) {\n\tconst csLocales = await getEntryLocales(\n\t\tctx.cs.client,\n\t\tcontentType.uid,\n\t\tentryUid,\n\t);\n\treturn new Set(csLocales.map((l) => l.code));\n}\n\nasync function updateAllLocales(\n\tctx: Ctx,\n\ttransformer: BeaconReplacer,\n\tcontentType: ContentType,\n\tfsLocaleVersions: Awaited<ReturnType<typeof loadFsLocaleVersions>>,\n\tentryUid: string,\n\tcsLocaleSet: Set<string>,\n) {\n\t// Ensure all required locales exist in the target stack before pushing entries\n\tconst localeEnsurePromises = fsLocaleVersions\n\t\t.filter((lv) => lv.locale !== 'default')\n\t\t.map(async (lv) => ensureLocaleExists(ctx.cs.client, lv.locale));\n\n\tawait Promise.all(localeEnsurePromises);\n\n\t// Import all locale versions in parallel for better performance\n\tconst importPromises = fsLocaleVersions.map(async (localeVersion) => {\n\t\tconst transformed = transformer.process(localeVersion.entry);\n\n\t\t// Pass undefined for 'default' locale (single-locale backward compat)\n\t\tconst locale =\n\t\t\tlocaleVersion.locale === 'default' ? undefined : localeVersion.locale;\n\n\t\t// Always use overwrite=true for locale-specific versions since the entry exists.\n\t\t// For 'default' locale (single-locale backward compat), only overwrite if entry has locales.\n\t\tconst overwrite = locale ? true : csLocaleSet.size > 0;\n\n\t\treturn importEntry(\n\t\t\tctx.cs.client,\n\t\t\tcontentType.uid,\n\t\t\t{ ...transformed, uid: entryUid },\n\t\t\toverwrite,\n\t\t\tlocale,\n\t\t);\n\t});\n\n\tawait Promise.all(importPromises);\n}\n"]}