@forge-ts/core 0.8.0 → 0.14.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.d.ts +511 -1
- package/dist/index.js +649 -28
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,168 @@
|
|
|
1
|
+
// src/audit.ts
|
|
2
|
+
import { appendFileSync, existsSync, readFileSync } from "fs";
|
|
3
|
+
import { userInfo } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
var AUDIT_FILENAME = ".forge-audit.jsonl";
|
|
6
|
+
function getCurrentUser() {
|
|
7
|
+
try {
|
|
8
|
+
return userInfo().username;
|
|
9
|
+
} catch {
|
|
10
|
+
return "unknown";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function appendAuditEvent(rootDir, event) {
|
|
14
|
+
const filePath = join(rootDir, AUDIT_FILENAME);
|
|
15
|
+
appendFileSync(filePath, `${JSON.stringify(event)}
|
|
16
|
+
`, "utf-8");
|
|
17
|
+
}
|
|
18
|
+
function readAuditLog(rootDir, options) {
|
|
19
|
+
const filePath = join(rootDir, AUDIT_FILENAME);
|
|
20
|
+
if (!existsSync(filePath)) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
24
|
+
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
25
|
+
let events = lines.map((line) => JSON.parse(line));
|
|
26
|
+
if (options?.eventType) {
|
|
27
|
+
events = events.filter((e) => e.event === options.eventType);
|
|
28
|
+
}
|
|
29
|
+
events.reverse();
|
|
30
|
+
if (options?.limit !== void 0 && options.limit >= 0) {
|
|
31
|
+
events = events.slice(0, options.limit);
|
|
32
|
+
}
|
|
33
|
+
return events;
|
|
34
|
+
}
|
|
35
|
+
function formatAuditEvent(event) {
|
|
36
|
+
const reasonPart = event.reason ? ` \u2014 ${event.reason}` : "";
|
|
37
|
+
const detailKeys = Object.keys(event.details);
|
|
38
|
+
const detailPart = detailKeys.length > 0 ? ` ${JSON.stringify(event.details)}` : "";
|
|
39
|
+
return `[${event.timestamp}] ${event.event} by ${event.user}${reasonPart}${detailPart}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/bypass.ts
|
|
43
|
+
import { randomUUID } from "crypto";
|
|
44
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
45
|
+
import { userInfo as userInfo2 } from "os";
|
|
46
|
+
import { join as join2 } from "path";
|
|
47
|
+
var BYPASS_FILENAME = ".forge-bypass.json";
|
|
48
|
+
var DEFAULT_BYPASS_CONFIG = {
|
|
49
|
+
dailyBudget: 3,
|
|
50
|
+
durationHours: 24
|
|
51
|
+
};
|
|
52
|
+
function getCurrentUser2() {
|
|
53
|
+
try {
|
|
54
|
+
return userInfo2().username;
|
|
55
|
+
} catch {
|
|
56
|
+
return "unknown";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function readBypassFile(rootDir) {
|
|
60
|
+
const filePath = join2(rootDir, BYPASS_FILENAME);
|
|
61
|
+
if (!existsSync2(filePath)) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
66
|
+
return JSON.parse(raw);
|
|
67
|
+
} catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function writeBypassFile(rootDir, records) {
|
|
72
|
+
const filePath = join2(rootDir, BYPASS_FILENAME);
|
|
73
|
+
writeFileSync(filePath, `${JSON.stringify(records, null, 2)}
|
|
74
|
+
`, "utf-8");
|
|
75
|
+
}
|
|
76
|
+
function resolveConfig(config) {
|
|
77
|
+
return {
|
|
78
|
+
...DEFAULT_BYPASS_CONFIG,
|
|
79
|
+
...config
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function startOfToday() {
|
|
83
|
+
const now = /* @__PURE__ */ new Date();
|
|
84
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
85
|
+
}
|
|
86
|
+
function createBypass(rootDir, reason, rule, config) {
|
|
87
|
+
const resolved = resolveConfig(config);
|
|
88
|
+
const remaining = getRemainingBudget(rootDir, config);
|
|
89
|
+
if (remaining <= 0) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Bypass budget exhausted: ${resolved.dailyBudget}/${resolved.dailyBudget} bypasses used today. Wait until tomorrow or increase bypass.dailyBudget in your forge-ts config.`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const now = /* @__PURE__ */ new Date();
|
|
95
|
+
const expiresAt = new Date(now.getTime() + resolved.durationHours * 60 * 60 * 1e3);
|
|
96
|
+
const record = {
|
|
97
|
+
id: randomUUID(),
|
|
98
|
+
createdAt: now.toISOString(),
|
|
99
|
+
expiresAt: expiresAt.toISOString(),
|
|
100
|
+
reason,
|
|
101
|
+
rule: rule ?? "all",
|
|
102
|
+
user: getCurrentUser2()
|
|
103
|
+
};
|
|
104
|
+
const records = readBypassFile(rootDir);
|
|
105
|
+
records.push(record);
|
|
106
|
+
writeBypassFile(rootDir, records);
|
|
107
|
+
appendAuditEvent(rootDir, {
|
|
108
|
+
timestamp: record.createdAt,
|
|
109
|
+
event: "bypass.create",
|
|
110
|
+
user: record.user,
|
|
111
|
+
reason,
|
|
112
|
+
details: {
|
|
113
|
+
bypassId: record.id,
|
|
114
|
+
rule: record.rule,
|
|
115
|
+
expiresAt: record.expiresAt,
|
|
116
|
+
durationHours: resolved.durationHours
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return record;
|
|
120
|
+
}
|
|
121
|
+
function getActiveBypasses(rootDir) {
|
|
122
|
+
const records = readBypassFile(rootDir);
|
|
123
|
+
const now = /* @__PURE__ */ new Date();
|
|
124
|
+
return records.filter((r) => new Date(r.expiresAt) > now);
|
|
125
|
+
}
|
|
126
|
+
function isRuleBypassed(rootDir, ruleCode) {
|
|
127
|
+
const active = getActiveBypasses(rootDir);
|
|
128
|
+
return active.some((r) => r.rule === ruleCode || r.rule === "all");
|
|
129
|
+
}
|
|
130
|
+
function getRemainingBudget(rootDir, config) {
|
|
131
|
+
const resolved = resolveConfig(config);
|
|
132
|
+
const records = readBypassFile(rootDir);
|
|
133
|
+
const todayStart = startOfToday();
|
|
134
|
+
const todayCount = records.filter((r) => new Date(r.createdAt) >= todayStart).length;
|
|
135
|
+
return Math.max(0, resolved.dailyBudget - todayCount);
|
|
136
|
+
}
|
|
137
|
+
function expireOldBypasses(rootDir) {
|
|
138
|
+
const records = readBypassFile(rootDir);
|
|
139
|
+
const now = /* @__PURE__ */ new Date();
|
|
140
|
+
const active = records.filter((r) => new Date(r.expiresAt) > now);
|
|
141
|
+
const expired = records.filter((r) => new Date(r.expiresAt) <= now);
|
|
142
|
+
if (expired.length === 0) {
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
writeBypassFile(rootDir, active);
|
|
146
|
+
for (const record of expired) {
|
|
147
|
+
appendAuditEvent(rootDir, {
|
|
148
|
+
timestamp: now.toISOString(),
|
|
149
|
+
event: "bypass.expire",
|
|
150
|
+
user: record.user,
|
|
151
|
+
details: {
|
|
152
|
+
bypassId: record.id,
|
|
153
|
+
rule: record.rule,
|
|
154
|
+
createdAt: record.createdAt,
|
|
155
|
+
expiresAt: record.expiresAt
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return expired.length;
|
|
160
|
+
}
|
|
161
|
+
|
|
1
162
|
// src/config.ts
|
|
2
|
-
import { existsSync } from "fs";
|
|
163
|
+
import { existsSync as existsSync3 } from "fs";
|
|
3
164
|
import { readFile } from "fs/promises";
|
|
4
|
-
import { join, resolve } from "path";
|
|
165
|
+
import { join as join3, resolve } from "path";
|
|
5
166
|
import { pathToFileURL } from "url";
|
|
6
167
|
|
|
7
168
|
// src/types.ts
|
|
@@ -17,8 +178,8 @@ var Visibility = /* @__PURE__ */ ((Visibility2) => {
|
|
|
17
178
|
function defaultConfig(rootDir) {
|
|
18
179
|
return {
|
|
19
180
|
rootDir,
|
|
20
|
-
tsconfig:
|
|
21
|
-
outDir:
|
|
181
|
+
tsconfig: join3(rootDir, "tsconfig.json"),
|
|
182
|
+
outDir: join3(rootDir, "docs"),
|
|
22
183
|
enforce: {
|
|
23
184
|
enabled: true,
|
|
24
185
|
minVisibility: "public" /* Public */,
|
|
@@ -30,17 +191,30 @@ function defaultConfig(rootDir) {
|
|
|
30
191
|
"require-example": "error",
|
|
31
192
|
"require-package-doc": "warn",
|
|
32
193
|
"require-class-member-doc": "error",
|
|
33
|
-
"require-interface-member-doc": "error"
|
|
194
|
+
"require-interface-member-doc": "error",
|
|
195
|
+
"require-tsdoc-syntax": "warn",
|
|
196
|
+
"require-remarks": "error",
|
|
197
|
+
"require-default-value": "warn",
|
|
198
|
+
"require-type-param": "error",
|
|
199
|
+
"require-see": "warn",
|
|
200
|
+
"require-release-tag": "error",
|
|
201
|
+
"require-fresh-guides": "warn",
|
|
202
|
+
"require-guide-coverage": "warn",
|
|
203
|
+
"require-internal-boundary": "error",
|
|
204
|
+
"require-route-response": "warn",
|
|
205
|
+
"require-inheritdoc-source": "warn",
|
|
206
|
+
"require-migration-path": "warn",
|
|
207
|
+
"require-since": "warn"
|
|
34
208
|
}
|
|
35
209
|
},
|
|
36
210
|
doctest: {
|
|
37
211
|
enabled: true,
|
|
38
|
-
cacheDir:
|
|
212
|
+
cacheDir: join3(rootDir, ".cache", "doctest")
|
|
39
213
|
},
|
|
40
214
|
api: {
|
|
41
215
|
enabled: false,
|
|
42
216
|
openapi: false,
|
|
43
|
-
openapiPath:
|
|
217
|
+
openapiPath: join3(rootDir, "docs", "openapi.json")
|
|
44
218
|
},
|
|
45
219
|
gen: {
|
|
46
220
|
enabled: true,
|
|
@@ -49,6 +223,39 @@ function defaultConfig(rootDir) {
|
|
|
49
223
|
readmeSync: false
|
|
50
224
|
},
|
|
51
225
|
skill: {},
|
|
226
|
+
bypass: {
|
|
227
|
+
dailyBudget: 3,
|
|
228
|
+
durationHours: 24
|
|
229
|
+
},
|
|
230
|
+
tsdoc: {
|
|
231
|
+
writeConfig: true,
|
|
232
|
+
customTags: [],
|
|
233
|
+
enforce: {
|
|
234
|
+
core: "error",
|
|
235
|
+
extended: "warn",
|
|
236
|
+
discretionary: "off"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
guides: {
|
|
240
|
+
enabled: true,
|
|
241
|
+
autoDiscover: true,
|
|
242
|
+
custom: []
|
|
243
|
+
},
|
|
244
|
+
guards: {
|
|
245
|
+
tsconfig: {
|
|
246
|
+
enabled: true,
|
|
247
|
+
requiredFlags: ["strict", "strictNullChecks", "noImplicitAny"]
|
|
248
|
+
},
|
|
249
|
+
biome: {
|
|
250
|
+
enabled: false,
|
|
251
|
+
lockedRules: []
|
|
252
|
+
},
|
|
253
|
+
packageJson: {
|
|
254
|
+
enabled: true,
|
|
255
|
+
minNodeVersion: "22.0.0",
|
|
256
|
+
requiredFields: ["type", "engines"]
|
|
257
|
+
}
|
|
258
|
+
},
|
|
52
259
|
project: {}
|
|
53
260
|
};
|
|
54
261
|
}
|
|
@@ -61,6 +268,10 @@ var KNOWN_TOP_KEYS = /* @__PURE__ */ new Set([
|
|
|
61
268
|
"api",
|
|
62
269
|
"gen",
|
|
63
270
|
"skill",
|
|
271
|
+
"bypass",
|
|
272
|
+
"tsdoc",
|
|
273
|
+
"guides",
|
|
274
|
+
"guards",
|
|
64
275
|
"project"
|
|
65
276
|
]);
|
|
66
277
|
var KNOWN_RULE_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -70,8 +281,35 @@ var KNOWN_RULE_KEYS = /* @__PURE__ */ new Set([
|
|
|
70
281
|
"require-example",
|
|
71
282
|
"require-package-doc",
|
|
72
283
|
"require-class-member-doc",
|
|
73
|
-
"require-interface-member-doc"
|
|
284
|
+
"require-interface-member-doc",
|
|
285
|
+
"require-tsdoc-syntax",
|
|
286
|
+
"require-remarks",
|
|
287
|
+
"require-default-value",
|
|
288
|
+
"require-type-param",
|
|
289
|
+
"require-see",
|
|
290
|
+
"require-release-tag",
|
|
291
|
+
"require-fresh-guides",
|
|
292
|
+
"require-guide-coverage",
|
|
293
|
+
"require-internal-boundary",
|
|
294
|
+
"require-route-response",
|
|
295
|
+
"require-inheritdoc-source",
|
|
296
|
+
"require-migration-path",
|
|
297
|
+
"require-since"
|
|
74
298
|
]);
|
|
299
|
+
var KNOWN_TSDOC_KEYS = /* @__PURE__ */ new Set(["writeConfig", "customTags", "enforce"]);
|
|
300
|
+
var KNOWN_TSDOC_ENFORCE_KEYS = /* @__PURE__ */ new Set(["core", "extended", "discretionary"]);
|
|
301
|
+
var KNOWN_GUIDES_KEYS = /* @__PURE__ */ new Set(["enabled", "autoDiscover", "custom"]);
|
|
302
|
+
var KNOWN_GUARDS_KEYS = /* @__PURE__ */ new Set(["tsconfig", "biome", "packageJson"]);
|
|
303
|
+
var KNOWN_GUARDS_TSCONFIG_KEYS = /* @__PURE__ */ new Set(["enabled", "requiredFlags"]);
|
|
304
|
+
var KNOWN_GUARDS_BIOME_KEYS = /* @__PURE__ */ new Set(["enabled", "lockedRules"]);
|
|
305
|
+
var KNOWN_GUARDS_PACKAGE_JSON_KEYS = /* @__PURE__ */ new Set(["enabled", "minNodeVersion", "requiredFields"]);
|
|
306
|
+
function validateKnownKeys(obj, knownKeys, section, warnings) {
|
|
307
|
+
for (const key of Object.keys(obj)) {
|
|
308
|
+
if (!knownKeys.has(key)) {
|
|
309
|
+
warnings.push(`Unknown key "${key}" in ${section} \u2014 ignored.`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
75
313
|
function collectUnknownKeyWarnings(partial) {
|
|
76
314
|
const warnings = [];
|
|
77
315
|
for (const key of Object.keys(partial)) {
|
|
@@ -88,6 +326,62 @@ function collectUnknownKeyWarnings(partial) {
|
|
|
88
326
|
}
|
|
89
327
|
}
|
|
90
328
|
}
|
|
329
|
+
if (partial.tsdoc) {
|
|
330
|
+
validateKnownKeys(
|
|
331
|
+
partial.tsdoc,
|
|
332
|
+
KNOWN_TSDOC_KEYS,
|
|
333
|
+
"tsdoc",
|
|
334
|
+
warnings
|
|
335
|
+
);
|
|
336
|
+
if (partial.tsdoc.enforce) {
|
|
337
|
+
validateKnownKeys(
|
|
338
|
+
partial.tsdoc.enforce,
|
|
339
|
+
KNOWN_TSDOC_ENFORCE_KEYS,
|
|
340
|
+
"tsdoc.enforce",
|
|
341
|
+
warnings
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (partial.guides) {
|
|
346
|
+
validateKnownKeys(
|
|
347
|
+
partial.guides,
|
|
348
|
+
KNOWN_GUIDES_KEYS,
|
|
349
|
+
"guides",
|
|
350
|
+
warnings
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
if (partial.guards) {
|
|
354
|
+
validateKnownKeys(
|
|
355
|
+
partial.guards,
|
|
356
|
+
KNOWN_GUARDS_KEYS,
|
|
357
|
+
"guards",
|
|
358
|
+
warnings
|
|
359
|
+
);
|
|
360
|
+
if (partial.guards.tsconfig) {
|
|
361
|
+
validateKnownKeys(
|
|
362
|
+
partial.guards.tsconfig,
|
|
363
|
+
KNOWN_GUARDS_TSCONFIG_KEYS,
|
|
364
|
+
"guards.tsconfig",
|
|
365
|
+
warnings
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
if (partial.guards.biome) {
|
|
369
|
+
validateKnownKeys(
|
|
370
|
+
partial.guards.biome,
|
|
371
|
+
KNOWN_GUARDS_BIOME_KEYS,
|
|
372
|
+
"guards.biome",
|
|
373
|
+
warnings
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (partial.guards.packageJson) {
|
|
377
|
+
validateKnownKeys(
|
|
378
|
+
partial.guards.packageJson,
|
|
379
|
+
KNOWN_GUARDS_PACKAGE_JSON_KEYS,
|
|
380
|
+
"guards.packageJson",
|
|
381
|
+
warnings
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
91
385
|
for (const w of warnings) {
|
|
92
386
|
console.error(`[forge-ts] warning: ${w}`);
|
|
93
387
|
}
|
|
@@ -108,6 +402,20 @@ function mergeWithDefaults(rootDir, partial) {
|
|
|
108
402
|
api: { ...defaults.api, ...partial.api },
|
|
109
403
|
gen: { ...defaults.gen, ...partial.gen },
|
|
110
404
|
skill: { ...defaults.skill, ...partial.skill },
|
|
405
|
+
bypass: { ...defaults.bypass, ...partial.bypass },
|
|
406
|
+
guides: { ...defaults.guides, ...partial.guides },
|
|
407
|
+
tsdoc: {
|
|
408
|
+
...defaults.tsdoc,
|
|
409
|
+
...partial.tsdoc,
|
|
410
|
+
enforce: { ...defaults.tsdoc.enforce, ...partial.tsdoc?.enforce }
|
|
411
|
+
},
|
|
412
|
+
guards: {
|
|
413
|
+
...defaults.guards,
|
|
414
|
+
...partial.guards,
|
|
415
|
+
tsconfig: { ...defaults.guards.tsconfig, ...partial.guards?.tsconfig },
|
|
416
|
+
biome: { ...defaults.guards.biome, ...partial.guards?.biome },
|
|
417
|
+
packageJson: { ...defaults.guards.packageJson, ...partial.guards?.packageJson }
|
|
418
|
+
},
|
|
111
419
|
project: { ...defaults.project, ...partial.project }
|
|
112
420
|
};
|
|
113
421
|
if (warnings.length > 0) {
|
|
@@ -150,11 +458,11 @@ async function loadPackageJsonConfig(pkgPath) {
|
|
|
150
458
|
async function loadConfig(rootDir) {
|
|
151
459
|
const root = resolve(rootDir ?? process.cwd());
|
|
152
460
|
let config;
|
|
153
|
-
const candidates = [
|
|
461
|
+
const candidates = [join3(root, "forge-ts.config.ts"), join3(root, "forge-ts.config.js")];
|
|
154
462
|
let found = false;
|
|
155
463
|
const loadWarnings = [];
|
|
156
464
|
for (const candidate of candidates) {
|
|
157
|
-
if (
|
|
465
|
+
if (existsSync3(candidate)) {
|
|
158
466
|
const partial = await loadModuleConfig(candidate);
|
|
159
467
|
if (partial) {
|
|
160
468
|
config = mergeWithDefaults(root, partial);
|
|
@@ -167,8 +475,8 @@ async function loadConfig(rootDir) {
|
|
|
167
475
|
}
|
|
168
476
|
}
|
|
169
477
|
if (!found) {
|
|
170
|
-
const pkgPath2 =
|
|
171
|
-
if (
|
|
478
|
+
const pkgPath2 = join3(root, "package.json");
|
|
479
|
+
if (existsSync3(pkgPath2)) {
|
|
172
480
|
const partial = await loadPackageJsonConfig(pkgPath2);
|
|
173
481
|
if (partial) {
|
|
174
482
|
config = mergeWithDefaults(root, partial);
|
|
@@ -181,8 +489,8 @@ async function loadConfig(rootDir) {
|
|
|
181
489
|
} else {
|
|
182
490
|
config = config;
|
|
183
491
|
}
|
|
184
|
-
const pkgPath =
|
|
185
|
-
if (
|
|
492
|
+
const pkgPath = join3(root, "package.json");
|
|
493
|
+
if (existsSync3(pkgPath)) {
|
|
186
494
|
try {
|
|
187
495
|
const raw = await readFile(pkgPath, "utf8");
|
|
188
496
|
const pkg = JSON.parse(raw);
|
|
@@ -224,6 +532,135 @@ async function loadConfig(rootDir) {
|
|
|
224
532
|
return config;
|
|
225
533
|
}
|
|
226
534
|
|
|
535
|
+
// src/lock.ts
|
|
536
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
537
|
+
import { join as join4 } from "path";
|
|
538
|
+
var LOCK_FILE_NAME = ".forge-lock.json";
|
|
539
|
+
function readLockFile(rootDir) {
|
|
540
|
+
const lockPath = join4(rootDir, LOCK_FILE_NAME);
|
|
541
|
+
if (!existsSync4(lockPath)) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
const raw = readFileSync3(lockPath, "utf8");
|
|
546
|
+
return JSON.parse(raw);
|
|
547
|
+
} catch {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function writeLockFile(rootDir, manifest) {
|
|
552
|
+
const lockPath = join4(rootDir, LOCK_FILE_NAME);
|
|
553
|
+
writeFileSync2(lockPath, `${JSON.stringify(manifest, null, 2)}
|
|
554
|
+
`, "utf8");
|
|
555
|
+
}
|
|
556
|
+
function removeLockFile(rootDir) {
|
|
557
|
+
const lockPath = join4(rootDir, LOCK_FILE_NAME);
|
|
558
|
+
if (!existsSync4(lockPath)) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
unlinkSync(lockPath);
|
|
563
|
+
return true;
|
|
564
|
+
} catch {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function createLockManifest(config, lockedBy = "forge-ts lock") {
|
|
569
|
+
const rules = {};
|
|
570
|
+
for (const [key, value] of Object.entries(config.enforce.rules)) {
|
|
571
|
+
rules[key] = value;
|
|
572
|
+
}
|
|
573
|
+
const lockConfig = { rules };
|
|
574
|
+
if (config.guards.tsconfig.enabled) {
|
|
575
|
+
lockConfig.tsconfig = {
|
|
576
|
+
enabled: config.guards.tsconfig.enabled,
|
|
577
|
+
requiredFlags: config.guards.tsconfig.requiredFlags
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
if (config.guards.biome.enabled) {
|
|
581
|
+
lockConfig.biome = {
|
|
582
|
+
enabled: config.guards.biome.enabled,
|
|
583
|
+
lockedRules: config.guards.biome.lockedRules
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
version: "1.0.0",
|
|
588
|
+
lockedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
589
|
+
lockedBy,
|
|
590
|
+
config: lockConfig
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function validateAgainstLock(config, lock) {
|
|
594
|
+
const violations = [];
|
|
595
|
+
const severityRank = {
|
|
596
|
+
off: 0,
|
|
597
|
+
warn: 1,
|
|
598
|
+
error: 2
|
|
599
|
+
};
|
|
600
|
+
for (const [ruleName, lockedSeverity] of Object.entries(lock.config.rules)) {
|
|
601
|
+
const currentSeverity = config.enforce.rules[ruleName] ?? "off";
|
|
602
|
+
const lockedRank = severityRank[lockedSeverity] ?? 0;
|
|
603
|
+
const currentRank = severityRank[currentSeverity] ?? 0;
|
|
604
|
+
if (currentRank < lockedRank) {
|
|
605
|
+
violations.push({
|
|
606
|
+
field: `rules.${ruleName}`,
|
|
607
|
+
locked: lockedSeverity,
|
|
608
|
+
current: currentSeverity,
|
|
609
|
+
message: `Rule "${ruleName}" was weakened from "${lockedSeverity}" to "${currentSeverity}". Locked settings cannot be weakened without running "forge-ts unlock --reason=...".`
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (lock.config.tsconfig) {
|
|
614
|
+
const lockedTsconfig = lock.config.tsconfig;
|
|
615
|
+
if (lockedTsconfig.enabled && !config.guards.tsconfig.enabled) {
|
|
616
|
+
violations.push({
|
|
617
|
+
field: "guards.tsconfig.enabled",
|
|
618
|
+
locked: "true",
|
|
619
|
+
current: "false",
|
|
620
|
+
message: 'tsconfig guard was disabled. Locked settings cannot be weakened without running "forge-ts unlock --reason=...".'
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
if (lockedTsconfig.requiredFlags && config.guards.tsconfig.enabled) {
|
|
624
|
+
const currentFlags = new Set(config.guards.tsconfig.requiredFlags);
|
|
625
|
+
for (const flag of lockedTsconfig.requiredFlags) {
|
|
626
|
+
if (!currentFlags.has(flag)) {
|
|
627
|
+
violations.push({
|
|
628
|
+
field: `guards.tsconfig.requiredFlags.${flag}`,
|
|
629
|
+
locked: flag,
|
|
630
|
+
current: "(removed)",
|
|
631
|
+
message: `tsconfig required flag "${flag}" was removed. Locked settings cannot be weakened without running "forge-ts unlock --reason=...".`
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
if (lock.config.biome) {
|
|
638
|
+
const lockedBiome = lock.config.biome;
|
|
639
|
+
if (lockedBiome.enabled && !config.guards.biome.enabled) {
|
|
640
|
+
violations.push({
|
|
641
|
+
field: "guards.biome.enabled",
|
|
642
|
+
locked: "true",
|
|
643
|
+
current: "false",
|
|
644
|
+
message: 'Biome guard was disabled. Locked settings cannot be weakened without running "forge-ts unlock --reason=...".'
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (lockedBiome.lockedRules && config.guards.biome.enabled) {
|
|
648
|
+
const currentRules = new Set(config.guards.biome.lockedRules);
|
|
649
|
+
for (const rule of lockedBiome.lockedRules) {
|
|
650
|
+
if (!currentRules.has(rule)) {
|
|
651
|
+
violations.push({
|
|
652
|
+
field: `guards.biome.lockedRules.${rule}`,
|
|
653
|
+
locked: rule,
|
|
654
|
+
current: "(removed)",
|
|
655
|
+
message: `Biome locked rule "${rule}" was removed. Locked settings cannot be weakened without running "forge-ts unlock --reason=...".`
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return violations;
|
|
662
|
+
}
|
|
663
|
+
|
|
227
664
|
// src/visibility.ts
|
|
228
665
|
function resolveVisibility(tags) {
|
|
229
666
|
if (!tags) return "public" /* Public */;
|
|
@@ -246,15 +683,34 @@ function filterByVisibility(symbols, minVisibility) {
|
|
|
246
683
|
}
|
|
247
684
|
|
|
248
685
|
// src/walker.ts
|
|
249
|
-
import { readFileSync } from "fs";
|
|
250
|
-
import { resolve as resolve2 } from "path";
|
|
686
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
687
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
251
688
|
import {
|
|
252
689
|
DocNodeKind,
|
|
253
690
|
StandardTags,
|
|
254
691
|
TSDocConfiguration,
|
|
255
692
|
TSDocParser
|
|
256
693
|
} from "@microsoft/tsdoc";
|
|
694
|
+
import { TSDocConfigFile } from "@microsoft/tsdoc-config";
|
|
257
695
|
import ts from "typescript";
|
|
696
|
+
var tsdocConfigCache = /* @__PURE__ */ new Map();
|
|
697
|
+
function clearTSDocConfigCache() {
|
|
698
|
+
tsdocConfigCache.clear();
|
|
699
|
+
}
|
|
700
|
+
function loadTSDocConfiguration(folderPath) {
|
|
701
|
+
const cached = tsdocConfigCache.get(folderPath);
|
|
702
|
+
if (cached) return cached;
|
|
703
|
+
const configuration = new TSDocConfiguration();
|
|
704
|
+
try {
|
|
705
|
+
const configFile = TSDocConfigFile.loadForFolder(folderPath);
|
|
706
|
+
if (!configFile.fileNotFound && !configFile.hasErrors) {
|
|
707
|
+
configFile.configureParser(configuration);
|
|
708
|
+
}
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
tsdocConfigCache.set(folderPath, configuration);
|
|
712
|
+
return configuration;
|
|
713
|
+
}
|
|
258
714
|
function renderInlineNodes(nodes) {
|
|
259
715
|
const parts = [];
|
|
260
716
|
for (const node of nodes) {
|
|
@@ -309,8 +765,8 @@ function extractExamples(comment, startLine) {
|
|
|
309
765
|
}
|
|
310
766
|
return examples;
|
|
311
767
|
}
|
|
312
|
-
function parseTSDoc(rawComment, startLine) {
|
|
313
|
-
const configuration = new TSDocConfiguration();
|
|
768
|
+
function parseTSDoc(rawComment, startLine, folderPath) {
|
|
769
|
+
const configuration = folderPath !== void 0 ? loadTSDocConfiguration(folderPath) : new TSDocConfiguration();
|
|
314
770
|
const parser = new TSDocParser(configuration);
|
|
315
771
|
const result = parser.parseString(rawComment);
|
|
316
772
|
const comment = result.docComment;
|
|
@@ -362,6 +818,139 @@ function parseTSDoc(rawComment, startLine) {
|
|
|
362
818
|
}
|
|
363
819
|
}
|
|
364
820
|
}
|
|
821
|
+
if (comment.remarksBlock) {
|
|
822
|
+
const remarksText = renderBlock(comment.remarksBlock).trim();
|
|
823
|
+
tags.remarks = remarksText ? [remarksText] : [];
|
|
824
|
+
}
|
|
825
|
+
if (comment.seeBlocks.length > 0) {
|
|
826
|
+
tags.see = comment.seeBlocks.map((block) => renderBlock(block).trim()).filter(Boolean);
|
|
827
|
+
}
|
|
828
|
+
if (comment.typeParams.count > 0) {
|
|
829
|
+
tags.typeParam = comment.typeParams.blocks.map(
|
|
830
|
+
(block) => `${block.parameterName} - ${renderBlock(block).trim()}`
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
for (const block of comment.customBlocks) {
|
|
834
|
+
if (block.blockTag.tagName.toLowerCase() === "@defaultvalue") {
|
|
835
|
+
const dvText = renderBlock(block).trim();
|
|
836
|
+
if (!tags.defaultValue) tags.defaultValue = [];
|
|
837
|
+
tags.defaultValue.push(dvText);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
for (const block of comment.customBlocks) {
|
|
841
|
+
if (block.blockTag.tagName.toLowerCase() === "@concept") {
|
|
842
|
+
const conceptText = renderBlock(block).trim();
|
|
843
|
+
if (conceptText) {
|
|
844
|
+
if (!tags.concept) tags.concept = [];
|
|
845
|
+
tags.concept.push(conceptText);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
for (const block of comment.customBlocks) {
|
|
850
|
+
if (block.blockTag.tagName.toLowerCase() === "@guide") {
|
|
851
|
+
const guideText = renderBlock(block).trim();
|
|
852
|
+
if (guideText) {
|
|
853
|
+
if (!tags.guide) tags.guide = [];
|
|
854
|
+
tags.guide.push(guideText);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
for (const block of comment.customBlocks) {
|
|
859
|
+
if (block.blockTag.tagName.toLowerCase() === "@category") {
|
|
860
|
+
const categoryText = renderBlock(block).trim();
|
|
861
|
+
if (categoryText) {
|
|
862
|
+
if (!tags.category) tags.category = [];
|
|
863
|
+
tags.category.push(categoryText);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
for (const block of comment.customBlocks) {
|
|
868
|
+
if (block.blockTag.tagName.toLowerCase() === "@since") {
|
|
869
|
+
const sinceText = renderBlock(block).trim();
|
|
870
|
+
if (sinceText) {
|
|
871
|
+
if (!tags.since) tags.since = [];
|
|
872
|
+
tags.since.push(sinceText);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
for (const block of comment.customBlocks) {
|
|
877
|
+
if (block.blockTag.tagName.toLowerCase() === "@response") {
|
|
878
|
+
const responseText = renderBlock(block).trim();
|
|
879
|
+
if (responseText) {
|
|
880
|
+
if (!tags.response) tags.response = [];
|
|
881
|
+
tags.response.push(responseText);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
for (const block of comment.customBlocks) {
|
|
886
|
+
if (block.blockTag.tagName.toLowerCase() === "@query") {
|
|
887
|
+
const queryText = renderBlock(block).trim();
|
|
888
|
+
if (queryText) {
|
|
889
|
+
if (!tags.query) tags.query = [];
|
|
890
|
+
tags.query.push(queryText);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
for (const block of comment.customBlocks) {
|
|
895
|
+
if (block.blockTag.tagName.toLowerCase() === "@header") {
|
|
896
|
+
const headerText = renderBlock(block).trim();
|
|
897
|
+
if (headerText) {
|
|
898
|
+
if (!tags.header) tags.header = [];
|
|
899
|
+
tags.header.push(headerText);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
for (const block of comment.customBlocks) {
|
|
904
|
+
if (block.blockTag.tagName.toLowerCase() === "@body") {
|
|
905
|
+
const bodyText = renderBlock(block).trim();
|
|
906
|
+
if (bodyText) {
|
|
907
|
+
if (!tags.body) tags.body = [];
|
|
908
|
+
tags.body.push(bodyText);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
for (const block of comment.customBlocks) {
|
|
913
|
+
if (block.blockTag.tagName.toLowerCase() === "@faq") {
|
|
914
|
+
const faqText = renderBlock(block).trim();
|
|
915
|
+
if (faqText) {
|
|
916
|
+
if (!tags.faq) tags.faq = [];
|
|
917
|
+
tags.faq.push(faqText);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
for (const block of comment.customBlocks) {
|
|
922
|
+
if (block.blockTag.tagName.toLowerCase() === "@breaking") {
|
|
923
|
+
const breakingText = renderBlock(block).trim();
|
|
924
|
+
if (breakingText) {
|
|
925
|
+
if (!tags.breaking) tags.breaking = [];
|
|
926
|
+
tags.breaking.push(breakingText);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
for (const block of comment.customBlocks) {
|
|
931
|
+
if (block.blockTag.tagName.toLowerCase() === "@migration") {
|
|
932
|
+
const migrationText = renderBlock(block).trim();
|
|
933
|
+
if (migrationText) {
|
|
934
|
+
if (!tags.migration) tags.migration = [];
|
|
935
|
+
tags.migration.push(migrationText);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
for (const block of comment.customBlocks) {
|
|
940
|
+
if (block.blockTag.tagName.toLowerCase() === "@complexity") {
|
|
941
|
+
const complexityText = renderBlock(block).trim();
|
|
942
|
+
if (complexityText) {
|
|
943
|
+
if (!tags.complexity) tags.complexity = [];
|
|
944
|
+
tags.complexity.push(complexityText);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
for (const tag of comment.modifierTagSet.nodes) {
|
|
949
|
+
if (tag.tagName.toLowerCase() === "@quickstart") {
|
|
950
|
+
tags.quickstart = [];
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
365
954
|
const examples = extractExamples(comment, startLine);
|
|
366
955
|
const links = [];
|
|
367
956
|
function walkForLinks(node) {
|
|
@@ -379,6 +968,22 @@ function parseTSDoc(rawComment, startLine) {
|
|
|
379
968
|
}
|
|
380
969
|
}
|
|
381
970
|
walkForLinks(comment);
|
|
971
|
+
if (comment.inheritDocTag?.declarationReference) {
|
|
972
|
+
const ref = comment.inheritDocTag.declarationReference;
|
|
973
|
+
const target = ref.memberReferences.map((r) => r.memberIdentifier?.identifier ?? "").filter(Boolean).join(".");
|
|
974
|
+
if (target) {
|
|
975
|
+
if (!tags.inheritDoc) tags.inheritDoc = [];
|
|
976
|
+
tags.inheritDoc.push(target);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const parseMessages = [];
|
|
980
|
+
for (const msg of result.log.messages) {
|
|
981
|
+
parseMessages.push({
|
|
982
|
+
messageId: msg.messageId,
|
|
983
|
+
text: msg.unformattedText,
|
|
984
|
+
line: startLine
|
|
985
|
+
});
|
|
986
|
+
}
|
|
382
987
|
const summary = renderDocSection(comment.summarySection);
|
|
383
988
|
return {
|
|
384
989
|
summary: summary || void 0,
|
|
@@ -388,7 +993,8 @@ function parseTSDoc(rawComment, startLine) {
|
|
|
388
993
|
examples: examples.length > 0 ? examples : void 0,
|
|
389
994
|
tags: Object.keys(tags).length > 0 ? tags : void 0,
|
|
390
995
|
deprecated,
|
|
391
|
-
links: links.length > 0 ? links : void 0
|
|
996
|
+
links: links.length > 0 ? links : void 0,
|
|
997
|
+
parseMessages: parseMessages.length > 0 ? parseMessages : void 0
|
|
392
998
|
};
|
|
393
999
|
}
|
|
394
1000
|
function getLeadingComment(node, sourceFile) {
|
|
@@ -439,9 +1045,10 @@ function buildSignature(node, checker) {
|
|
|
439
1045
|
return void 0;
|
|
440
1046
|
}
|
|
441
1047
|
}
|
|
442
|
-
function extractSymbolsFromFile(sourceFile, checker
|
|
1048
|
+
function extractSymbolsFromFile(sourceFile, checker) {
|
|
443
1049
|
const symbols = [];
|
|
444
1050
|
const filePath = sourceFile.fileName;
|
|
1051
|
+
const fileDir = dirname(filePath);
|
|
445
1052
|
function visit(node, parentExported) {
|
|
446
1053
|
const isExported = parentExported || (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0;
|
|
447
1054
|
if (ts.isExportDeclaration(node)) {
|
|
@@ -458,7 +1065,7 @@ function extractSymbolsFromFile(sourceFile, checker, _tsdocParser) {
|
|
|
458
1065
|
const name2 = decl.name.getText(sourceFile);
|
|
459
1066
|
const pos2 = sourceFile.getLineAndCharacterOfPosition(decl.getStart());
|
|
460
1067
|
const rawComment2 = getLeadingComment(node, sourceFile);
|
|
461
|
-
const documentation2 = rawComment2 ? parseTSDoc(rawComment2, pos2.line + 1) : void 0;
|
|
1068
|
+
const documentation2 = rawComment2 ? parseTSDoc(rawComment2, pos2.line + 1, fileDir) : void 0;
|
|
462
1069
|
const tags2 = documentation2?.tags;
|
|
463
1070
|
const visibility2 = resolveVisibility(tags2);
|
|
464
1071
|
symbols.push({
|
|
@@ -488,7 +1095,7 @@ function extractSymbolsFromFile(sourceFile, checker, _tsdocParser) {
|
|
|
488
1095
|
const name = nameNode.getText(sourceFile);
|
|
489
1096
|
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
490
1097
|
const rawComment = getLeadingComment(node, sourceFile);
|
|
491
|
-
const documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1) : void 0;
|
|
1098
|
+
const documentation = rawComment ? parseTSDoc(rawComment, pos.line + 1, fileDir) : void 0;
|
|
492
1099
|
const tags = documentation?.tags;
|
|
493
1100
|
const visibility = resolveVisibility(tags);
|
|
494
1101
|
const children = [];
|
|
@@ -499,7 +1106,7 @@ function extractSymbolsFromFile(sourceFile, checker, _tsdocParser) {
|
|
|
499
1106
|
const memberName = member.name?.getText(sourceFile) ?? "";
|
|
500
1107
|
const memberPos = sourceFile.getLineAndCharacterOfPosition(member.getStart());
|
|
501
1108
|
const memberComment = getLeadingComment(member, sourceFile);
|
|
502
|
-
const memberDoc = memberComment ? parseTSDoc(memberComment, memberPos.line + 1) : void 0;
|
|
1109
|
+
const memberDoc = memberComment ? parseTSDoc(memberComment, memberPos.line + 1, fileDir) : void 0;
|
|
503
1110
|
const memberTags = memberDoc?.tags;
|
|
504
1111
|
const memberVisibility = resolveVisibility(memberTags);
|
|
505
1112
|
children.push({
|
|
@@ -535,7 +1142,7 @@ function createWalker(config) {
|
|
|
535
1142
|
return {
|
|
536
1143
|
walk() {
|
|
537
1144
|
const tsconfigPath = resolve2(config.tsconfig);
|
|
538
|
-
const configFile = ts.readConfigFile(tsconfigPath, (path) =>
|
|
1145
|
+
const configFile = ts.readConfigFile(tsconfigPath, (path) => readFileSync4(path, "utf8"));
|
|
539
1146
|
if (configFile.error) {
|
|
540
1147
|
throw new Error(
|
|
541
1148
|
`Failed to read tsconfig at ${tsconfigPath}: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
|
|
@@ -551,14 +1158,12 @@ function createWalker(config) {
|
|
|
551
1158
|
options: parsedCommandLine.options
|
|
552
1159
|
});
|
|
553
1160
|
const checker = program.getTypeChecker();
|
|
554
|
-
const tsdocConfiguration = new TSDocConfiguration();
|
|
555
|
-
const tsdocParser = new TSDocParser(tsdocConfiguration);
|
|
556
1161
|
const allSymbols = [];
|
|
557
1162
|
for (const sourceFile of program.getSourceFiles()) {
|
|
558
1163
|
if (sourceFile.isDeclarationFile || sourceFile.fileName.includes("node_modules")) {
|
|
559
1164
|
continue;
|
|
560
1165
|
}
|
|
561
|
-
const fileSymbols = extractSymbolsFromFile(sourceFile, checker
|
|
1166
|
+
const fileSymbols = extractSymbolsFromFile(sourceFile, checker);
|
|
562
1167
|
allSymbols.push(...fileSymbols);
|
|
563
1168
|
}
|
|
564
1169
|
return allSymbols;
|
|
@@ -567,11 +1172,27 @@ function createWalker(config) {
|
|
|
567
1172
|
}
|
|
568
1173
|
export {
|
|
569
1174
|
Visibility,
|
|
1175
|
+
appendAuditEvent,
|
|
1176
|
+
clearTSDocConfigCache,
|
|
1177
|
+
createBypass,
|
|
1178
|
+
createLockManifest,
|
|
570
1179
|
createWalker,
|
|
571
1180
|
defaultConfig,
|
|
1181
|
+
expireOldBypasses,
|
|
572
1182
|
filterByVisibility,
|
|
1183
|
+
formatAuditEvent,
|
|
1184
|
+
getActiveBypasses,
|
|
1185
|
+
getCurrentUser,
|
|
1186
|
+
getRemainingBudget,
|
|
1187
|
+
isRuleBypassed,
|
|
573
1188
|
loadConfig,
|
|
1189
|
+
loadTSDocConfiguration,
|
|
574
1190
|
meetsVisibility,
|
|
575
|
-
|
|
1191
|
+
readAuditLog,
|
|
1192
|
+
readLockFile,
|
|
1193
|
+
removeLockFile,
|
|
1194
|
+
resolveVisibility,
|
|
1195
|
+
validateAgainstLock,
|
|
1196
|
+
writeLockFile
|
|
576
1197
|
};
|
|
577
1198
|
//# sourceMappingURL=index.js.map
|