@verbatra/sdk 0.6.3 → 0.6.4

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.cts CHANGED
@@ -527,6 +527,7 @@ type GlossaryProvenance = {
527
527
  readonly path: string;
528
528
  };
529
529
 
530
+ /** Where {@link loadConfig} should obtain the configuration. The three sources are alternatives. */
530
531
  interface LoadConfigOptions {
531
532
  /** Directory to start the search from. Defaults to the current working directory. */
532
533
  readonly cwd?: string;
package/dist/index.d.ts CHANGED
@@ -527,6 +527,7 @@ type GlossaryProvenance = {
527
527
  readonly path: string;
528
528
  };
529
529
 
530
+ /** Where {@link loadConfig} should obtain the configuration. The three sources are alternatives. */
530
531
  interface LoadConfigOptions {
531
532
  /** Directory to start the search from. Defaults to the current working directory. */
532
533
  readonly cwd?: string;
package/dist/index.js CHANGED
@@ -122,6 +122,18 @@ function defineConfig(config) {
122
122
  }
123
123
 
124
124
  // src/errors.ts
125
+ function errorMessage(error) {
126
+ return error instanceof Error ? error.message : String(error);
127
+ }
128
+ function stringCode(error) {
129
+ if (error instanceof Error && "code" in error && typeof error.code === "string") {
130
+ return error.code;
131
+ }
132
+ return void 0;
133
+ }
134
+ function describeError(error, fallbackCode) {
135
+ return { code: stringCode(error) ?? fallbackCode, message: errorMessage(error) };
136
+ }
125
137
  var SdkError = class extends Error {
126
138
  /** The stable {@link SdkErrorCode} for this failure; branch on this, not the message. */
127
139
  code;
@@ -1919,7 +1931,7 @@ async function loadExplicitWithMeta(explorer, configPath, cwd, fs) {
1919
1931
  try {
1920
1932
  result = await explorer.load(resolved);
1921
1933
  } catch (error) {
1922
- const detail = error instanceof Error ? error.message : String(error);
1934
+ const detail = errorMessage(error);
1923
1935
  throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
1924
1936
  }
1925
1937
  const parsed = parseConfig(result?.config);
@@ -1944,7 +1956,7 @@ async function loadConfigWithMeta(options = {}) {
1944
1956
  try {
1945
1957
  result = await explorer.search(options.cwd);
1946
1958
  } catch (error) {
1947
- const detail = error instanceof Error ? error.message : String(error);
1959
+ const detail = errorMessage(error);
1948
1960
  throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
1949
1961
  }
1950
1962
  if (result === null || result.isEmpty === true) {
@@ -2029,15 +2041,15 @@ async function acquireLock(path, fs, pollIntervalMs, deadline, notify) {
2029
2041
  if (await fs.createExclusive(path, lockPayload())) {
2030
2042
  return;
2031
2043
  }
2044
+ if (notify !== void 0) {
2045
+ await notify();
2046
+ }
2032
2047
  if (Date.now() >= deadline) {
2033
2048
  throw new SdkError(
2034
2049
  "LOCK_CONTENDED",
2035
2050
  `Could not acquire the write lock at ${path}: another process may be holding it. If no verbatra process is currently running, this lock file was likely left behind by one that was killed; delete it and retry.`
2036
2051
  );
2037
2052
  }
2038
- if (notify !== void 0) {
2039
- await notify();
2040
- }
2041
2053
  const jitter = Math.random() * pollIntervalMs;
2042
2054
  await sleep(pollIntervalMs + jitter);
2043
2055
  }
@@ -2627,6 +2639,9 @@ async function fsyncDirBestEffort(path) {
2627
2639
  }
2628
2640
  }
2629
2641
  var nodeOps = {
2642
+ mkdir: async (path) => {
2643
+ await mkdir(path, { recursive: true });
2644
+ },
2630
2645
  writeFile: (path, data) => writeFile(path, data, "utf8"),
2631
2646
  fsyncFile: (path) => fsyncPath(path),
2632
2647
  rename: (from, to) => rename(from, to),
@@ -2643,8 +2658,10 @@ function tempFileName2(path) {
2643
2658
  return join(dirname(path), `.${basename(path)}.tmp-${process.pid}-${Date.now()}-${randomUUID()}`);
2644
2659
  }
2645
2660
  async function atomicWriteFile(path, data, ops = nodeOps) {
2661
+ const directory = dirname(path);
2646
2662
  const tmp = tempFileName2(path);
2647
2663
  try {
2664
+ await ops.mkdir(directory);
2648
2665
  await ops.writeFile(tmp, data);
2649
2666
  await ops.fsyncFile(tmp);
2650
2667
  await ops.rename(tmp, path);
@@ -2653,7 +2670,7 @@ async function atomicWriteFile(path, data, ops = nodeOps) {
2653
2670
  throw error;
2654
2671
  }
2655
2672
  try {
2656
- await ops.fsyncDir(dirname(path));
2673
+ await ops.fsyncDir(directory);
2657
2674
  } catch {
2658
2675
  }
2659
2676
  }
@@ -4014,7 +4031,7 @@ async function readSource(config, cwd, fs, adapter) {
4014
4031
  try {
4015
4032
  return await adapter.read(sourcePath, config.sourceLocale);
4016
4033
  } catch (error) {
4017
- const detail = error instanceof Error ? error.message : String(error);
4034
+ const detail = errorMessage(error);
4018
4035
  throw new SdkError(
4019
4036
  "SOURCE_INVALID",
4020
4037
  `The source locale file at ${sourcePath} could not be read: ${detail}`
@@ -4314,7 +4331,7 @@ function selectProvider(config, createProvider = buildProvider) {
4314
4331
  try {
4315
4332
  return createProvider(config);
4316
4333
  } catch (error) {
4317
- const detail = error instanceof Error ? error.message : String(error);
4334
+ const detail = errorMessage(error);
4318
4335
  throw new SdkError(
4319
4336
  "PROVIDER_CONSTRUCTION_FAILED",
4320
4337
  `Failed to construct provider "${config.id}": ${detail}`
@@ -4537,13 +4554,6 @@ function budgetExceededNotice(tracker) {
4537
4554
  }
4538
4555
 
4539
4556
  // src/flow/locale-failure.ts
4540
- function describeError(error) {
4541
- if (error instanceof Error) {
4542
- const code = error.code;
4543
- return { code: typeof code === "string" ? code : "LOCALE_FAILED", message: error.message };
4544
- }
4545
- return { code: "LOCALE_FAILED", message: String(error) };
4546
- }
4547
4557
  function failureSummary(locale, error) {
4548
4558
  return {
4549
4559
  locale,
@@ -4563,7 +4573,7 @@ function failureSummary(locale, error) {
4563
4573
  unfilled: [],
4564
4574
  malformedRows: [],
4565
4575
  duplicateKeys: [],
4566
- error: describeError(error)
4576
+ error: describeError(error, "LOCALE_FAILED")
4567
4577
  };
4568
4578
  }
4569
4579
  function deriveLocaleStatus(parts) {
@@ -4997,6 +5007,12 @@ function buildRequest3(params, entries) {
4997
5007
  ...params.adapter.comparePlaceholders !== void 0 ? { comparePlaceholders: params.adapter.comparePlaceholders } : {}
4998
5008
  };
4999
5009
  }
5010
+ async function shouldWriteTarget(params, path, changed) {
5011
+ if (changed.accepted > 0 || changed.pruned > 0 || changed.generated > 0) {
5012
+ return true;
5013
+ }
5014
+ return !await params.fs.fileExists(path);
5015
+ }
5000
5016
  async function runLocale(params) {
5001
5017
  const target = await readTargetResource({
5002
5018
  cwd: params.cwd,
@@ -5082,15 +5098,22 @@ async function runLocale(params) {
5082
5098
  merged.set(form.targetKey, { ...form.entry, namespace: target.namespace });
5083
5099
  }
5084
5100
  const path = localeFilePath(params.cwd, params.filesPattern, params.targetLocale);
5085
- await params.adapter.write(
5086
- {
5087
- locale: params.targetLocale,
5088
- namespace: target.namespace,
5089
- format: params.format,
5090
- entries: merged
5091
- },
5092
- path
5093
- );
5101
+ const writeNeeded = await shouldWriteTarget(params, path, {
5102
+ accepted: accepted.size,
5103
+ pruned: pruned.length,
5104
+ generated: generation.accepted.length
5105
+ });
5106
+ if (writeNeeded) {
5107
+ await params.adapter.write(
5108
+ {
5109
+ locale: params.targetLocale,
5110
+ namespace: target.namespace,
5111
+ format: params.format,
5112
+ entries: merged
5113
+ },
5114
+ path
5115
+ );
5116
+ }
5094
5117
  const pluralNotices = params.generatePlurals ? pluralNoticeFor(params, merged) : sdkNotices;
5095
5118
  const notices = [
5096
5119
  ...pluralNotices,
@@ -6350,7 +6373,7 @@ async function importWorkbook(input, deps = {}) {
6350
6373
  try {
6351
6374
  data = await readWorkbook(bytes);
6352
6375
  } catch (error) {
6353
- throw new SdkError("SOURCE_INVALID", error.message);
6376
+ throw new SdkError("SOURCE_INVALID", errorMessage(error));
6354
6377
  }
6355
6378
  const lock = await readLockFile(lockFilePath(cwd), fs);
6356
6379
  const ctx = {
@@ -6436,13 +6459,6 @@ function defaultRunTranslate(deps) {
6436
6459
 
6437
6460
  // src/watch/watch.ts
6438
6461
  var DEFAULT_DEBOUNCE_MS = 300;
6439
- function describeError2(error) {
6440
- if (error instanceof Error) {
6441
- const code = error.code;
6442
- return { code: typeof code === "string" ? code : "WATCH_RUN_FAILED", message: error.message };
6443
- }
6444
- return { code: "WATCH_RUN_FAILED", message: String(error) };
6445
- }
6446
6462
  async function watch(input, deps = {}) {
6447
6463
  const cwd = input.cwd ?? process.cwd();
6448
6464
  const debounceMs = input.debounceMs ?? DEFAULT_DEBOUNCE_MS;
@@ -6474,7 +6490,7 @@ async function watch(input, deps = {}) {
6474
6490
  try {
6475
6491
  input.onRun({ status: "succeeded", summary: await runTranslate(runInput) });
6476
6492
  } catch (error) {
6477
- input.onRun({ status: "failed", error: describeError2(error) });
6493
+ input.onRun({ status: "failed", error: describeError(error, "WATCH_RUN_FAILED") });
6478
6494
  }
6479
6495
  }
6480
6496
  function startRun() {