@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.cjs CHANGED
@@ -152,6 +152,18 @@ function defineConfig(config) {
152
152
  }
153
153
 
154
154
  // src/errors.ts
155
+ function errorMessage(error) {
156
+ return error instanceof Error ? error.message : String(error);
157
+ }
158
+ function stringCode(error) {
159
+ if (error instanceof Error && "code" in error && typeof error.code === "string") {
160
+ return error.code;
161
+ }
162
+ return void 0;
163
+ }
164
+ function describeError(error, fallbackCode) {
165
+ return { code: stringCode(error) ?? fallbackCode, message: errorMessage(error) };
166
+ }
155
167
  var SdkError = class extends Error {
156
168
  /** The stable {@link SdkErrorCode} for this failure; branch on this, not the message. */
157
169
  code;
@@ -1949,7 +1961,7 @@ async function loadExplicitWithMeta(explorer, configPath, cwd, fs$1) {
1949
1961
  try {
1950
1962
  result = await explorer.load(resolved);
1951
1963
  } catch (error) {
1952
- const detail = error instanceof Error ? error.message : String(error);
1964
+ const detail = errorMessage(error);
1953
1965
  throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
1954
1966
  }
1955
1967
  const parsed = parseConfig(result?.config);
@@ -1974,7 +1986,7 @@ async function loadConfigWithMeta(options = {}) {
1974
1986
  try {
1975
1987
  result = await explorer.search(options.cwd);
1976
1988
  } catch (error) {
1977
- const detail = error instanceof Error ? error.message : String(error);
1989
+ const detail = errorMessage(error);
1978
1990
  throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
1979
1991
  }
1980
1992
  if (result === null || result.isEmpty === true) {
@@ -2059,15 +2071,15 @@ async function acquireLock(path, fs, pollIntervalMs, deadline, notify) {
2059
2071
  if (await fs.createExclusive(path, lockPayload())) {
2060
2072
  return;
2061
2073
  }
2074
+ if (notify !== void 0) {
2075
+ await notify();
2076
+ }
2062
2077
  if (Date.now() >= deadline) {
2063
2078
  throw new SdkError(
2064
2079
  "LOCK_CONTENDED",
2065
2080
  `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.`
2066
2081
  );
2067
2082
  }
2068
- if (notify !== void 0) {
2069
- await notify();
2070
- }
2071
2083
  const jitter = Math.random() * pollIntervalMs;
2072
2084
  await sleep(pollIntervalMs + jitter);
2073
2085
  }
@@ -2657,6 +2669,9 @@ async function fsyncDirBestEffort(path) {
2657
2669
  }
2658
2670
  }
2659
2671
  var nodeOps = {
2672
+ mkdir: async (path) => {
2673
+ await promises.mkdir(path, { recursive: true });
2674
+ },
2660
2675
  writeFile: (path, data) => promises.writeFile(path, data, "utf8"),
2661
2676
  fsyncFile: (path) => fsyncPath(path),
2662
2677
  rename: (from, to) => promises.rename(from, to),
@@ -2673,8 +2688,10 @@ function tempFileName2(path$1) {
2673
2688
  return path.join(path.dirname(path$1), `.${path.basename(path$1)}.tmp-${process.pid}-${Date.now()}-${crypto.randomUUID()}`);
2674
2689
  }
2675
2690
  async function atomicWriteFile(path$1, data, ops = nodeOps) {
2691
+ const directory = path.dirname(path$1);
2676
2692
  const tmp = tempFileName2(path$1);
2677
2693
  try {
2694
+ await ops.mkdir(directory);
2678
2695
  await ops.writeFile(tmp, data);
2679
2696
  await ops.fsyncFile(tmp);
2680
2697
  await ops.rename(tmp, path$1);
@@ -2683,7 +2700,7 @@ async function atomicWriteFile(path$1, data, ops = nodeOps) {
2683
2700
  throw error;
2684
2701
  }
2685
2702
  try {
2686
- await ops.fsyncDir(path.dirname(path$1));
2703
+ await ops.fsyncDir(directory);
2687
2704
  } catch {
2688
2705
  }
2689
2706
  }
@@ -4044,7 +4061,7 @@ async function readSource(config, cwd, fs, adapter) {
4044
4061
  try {
4045
4062
  return await adapter.read(sourcePath, config.sourceLocale);
4046
4063
  } catch (error) {
4047
- const detail = error instanceof Error ? error.message : String(error);
4064
+ const detail = errorMessage(error);
4048
4065
  throw new SdkError(
4049
4066
  "SOURCE_INVALID",
4050
4067
  `The source locale file at ${sourcePath} could not be read: ${detail}`
@@ -4344,7 +4361,7 @@ function selectProvider(config, createProvider = buildProvider) {
4344
4361
  try {
4345
4362
  return createProvider(config);
4346
4363
  } catch (error) {
4347
- const detail = error instanceof Error ? error.message : String(error);
4364
+ const detail = errorMessage(error);
4348
4365
  throw new SdkError(
4349
4366
  "PROVIDER_CONSTRUCTION_FAILED",
4350
4367
  `Failed to construct provider "${config.id}": ${detail}`
@@ -4567,13 +4584,6 @@ function budgetExceededNotice(tracker) {
4567
4584
  }
4568
4585
 
4569
4586
  // src/flow/locale-failure.ts
4570
- function describeError(error) {
4571
- if (error instanceof Error) {
4572
- const code = error.code;
4573
- return { code: typeof code === "string" ? code : "LOCALE_FAILED", message: error.message };
4574
- }
4575
- return { code: "LOCALE_FAILED", message: String(error) };
4576
- }
4577
4587
  function failureSummary(locale, error) {
4578
4588
  return {
4579
4589
  locale,
@@ -4593,7 +4603,7 @@ function failureSummary(locale, error) {
4593
4603
  unfilled: [],
4594
4604
  malformedRows: [],
4595
4605
  duplicateKeys: [],
4596
- error: describeError(error)
4606
+ error: describeError(error, "LOCALE_FAILED")
4597
4607
  };
4598
4608
  }
4599
4609
  function deriveLocaleStatus(parts) {
@@ -5027,6 +5037,12 @@ function buildRequest3(params, entries) {
5027
5037
  ...params.adapter.comparePlaceholders !== void 0 ? { comparePlaceholders: params.adapter.comparePlaceholders } : {}
5028
5038
  };
5029
5039
  }
5040
+ async function shouldWriteTarget(params, path, changed) {
5041
+ if (changed.accepted > 0 || changed.pruned > 0 || changed.generated > 0) {
5042
+ return true;
5043
+ }
5044
+ return !await params.fs.fileExists(path);
5045
+ }
5030
5046
  async function runLocale(params) {
5031
5047
  const target = await readTargetResource({
5032
5048
  cwd: params.cwd,
@@ -5112,15 +5128,22 @@ async function runLocale(params) {
5112
5128
  merged.set(form.targetKey, { ...form.entry, namespace: target.namespace });
5113
5129
  }
5114
5130
  const path = localeFilePath(params.cwd, params.filesPattern, params.targetLocale);
5115
- await params.adapter.write(
5116
- {
5117
- locale: params.targetLocale,
5118
- namespace: target.namespace,
5119
- format: params.format,
5120
- entries: merged
5121
- },
5122
- path
5123
- );
5131
+ const writeNeeded = await shouldWriteTarget(params, path, {
5132
+ accepted: accepted.size,
5133
+ pruned: pruned.length,
5134
+ generated: generation.accepted.length
5135
+ });
5136
+ if (writeNeeded) {
5137
+ await params.adapter.write(
5138
+ {
5139
+ locale: params.targetLocale,
5140
+ namespace: target.namespace,
5141
+ format: params.format,
5142
+ entries: merged
5143
+ },
5144
+ path
5145
+ );
5146
+ }
5124
5147
  const pluralNotices = params.generatePlurals ? pluralNoticeFor(params, merged) : sdkNotices;
5125
5148
  const notices = [
5126
5149
  ...pluralNotices,
@@ -6380,7 +6403,7 @@ async function importWorkbook(input, deps = {}) {
6380
6403
  try {
6381
6404
  data = await readWorkbook(bytes);
6382
6405
  } catch (error) {
6383
- throw new SdkError("SOURCE_INVALID", error.message);
6406
+ throw new SdkError("SOURCE_INVALID", errorMessage(error));
6384
6407
  }
6385
6408
  const lock = await readLockFile(lockFilePath(cwd), fs);
6386
6409
  const ctx = {
@@ -6466,13 +6489,6 @@ function defaultRunTranslate(deps) {
6466
6489
 
6467
6490
  // src/watch/watch.ts
6468
6491
  var DEFAULT_DEBOUNCE_MS = 300;
6469
- function describeError2(error) {
6470
- if (error instanceof Error) {
6471
- const code = error.code;
6472
- return { code: typeof code === "string" ? code : "WATCH_RUN_FAILED", message: error.message };
6473
- }
6474
- return { code: "WATCH_RUN_FAILED", message: String(error) };
6475
- }
6476
6492
  async function watch(input, deps = {}) {
6477
6493
  const cwd = input.cwd ?? process.cwd();
6478
6494
  const debounceMs = input.debounceMs ?? DEFAULT_DEBOUNCE_MS;
@@ -6504,7 +6520,7 @@ async function watch(input, deps = {}) {
6504
6520
  try {
6505
6521
  input.onRun({ status: "succeeded", summary: await runTranslate(runInput) });
6506
6522
  } catch (error) {
6507
- input.onRun({ status: "failed", error: describeError2(error) });
6523
+ input.onRun({ status: "failed", error: describeError(error, "WATCH_RUN_FAILED") });
6508
6524
  }
6509
6525
  }
6510
6526
  function startRun() {