@x18n/core 0.0.0 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -426,6 +426,7 @@ interface CheckContext {
426
426
  /** Usages whose key is not defined in the source locale. */
427
427
  readonly undefinedUsages: () => readonly Usage[];
428
428
  readonly placeholders: (value: string) => readonly Placeholder[];
429
+ readonly placeholderSyntaxes: readonly PlaceholderSyntax[];
429
430
  /** Errors reported by the `validate` of every placeholder syntax. */
430
431
  readonly syntaxErrors: (value: string) => readonly string[];
431
432
  readonly localeInfo: (code: LocaleCode) => LocaleInfo;
@@ -475,6 +476,8 @@ interface PlaceholderSyntax {
475
476
  readonly example?: string | undefined;
476
477
  /** The placeholder name is another key (vue-i18n `@:key`, i18next `$t(key)`), which then counts as used. */
477
478
  readonly reference?: boolean | undefined;
479
+ /** Names the library always passes, which a translation may leave out or add (vue-i18n `n` and `count`). */
480
+ readonly implicit?: readonly string[] | undefined;
478
481
  }
479
482
  interface KeyContext {
480
483
  readonly path: string;
@@ -645,7 +648,10 @@ interface NamespaceOptions {
645
648
  readonly separator?: string | undefined;
646
649
  /** Namespace of keys written without one. */
647
650
  readonly default?: string | undefined;
651
+ /** How `{namespaces}` folders name a namespace: `dot` makes `pages/home` into `pages.home`, `slash` keeps `pages/home`, `camel` makes `todos-page` into `todosPage`. Default `dot`. */
652
+ readonly fromPath?: "dot" | "slash" | "camel" | undefined;
648
653
  }
654
+ type NamespaceFromPath = NonNullable<NamespaceOptions["fromPath"]>;
649
655
  type PluginSpecifier = string | readonly [string, JsonObject];
650
656
  /** The part of the config that YAML and JSON files can hold. Validated by `ConfigSchema`. */
651
657
  interface SerializableConfig {
@@ -713,6 +719,7 @@ interface ResolvedConfig {
713
719
  readonly namespace: {
714
720
  readonly separator: string;
715
721
  readonly default: string | undefined;
722
+ readonly fromPath: NamespaceFromPath;
716
723
  };
717
724
  readonly usage: {
718
725
  readonly include: readonly string[];
@@ -1093,6 +1100,8 @@ interface Project {
1093
1100
  readonly keys: (query?: KeyQuery) => KeyString[];
1094
1101
  readonly get: (key: KeyString) => KeyInfo | undefined;
1095
1102
  readonly message: (key: KeyString, locale: LocaleCode) => Message | undefined;
1103
+ /** The message a usage of `key` shows: the key's own, or one of its derived keys (`item` → `item_other`). */
1104
+ readonly lookup: (key: KeyString, locale: LocaleCode) => Message | undefined;
1096
1105
  /** Parses user input such as `common:save` or `save` into a key string. */
1097
1106
  readonly parseKey: (input: string) => KeyString;
1098
1107
  readonly usages: (query?: UsageQuery) => UsageMatch[];
@@ -1137,6 +1146,15 @@ interface PlaceholderProblem {
1137
1146
  /** Parses the batch shape `{ "<locale>": { "<key>": "<value>" } }` (as in `x18n apply`) into set ops. */
1138
1147
  export declare function parseMessageBatch(project: Project, data: JsonValue): EditOp[];
1139
1148
  /** Set ops whose value drops or adds placeholders compared to the source value. */
1149
+ type PlaceholderComparer = (source: string, target: string) => {
1150
+ readonly missing: string[];
1151
+ readonly extra: string[];
1152
+ };
1153
+ /**
1154
+ * Compares the placeholders of a target value with its source. Key references (`@:key`) are not
1155
+ * parameters, and implicit names (vue-i18n `{n}` in plural messages) may be left out. Build it once per run.
1156
+ */
1157
+ export declare function createPlaceholderComparer(syntaxes: readonly PlaceholderSyntax[], find?: (value: string) => readonly Placeholder[]): PlaceholderComparer;
1140
1158
  export declare function placeholderProblems(project: Project, ops: readonly EditOp[]): PlaceholderProblem[];
1141
1159
  //#endregion
1142
1160
  //#region src/project/project.d.ts
@@ -1166,10 +1184,7 @@ interface PluginFile {
1166
1184
  readonly sourceLocale?: string | undefined;
1167
1185
  readonly locales?: readonly string[] | undefined;
1168
1186
  readonly resources?: readonly ResourceSpec[] | undefined;
1169
- readonly namespace?: {
1170
- readonly separator?: string | undefined;
1171
- readonly default?: string | undefined;
1172
- } | undefined;
1187
+ readonly namespace?: NamespaceOptions | undefined;
1173
1188
  readonly keyStyle?: "auto" | "nested" | "flat" | undefined;
1174
1189
  } | undefined;
1175
1190
  readonly scanners?: {
@@ -1237,4 +1252,4 @@ export declare function rangeContains(range: TextRange, offset: number): boolean
1237
1252
  /** Fast non-cryptographic string hash (cyrb53), as hex. */
1238
1253
  export declare function hashText(text: string): string;
1239
1254
  //#endregion
1240
- export type { Analysis, Answers, ApplyResult, ArgSource, Builtins, CacheStore, CallSpec, CapabilityConflict, Check, CheckContext, CheckIds, CheckLevel, CheckSetting, ConfigContext, ConfigDraft, ConfigOrigin, CreateProjectOptions, Decision, DecisionOption, DetectContext, Diagnostic, DiagnosticInput, Disposable, EditOp, Envelope, ErrorCode, ErrorInfo, ExtractItem, ExtractOptions, ExtractTemplate, Extractor, FileChange, FileEvent, FileScan, FinderContext, Fix, Format, FormatContext, GlobOptions, GlossaryEntry, HardString, Host, JsonObject, JsonPrimitive, JsonValue, KeyContext, KeyId, KeyInfo, KeyQuery, KeyString, KeyTarget, LineIndex, LinePosition, LocaleCode, LocaleCoverage, LocaleFinder, LocaleInfo, Location, Logger, ManifestReader, MemoryHost, Message, MessageLeaf, MessageOp, MessageTree, NamespaceOptions, NodeRange, OverlayHost, ParseResult, Placeholder, PlaceholderProblem, PlaceholderSyntax, Plan, Plugin, PluginConfigs, PluginFile, PluginOption, PluginRegistry, PluginSpecifier, Preset, PresetExplanation, PresetFactory, PresetOption, Project, ProjectChange, ProjectExplanation, PromptContext, PromptData, PromptDraft, PromptItem, PromptOptions, RegexScannerSpec, ReportInput, ReportSummary, Reporter, ReporterContext, ResolveConfigOptions, ResolvedConfig, Resource, ResourceBlock, ResourceCandidate, ResourceId, ResourceNode, ResourceSpec, ResourceTransform, ResourceTransformContext, ScanContext, ScanResult, Scanner, SchemaIssue, Scope, SerializableConfig, Setup, Severity, SourceFile, TextEdit, TextRange, TreeLeaf, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions };
1255
+ export type { Analysis, Answers, ApplyResult, ArgSource, Builtins, CacheStore, CallSpec, CapabilityConflict, Check, CheckContext, CheckIds, CheckLevel, CheckSetting, ConfigContext, ConfigDraft, ConfigOrigin, CreateProjectOptions, Decision, DecisionOption, DetectContext, Diagnostic, DiagnosticInput, Disposable, EditOp, Envelope, ErrorCode, ErrorInfo, ExtractItem, ExtractOptions, ExtractTemplate, Extractor, FileChange, FileEvent, FileScan, FinderContext, Fix, Format, FormatContext, GlobOptions, GlossaryEntry, HardString, Host, JsonObject, JsonPrimitive, JsonValue, KeyContext, KeyId, KeyInfo, KeyQuery, KeyString, KeyTarget, LineIndex, LinePosition, LocaleCode, LocaleCoverage, LocaleFinder, LocaleInfo, Location, Logger, ManifestReader, MemoryHost, Message, MessageLeaf, MessageOp, MessageTree, NamespaceFromPath, NamespaceOptions, NodeRange, OverlayHost, ParseResult, Placeholder, PlaceholderComparer, PlaceholderProblem, PlaceholderSyntax, Plan, Plugin, PluginConfigs, PluginFile, PluginOption, PluginRegistry, PluginSpecifier, Preset, PresetExplanation, PresetFactory, PresetOption, Project, ProjectChange, ProjectExplanation, PromptContext, PromptData, PromptDraft, PromptItem, PromptOptions, RegexScannerSpec, ReportInput, ReportSummary, Reporter, ReporterContext, ResolveConfigOptions, ResolvedConfig, Resource, ResourceBlock, ResourceCandidate, ResourceId, ResourceNode, ResourceSpec, ResourceTransform, ResourceTransformContext, ScanContext, ScanResult, Scanner, SchemaIssue, Scope, SerializableConfig, Setup, Severity, SourceFile, TextEdit, TextRange, TreeLeaf, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions };
package/dist/index.mjs CHANGED
@@ -690,7 +690,12 @@ const glossaryEntry = v.strictObject({
690
690
  const checkSetting = v.union([level, v.tuple([level, jsonObject])]);
691
691
  const namespaceOptions = v.strictObject({
692
692
  separator: v.optional(v.string()),
693
- default: v.optional(v.string())
693
+ default: v.optional(v.string()),
694
+ fromPath: v.optional(v.picklist([
695
+ "dot",
696
+ "slash",
697
+ "camel"
698
+ ]))
694
699
  });
695
700
  /** Validates YAML and JSON configs, and the serializable part of TS configs. */
696
701
  const ConfigSchema = v.strictObject({
@@ -808,17 +813,38 @@ function parseMessageBatch(project, data) {
808
813
  }
809
814
  return ops;
810
815
  }
811
- /** Set ops whose value drops or adds placeholders compared to the source value. */
816
+ /**
817
+ * Compares the placeholders of a target value with its source. Key references (`@:key`) are not
818
+ * parameters, and implicit names (vue-i18n `{n}` in plural messages) may be left out. Build it once per run.
819
+ */
820
+ function createPlaceholderComparer(syntaxes, find = (value) => syntaxes.flatMap((s) => s.find(value))) {
821
+ const references = new Set(syntaxes.filter((s) => s.reference).map((s) => s.id));
822
+ const implicit = new Set(syntaxes.flatMap((s) => s.implicit ?? []));
823
+ const seen = /* @__PURE__ */ new Map();
824
+ const names = (text) => {
825
+ let found = seen.get(text);
826
+ if (!found) {
827
+ found = new Set(find(text).filter((p) => !references.has(p.syntax) && !implicit.has(p.name)).map((p) => p.name));
828
+ seen.set(text, found);
829
+ }
830
+ return found;
831
+ };
832
+ return (source, target) => {
833
+ const expected = names(source);
834
+ const actual = names(target);
835
+ return {
836
+ missing: [...expected].filter((name) => !actual.has(name)).sort(),
837
+ extra: [...actual].filter((name) => !expected.has(name)).sort()
838
+ };
839
+ };
840
+ }
812
841
  function placeholderProblems(project, ops) {
813
- const names = (text) => project.placeholderSyntaxes.flatMap((s) => s.find(text)).map((ph) => ph.name).sort();
842
+ const compare = createPlaceholderComparer(project.placeholderSyntaxes);
814
843
  return ops.flatMap((op) => {
815
844
  if (op.type !== "set" || op.locale === project.sourceLocale || typeof op.value !== "string") return [];
816
845
  const source = project.message(op.key, project.sourceLocale)?.value;
817
846
  if (typeof source !== "string") return [];
818
- const expected = names(source);
819
- const actual = names(op.value);
820
- const missing = expected.filter((n) => !actual.includes(n));
821
- const extra = actual.filter((n) => !expected.includes(n));
847
+ const { missing, extra } = compare(source, op.value);
822
848
  return missing.length || extra.length ? [{
823
849
  key: op.key,
824
850
  locale: op.locale,
@@ -991,6 +1017,7 @@ function createAnalyzer(options) {
991
1017
  unused: () => unused,
992
1018
  undefinedUsages: () => undefinedUsages,
993
1019
  placeholders,
1020
+ placeholderSyntaxes: registry.placeholders,
994
1021
  syntaxErrors: (value) => registry.placeholders.flatMap((syntax) => syntax.validate?.(value) ?? []),
995
1022
  localeInfo: options.localeInfo,
996
1023
  text: options.text,
@@ -1151,9 +1178,12 @@ var PlanBuilder = class {
1151
1178
  createTarget(key, locale) {
1152
1179
  const { resources, sourceLocale, namespaced } = this.state;
1153
1180
  const fits = (s) => this.relativePath(key, s.resource) !== void 0;
1154
- const namespace = namespaced ? this.keyId(key).namespace ?? this.config.namespace.default : void 0;
1181
+ const source = this.options.message(key, sourceLocale);
1182
+ const sourceState = source && this.stateById.get(source.resource);
1183
+ const namespace = namespaced ? this.keyId(key).namespace ?? this.config.namespace.default : sourceState?.resource.namespace;
1184
+ const exists = (path) => resources.some((r) => r.resource.path === path);
1155
1185
  const resolved = this.options.resolveNew(locale, namespace);
1156
- if (resolved) {
1186
+ if (resolved && !exists(resolved)) {
1157
1187
  const format = this.options.registry.formatFor(resolved);
1158
1188
  if (format?.serialize) {
1159
1189
  const target = {
@@ -1168,15 +1198,17 @@ var PlanBuilder = class {
1168
1198
  return target;
1169
1199
  }
1170
1200
  }
1171
- const model = resources.find((s) => s.resource.locale === sourceLocale && fits(s)) ?? resources.find(fits);
1201
+ const sibling = (r) => r.resource.locale === locale && r.resource.namespace !== void 0 && namespace !== void 0;
1202
+ const model = (sourceState && fits(sourceState) ? sourceState : void 0) ?? resources.find((s) => s.resource.locale === sourceLocale && fits(s)) ?? resources.find(fits) ?? resources.find(sibling);
1172
1203
  const format = model && this.options.registry.formatById(model.resource.format);
1173
- const path = model && mirrorPath(model.resource.path, model.resource.locale, locale);
1174
- if (!model || !format?.serialize || model.resource.block || !path || path === model.resource.path) throw new X18nError("X18N4005", `${key} in ${locale}`);
1204
+ let path = model && mirrorPath(model.resource.path, model.resource.locale, locale);
1205
+ if (model && path && namespace !== void 0 && model.resource.namespace !== void 0 && model.resource.namespace !== namespace) path = mirrorPath(path, model.resource.namespace, namespace);
1206
+ if (!model || !format?.serialize || model.resource.block || !path || exists(path)) throw new X18nError("X18N4005", `${key} in ${locale}`);
1175
1207
  const target = {
1176
1208
  id: path,
1177
1209
  path,
1178
1210
  locale,
1179
- namespace: model.resource.namespace ?? namespace,
1211
+ namespace: namespace ?? model.resource.namespace,
1180
1212
  format,
1181
1213
  state: void 0
1182
1214
  };
@@ -1185,7 +1217,10 @@ var PlanBuilder = class {
1185
1217
  }
1186
1218
  /** Placement: the namespace's resource, then the longest shared prefix, then the first; a tie is a decision. */
1187
1219
  pickTarget(key, locale) {
1188
- const inLocale = this.state.resources.filter((s) => s.resource.locale === locale && this.relativePath(key, s.resource) !== void 0);
1220
+ let inLocale = this.state.resources.filter((s) => s.resource.locale === locale && this.relativePath(key, s.resource) !== void 0);
1221
+ const source = this.options.message(key, this.state.sourceLocale);
1222
+ const sourceNamespace = source && this.stateById.get(source.resource)?.resource.namespace;
1223
+ if (sourceNamespace !== void 0 && !this.state.namespaced) inLocale = inLocale.filter((s) => s.resource.namespace === sourceNamespace);
1189
1224
  if (inLocale.length === 0) return [...this.created.values()].find((t) => t.locale === locale && this.relativePath(key, t) !== void 0) ?? this.createTarget(key, locale);
1190
1225
  if (inLocale.length === 1) return this.targetOf(inLocale[0]);
1191
1226
  const path = this.keyId(key).path;
@@ -1253,11 +1288,50 @@ var PlanBuilder = class {
1253
1288
  });
1254
1289
  }
1255
1290
  /** Renames a key in every locale, in place when only the last segment changes. */
1256
- moveKey(from, to) {
1291
+ /**
1292
+ * Renames a parent object in place where only its last segment changes, so the subtree keeps its
1293
+ * position and layout. Returns the resources it handled.
1294
+ */
1295
+ renameNode(from, to) {
1296
+ const handled = /* @__PURE__ */ new Set();
1297
+ for (const s of this.state.resources) {
1298
+ const relativeFrom = this.relativePath(from, s.resource);
1299
+ const relativeTo = this.relativePath(to, s.resource);
1300
+ if (!relativeFrom || !relativeTo || s.resource.readonly || !this.options.registry.formatById(s.resource.format)?.edit) continue;
1301
+ const stored = s.toStored(relativeFrom);
1302
+ const next = s.toStored(relativeTo);
1303
+ const node = nodeAt(s.rawTree, stored);
1304
+ const range = s.ranges.get(pathId(stored));
1305
+ const last = next.at(-1);
1306
+ const sameParent = next.length === stored.length && next.slice(0, -1).every((segment, i) => segment === stored[i]);
1307
+ if (node === void 0 || isMessageLeaf(node) || !range || !sameParent || !safeSegment.test(last)) continue;
1308
+ const entry = this.workFor(this.targetOf(s));
1309
+ entry.keyRenames.push({
1310
+ range: {
1311
+ start: range.key.start + s.offset,
1312
+ end: range.key.end + s.offset
1313
+ },
1314
+ text: last
1315
+ });
1316
+ const leaves = [...walkLeaves(node, stored)];
1317
+ entry.tree = applyMessageOps(entry.tree, [...leaves.map((leaf) => ({
1318
+ type: "delete",
1319
+ path: leaf.path
1320
+ })), ...leaves.map((leaf) => ({
1321
+ type: "set",
1322
+ path: [...next, ...leaf.path.slice(stored.length)],
1323
+ value: leaf.value
1324
+ }))]);
1325
+ handled.add(s.resource.id);
1326
+ }
1327
+ return handled;
1328
+ }
1329
+ moveKey(from, to, renamed = /* @__PURE__ */ new Set()) {
1257
1330
  this.touched.add(from);
1258
1331
  this.touched.add(to);
1259
1332
  for (const [locale, list] of this.options.messages(from) ?? []) {
1260
1333
  const m = list[0];
1334
+ if (renamed.has(m.resource)) continue;
1261
1335
  const s = this.writable(m.resource);
1262
1336
  const relative = this.relativePath(to, s.resource);
1263
1337
  if (!relative) {
@@ -1295,6 +1369,10 @@ var PlanBuilder = class {
1295
1369
  }
1296
1370
  /** The raw text a usage needs to refer to `next`, given its scope. */
1297
1371
  rawFor(usage, next) {
1372
+ if (usage.raw.startsWith(".") && usage.key?.endsWith(usage.raw)) {
1373
+ const scope = usage.key.slice(0, usage.key.length - usage.raw.length);
1374
+ if (next.startsWith(`${scope}.`)) return next.slice(scope.length);
1375
+ }
1298
1376
  const { namespace, path } = this.keyId(next);
1299
1377
  let rest = path.join(".");
1300
1378
  const separator = this.config.namespace.separator;
@@ -1355,8 +1433,9 @@ var PlanBuilder = class {
1355
1433
  if (keys.length === 0) throw new X18nError("X18N4006", op.from);
1356
1434
  const pairs = keys.map((key) => [key, replaceKeyPrefix(key, op.from, op.to)]);
1357
1435
  for (const [, to] of pairs) this.conflictCheck(to);
1436
+ const renamed = keys.includes(op.from) ? /* @__PURE__ */ new Set() : this.renameNode(op.from, op.to);
1358
1437
  for (const [from, to] of pairs) {
1359
- this.moveKey(from, to);
1438
+ this.moveKey(from, to, renamed);
1360
1439
  if (op.usages !== false) this.rewriteUsages(from, to);
1361
1440
  }
1362
1441
  if (op.usages === false) return;
@@ -1452,6 +1531,11 @@ var PlanBuilder = class {
1452
1531
  path: newPath,
1453
1532
  value
1454
1533
  });
1534
+ else if (value !== void 0) renameOps.push(...[...walkLeaves(value, newPath)].map((leaf) => ({
1535
+ type: "set",
1536
+ path: leaf.path,
1537
+ value: leaf.value
1538
+ })));
1455
1539
  }
1456
1540
  return applyTextEdits(s.content, edit(s.content, [...renameOps, ...entry.ops], ctx));
1457
1541
  }
@@ -2185,7 +2269,7 @@ function createProject(options) {
2185
2269
  function buildIndex() {
2186
2270
  resourceIndex ??= buildResourceIndex();
2187
2271
  const usages = [];
2188
- for (const [path, state] of files) {
2272
+ for (const [path, state] of [...files].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
2189
2273
  let list = resolved.get(state);
2190
2274
  if (!list) {
2191
2275
  list = state.result.usages.map((candidate) => resolver.resolve(candidate, state.result.scopes ?? [], path, "scanner"));
@@ -2501,10 +2585,23 @@ function createProject(options) {
2501
2585
  nodes: (path) => idx().nodes.get(path) ?? [],
2502
2586
  locations(key) {
2503
2587
  const order = new Map(locales.map((locale, i) => [locale, i]));
2504
- return [...idx().nodes.values()].flat().filter((node) => node.key === key).sort((a, b) => (order.get(a.locale) ?? 0) - (order.get(b.locale) ?? 0));
2588
+ const all = [...idx().nodes.values()].flat();
2589
+ let found = all.filter((node) => node.key === key);
2590
+ if (found.length === 0) {
2591
+ const derived = new Set(idx().derived.get(key) ?? []);
2592
+ found = all.filter((node) => derived.has(node.key));
2593
+ }
2594
+ return found.sort((a, b) => (order.get(a.locale) ?? 0) - (order.get(b.locale) ?? 0));
2595
+ },
2596
+ lookup(key, locale) {
2597
+ const exact = message(key, locale);
2598
+ if (exact) return exact;
2599
+ const derived = [...idx().derived.get(key) ?? []].sort();
2600
+ const other = derived.find((k) => /[._-]other$/.test(k)) ?? derived[0];
2601
+ return other === void 0 ? void 0 : message(other, locale);
2505
2602
  },
2506
2603
  keySlots: (path) => files.get(path)?.result.keySlots ?? [],
2507
- hardStrings: (path) => [...files].filter(([p]) => path === void 0 || p === path).flatMap(([p, state]) => (state.result.hardStrings ?? []).map((h) => ({
2604
+ hardStrings: (path) => [...files].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).filter(([p]) => path === void 0 || p === path).flatMap(([p, state]) => (state.result.hardStrings ?? []).map((h) => ({
2508
2605
  ...h,
2509
2606
  path: p
2510
2607
  }))),
@@ -2562,7 +2659,8 @@ function defaultDraft() {
2562
2659
  keyStyle: "auto",
2563
2660
  namespace: {
2564
2661
  separator: ".",
2565
- default: void 0
2662
+ default: void 0,
2663
+ fromPath: "dot"
2566
2664
  },
2567
2665
  usage: {
2568
2666
  include: ["**/*"],
@@ -2625,7 +2723,8 @@ function applyLayer(draft, layer, origin, origins) {
2625
2723
  if (layer.namespace !== void 0) {
2626
2724
  draft.namespace = {
2627
2725
  separator: layer.namespace.separator ?? draft.namespace.separator,
2628
- default: layer.namespace.default ?? draft.namespace.default
2726
+ default: layer.namespace.default ?? draft.namespace.default,
2727
+ fromPath: layer.namespace.fromPath ?? draft.namespace.fromPath
2629
2728
  };
2630
2729
  mark("namespace");
2631
2730
  }
@@ -2821,4 +2920,4 @@ async function resolveConfig(options) {
2821
2920
  };
2822
2921
  }
2823
2922
  //#endregion
2824
- export { ConfigSchema, PluginFileSchema, X18nError, applyMessageOps, applyTextEdits, buildTree, contractVersion, createLineIndex, createMemoryHost, createOverlayHost, createProject, createRegistry, defineConfig, definePlugin, definePreset, diffText, envelope, errorCodes, extensionOf, globToRegExp, hashText, isJsonObject, isKeyUnder, isMessageLeaf, isMessageTree, isPreset, isX18nError, joinKey, keyMatcher, localeSpellingKey, parseLocaleInfo, parseMessageBatch, pathId, pathMatcher, placeholderProblems, rangeContains, renderPrompt, replaceKeyPrefix, resolveConfig, sortTree, splitKey, toWireDiagnostic, toWireRange, validate, walkLeaves };
2923
+ export { ConfigSchema, PluginFileSchema, X18nError, applyMessageOps, applyTextEdits, buildTree, contractVersion, createLineIndex, createMemoryHost, createOverlayHost, createPlaceholderComparer, createProject, createRegistry, defineConfig, definePlugin, definePreset, diffText, envelope, errorCodes, extensionOf, globToRegExp, hashText, isJsonObject, isKeyUnder, isMessageLeaf, isMessageTree, isPreset, isX18nError, joinKey, keyMatcher, localeSpellingKey, parseLocaleInfo, parseMessageBatch, pathId, pathMatcher, placeholderProblems, rangeContains, renderPrompt, replaceKeyPrefix, resolveConfig, sortTree, splitKey, toWireDiagnostic, toWireRange, validate, walkLeaves };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@x18n/core",
3
3
  "type": "module",
4
- "version": "0.0.0",
4
+ "version": "0.0.3",
5
5
  "description": "Runtime-neutral engine of x18n: domain model, plugin API and project analysis",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -128,6 +128,14 @@
128
128
  },
129
129
  "default": {
130
130
  "type": "string"
131
+ },
132
+ "fromPath": {
133
+ "enum": [
134
+ "dot",
135
+ "slash",
136
+ "camel"
137
+ ],
138
+ "type": "string"
131
139
  }
132
140
  },
133
141
  "required": [],
@@ -89,6 +89,14 @@
89
89
  },
90
90
  "default": {
91
91
  "type": "string"
92
+ },
93
+ "fromPath": {
94
+ "enum": [
95
+ "dot",
96
+ "slash",
97
+ "camel"
98
+ ],
99
+ "type": "string"
92
100
  }
93
101
  },
94
102
  "required": [],