@verbatra/sdk 0.4.4 → 0.5.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +229 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +216 -57
- package/dist/index.d.ts +216 -57
- package/dist/index.js +227 -102
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,8 @@ var fs = require('fs');
|
|
|
4
4
|
var path = require('path');
|
|
5
5
|
var cosmiconfig = require('cosmiconfig');
|
|
6
6
|
var cosmiconfigTypescriptLoader = require('cosmiconfig-typescript-loader');
|
|
7
|
+
var crypto = require('crypto');
|
|
8
|
+
var promises = require('fs/promises');
|
|
7
9
|
var zod = require('zod');
|
|
8
10
|
var Anthropic = require('@anthropic-ai/sdk');
|
|
9
11
|
var deepl = require('deepl-node');
|
|
@@ -11,8 +13,6 @@ var module$1 = require('module');
|
|
|
11
13
|
var log = require('loglevel');
|
|
12
14
|
var genai = require('@google/genai');
|
|
13
15
|
var OpenAI = require('openai');
|
|
14
|
-
var crypto = require('crypto');
|
|
15
|
-
var promises = require('fs/promises');
|
|
16
16
|
var icuMessageformatParser = require('@formatjs/icu-messageformat-parser');
|
|
17
17
|
var xmldom = require('@xmldom/xmldom');
|
|
18
18
|
var yaml = require('yaml');
|
|
@@ -68,6 +68,155 @@ var SdkError = class extends Error {
|
|
|
68
68
|
this.code = code;
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
|
+
async function readBoundedUtf8(handle, size) {
|
|
72
|
+
const buffer = Buffer.allocUnsafe(size);
|
|
73
|
+
let offset = 0;
|
|
74
|
+
while (offset < size) {
|
|
75
|
+
const { bytesRead } = await handle.read(buffer, offset, size - offset, offset);
|
|
76
|
+
if (bytesRead === 0) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
offset += bytesRead;
|
|
80
|
+
}
|
|
81
|
+
return buffer.toString("utf8", 0, offset);
|
|
82
|
+
}
|
|
83
|
+
async function readBounded(path, maxBytes) {
|
|
84
|
+
let handle;
|
|
85
|
+
try {
|
|
86
|
+
handle = await promises.open(path, "r");
|
|
87
|
+
} catch {
|
|
88
|
+
return { kind: "missing" };
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const info = await handle.stat();
|
|
92
|
+
if (!info.isFile()) {
|
|
93
|
+
return { kind: "missing" };
|
|
94
|
+
}
|
|
95
|
+
if (info.size > maxBytes) {
|
|
96
|
+
return { kind: "too-large" };
|
|
97
|
+
}
|
|
98
|
+
return { kind: "ok", content: await readBoundedUtf8(handle, info.size) };
|
|
99
|
+
} finally {
|
|
100
|
+
await handle.close();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function readBoundedBytesInto(handle, size) {
|
|
104
|
+
const buffer = Buffer.allocUnsafeSlow(size);
|
|
105
|
+
let offset = 0;
|
|
106
|
+
while (offset < size) {
|
|
107
|
+
const { bytesRead } = await handle.read(buffer, offset, size - offset, offset);
|
|
108
|
+
if (bytesRead === 0) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
offset += bytesRead;
|
|
112
|
+
}
|
|
113
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, offset);
|
|
114
|
+
}
|
|
115
|
+
async function readBoundedBytes(path, maxBytes) {
|
|
116
|
+
let handle;
|
|
117
|
+
try {
|
|
118
|
+
handle = await promises.open(path, "r");
|
|
119
|
+
} catch {
|
|
120
|
+
return { kind: "missing" };
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const info = await handle.stat();
|
|
124
|
+
if (!info.isFile()) {
|
|
125
|
+
return { kind: "missing" };
|
|
126
|
+
}
|
|
127
|
+
if (info.size > maxBytes) {
|
|
128
|
+
return { kind: "too-large" };
|
|
129
|
+
}
|
|
130
|
+
return { kind: "ok", bytes: await readBoundedBytesInto(handle, info.size) };
|
|
131
|
+
} finally {
|
|
132
|
+
await handle.close();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function tempFileName(path$1) {
|
|
136
|
+
return path.join(path.dirname(path$1), `.${path.basename(path$1)}.tmp-${process.pid}-${Date.now()}-${crypto.randomUUID()}`);
|
|
137
|
+
}
|
|
138
|
+
async function atomicWrite(path, data) {
|
|
139
|
+
const tmp = tempFileName(path);
|
|
140
|
+
await (typeof data === "string" ? promises.writeFile(tmp, data, "utf8") : promises.writeFile(tmp, data));
|
|
141
|
+
try {
|
|
142
|
+
await promises.rename(tmp, path);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
await promises.rm(tmp, { force: true });
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var defaultFs = {
|
|
149
|
+
async fileExists(path) {
|
|
150
|
+
try {
|
|
151
|
+
await promises.access(path);
|
|
152
|
+
return true;
|
|
153
|
+
} catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
readFileBounded: (path, maxBytes) => readBounded(path, maxBytes),
|
|
158
|
+
readBytesBounded: (path, maxBytes) => readBoundedBytes(path, maxBytes),
|
|
159
|
+
writeFile: (path, data) => atomicWrite(path, data),
|
|
160
|
+
writeBytes: (path, data) => atomicWrite(path, data)
|
|
161
|
+
};
|
|
162
|
+
var MAX_GLOSSARY_FILE_BYTES = 1024 * 1024;
|
|
163
|
+
var glossaryRecordSchema = zod.z.record(zod.z.string(), zod.z.string());
|
|
164
|
+
var BOM = "\uFEFF";
|
|
165
|
+
var REPLACEMENT_CHARACTER = "\uFFFD";
|
|
166
|
+
var NUL = "\0";
|
|
167
|
+
function stripBom(content) {
|
|
168
|
+
return content.startsWith(BOM) ? content.slice(BOM.length) : content;
|
|
169
|
+
}
|
|
170
|
+
function looksLikeInvalidEncoding(content) {
|
|
171
|
+
return content.startsWith(REPLACEMENT_CHARACTER) || content.includes(NUL);
|
|
172
|
+
}
|
|
173
|
+
async function readGlossaryFile(resolvedPath, fs) {
|
|
174
|
+
const read = await fs.readFileBounded(resolvedPath, MAX_GLOSSARY_FILE_BYTES);
|
|
175
|
+
if (read.kind === "missing") {
|
|
176
|
+
throw new SdkError(
|
|
177
|
+
"CONFIG_INVALID",
|
|
178
|
+
`The glossary file at ${resolvedPath} was not found or could not be read.`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (read.kind === "too-large") {
|
|
182
|
+
throw new SdkError(
|
|
183
|
+
"CONFIG_INVALID",
|
|
184
|
+
`The glossary file at ${resolvedPath} exceeds the maximum allowed size of ${MAX_GLOSSARY_FILE_BYTES} bytes.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
const content = stripBom(read.content);
|
|
188
|
+
if (looksLikeInvalidEncoding(content)) {
|
|
189
|
+
throw new SdkError(
|
|
190
|
+
"CONFIG_INVALID",
|
|
191
|
+
`The glossary file at ${resolvedPath} must be UTF-8 encoded.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
let parsed;
|
|
195
|
+
try {
|
|
196
|
+
parsed = JSON.parse(content);
|
|
197
|
+
} catch {
|
|
198
|
+
throw new SdkError("CONFIG_INVALID", `The glossary file at ${resolvedPath} is not valid JSON.`);
|
|
199
|
+
}
|
|
200
|
+
const result = glossaryRecordSchema.safeParse(parsed);
|
|
201
|
+
if (!result.success) {
|
|
202
|
+
throw new SdkError(
|
|
203
|
+
"CONFIG_INVALID",
|
|
204
|
+
`The glossary file at ${resolvedPath} must contain a flat object of string keys to string values.`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return result.data;
|
|
208
|
+
}
|
|
209
|
+
async function resolveGlossary(glossary, baseDir, fs) {
|
|
210
|
+
if (glossary === void 0) {
|
|
211
|
+
return { glossary: void 0, provenance: { source: "none" } };
|
|
212
|
+
}
|
|
213
|
+
if (typeof glossary === "string") {
|
|
214
|
+
const resolvedPath = path.resolve(baseDir, glossary);
|
|
215
|
+
const record = await readGlossaryFile(resolvedPath, fs);
|
|
216
|
+
return { glossary: record, provenance: { source: "file", path: resolvedPath } };
|
|
217
|
+
}
|
|
218
|
+
return { glossary, provenance: { source: "inline" } };
|
|
219
|
+
}
|
|
71
220
|
var FNV_OFFSET_BASIS = 14695981039346656037n;
|
|
72
221
|
var FNV_PRIME = 1099511628211n;
|
|
73
222
|
var U64_MASK = (1n << 64n) - 1n;
|
|
@@ -903,7 +1052,13 @@ var verbatraConfigSchema = zod.z.strictObject({
|
|
|
903
1052
|
pattern: zod.z.string().min(1)
|
|
904
1053
|
}),
|
|
905
1054
|
provider: providerConfigSchema,
|
|
906
|
-
|
|
1055
|
+
/**
|
|
1056
|
+
* A glossary of source terms to preferred target terms, either inline or as a path to a JSON file
|
|
1057
|
+
* carrying the same shape. The two forms are mutually exclusive by type; there is no merge or
|
|
1058
|
+
* precedence between them. A path is resolved and validated by the loader, not by this schema; see
|
|
1059
|
+
* `resolve-glossary.ts`.
|
|
1060
|
+
*/
|
|
1061
|
+
glossary: zod.z.union([zod.z.record(zod.z.string(), zod.z.string()), zod.z.string().min(1)]).optional(),
|
|
907
1062
|
tone: zod.z.enum(["formal", "informal", "neutral"]).optional(),
|
|
908
1063
|
/**
|
|
909
1064
|
* Opt-in orphan pruning, off by default. When true, keys present in a target file but absent from
|
|
@@ -957,7 +1112,7 @@ function formatIssues(error) {
|
|
|
957
1112
|
return issue.code === "unrecognized_keys" ? `${base} (API keys are read from the environment, not the config)` : base;
|
|
958
1113
|
}).join("; ");
|
|
959
1114
|
}
|
|
960
|
-
function
|
|
1115
|
+
function parseConfig(input) {
|
|
961
1116
|
const parsed = verbatraConfigSchema.safeParse(input);
|
|
962
1117
|
if (!parsed.success) {
|
|
963
1118
|
throw new SdkError(
|
|
@@ -967,7 +1122,16 @@ function validate(input) {
|
|
|
967
1122
|
}
|
|
968
1123
|
return parsed.data;
|
|
969
1124
|
}
|
|
970
|
-
async function
|
|
1125
|
+
async function finalizeConfig(parsed, baseDir, fs) {
|
|
1126
|
+
const { glossary: glossaryInput, ...rest } = parsed;
|
|
1127
|
+
const resolved = await resolveGlossary(glossaryInput, baseDir, fs);
|
|
1128
|
+
const config = {
|
|
1129
|
+
...rest,
|
|
1130
|
+
...resolved.glossary !== void 0 ? { glossary: resolved.glossary } : {}
|
|
1131
|
+
};
|
|
1132
|
+
return { config, glossary: resolved.provenance };
|
|
1133
|
+
}
|
|
1134
|
+
async function loadExplicitWithMeta(explorer, configPath, cwd, fs$1) {
|
|
971
1135
|
const resolved = path.resolve(cwd ?? process.cwd(), configPath);
|
|
972
1136
|
if (!fs.existsSync(resolved)) {
|
|
973
1137
|
throw new SdkError("CONFIG_NOT_FOUND", `No verbatra configuration file at ${resolved}.`);
|
|
@@ -979,18 +1143,23 @@ async function loadExplicit(explorer, configPath, cwd) {
|
|
|
979
1143
|
const detail = error instanceof Error ? error.message : String(error);
|
|
980
1144
|
throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
|
|
981
1145
|
}
|
|
982
|
-
|
|
1146
|
+
const parsed = parseConfig(result?.config);
|
|
1147
|
+
const { config, glossary } = await finalizeConfig(parsed, path.dirname(resolved), fs$1);
|
|
1148
|
+
return { config, source: { kind: "explicit", filepath: resolved }, glossary };
|
|
983
1149
|
}
|
|
984
|
-
async function
|
|
1150
|
+
async function loadConfigWithMeta(options = {}) {
|
|
1151
|
+
const fs = options.fs ?? defaultFs;
|
|
985
1152
|
if (options.configOverride !== void 0) {
|
|
986
|
-
|
|
1153
|
+
const parsed2 = parseConfig(options.configOverride);
|
|
1154
|
+
const { config: config2, glossary: glossary2 } = await finalizeConfig(parsed2, options.cwd ?? process.cwd(), fs);
|
|
1155
|
+
return { config: config2, source: { kind: "override" }, glossary: glossary2 };
|
|
987
1156
|
}
|
|
988
1157
|
const explorer = cosmiconfig.cosmiconfig(MODULE_NAME, {
|
|
989
1158
|
searchPlaces: SEARCH_PLACES,
|
|
990
1159
|
loaders: { ".ts": cosmiconfigTypescriptLoader.TypeScriptLoader() }
|
|
991
1160
|
});
|
|
992
1161
|
if (options.configPath !== void 0) {
|
|
993
|
-
return
|
|
1162
|
+
return loadExplicitWithMeta(explorer, options.configPath, options.cwd, fs);
|
|
994
1163
|
}
|
|
995
1164
|
let result;
|
|
996
1165
|
try {
|
|
@@ -1005,99 +1174,14 @@ async function loadConfig(options = {}) {
|
|
|
1005
1174
|
"No verbatra configuration found. Create a verbatra.config.ts, a .verbatrarc.json, or a 'verbatra' property in package.json."
|
|
1006
1175
|
);
|
|
1007
1176
|
}
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
const buffer = Buffer.allocUnsafe(size);
|
|
1012
|
-
let offset = 0;
|
|
1013
|
-
while (offset < size) {
|
|
1014
|
-
const { bytesRead } = await handle.read(buffer, offset, size - offset, offset);
|
|
1015
|
-
if (bytesRead === 0) {
|
|
1016
|
-
break;
|
|
1017
|
-
}
|
|
1018
|
-
offset += bytesRead;
|
|
1019
|
-
}
|
|
1020
|
-
return buffer.toString("utf8", 0, offset);
|
|
1021
|
-
}
|
|
1022
|
-
async function readBounded(path, maxBytes) {
|
|
1023
|
-
let handle;
|
|
1024
|
-
try {
|
|
1025
|
-
handle = await promises.open(path, "r");
|
|
1026
|
-
} catch {
|
|
1027
|
-
return { kind: "missing" };
|
|
1028
|
-
}
|
|
1029
|
-
try {
|
|
1030
|
-
const info = await handle.stat();
|
|
1031
|
-
if (!info.isFile()) {
|
|
1032
|
-
return { kind: "missing" };
|
|
1033
|
-
}
|
|
1034
|
-
if (info.size > maxBytes) {
|
|
1035
|
-
return { kind: "too-large" };
|
|
1036
|
-
}
|
|
1037
|
-
return { kind: "ok", content: await readBoundedUtf8(handle, info.size) };
|
|
1038
|
-
} finally {
|
|
1039
|
-
await handle.close();
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
async function readBoundedBytesInto(handle, size) {
|
|
1043
|
-
const buffer = Buffer.allocUnsafeSlow(size);
|
|
1044
|
-
let offset = 0;
|
|
1045
|
-
while (offset < size) {
|
|
1046
|
-
const { bytesRead } = await handle.read(buffer, offset, size - offset, offset);
|
|
1047
|
-
if (bytesRead === 0) {
|
|
1048
|
-
break;
|
|
1049
|
-
}
|
|
1050
|
-
offset += bytesRead;
|
|
1051
|
-
}
|
|
1052
|
-
return new Uint8Array(buffer.buffer, buffer.byteOffset, offset);
|
|
1053
|
-
}
|
|
1054
|
-
async function readBoundedBytes(path, maxBytes) {
|
|
1055
|
-
let handle;
|
|
1056
|
-
try {
|
|
1057
|
-
handle = await promises.open(path, "r");
|
|
1058
|
-
} catch {
|
|
1059
|
-
return { kind: "missing" };
|
|
1060
|
-
}
|
|
1061
|
-
try {
|
|
1062
|
-
const info = await handle.stat();
|
|
1063
|
-
if (!info.isFile()) {
|
|
1064
|
-
return { kind: "missing" };
|
|
1065
|
-
}
|
|
1066
|
-
if (info.size > maxBytes) {
|
|
1067
|
-
return { kind: "too-large" };
|
|
1068
|
-
}
|
|
1069
|
-
return { kind: "ok", bytes: await readBoundedBytesInto(handle, info.size) };
|
|
1070
|
-
} finally {
|
|
1071
|
-
await handle.close();
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
function tempFileName(path$1) {
|
|
1075
|
-
return path.join(path.dirname(path$1), `.${path.basename(path$1)}.tmp-${process.pid}-${Date.now()}-${crypto.randomUUID()}`);
|
|
1177
|
+
const parsed = parseConfig(result.config);
|
|
1178
|
+
const { config, glossary } = await finalizeConfig(parsed, path.dirname(result.filepath), fs);
|
|
1179
|
+
return { config, source: { kind: "search", filepath: result.filepath }, glossary };
|
|
1076
1180
|
}
|
|
1077
|
-
async function
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
try {
|
|
1081
|
-
await promises.rename(tmp, path);
|
|
1082
|
-
} catch (error) {
|
|
1083
|
-
await promises.rm(tmp, { force: true });
|
|
1084
|
-
throw error;
|
|
1085
|
-
}
|
|
1181
|
+
async function loadConfig(options = {}) {
|
|
1182
|
+
const { config } = await loadConfigWithMeta(options);
|
|
1183
|
+
return config;
|
|
1086
1184
|
}
|
|
1087
|
-
var defaultFs = {
|
|
1088
|
-
async fileExists(path) {
|
|
1089
|
-
try {
|
|
1090
|
-
await promises.access(path);
|
|
1091
|
-
return true;
|
|
1092
|
-
} catch {
|
|
1093
|
-
return false;
|
|
1094
|
-
}
|
|
1095
|
-
},
|
|
1096
|
-
readFileBounded: (path, maxBytes) => readBounded(path, maxBytes),
|
|
1097
|
-
readBytesBounded: (path, maxBytes) => readBoundedBytes(path, maxBytes),
|
|
1098
|
-
writeFile: (path, data) => atomicWrite(path, data),
|
|
1099
|
-
writeBytes: (path, data) => atomicWrite(path, data)
|
|
1100
|
-
};
|
|
1101
1185
|
var LOCK_FILE_NAME = "verbatra.lock.json";
|
|
1102
1186
|
var CURRENT_VERSION = 1;
|
|
1103
1187
|
var EMPTY_LOCK = { version: CURRENT_VERSION, locales: {} };
|
|
@@ -2254,6 +2338,40 @@ async function diff(input, deps = {}) {
|
|
|
2254
2338
|
return { hasPendingChanges: locales.some((entry) => entry.hasPendingChanges), locales };
|
|
2255
2339
|
}
|
|
2256
2340
|
|
|
2341
|
+
// src/flow/lock-state.ts
|
|
2342
|
+
function toLockLocaleState(locale, keyCount, diff2) {
|
|
2343
|
+
return {
|
|
2344
|
+
locale,
|
|
2345
|
+
keyCount,
|
|
2346
|
+
missing: diff2.missing.length,
|
|
2347
|
+
stale: diff2.changed.length,
|
|
2348
|
+
upToDate: diff2.unchanged.length
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
async function lockState(input, deps = {}) {
|
|
2352
|
+
const config = input.config;
|
|
2353
|
+
const cwd = input.cwd ?? process.cwd();
|
|
2354
|
+
const fs = deps.fs ?? defaultFs;
|
|
2355
|
+
const locales = selectLocales(config, input.locales);
|
|
2356
|
+
const path = lockFilePath(cwd);
|
|
2357
|
+
const exists = await fs.fileExists(path);
|
|
2358
|
+
if (!exists) {
|
|
2359
|
+
return { exists: false };
|
|
2360
|
+
}
|
|
2361
|
+
const lock = await readLockFile(path, fs);
|
|
2362
|
+
const adapter = selectAdapter(config.format, deps.adapterRegistry);
|
|
2363
|
+
const source = await readSource(config, cwd, fs, adapter);
|
|
2364
|
+
const localeStates = await Promise.all(
|
|
2365
|
+
locales.map(async (locale) => {
|
|
2366
|
+
const target = await readTarget(cwd, config, adapter, fs, locale);
|
|
2367
|
+
const baseline = baselineFor(lock, locale);
|
|
2368
|
+
const diff2 = diffResources(source.resource, target, { baseline });
|
|
2369
|
+
return toLockLocaleState(locale, baseline.size, diff2);
|
|
2370
|
+
})
|
|
2371
|
+
);
|
|
2372
|
+
return { exists: true, version: lock.version, locales: localeStates };
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2257
2375
|
// src/selection/select-provider.ts
|
|
2258
2376
|
function selectProvider(config, createProvider = buildProvider) {
|
|
2259
2377
|
try {
|
|
@@ -3459,6 +3577,13 @@ async function importWorkbook(input, deps = {}) {
|
|
|
3459
3577
|
return { dryRun, locales: summaries, succeeded, failed };
|
|
3460
3578
|
}
|
|
3461
3579
|
|
|
3580
|
+
// src/lock/load-lock-file.ts
|
|
3581
|
+
async function loadLockFile(input = {}, deps = {}) {
|
|
3582
|
+
const cwd = input.cwd ?? process.cwd();
|
|
3583
|
+
const fs = deps.fs ?? defaultFs;
|
|
3584
|
+
return readLockFile(lockFilePath(cwd), fs);
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3462
3587
|
// src/scaffolding.ts
|
|
3463
3588
|
var scaffoldingMetadata = {
|
|
3464
3589
|
/** Provider id -> the environment variable its API key is read from. Owned by ai-providers. */
|
|
@@ -3575,6 +3700,7 @@ async function watch(input, deps = {}) {
|
|
|
3575
3700
|
}
|
|
3576
3701
|
|
|
3577
3702
|
exports.DEFAULT_WORKBOOK_PATH = DEFAULT_WORKBOOK_PATH;
|
|
3703
|
+
exports.LOCK_FILE_NAME = LOCK_FILE_NAME;
|
|
3578
3704
|
exports.SdkError = SdkError;
|
|
3579
3705
|
exports.check = check;
|
|
3580
3706
|
exports.defineConfig = defineConfig;
|
|
@@ -3582,6 +3708,9 @@ exports.diff = diff;
|
|
|
3582
3708
|
exports.exportWorkbook = exportWorkbook;
|
|
3583
3709
|
exports.importWorkbook = importWorkbook;
|
|
3584
3710
|
exports.loadConfig = loadConfig;
|
|
3711
|
+
exports.loadConfigWithMeta = loadConfigWithMeta;
|
|
3712
|
+
exports.loadLockFile = loadLockFile;
|
|
3713
|
+
exports.lockState = lockState;
|
|
3585
3714
|
exports.scaffoldingMetadata = scaffoldingMetadata;
|
|
3586
3715
|
exports.translate = translate2;
|
|
3587
3716
|
exports.verbatraConfigSchema = verbatraConfigSchema;
|