@wairon/cli 5.1.1-dev.95 → 5.1.1-dev.96
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/cli/index.js +2155 -456
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1850 -347
- package/dist/index.js.map +1 -1
- package/dist/templates/skills/sdd-architect.md +3 -2
- package/dist/templates/skills/sdd-delegate.md +2 -2
- package/dist/templates/skills/sdd-implement.md +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var init_defaults = __esm({
|
|
|
65
65
|
copilot: ".github/prompts",
|
|
66
66
|
codex: ".codex/agents"
|
|
67
67
|
};
|
|
68
|
-
WAIRON_VERSION = "5.1.1-dev.
|
|
68
|
+
WAIRON_VERSION = "5.1.1-dev.96";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
SUPPORTED_ALIASES = ["wai"];
|
|
71
71
|
SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -651,6 +651,14 @@ var init_agent = __esm({
|
|
|
651
651
|
instructions: import_zod2.z.string(),
|
|
652
652
|
/** Rendered variant guidance, also folded into instructions */
|
|
653
653
|
variantGuidance: import_zod2.z.string().optional(),
|
|
654
|
+
/**
|
|
655
|
+
* How the neutral types of the contracts this agent implements are spelled
|
|
656
|
+
* in its language: the write table (type_dialect.mappingLines) of the dialect
|
|
657
|
+
* for the language its implementations are written in, also folded into
|
|
658
|
+
* instructions. Absent when no dialect is shipped for that language or the
|
|
659
|
+
* agent implements nothing.
|
|
660
|
+
*/
|
|
661
|
+
typeMapping: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
654
662
|
/**
|
|
655
663
|
* Set only on a brief for a member's agent (an id qualified `<alias>::`): the
|
|
656
664
|
* member's directory relative to the root the brief was asked from. The
|
|
@@ -1658,14 +1666,16 @@ function locateScalar(tokens, path92) {
|
|
|
1658
1666
|
const base = Math.min(...region.map((t) => t.col));
|
|
1659
1667
|
const last = k === path92.length - 1;
|
|
1660
1668
|
let at;
|
|
1661
|
-
|
|
1669
|
+
const items = region.map((t, i) => ({ t, i })).filter(({ t }) => t.kind === "item" && t.col === base);
|
|
1670
|
+
if (items.length === 0) {
|
|
1662
1671
|
at = region.findIndex((t) => t.kind === "key" && t.col === base && t.name === segment);
|
|
1663
1672
|
if (at < 0) return `no block key "${segment}" at ${path92.slice(0, k).join(".") || "the document root"}`;
|
|
1664
1673
|
if (last) return region[at].valueStart !== void 0 ? region[at] : `"${segment}" holds no inline scalar`;
|
|
1665
1674
|
} else {
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1675
|
+
if (!/^\d+$/.test(segment)) return `"${segment}" is not a sequence index at ${path92.slice(0, k).join(".") || "the document root"}`;
|
|
1676
|
+
const index = Number(segment);
|
|
1677
|
+
if (index >= items.length) return `no block sequence item ${segment} at ${path92.slice(0, k).join(".")}`;
|
|
1678
|
+
at = items[index].i;
|
|
1669
1679
|
if (last) {
|
|
1670
1680
|
const value = region[at + 1];
|
|
1671
1681
|
return value && value.kind === "scalar" && value.line === region[at].line ? value : `item ${segment} holds no inline scalar`;
|
|
@@ -1994,7 +2004,7 @@ function registryOver(store, root) {
|
|
|
1994
2004
|
const at = typeof entry.at === "string" ? entry.at : void 0;
|
|
1995
2005
|
const covers = Array.isArray(entry.covers) ? entry.covers.filter((u) => typeof u === "string") : void 0;
|
|
1996
2006
|
const next = rekeyAnchor(rename, { spec: entry.spec, at, covers });
|
|
1997
|
-
const base = ["rules", "conformance", "carried", g, "findings", f];
|
|
2007
|
+
const base = ["rules", "conformance", "carried", String(g), "findings", String(f)];
|
|
1998
2008
|
const named2 = { code: String(entry.code), spec: entry.spec, at: at ?? "" };
|
|
1999
2009
|
const change = (path92, field, from, to) => {
|
|
2000
2010
|
if (from === to) return;
|
|
@@ -2003,7 +2013,7 @@ function registryOver(store, root) {
|
|
|
2003
2013
|
};
|
|
2004
2014
|
change(["spec"], "spec", entry.spec, next.spec);
|
|
2005
2015
|
if (at !== void 0) change(["at"], "at", at, next.at);
|
|
2006
|
-
(covers ?? []).forEach((unit, u) => change(["covers", u], "covers", unit, next.covers[u]));
|
|
2016
|
+
(covers ?? []).forEach((unit, u) => change(["covers", String(u)], "covers", unit, next.covers[u]));
|
|
2007
2017
|
});
|
|
2008
2018
|
});
|
|
2009
2019
|
store.rewriteScalars(edits, dryRun);
|
|
@@ -3304,7 +3314,7 @@ function relationHealth(status2) {
|
|
|
3304
3314
|
if (status2.drifted) return "drifted";
|
|
3305
3315
|
return "ok";
|
|
3306
3316
|
}
|
|
3307
|
-
var import_zod8, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, RETIRED_STEREOTYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, DependencyClassSchema, PatternRefSchema, EventBindingSchema, ExternalLinkTypeSchema, ExternalLinkSchema, PortalAuthSchemeSchema, PortalAuthSchema, PortalMountSchema, ComponentSpecSchema, BLOCK_NOUNS, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, FindingDeclarationSchema, MethodSignatureSchema, StoredMethodSignatureSchema, ResolvedMethodSignatureSchema, INTENT_FLOOR_MIN_CHARS, InterfaceSpecSchema, ResolvedInterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, TechnologySchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, ResolvedTypeMethodSchema, StoredTypeMethodSchema, InvariantSchema, TypeSpecSchema, ResolvedTypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceTypeExportSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, ExternalLockEntrySchema, ExternalsLockSchema, ParentExcerptSchema, NamedOpenApiSpecSchema, GroupSpecSchema;
|
|
3317
|
+
var import_zod8, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, RETIRED_STEREOTYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, DependencyClassSchema, PatternRefSchema, EventBindingSchema, ExternalLinkTypeSchema, ExternalLinkSchema, PortalAuthSchemeSchema, PortalAuthSchema, PortalMountSchema, ComponentSpecSchema, BLOCK_NOUNS, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, FindingDeclarationSchema, MethodSignatureSchema, StoredMethodSignatureSchema, ResolvedMethodSignatureSchema, INTENT_FLOOR_MIN_CHARS, InterfaceSpecSchema, ResolvedInterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, TechnologySchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, ResolvedTypeMethodSchema, StoredTypeMethodSchema, InvariantSchema, EnumValueSchema, TypeSpecSchema, ResolvedTypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceTypeExportSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, ExternalLockEntrySchema, ExternalsLockSchema, ParentExcerptSchema, NamedOpenApiSpecSchema, GroupSpecSchema;
|
|
3308
3318
|
var init_specs = __esm({
|
|
3309
3319
|
"src/models/specs.ts"() {
|
|
3310
3320
|
"use strict";
|
|
@@ -3681,11 +3691,10 @@ var init_specs = __esm({
|
|
|
3681
3691
|
MethodParamSchema = import_zod8.z.object({
|
|
3682
3692
|
name: import_zod8.z.string(),
|
|
3683
3693
|
/**
|
|
3684
|
-
* A
|
|
3685
|
-
*
|
|
3686
|
-
* `
|
|
3687
|
-
*
|
|
3688
|
-
* src/models/type-references.ts.
|
|
3694
|
+
* A type expression in the neutral type grammar (src/models/type-grammar.ts):
|
|
3695
|
+
* a primitive, a named type (`billing.Invoice`, `alias::name`), `list<T>`,
|
|
3696
|
+
* `set<T>`, `map<K, V>`, `T?`, a union of named types. Stored canonical; an
|
|
3697
|
+
* alias (`Invoice[]`, `Invoice | null`, `boolean`) is normalised on write.
|
|
3689
3698
|
*/
|
|
3690
3699
|
type: import_zod8.z.string(),
|
|
3691
3700
|
description: import_zod8.z.string().optional(),
|
|
@@ -3704,8 +3713,9 @@ var init_specs = __esm({
|
|
|
3704
3713
|
description: import_zod8.z.string(),
|
|
3705
3714
|
signature: import_zod8.z.string().optional(),
|
|
3706
3715
|
// e.g. "save(key: string, data: Buffer): Promise<void>"
|
|
3707
|
-
//
|
|
3708
|
-
//
|
|
3716
|
+
// A type expression in the neutral grammar, at the returns position — the only
|
|
3717
|
+
// one `async T` and `void` may stand in: "async void", "Invoice?". Stored
|
|
3718
|
+
// canonical; see src/models/type-grammar.ts.
|
|
3709
3719
|
returns: import_zod8.z.string().optional(),
|
|
3710
3720
|
/** Structured parameters (authoritative for type checking when present). */
|
|
3711
3721
|
params: import_zod8.z.array(MethodParamSchema).optional(),
|
|
@@ -4069,12 +4079,12 @@ var init_specs = __esm({
|
|
|
4069
4079
|
createdAt: import_zod8.z.string().datetime(),
|
|
4070
4080
|
updatedAt: import_zod8.z.string().datetime()
|
|
4071
4081
|
});
|
|
4072
|
-
TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature"]);
|
|
4082
|
+
TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature", "enum"]);
|
|
4073
4083
|
TypeFieldSchema = import_zod8.z.object({
|
|
4074
4084
|
name: import_zod8.z.string(),
|
|
4075
|
-
// A
|
|
4076
|
-
// "billing.Invoice")
|
|
4077
|
-
//
|
|
4085
|
+
// A type expression in the neutral grammar (src/models/type-grammar.ts): a
|
|
4086
|
+
// primitive, a named type ("billing.Invoice"), list/set/map, `T?`, a union
|
|
4087
|
+
// of named types. Stored canonical.
|
|
4078
4088
|
type: import_zod8.z.string(),
|
|
4079
4089
|
description: import_zod8.z.string().optional(),
|
|
4080
4090
|
optional: import_zod8.z.boolean().default(false),
|
|
@@ -4128,9 +4138,13 @@ var init_specs = __esm({
|
|
|
4128
4138
|
/** The property that must hold, stated precisely enough to test against. */
|
|
4129
4139
|
description: import_zod8.z.string().min(1)
|
|
4130
4140
|
});
|
|
4141
|
+
EnumValueSchema = import_zod8.z.object({
|
|
4142
|
+
name: import_zod8.z.string().min(1),
|
|
4143
|
+
description: import_zod8.z.string().optional()
|
|
4144
|
+
});
|
|
4131
4145
|
TypeSpecSchema = import_zod8.z.object({
|
|
4132
4146
|
kind: TypeKindSchema,
|
|
4133
|
-
// discriminator — entity | value-object | signature
|
|
4147
|
+
// discriminator — entity | value-object | signature | enum
|
|
4134
4148
|
id: SpecIdSchema,
|
|
4135
4149
|
name: import_zod8.z.string(),
|
|
4136
4150
|
description: import_zod8.z.string().optional(),
|
|
@@ -4193,6 +4207,20 @@ var init_specs = __esm({
|
|
|
4193
4207
|
params: import_zod8.z.array(MethodParamSchema).optional(),
|
|
4194
4208
|
/** A signature's one output type; required on kind signature and only there (SIGNATURE_TYPE_MEMBERS). */
|
|
4195
4209
|
returns: import_zod8.z.string().optional(),
|
|
4210
|
+
/**
|
|
4211
|
+
* An enum's values, in declared order (the order is part of the design),
|
|
4212
|
+
* unique by nameKey; required and non-empty on kind enum and only there
|
|
4213
|
+
* (ENUM_MEMBERS).
|
|
4214
|
+
*/
|
|
4215
|
+
values: import_zod8.z.array(EnumValueSchema).optional(),
|
|
4216
|
+
/**
|
|
4217
|
+
* A named scalar's one primitive (string, int, float, bool, bytes, date,
|
|
4218
|
+
* datetime or duration), in place of fields: a value-object that is a
|
|
4219
|
+
* newtype or type alias in every language. Read as a type position (the
|
|
4220
|
+
* grammar's `holds` position); only on a value-object and never beside
|
|
4221
|
+
* fields (NAMED_SCALAR_MEMBERS).
|
|
4222
|
+
*/
|
|
4223
|
+
holds: import_zod8.z.string().optional(),
|
|
4196
4224
|
createdAt: import_zod8.z.string().datetime(),
|
|
4197
4225
|
updatedAt: import_zod8.z.string().datetime()
|
|
4198
4226
|
});
|
|
@@ -4218,7 +4246,11 @@ var init_specs = __esm({
|
|
|
4218
4246
|
optional: import_zod8.z.boolean().optional()
|
|
4219
4247
|
})).optional(),
|
|
4220
4248
|
/** A signature's one output type; only on kind signature. */
|
|
4221
|
-
returns: import_zod8.z.string().optional()
|
|
4249
|
+
returns: import_zod8.z.string().optional(),
|
|
4250
|
+
/** An enum's values in declared order; only on kind enum. */
|
|
4251
|
+
values: import_zod8.z.array(EnumValueSchema).optional(),
|
|
4252
|
+
/** A named scalar's one primitive, in place of fields; only on a value-object that declares it. */
|
|
4253
|
+
holds: import_zod8.z.string().optional()
|
|
4222
4254
|
});
|
|
4223
4255
|
SurfaceTypeExportSchema = import_zod8.z.object({
|
|
4224
4256
|
/** The type's public name in the producer's export table. */
|
|
@@ -4323,9 +4355,773 @@ var init_specs = __esm({
|
|
|
4323
4355
|
}
|
|
4324
4356
|
});
|
|
4325
4357
|
|
|
4358
|
+
// src/models/type-grammar.ts
|
|
4359
|
+
function isTypeVocabulary(name) {
|
|
4360
|
+
const lower = name.toLowerCase();
|
|
4361
|
+
return LOWER_PRIMITIVE.has(lower) || LOWER_GENERIC.has(lower) || NOT_NEUTRAL.has(lower) || NONES.has(lower) || lower === "true" || lower === "false" || lower === "number";
|
|
4362
|
+
}
|
|
4363
|
+
function primitiveOf(name) {
|
|
4364
|
+
if (PRIMITIVES.has(name)) return name;
|
|
4365
|
+
const exact = PRIMITIVE_ALIASES.get(name);
|
|
4366
|
+
if (exact) return exact;
|
|
4367
|
+
return LOWER_PRIMITIVE.get(name.toLowerCase());
|
|
4368
|
+
}
|
|
4369
|
+
function genericOf(name) {
|
|
4370
|
+
return GENERIC_ALIASES.get(name) ?? LOWER_GENERIC.get(name.toLowerCase());
|
|
4371
|
+
}
|
|
4372
|
+
function tokenize2(text3) {
|
|
4373
|
+
const out = [];
|
|
4374
|
+
let i = 0;
|
|
4375
|
+
while (i < text3.length) {
|
|
4376
|
+
const c = text3[i];
|
|
4377
|
+
if (/\s/.test(c)) {
|
|
4378
|
+
i++;
|
|
4379
|
+
continue;
|
|
4380
|
+
}
|
|
4381
|
+
if (/[A-Za-z_$]/.test(c)) {
|
|
4382
|
+
let j = i + 1;
|
|
4383
|
+
while (j < text3.length && /[A-Za-z0-9_$-]/.test(text3[j])) j++;
|
|
4384
|
+
while (text3[j - 1] === "-") j--;
|
|
4385
|
+
out.push({ t: "id", v: text3.slice(i, j) });
|
|
4386
|
+
i = j;
|
|
4387
|
+
continue;
|
|
4388
|
+
}
|
|
4389
|
+
if (/[0-9]/.test(c)) {
|
|
4390
|
+
let j = i + 1;
|
|
4391
|
+
while (j < text3.length && /[0-9.]/.test(text3[j])) j++;
|
|
4392
|
+
out.push({ t: "num", v: text3.slice(i, j) });
|
|
4393
|
+
i = j;
|
|
4394
|
+
continue;
|
|
4395
|
+
}
|
|
4396
|
+
if (c === "'" || c === '"' || c === "`") {
|
|
4397
|
+
let j = i + 1;
|
|
4398
|
+
while (j < text3.length && text3[j] !== c) j += text3[j] === "\\" ? 2 : 1;
|
|
4399
|
+
if (j >= text3.length) throw new TypeSyntaxError(`an unterminated string literal at "${text3.slice(i)}"`);
|
|
4400
|
+
out.push({ t: "str", v: text3.slice(i, j + 1) });
|
|
4401
|
+
i = j + 1;
|
|
4402
|
+
continue;
|
|
4403
|
+
}
|
|
4404
|
+
const punct = PUNCTUATION.find((p) => text3.startsWith(p, i));
|
|
4405
|
+
if (!punct) throw new TypeSyntaxError(`"${c}" is not part of any type spelling`);
|
|
4406
|
+
out.push({ t: "p", v: punct });
|
|
4407
|
+
i += punct.length;
|
|
4408
|
+
}
|
|
4409
|
+
return out;
|
|
4410
|
+
}
|
|
4411
|
+
function readRaw(text3) {
|
|
4412
|
+
return new RawParser(tokenize2(text3)).position();
|
|
4413
|
+
}
|
|
4414
|
+
function primitive(name) {
|
|
4415
|
+
return { form: "primitive", name, args: [] };
|
|
4416
|
+
}
|
|
4417
|
+
function optionalOf(inner2) {
|
|
4418
|
+
if (inner2.form === "primitive" && inner2.name === "any") return inner2;
|
|
4419
|
+
if (inner2.form === "optional") throw new TypeProblemError("TYPE_POSITION_INVALID", "a type is made optional twice (T??)", "T?");
|
|
4420
|
+
if (inner2.form === "primitive" && inner2.name === "void") throw new TypeProblemError("TYPE_POSITION_INVALID", "void cannot be optional (void?)", "void");
|
|
4421
|
+
return { form: "optional", args: [inner2] };
|
|
4422
|
+
}
|
|
4423
|
+
function inner(ctx) {
|
|
4424
|
+
return { ...ctx, top: false, voidAllowed: false, omittable: false };
|
|
4425
|
+
}
|
|
4426
|
+
function normalise(node, ctx, notes) {
|
|
4427
|
+
switch (node.k) {
|
|
4428
|
+
case "paren":
|
|
4429
|
+
return normalise(node.inner, ctx, notes);
|
|
4430
|
+
case "async":
|
|
4431
|
+
return asyncOf(node.inner, ctx, notes, "async");
|
|
4432
|
+
case "array":
|
|
4433
|
+
return { form: "list", args: [normalise(node.elem, inner(ctx), notes)] };
|
|
4434
|
+
case "opt":
|
|
4435
|
+
return optionalOf(normalise(node.inner, inner(ctx), notes));
|
|
4436
|
+
case "union":
|
|
4437
|
+
return unionOf(node.members, ctx, notes);
|
|
4438
|
+
case "name":
|
|
4439
|
+
return node.args === void 0 ? bareName(node.name, ctx, notes) : appliedName(node.name, node.args, ctx, notes);
|
|
4440
|
+
case "literal":
|
|
4441
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `${node.text} is a literal value, not a type \u2014 a literal union is not in the grammar`, "an enum type naming the values");
|
|
4442
|
+
case "object":
|
|
4443
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline object shape is not in the grammar", "a named value-object");
|
|
4444
|
+
case "function":
|
|
4445
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline function type is not in the grammar", "a signature type");
|
|
4446
|
+
case "intersection":
|
|
4447
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an intersection (A & B) is not in the grammar", "a named type");
|
|
4448
|
+
case "tuple":
|
|
4449
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a tuple is not in the grammar", "a named value-object");
|
|
4450
|
+
case "operator":
|
|
4451
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${node.op}" is TypeScript's type algebra, not in the grammar`, "a named type");
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
function asyncOf(innerNode, ctx, notes, spelled) {
|
|
4455
|
+
if (!ctx.top || !RETURNS_POSITIONS.has(ctx.position)) {
|
|
4456
|
+
throw new TypeProblemError("TYPE_POSITION_INVALID", `${spelled} may stand only at the top of a returns, not in a ${ctx.position}`);
|
|
4457
|
+
}
|
|
4458
|
+
const read2 = normalise(innerNode, { ...inner(ctx), voidAllowed: true }, notes);
|
|
4459
|
+
return { form: "async", args: [read2] };
|
|
4460
|
+
}
|
|
4461
|
+
function bareName(name, ctx, notes) {
|
|
4462
|
+
const lower = name.toLowerCase();
|
|
4463
|
+
if (NONES.has(name)) {
|
|
4464
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" on its own names no type \u2014 "no value" joins a type as T?`, "T?, or void for a returns that answers nothing");
|
|
4465
|
+
}
|
|
4466
|
+
if (lower === "true" || lower === "false") {
|
|
4467
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `${name} is a literal value, not a type`, "bool, or an enum type naming the values");
|
|
4468
|
+
}
|
|
4469
|
+
if (name === "number" || lower === "number") {
|
|
4470
|
+
if (ctx.looseNumber) return primitive(LOOSE_NUMBER);
|
|
4471
|
+
notes.notNeutral ??= { detail: '"number" does not say whether it holds an integer \u2014 int or float?', replacement: "int or float" };
|
|
4472
|
+
return primitive("float");
|
|
4473
|
+
}
|
|
4474
|
+
const prim = primitiveOf(name);
|
|
4475
|
+
if (prim !== void 0) {
|
|
4476
|
+
if (prim === "void" && !ctx.voidAllowed) {
|
|
4477
|
+
throw new TypeProblemError("TYPE_POSITION_INVALID", `void may stand only as a whole returns (or async void), not in a ${ctx.top ? ctx.position : "collection, union or argument"}`);
|
|
4478
|
+
}
|
|
4479
|
+
return primitive(prim);
|
|
4480
|
+
}
|
|
4481
|
+
if (genericOf(name) !== void 0) {
|
|
4482
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" needs its type arguments`, `${genericOf(name)?.form ?? "list"}<...>`);
|
|
4483
|
+
}
|
|
4484
|
+
const legacy = NOT_NEUTRAL.get(lower);
|
|
4485
|
+
if (legacy !== void 0) {
|
|
4486
|
+
notes.notNeutral ??= { detail: `"${name}" has no neutral meaning`, replacement: legacy };
|
|
4487
|
+
return primitive("any");
|
|
4488
|
+
}
|
|
4489
|
+
return { form: "named", name, args: [] };
|
|
4490
|
+
}
|
|
4491
|
+
function appliedName(name, args, ctx, notes) {
|
|
4492
|
+
const alias = genericOf(name);
|
|
4493
|
+
if (alias !== void 0) {
|
|
4494
|
+
if (args.length !== alias.arity) {
|
|
4495
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes ${alias.arity} type argument${alias.arity === 1 ? "" : "s"}, ${args.length} given`);
|
|
4496
|
+
}
|
|
4497
|
+
if (alias.form === "async") return asyncOf(args[0], ctx, notes, `${name}<...>`);
|
|
4498
|
+
if (alias.form === "optional") return optionalOf(normalise(args[0], inner(ctx), notes));
|
|
4499
|
+
const read2 = args.map((a) => normalise(a, inner(ctx), notes));
|
|
4500
|
+
if (alias.form === "map") assertMapKey(read2[0], args[0]);
|
|
4501
|
+
return { form: alias.form, args: read2 };
|
|
4502
|
+
}
|
|
4503
|
+
if (UTILITY_TYPES.has(name)) {
|
|
4504
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${name}<...>" is a TypeScript utility type, not in the grammar`, "a named type");
|
|
4505
|
+
}
|
|
4506
|
+
if (primitiveOf(name) !== void 0 || NONES.has(name)) {
|
|
4507
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes no type arguments`);
|
|
4508
|
+
}
|
|
4509
|
+
const legacy = NOT_NEUTRAL.get(name.toLowerCase());
|
|
4510
|
+
if (legacy !== void 0) {
|
|
4511
|
+
args.forEach((a) => normalise(a, { ...inner(ctx), voidAllowed: true }, notes));
|
|
4512
|
+
notes.notNeutral ??= { detail: `"${name}<...>" has no neutral meaning`, replacement: legacy };
|
|
4513
|
+
return primitive("any");
|
|
4514
|
+
}
|
|
4515
|
+
return { form: "applied", name, args: args.map((a) => normalise(a, inner(ctx), notes)) };
|
|
4516
|
+
}
|
|
4517
|
+
function assertHoldable(expression) {
|
|
4518
|
+
if (expression.form === "primitive" && HOLDABLE_PRIMITIVES.includes(expression.name ?? "")) return;
|
|
4519
|
+
throw new TypeProblemError(
|
|
4520
|
+
"TYPE_POSITION_INVALID",
|
|
4521
|
+
`a named scalar holds one primitive (${HOLDABLE_PRIMITIVES.join(", ")}), not ${canonicalTypeText(expression)}`,
|
|
4522
|
+
"one of those primitives, or fields for a value-object that holds more than one value"
|
|
4523
|
+
);
|
|
4524
|
+
}
|
|
4525
|
+
function assertMapKey(key, written) {
|
|
4526
|
+
if (key.form === "named") return;
|
|
4527
|
+
if (key.form === "primitive" && (key.name === "string" || key.name === "int" || key.name === LOOSE_NUMBER)) return;
|
|
4528
|
+
if (key.form === "primitive" && key.name === "float" && written.k === "name" && written.name.toLowerCase() === "number") return;
|
|
4529
|
+
throw new TypeProblemError("TYPE_POSITION_INVALID", "a map key must be string, int or an enum", "map<string, V>");
|
|
4530
|
+
}
|
|
4531
|
+
function unionOf(members, ctx, notes) {
|
|
4532
|
+
const nones = members.filter((m) => m.k === "name" && m.args === void 0 && NONES.has(m.name));
|
|
4533
|
+
const rest = members.filter((m) => !(m.k === "name" && m.args === void 0 && NONES.has(m.name)));
|
|
4534
|
+
if (rest.length === 0) throw new TypeProblemError("TYPE_EXPRESSION_INVALID", "a union of nones names no type");
|
|
4535
|
+
if (rest.some((m) => m.k === "literal" || m.k === "name" && m.args === void 0 && /^(true|false)$/i.test(m.name))) {
|
|
4536
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a union of literal values is not in the grammar", "an enum type naming the values");
|
|
4537
|
+
}
|
|
4538
|
+
const memberCtx = inner(ctx);
|
|
4539
|
+
let hasNone = nones.length > 0;
|
|
4540
|
+
const read2 = rest.map((m) => {
|
|
4541
|
+
const e = normalise(m, memberCtx, notes);
|
|
4542
|
+
if (e.form !== "optional") return e;
|
|
4543
|
+
hasNone = true;
|
|
4544
|
+
return e.args[0];
|
|
4545
|
+
});
|
|
4546
|
+
let base;
|
|
4547
|
+
if (read2.length === 1) {
|
|
4548
|
+
base = read2[0];
|
|
4549
|
+
} else {
|
|
4550
|
+
const loose = read2.find((e) => e.form !== "named" && e.form !== "applied");
|
|
4551
|
+
if (loose) {
|
|
4552
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a union may hold only named types \u2014 this one mixes in a primitive or a collection", "a named type (an entity, value-object or enum), or two params");
|
|
4553
|
+
}
|
|
4554
|
+
base = { form: "union", args: read2 };
|
|
4555
|
+
}
|
|
4556
|
+
if (!hasNone) return base;
|
|
4557
|
+
const onlyUndefined = nones.length > 0 && nones.every((n) => n.name === "undefined") && read2.length === rest.length && !rest.some((m) => m.k === "opt");
|
|
4558
|
+
if (ctx.omittable && ctx.top && onlyUndefined) return base;
|
|
4559
|
+
return optionalOf(base);
|
|
4560
|
+
}
|
|
4561
|
+
function canonicalTypeText(expr) {
|
|
4562
|
+
switch (expr.form) {
|
|
4563
|
+
case "primitive":
|
|
4564
|
+
case "named":
|
|
4565
|
+
return expr.name ?? "";
|
|
4566
|
+
case "list":
|
|
4567
|
+
case "set":
|
|
4568
|
+
return `${expr.form}<${canonicalTypeText(expr.args[0])}>`;
|
|
4569
|
+
case "map":
|
|
4570
|
+
return `map<${canonicalTypeText(expr.args[0])}, ${canonicalTypeText(expr.args[1])}>`;
|
|
4571
|
+
case "optional": {
|
|
4572
|
+
const innerText = canonicalTypeText(expr.args[0]);
|
|
4573
|
+
return expr.args[0].form === "union" ? `(${innerText})?` : `${innerText}?`;
|
|
4574
|
+
}
|
|
4575
|
+
case "union":
|
|
4576
|
+
return expr.args.map(canonicalTypeText).join(" | ");
|
|
4577
|
+
case "async":
|
|
4578
|
+
return `async ${canonicalTypeText(expr.args[0])}`;
|
|
4579
|
+
case "applied":
|
|
4580
|
+
return `${expr.name}<${expr.args.map(canonicalTypeText).join(", ")}>`;
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
function typeNamedRefs(expr) {
|
|
4584
|
+
if (expr.form === "named") return [expr.name];
|
|
4585
|
+
const own = expr.form === "applied" ? [expr.name] : [];
|
|
4586
|
+
return [...own, ...expr.args.flatMap(typeNamedRefs)];
|
|
4587
|
+
}
|
|
4588
|
+
function typeIsMany(expr) {
|
|
4589
|
+
if (expr.form === "list" || expr.form === "set" || expr.form === "map") return true;
|
|
4590
|
+
if (expr.form === "optional" || expr.form === "async") return typeIsMany(expr.args[0]);
|
|
4591
|
+
return false;
|
|
4592
|
+
}
|
|
4593
|
+
function contextFor(position, omittable2, looseNumber = false) {
|
|
4594
|
+
return { position, top: true, voidAllowed: RETURNS_POSITIONS.has(position), omittable: omittable2, looseNumber };
|
|
4595
|
+
}
|
|
4596
|
+
function parseTypePosition(text3, position, omittable2 = false) {
|
|
4597
|
+
let raw;
|
|
4598
|
+
try {
|
|
4599
|
+
raw = readRaw(text3);
|
|
4600
|
+
} catch (e) {
|
|
4601
|
+
if (!(e instanceof TypeSyntaxError)) throw e;
|
|
4602
|
+
return { expression: null, canonical: text3, problem: { code: "TYPE_EXPRESSION_INVALID", written: text3, detail: `"${text3}" does not parse as a type: ${e.message}` } };
|
|
4603
|
+
}
|
|
4604
|
+
const notes = {};
|
|
4605
|
+
try {
|
|
4606
|
+
const expression = normalise(raw, contextFor(position, omittable2), notes);
|
|
4607
|
+
if (position === "holds") assertHoldable(expression);
|
|
4608
|
+
const problem = notes.notNeutral ? { code: "TYPE_NOT_NEUTRAL", written: text3, detail: notes.notNeutral.detail, replacement: notes.notNeutral.replacement } : null;
|
|
4609
|
+
return { expression, canonical: canonicalTypeText(expression), problem };
|
|
4610
|
+
} catch (e) {
|
|
4611
|
+
if (!(e instanceof TypeProblemError)) throw e;
|
|
4612
|
+
return {
|
|
4613
|
+
expression: null,
|
|
4614
|
+
canonical: text3,
|
|
4615
|
+
problem: { code: e.code, written: text3, detail: `"${text3}": ${e.detail}`, ...e.replacement ? { replacement: e.replacement } : {} }
|
|
4616
|
+
};
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
function parseTypeExpression(text3, position) {
|
|
4620
|
+
return parseTypePosition(text3, position);
|
|
4621
|
+
}
|
|
4622
|
+
function readCodeAnnotation(annotation, looseNumber) {
|
|
4623
|
+
let raw;
|
|
4624
|
+
try {
|
|
4625
|
+
raw = readRaw(annotation);
|
|
4626
|
+
} catch (e) {
|
|
4627
|
+
if (e instanceof TypeSyntaxError) return null;
|
|
4628
|
+
throw e;
|
|
4629
|
+
}
|
|
4630
|
+
try {
|
|
4631
|
+
return normalise(raw, contextFor("returns", false, looseNumber), {});
|
|
4632
|
+
} catch (e) {
|
|
4633
|
+
if (e instanceof TypeProblemError) return null;
|
|
4634
|
+
throw e;
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
function writtenTypeRefs(text3, position) {
|
|
4638
|
+
const parse = parseTypePosition(text3, position);
|
|
4639
|
+
if (parse.expression && !parse.problem) return typeNamedRefs(parse.expression);
|
|
4640
|
+
try {
|
|
4641
|
+
return rawRefs(readRaw(text3));
|
|
4642
|
+
} catch (e) {
|
|
4643
|
+
if (e instanceof TypeSyntaxError) return [];
|
|
4644
|
+
throw e;
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
function rawRefs(node) {
|
|
4648
|
+
switch (node.k) {
|
|
4649
|
+
case "name": {
|
|
4650
|
+
const own = isTypeVocabulary(node.name) || UTILITY_TYPES.has(node.name) ? [] : [node.name];
|
|
4651
|
+
return [...own, ...(node.args ?? []).flatMap(rawRefs)];
|
|
4652
|
+
}
|
|
4653
|
+
case "array":
|
|
4654
|
+
return rawRefs(node.elem);
|
|
4655
|
+
case "opt":
|
|
4656
|
+
case "paren":
|
|
4657
|
+
case "async":
|
|
4658
|
+
case "operator":
|
|
4659
|
+
return rawRefs(node.inner);
|
|
4660
|
+
case "union":
|
|
4661
|
+
case "intersection":
|
|
4662
|
+
case "object":
|
|
4663
|
+
return node.members.flatMap(rawRefs);
|
|
4664
|
+
case "tuple":
|
|
4665
|
+
return node.elems.flatMap(rawRefs);
|
|
4666
|
+
case "function":
|
|
4667
|
+
return [...node.params.flatMap(rawRefs), ...rawRefs(node.ret)];
|
|
4668
|
+
case "literal":
|
|
4669
|
+
return [];
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
function interfaceCanonicalTypes(intf) {
|
|
4673
|
+
const reader = new Canonicalizer(intf.id, "interface");
|
|
4674
|
+
const methods = (intf.methods ?? []).map((m) => {
|
|
4675
|
+
if (m.signatureFrom !== void 0) return m;
|
|
4676
|
+
const out = { ...m };
|
|
4677
|
+
if (m.params !== void 0) out.params = reader.params(m.params, "param", `methods.${m.name}.params`);
|
|
4678
|
+
if (typeof m.returns === "string") out.returns = reader.read(m.returns, "returns", `methods.${m.name}.returns`);
|
|
4679
|
+
return out;
|
|
4680
|
+
});
|
|
4681
|
+
return { spec: { ...intf, methods }, respellings: reader.respellings, problems: reader.problems };
|
|
4682
|
+
}
|
|
4683
|
+
function typeCanonicalTypes(type) {
|
|
4684
|
+
const reader = new Canonicalizer(type.id, "type");
|
|
4685
|
+
const out = { ...type };
|
|
4686
|
+
if (Array.isArray(type.fields)) {
|
|
4687
|
+
out.fields = type.fields.map((f) => ({ ...f, type: reader.read(f.type, "field", `fields.${f.name}`, !!f.optional) }));
|
|
4688
|
+
}
|
|
4689
|
+
if (Array.isArray(type.methods)) {
|
|
4690
|
+
out.methods = type.methods.map((m) => {
|
|
4691
|
+
const method2 = { ...m };
|
|
4692
|
+
if (m.params !== void 0) method2.params = reader.params(m.params, "type-method-param", `methods.${m.name}.params`);
|
|
4693
|
+
if (typeof m.returns === "string") method2.returns = reader.read(m.returns, "type-method-returns", `methods.${m.name}.returns`);
|
|
4694
|
+
return method2;
|
|
4695
|
+
});
|
|
4696
|
+
}
|
|
4697
|
+
if (type.params !== void 0) out.params = reader.params(type.params, "signature-param", "params");
|
|
4698
|
+
if (typeof type.holds === "string") out.holds = reader.read(type.holds, "holds", "holds");
|
|
4699
|
+
if (typeof type.returns === "string") out.returns = reader.read(type.returns, "signature-returns", "returns");
|
|
4700
|
+
return { spec: out, respellings: reader.respellings, problems: reader.problems };
|
|
4701
|
+
}
|
|
4702
|
+
function namesAnInteger(name) {
|
|
4703
|
+
const words2 = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[\s_\-.]+/).filter(Boolean);
|
|
4704
|
+
return words2.some((word) => INTEGER_WORDS.has(word));
|
|
4705
|
+
}
|
|
4706
|
+
function positionNameOf(path92) {
|
|
4707
|
+
const segments = path92.split(".");
|
|
4708
|
+
const last = segments[segments.length - 1];
|
|
4709
|
+
return last === "returns" && segments.length >= 3 ? segments[segments.length - 2] : last;
|
|
4710
|
+
}
|
|
4711
|
+
function typeProblemIntProposal(problem) {
|
|
4712
|
+
if (problem.code !== "TYPE_NOT_NEUTRAL" || problem.replacement !== "int or float") return null;
|
|
4713
|
+
if (problem.specId === void 0 || problem.kind === void 0 || problem.path === void 0) return null;
|
|
4714
|
+
if (!namesAnInteger(positionNameOf(problem.path))) return null;
|
|
4715
|
+
const parse = parseTypePosition(problem.written.replace(NUMBER_NAME, "int"), "returns");
|
|
4716
|
+
if (!parse.expression || parse.problem) return null;
|
|
4717
|
+
return { specId: problem.specId, kind: problem.kind, path: problem.path, written: problem.written, stored: parse.canonical };
|
|
4718
|
+
}
|
|
4719
|
+
function emptyTypeSpellingFacts() {
|
|
4720
|
+
return { respellings: [], problems: [] };
|
|
4721
|
+
}
|
|
4722
|
+
var PRIMITIVE_TYPES, PRIMITIVES, HOLDABLE_PRIMITIVES, PRIMITIVE_ALIASES, GENERIC_ALIASES, NOT_NEUTRAL, UTILITY_TYPES, NONES, LOWER_PRIMITIVE, LOWER_GENERIC, TypeSyntaxError, PUNCTUATION, RawParser, TypeProblemError, RETURNS_POSITIONS, LOOSE_NUMBER, Canonicalizer, INTEGER_WORDS, NUMBER_NAME;
|
|
4723
|
+
var init_type_grammar = __esm({
|
|
4724
|
+
"src/models/type-grammar.ts"() {
|
|
4725
|
+
"use strict";
|
|
4726
|
+
PRIMITIVE_TYPES = ["string", "int", "float", "bool", "bytes", "date", "datetime", "duration", "void", "any"];
|
|
4727
|
+
PRIMITIVES = new Set(PRIMITIVE_TYPES);
|
|
4728
|
+
HOLDABLE_PRIMITIVES = PRIMITIVE_TYPES.filter((p) => p !== "void" && p !== "any");
|
|
4729
|
+
PRIMITIVE_ALIASES = /* @__PURE__ */ new Map([
|
|
4730
|
+
["boolean", "bool"],
|
|
4731
|
+
["integer", "int"],
|
|
4732
|
+
["long", "int"],
|
|
4733
|
+
["i8", "int"],
|
|
4734
|
+
["i16", "int"],
|
|
4735
|
+
["i32", "int"],
|
|
4736
|
+
["i64", "int"],
|
|
4737
|
+
["i128", "int"],
|
|
4738
|
+
["isize", "int"],
|
|
4739
|
+
["u8", "int"],
|
|
4740
|
+
["u16", "int"],
|
|
4741
|
+
["u32", "int"],
|
|
4742
|
+
["u64", "int"],
|
|
4743
|
+
["u128", "int"],
|
|
4744
|
+
["usize", "int"],
|
|
4745
|
+
["double", "float"],
|
|
4746
|
+
["f32", "float"],
|
|
4747
|
+
["f64", "float"],
|
|
4748
|
+
["Buffer", "bytes"],
|
|
4749
|
+
["Uint8Array", "bytes"],
|
|
4750
|
+
["Date", "datetime"],
|
|
4751
|
+
["timestamp", "datetime"],
|
|
4752
|
+
["object", "any"],
|
|
4753
|
+
["unknown", "any"],
|
|
4754
|
+
["json", "any"],
|
|
4755
|
+
["Json", "any"],
|
|
4756
|
+
["str", "string"]
|
|
4757
|
+
]);
|
|
4758
|
+
GENERIC_ALIASES = /* @__PURE__ */ new Map([
|
|
4759
|
+
["list", { form: "list", arity: 1 }],
|
|
4760
|
+
["Array", { form: "list", arity: 1 }],
|
|
4761
|
+
["ReadonlyArray", { form: "list", arity: 1 }],
|
|
4762
|
+
["List", { form: "list", arity: 1 }],
|
|
4763
|
+
["vec", { form: "list", arity: 1 }],
|
|
4764
|
+
["vector", { form: "list", arity: 1 }],
|
|
4765
|
+
["set", { form: "set", arity: 1 }],
|
|
4766
|
+
["Set", { form: "set", arity: 1 }],
|
|
4767
|
+
["ReadonlySet", { form: "set", arity: 1 }],
|
|
4768
|
+
["map", { form: "map", arity: 2 }],
|
|
4769
|
+
["Map", { form: "map", arity: 2 }],
|
|
4770
|
+
["Record", { form: "map", arity: 2 }],
|
|
4771
|
+
["ReadonlyMap", { form: "map", arity: 2 }],
|
|
4772
|
+
["dict", { form: "map", arity: 2 }],
|
|
4773
|
+
["dictionary", { form: "map", arity: 2 }],
|
|
4774
|
+
["HashMap", { form: "map", arity: 2 }],
|
|
4775
|
+
["Option", { form: "optional", arity: 1 }],
|
|
4776
|
+
["Optional", { form: "optional", arity: 1 }],
|
|
4777
|
+
["Promise", { form: "async", arity: 1 }]
|
|
4778
|
+
]);
|
|
4779
|
+
NOT_NEUTRAL = /* @__PURE__ */ new Map([
|
|
4780
|
+
["uuid", "a named value-object holding a string (e.g. order_id)"],
|
|
4781
|
+
["decimal", "a named value-object (e.g. money), or float"],
|
|
4782
|
+
["char", "string"],
|
|
4783
|
+
["byte", "int, or bytes for binary data"],
|
|
4784
|
+
["time", "datetime for an instant, or duration for an elapsed time"],
|
|
4785
|
+
["tuple", "a named value-object"],
|
|
4786
|
+
["result", "the success type as the returns (failures as findings or throws), or a named value-object"],
|
|
4787
|
+
["error", "a named value-object"],
|
|
4788
|
+
["never", "void"],
|
|
4789
|
+
["box", "the inner type (ownership is an implementation detail)"],
|
|
4790
|
+
["arc", "the inner type (ownership is an implementation detail)"],
|
|
4791
|
+
["rc", "the inner type (ownership is an implementation detail)"],
|
|
4792
|
+
["ref", "the inner type (ownership is an implementation detail)"],
|
|
4793
|
+
["cell", "the inner type (ownership is an implementation detail)"],
|
|
4794
|
+
["refcell", "the inner type (ownership is an implementation detail)"],
|
|
4795
|
+
["mutex", "the inner type (synchronisation is an implementation detail)"],
|
|
4796
|
+
["rwlock", "the inner type (synchronisation is an implementation detail)"],
|
|
4797
|
+
["std", "a named type"],
|
|
4798
|
+
["mcpserver", "a named type"]
|
|
4799
|
+
]);
|
|
4800
|
+
UTILITY_TYPES = /* @__PURE__ */ new Set([
|
|
4801
|
+
"Partial",
|
|
4802
|
+
"Required",
|
|
4803
|
+
"Readonly",
|
|
4804
|
+
"Pick",
|
|
4805
|
+
"Omit",
|
|
4806
|
+
"Exclude",
|
|
4807
|
+
"Extract",
|
|
4808
|
+
"NonNullable",
|
|
4809
|
+
"ReturnType",
|
|
4810
|
+
"Parameters",
|
|
4811
|
+
"InstanceType",
|
|
4812
|
+
"Awaited",
|
|
4813
|
+
"ConstructorParameters",
|
|
4814
|
+
"ThisType",
|
|
4815
|
+
"Uppercase",
|
|
4816
|
+
"Lowercase"
|
|
4817
|
+
]);
|
|
4818
|
+
NONES = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
4819
|
+
LOWER_PRIMITIVE = new Map([
|
|
4820
|
+
...PRIMITIVE_TYPES.map((p) => [p, p]),
|
|
4821
|
+
...[...PRIMITIVE_ALIASES].map(([k, v]) => [k.toLowerCase(), v])
|
|
4822
|
+
]);
|
|
4823
|
+
LOWER_GENERIC = new Map([...GENERIC_ALIASES].map(([k, v]) => [k.toLowerCase(), v]));
|
|
4824
|
+
TypeSyntaxError = class extends Error {
|
|
4825
|
+
};
|
|
4826
|
+
PUNCTUATION = ["...", "::", "=>", "<", ">", ",", "|", "?", "(", ")", "[", "]", "{", "}", ":", "&", ";", "."];
|
|
4827
|
+
RawParser = class {
|
|
4828
|
+
constructor(tokens) {
|
|
4829
|
+
this.tokens = tokens;
|
|
4830
|
+
this.at = 0;
|
|
4831
|
+
}
|
|
4832
|
+
/** type-position: an optional `async` prefix, one type, and nothing after it. */
|
|
4833
|
+
position() {
|
|
4834
|
+
if (this.tokens.length === 0) throw new TypeSyntaxError("the position is empty");
|
|
4835
|
+
const node = this.isAsyncPrefix() ? (this.at++, { k: "async", inner: this.type() }) : this.type();
|
|
4836
|
+
if (this.at < this.tokens.length) throw new TypeSyntaxError(`"${this.rest()}" is left over after the type`);
|
|
4837
|
+
return node;
|
|
4838
|
+
}
|
|
4839
|
+
isAsyncPrefix() {
|
|
4840
|
+
const first = this.tokens[0];
|
|
4841
|
+
const next = this.tokens[1];
|
|
4842
|
+
if (!first || first.t !== "id" || first.v !== "async" || !next) return false;
|
|
4843
|
+
return next.t !== "p" || ["(", "{", "[", "::"].includes(next.v);
|
|
4844
|
+
}
|
|
4845
|
+
rest() {
|
|
4846
|
+
return this.tokens.slice(this.at).map((t) => t.v).join(" ");
|
|
4847
|
+
}
|
|
4848
|
+
peek(offset = 0) {
|
|
4849
|
+
return this.tokens[this.at + offset];
|
|
4850
|
+
}
|
|
4851
|
+
isP(v, offset = 0) {
|
|
4852
|
+
const t = this.peek(offset);
|
|
4853
|
+
return !!t && t.t === "p" && t.v === v;
|
|
4854
|
+
}
|
|
4855
|
+
expect(v) {
|
|
4856
|
+
if (!this.isP(v)) {
|
|
4857
|
+
const got = this.peek();
|
|
4858
|
+
throw new TypeSyntaxError(got ? `expected "${v}" but found "${got.v}"` : `expected "${v}" but the text ended`);
|
|
4859
|
+
}
|
|
4860
|
+
this.at++;
|
|
4861
|
+
}
|
|
4862
|
+
type() {
|
|
4863
|
+
if (this.isP("|")) this.at++;
|
|
4864
|
+
const members = [this.intersection()];
|
|
4865
|
+
while (this.isP("|")) {
|
|
4866
|
+
this.at++;
|
|
4867
|
+
members.push(this.intersection());
|
|
4868
|
+
}
|
|
4869
|
+
return members.length === 1 ? members[0] : { k: "union", members };
|
|
4870
|
+
}
|
|
4871
|
+
intersection() {
|
|
4872
|
+
const members = [this.postfix()];
|
|
4873
|
+
while (this.isP("&")) {
|
|
4874
|
+
this.at++;
|
|
4875
|
+
members.push(this.postfix());
|
|
4876
|
+
}
|
|
4877
|
+
return members.length === 1 ? members[0] : { k: "intersection", members };
|
|
4878
|
+
}
|
|
4879
|
+
postfix() {
|
|
4880
|
+
let node = this.primary();
|
|
4881
|
+
for (; ; ) {
|
|
4882
|
+
if (this.isP("[") && this.isP("]", 1)) {
|
|
4883
|
+
this.at += 2;
|
|
4884
|
+
node = { k: "array", elem: node };
|
|
4885
|
+
} else if (this.isP("?")) {
|
|
4886
|
+
this.at++;
|
|
4887
|
+
node = { k: "opt", inner: node };
|
|
4888
|
+
} else {
|
|
4889
|
+
return node;
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
primary() {
|
|
4894
|
+
const tok = this.peek();
|
|
4895
|
+
if (!tok) throw new TypeSyntaxError("a type was expected but the text ended");
|
|
4896
|
+
if (tok.t === "str" || tok.t === "num") {
|
|
4897
|
+
this.at++;
|
|
4898
|
+
return { k: "literal", text: tok.v };
|
|
4899
|
+
}
|
|
4900
|
+
if (tok.t === "id" && (tok.v === "keyof" || tok.v === "typeof" || tok.v === "unique") && this.peek(1)?.t === "id") {
|
|
4901
|
+
this.at++;
|
|
4902
|
+
return { k: "operator", op: tok.v, inner: this.postfix() };
|
|
4903
|
+
}
|
|
4904
|
+
const next = this.peek(1);
|
|
4905
|
+
if (tok.t === "id" && tok.v === "readonly" && next && (next.t === "id" || next.t === "p" && (next.v === "(" || next.v === "["))) {
|
|
4906
|
+
this.at++;
|
|
4907
|
+
return this.postfix();
|
|
4908
|
+
}
|
|
4909
|
+
if (tok.t === "id" || tok.t === "p" && tok.v === "::") return this.named();
|
|
4910
|
+
if (tok.t === "p" && tok.v === "(") return this.parenOrFunction();
|
|
4911
|
+
if (tok.t === "p" && tok.v === "{") return this.objectShape();
|
|
4912
|
+
if (tok.t === "p" && tok.v === "[") return this.tuple();
|
|
4913
|
+
throw new TypeSyntaxError(`"${tok.v}" cannot start a type`);
|
|
4914
|
+
}
|
|
4915
|
+
ident() {
|
|
4916
|
+
const tok = this.peek();
|
|
4917
|
+
if (!tok || tok.t !== "id") throw new TypeSyntaxError(tok ? `expected a name but found "${tok.v}"` : "expected a name but the text ended");
|
|
4918
|
+
this.at++;
|
|
4919
|
+
return tok.v;
|
|
4920
|
+
}
|
|
4921
|
+
named() {
|
|
4922
|
+
let name = "";
|
|
4923
|
+
if (this.isP("::")) {
|
|
4924
|
+
this.at++;
|
|
4925
|
+
name = "::";
|
|
4926
|
+
}
|
|
4927
|
+
name += this.ident();
|
|
4928
|
+
while (this.isP("::") || this.isP(".")) {
|
|
4929
|
+
const sep18 = this.peek().v;
|
|
4930
|
+
this.at++;
|
|
4931
|
+
name += sep18 + this.ident();
|
|
4932
|
+
}
|
|
4933
|
+
if (!this.isP("<")) return { k: "name", name };
|
|
4934
|
+
this.at++;
|
|
4935
|
+
const args = [this.type()];
|
|
4936
|
+
while (this.isP(",")) {
|
|
4937
|
+
this.at++;
|
|
4938
|
+
args.push(this.type());
|
|
4939
|
+
}
|
|
4940
|
+
this.expect(">");
|
|
4941
|
+
return { k: "name", name, args };
|
|
4942
|
+
}
|
|
4943
|
+
/** The index of the `)` closing the `(` at the cursor, or -1. */
|
|
4944
|
+
closingParen() {
|
|
4945
|
+
let depth = 0;
|
|
4946
|
+
for (let i = this.at; i < this.tokens.length; i++) {
|
|
4947
|
+
const t = this.tokens[i];
|
|
4948
|
+
if (t.t !== "p") continue;
|
|
4949
|
+
if (t.v === "(") depth++;
|
|
4950
|
+
else if (t.v === ")" && --depth === 0) return i;
|
|
4951
|
+
}
|
|
4952
|
+
return -1;
|
|
4953
|
+
}
|
|
4954
|
+
parenOrFunction() {
|
|
4955
|
+
const close2 = this.closingParen();
|
|
4956
|
+
const after = close2 === -1 ? void 0 : this.tokens[close2 + 1];
|
|
4957
|
+
if (!after || after.t !== "p" || after.v !== "=>") {
|
|
4958
|
+
this.expect("(");
|
|
4959
|
+
const inner2 = this.type();
|
|
4960
|
+
this.expect(")");
|
|
4961
|
+
return { k: "paren", inner: inner2 };
|
|
4962
|
+
}
|
|
4963
|
+
this.expect("(");
|
|
4964
|
+
const params = [];
|
|
4965
|
+
while (!this.isP(")")) {
|
|
4966
|
+
if (this.isP("...")) this.at++;
|
|
4967
|
+
this.ident();
|
|
4968
|
+
if (this.isP("?")) this.at++;
|
|
4969
|
+
if (this.isP(":")) {
|
|
4970
|
+
this.at++;
|
|
4971
|
+
params.push(this.type());
|
|
4972
|
+
}
|
|
4973
|
+
if (!this.isP(",")) break;
|
|
4974
|
+
this.at++;
|
|
4975
|
+
}
|
|
4976
|
+
this.expect(")");
|
|
4977
|
+
this.expect("=>");
|
|
4978
|
+
return { k: "function", params, ret: this.type() };
|
|
4979
|
+
}
|
|
4980
|
+
objectShape() {
|
|
4981
|
+
this.expect("{");
|
|
4982
|
+
const members = [];
|
|
4983
|
+
while (!this.isP("}")) {
|
|
4984
|
+
if (this.isP("[")) {
|
|
4985
|
+
this.at++;
|
|
4986
|
+
this.ident();
|
|
4987
|
+
this.expect(":");
|
|
4988
|
+
members.push(this.type());
|
|
4989
|
+
this.expect("]");
|
|
4990
|
+
} else {
|
|
4991
|
+
if (this.peek()?.t === "id" && this.peek().v === "readonly" && this.peek(1)?.t === "id") this.at++;
|
|
4992
|
+
const key = this.peek();
|
|
4993
|
+
if (!key || key.t !== "id" && key.t !== "str" && key.t !== "num") throw new TypeSyntaxError("an inline object member has no name");
|
|
4994
|
+
this.at++;
|
|
4995
|
+
if (this.isP("?")) this.at++;
|
|
4996
|
+
if (this.isP("(")) {
|
|
4997
|
+
members.push(this.parenOrFunctionMember());
|
|
4998
|
+
this.skipSeparator();
|
|
4999
|
+
continue;
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
this.expect(":");
|
|
5003
|
+
members.push(this.type());
|
|
5004
|
+
this.skipSeparator();
|
|
5005
|
+
}
|
|
5006
|
+
this.expect("}");
|
|
5007
|
+
return { k: "object", members };
|
|
5008
|
+
}
|
|
5009
|
+
/** A method member of an inline object: (params): returns. */
|
|
5010
|
+
parenOrFunctionMember() {
|
|
5011
|
+
this.expect("(");
|
|
5012
|
+
const params = [];
|
|
5013
|
+
while (!this.isP(")")) {
|
|
5014
|
+
if (this.isP("...")) this.at++;
|
|
5015
|
+
this.ident();
|
|
5016
|
+
if (this.isP("?")) this.at++;
|
|
5017
|
+
if (this.isP(":")) {
|
|
5018
|
+
this.at++;
|
|
5019
|
+
params.push(this.type());
|
|
5020
|
+
}
|
|
5021
|
+
if (!this.isP(",")) break;
|
|
5022
|
+
this.at++;
|
|
5023
|
+
}
|
|
5024
|
+
this.expect(")");
|
|
5025
|
+
this.expect(":");
|
|
5026
|
+
return { k: "function", params, ret: this.type() };
|
|
5027
|
+
}
|
|
5028
|
+
skipSeparator() {
|
|
5029
|
+
if (this.isP(";") || this.isP(",")) this.at++;
|
|
5030
|
+
}
|
|
5031
|
+
tuple() {
|
|
5032
|
+
this.expect("[");
|
|
5033
|
+
const elems = [];
|
|
5034
|
+
while (!this.isP("]")) {
|
|
5035
|
+
elems.push(this.type());
|
|
5036
|
+
if (!this.isP(",")) break;
|
|
5037
|
+
this.at++;
|
|
5038
|
+
}
|
|
5039
|
+
this.expect("]");
|
|
5040
|
+
return { k: "tuple", elems };
|
|
5041
|
+
}
|
|
5042
|
+
};
|
|
5043
|
+
TypeProblemError = class extends Error {
|
|
5044
|
+
constructor(code, detail, replacement) {
|
|
5045
|
+
super(detail);
|
|
5046
|
+
this.code = code;
|
|
5047
|
+
this.detail = detail;
|
|
5048
|
+
this.replacement = replacement;
|
|
5049
|
+
}
|
|
5050
|
+
};
|
|
5051
|
+
RETURNS_POSITIONS = /* @__PURE__ */ new Set(["returns", "type-method-returns", "signature-returns"]);
|
|
5052
|
+
LOOSE_NUMBER = "number";
|
|
5053
|
+
Canonicalizer = class {
|
|
5054
|
+
constructor(specId, kind) {
|
|
5055
|
+
this.specId = specId;
|
|
5056
|
+
this.kind = kind;
|
|
5057
|
+
this.respellings = [];
|
|
5058
|
+
this.problems = [];
|
|
5059
|
+
}
|
|
5060
|
+
/** One position: its canonical text when it has one, else the text as written, recorded either way. */
|
|
5061
|
+
read(text3, position, path92, omittable2 = false) {
|
|
5062
|
+
const parse = parseTypePosition(text3, position, omittable2);
|
|
5063
|
+
if (parse.problem) {
|
|
5064
|
+
this.problems.push({ ...parse.problem, specId: this.specId, kind: this.kind, path: path92 });
|
|
5065
|
+
return text3;
|
|
5066
|
+
}
|
|
5067
|
+
if (parse.canonical !== text3) this.respellings.push({ specId: this.specId, kind: this.kind, path: path92, written: text3, stored: parse.canonical });
|
|
5068
|
+
return parse.canonical;
|
|
5069
|
+
}
|
|
5070
|
+
params(params, position, prefix) {
|
|
5071
|
+
return params.map((p) => ({ ...p, type: this.read(p.type, position, `${prefix}.${p.name}`, !!p.optional) }));
|
|
5072
|
+
}
|
|
5073
|
+
};
|
|
5074
|
+
INTEGER_WORDS = /* @__PURE__ */ new Set([
|
|
5075
|
+
"count",
|
|
5076
|
+
"counts",
|
|
5077
|
+
"size",
|
|
5078
|
+
"sizes",
|
|
5079
|
+
"length",
|
|
5080
|
+
"len",
|
|
5081
|
+
"limit",
|
|
5082
|
+
"limits",
|
|
5083
|
+
"port",
|
|
5084
|
+
"step",
|
|
5085
|
+
"steps",
|
|
5086
|
+
"index",
|
|
5087
|
+
"idx",
|
|
5088
|
+
"depth",
|
|
5089
|
+
"level",
|
|
5090
|
+
"levels",
|
|
5091
|
+
"days",
|
|
5092
|
+
"day",
|
|
5093
|
+
"hours",
|
|
5094
|
+
"minutes",
|
|
5095
|
+
"seconds",
|
|
5096
|
+
"ms",
|
|
5097
|
+
"millis",
|
|
5098
|
+
"milliseconds",
|
|
5099
|
+
"bytes",
|
|
5100
|
+
"version",
|
|
5101
|
+
"total",
|
|
5102
|
+
"offset",
|
|
5103
|
+
"page",
|
|
5104
|
+
"pages",
|
|
5105
|
+
"retries",
|
|
5106
|
+
"attempts",
|
|
5107
|
+
"number",
|
|
5108
|
+
"num",
|
|
5109
|
+
"line",
|
|
5110
|
+
"lines",
|
|
5111
|
+
"column",
|
|
5112
|
+
"columns",
|
|
5113
|
+
"max",
|
|
5114
|
+
"min",
|
|
5115
|
+
"width",
|
|
5116
|
+
"height"
|
|
5117
|
+
]);
|
|
5118
|
+
NUMBER_NAME = /(?<![\w:.-])number(?![\w:.-])/g;
|
|
5119
|
+
}
|
|
5120
|
+
});
|
|
5121
|
+
|
|
4326
5122
|
// src/models/type-references.ts
|
|
4327
5123
|
function extractTypeIdentifiers(typeStr) {
|
|
4328
|
-
let cleaned = typeStr.replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
5124
|
+
let cleaned = typeStr.replace(/^\s*async\s+(?=\S)/, "").replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
4329
5125
|
cleaned = cleaned.replace(/(?<=\S)\s*\([^)]*\)\s*$/, "");
|
|
4330
5126
|
cleaned = cleaned.replace(/(?<=\S)\s+[-—:]\s+[a-z\s_-]+$/, "");
|
|
4331
5127
|
cleaned = cleaned.replace(/(["'`])(?:\\.|[^\\])*?\1/g, " ");
|
|
@@ -4411,16 +5207,19 @@ function methodTypeRefs(m) {
|
|
|
4411
5207
|
if (m.params && m.params.length > 0) {
|
|
4412
5208
|
const refs = [];
|
|
4413
5209
|
for (const p of m.params) {
|
|
4414
|
-
refs.push(...
|
|
5210
|
+
refs.push(...writtenTypeRefs(p.type, "param"));
|
|
4415
5211
|
}
|
|
4416
|
-
refs.push(...
|
|
5212
|
+
if (m.returns !== void 0) refs.push(...writtenTypeRefs(m.returns, "returns"));
|
|
4417
5213
|
return Array.from(new Set(refs));
|
|
4418
5214
|
}
|
|
4419
5215
|
return extractTypesFromSignature(m.signature ?? "", m.returns ?? "");
|
|
4420
5216
|
}
|
|
4421
5217
|
function signatureTypeRefs(type) {
|
|
4422
5218
|
if (type.kind !== "signature") return [];
|
|
4423
|
-
const refs = [
|
|
5219
|
+
const refs = [
|
|
5220
|
+
...(type.params ?? []).flatMap((p) => writtenTypeRefs(p.type, "signature-param")),
|
|
5221
|
+
...type.returns !== void 0 ? writtenTypeRefs(type.returns, "signature-returns") : []
|
|
5222
|
+
];
|
|
4424
5223
|
return Array.from(new Set(refs));
|
|
4425
5224
|
}
|
|
4426
5225
|
function methodGenericParameters(method2) {
|
|
@@ -4455,85 +5254,117 @@ function typeGenericParameters(type) {
|
|
|
4455
5254
|
}
|
|
4456
5255
|
function fieldTypeRefs(type, fieldType) {
|
|
4457
5256
|
const generics = new Set(Array.from(typeGenericParameters(type)).map((g) => g.toLowerCase()));
|
|
4458
|
-
return
|
|
5257
|
+
return writtenTypeRefs(fieldType, "field").filter((ref) => !generics.has(ref.toLowerCase()));
|
|
4459
5258
|
}
|
|
4460
5259
|
function interfaceGenericParameters(intf) {
|
|
4461
5260
|
return extractTypeGenerics(intf.name);
|
|
4462
5261
|
}
|
|
4463
|
-
var BUILTIN_TYPES;
|
|
4464
5262
|
var init_type_references = __esm({
|
|
4465
5263
|
"src/models/type-references.ts"() {
|
|
4466
5264
|
"use strict";
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
"
|
|
4496
|
-
|
|
4497
|
-
"
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
"
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
"
|
|
4526
|
-
"
|
|
4527
|
-
"
|
|
4528
|
-
"
|
|
4529
|
-
"
|
|
4530
|
-
"
|
|
4531
|
-
"
|
|
4532
|
-
"
|
|
4533
|
-
"
|
|
4534
|
-
"
|
|
4535
|
-
|
|
4536
|
-
|
|
5265
|
+
init_type_grammar();
|
|
5266
|
+
}
|
|
5267
|
+
});
|
|
5268
|
+
|
|
5269
|
+
// src/models/type-dialects.ts
|
|
5270
|
+
function lastSegment(name) {
|
|
5271
|
+
return name.split(/::|\./).filter(Boolean).pop() ?? name;
|
|
5272
|
+
}
|
|
5273
|
+
function sameType(code, spec, codeNames) {
|
|
5274
|
+
if (code.form === "primitive" && code.name === "number") return spec.form === "primitive" && (spec.name === "int" || spec.name === "float");
|
|
5275
|
+
if (code.form === "named" && (spec.form === "named" || spec.form === "applied")) {
|
|
5276
|
+
if (spec.form === "applied") return false;
|
|
5277
|
+
return namesAgree(code.name, spec.name, codeNames);
|
|
5278
|
+
}
|
|
5279
|
+
if (code.form !== spec.form) return false;
|
|
5280
|
+
if (code.form === "primitive") return code.name === spec.name;
|
|
5281
|
+
if (code.form === "applied" && !namesAgree(code.name, spec.name, codeNames)) return false;
|
|
5282
|
+
if (code.args.length !== spec.args.length) return false;
|
|
5283
|
+
return code.args.every((arg, i) => sameType(arg, spec.args[i], codeNames));
|
|
5284
|
+
}
|
|
5285
|
+
function namesAgree(codeName, specName, codeNames) {
|
|
5286
|
+
if (codeName === specName) return true;
|
|
5287
|
+
const mapped = codeNames.get(specName) ?? codeNames.get(lastSegment(specName));
|
|
5288
|
+
return mapped === codeName || mapped === lastSegment(codeName);
|
|
5289
|
+
}
|
|
5290
|
+
function writeTypeScript(expr) {
|
|
5291
|
+
switch (expr.form) {
|
|
5292
|
+
case "primitive":
|
|
5293
|
+
return TS_PRIMITIVES[expr.name ?? ""] ?? expr.name ?? "unknown";
|
|
5294
|
+
case "named":
|
|
5295
|
+
return expr.name ?? "unknown";
|
|
5296
|
+
case "list": {
|
|
5297
|
+
const elem = writeTypeScript(expr.args[0]);
|
|
5298
|
+
return /[|\s]/.test(elem) ? `(${elem})[]` : `${elem}[]`;
|
|
5299
|
+
}
|
|
5300
|
+
case "set":
|
|
5301
|
+
return `Set<${writeTypeScript(expr.args[0])}>`;
|
|
5302
|
+
case "map":
|
|
5303
|
+
return `Record<${writeTypeScript(expr.args[0])}, ${writeTypeScript(expr.args[1])}>`;
|
|
5304
|
+
case "optional":
|
|
5305
|
+
return `${writeTypeScript(expr.args[0])} | null`;
|
|
5306
|
+
case "union":
|
|
5307
|
+
return expr.args.map(writeTypeScript).join(" | ");
|
|
5308
|
+
case "async":
|
|
5309
|
+
return `Promise<${writeTypeScript(expr.args[0])}>`;
|
|
5310
|
+
case "applied":
|
|
5311
|
+
return `${expr.name}<${expr.args.map(writeTypeScript).join(", ")}>`;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
function typeDialectFor(language) {
|
|
5315
|
+
return DIALECTS.get(language.toLowerCase()) ?? null;
|
|
5316
|
+
}
|
|
5317
|
+
var TS_PRIMITIVES, typescriptDialect, DIALECTS;
|
|
5318
|
+
var init_type_dialects = __esm({
|
|
5319
|
+
"src/models/type-dialects.ts"() {
|
|
5320
|
+
"use strict";
|
|
5321
|
+
init_type_grammar();
|
|
5322
|
+
TS_PRIMITIVES = {
|
|
5323
|
+
string: "string",
|
|
5324
|
+
int: "number",
|
|
5325
|
+
float: "number",
|
|
5326
|
+
bool: "boolean",
|
|
5327
|
+
bytes: "Uint8Array",
|
|
5328
|
+
date: "string",
|
|
5329
|
+
datetime: "string",
|
|
5330
|
+
duration: "string",
|
|
5331
|
+
void: "void",
|
|
5332
|
+
any: "unknown"
|
|
5333
|
+
};
|
|
5334
|
+
typescriptDialect = {
|
|
5335
|
+
language: "typescript",
|
|
5336
|
+
read(annotation) {
|
|
5337
|
+
return readCodeAnnotation(annotation, false);
|
|
5338
|
+
},
|
|
5339
|
+
agrees(annotation, expression, codeNames) {
|
|
5340
|
+
const code = readCodeAnnotation(annotation, true);
|
|
5341
|
+
return code !== null && sameType(code, expression, codeNames);
|
|
5342
|
+
},
|
|
5343
|
+
write(expression) {
|
|
5344
|
+
return writeTypeScript(expression);
|
|
5345
|
+
},
|
|
5346
|
+
mappingLines() {
|
|
5347
|
+
return [
|
|
5348
|
+
"string \u2192 string",
|
|
5349
|
+
"int, float \u2192 number",
|
|
5350
|
+
"bool \u2192 boolean",
|
|
5351
|
+
"bytes \u2192 Uint8Array",
|
|
5352
|
+
"date, datetime, duration \u2192 string (ISO 8601)",
|
|
5353
|
+
"any \u2192 unknown",
|
|
5354
|
+
"list<T> \u2192 T[]",
|
|
5355
|
+
"set<T> \u2192 Set<T>",
|
|
5356
|
+
"map<K, V> \u2192 Record<K, V>",
|
|
5357
|
+
"T? \u2192 T | null",
|
|
5358
|
+
"A | B \u2192 A | B",
|
|
5359
|
+
"async T \u2192 Promise<T>",
|
|
5360
|
+
"an enum E \u2192 type E = 'a' | 'b' (a string-literal union alias)",
|
|
5361
|
+
"a named scalar E holding P \u2192 type E = P (an alias of the primitive)"
|
|
5362
|
+
];
|
|
5363
|
+
}
|
|
5364
|
+
};
|
|
5365
|
+
DIALECTS = /* @__PURE__ */ new Map([
|
|
5366
|
+
["typescript", typescriptDialect],
|
|
5367
|
+
["javascript", typescriptDialect]
|
|
4537
5368
|
]);
|
|
4538
5369
|
}
|
|
4539
5370
|
});
|
|
@@ -4834,6 +5665,12 @@ function callSitesOf(facts, fn) {
|
|
|
4834
5665
|
function hasFunctionBody(facts, symbol) {
|
|
4835
5666
|
return callSitesOf(facts, symbol) !== void 0;
|
|
4836
5667
|
}
|
|
5668
|
+
function languageOfSourcePath(sourcePath) {
|
|
5669
|
+
return EXTENSION_LANGUAGE[path12.extname(sourcePath).toLowerCase()];
|
|
5670
|
+
}
|
|
5671
|
+
function dialectOf(facts) {
|
|
5672
|
+
return facts.language ? typeDialectFor(facts.language) : null;
|
|
5673
|
+
}
|
|
4837
5674
|
function resolveImport(fromFile, specifier, knownPaths) {
|
|
4838
5675
|
if (!specifier.startsWith(".")) return void 0;
|
|
4839
5676
|
const joined = pathKey(path12.posix.normalize(path12.posix.join(path12.posix.dirname(fromFile), specifier)));
|
|
@@ -4852,12 +5689,37 @@ function resolveImport(fromFile, specifier, knownPaths) {
|
|
|
4852
5689
|
}
|
|
4853
5690
|
return void 0;
|
|
4854
5691
|
}
|
|
4855
|
-
var path12, NO_DECLARED_TYPES;
|
|
5692
|
+
var path12, NO_DECLARED_TYPES, EXTENSION_LANGUAGE;
|
|
4856
5693
|
var init_code_model = __esm({
|
|
4857
5694
|
"src/models/code-model.ts"() {
|
|
4858
5695
|
"use strict";
|
|
4859
5696
|
path12 = __toESM(require("path"));
|
|
5697
|
+
init_type_dialects();
|
|
4860
5698
|
NO_DECLARED_TYPES = [];
|
|
5699
|
+
EXTENSION_LANGUAGE = {
|
|
5700
|
+
".ts": "typescript",
|
|
5701
|
+
".tsx": "typescript",
|
|
5702
|
+
".mts": "typescript",
|
|
5703
|
+
".cts": "typescript",
|
|
5704
|
+
".js": "javascript",
|
|
5705
|
+
".jsx": "javascript",
|
|
5706
|
+
".mjs": "javascript",
|
|
5707
|
+
".cjs": "javascript",
|
|
5708
|
+
".py": "python",
|
|
5709
|
+
".rs": "rust",
|
|
5710
|
+
".go": "go",
|
|
5711
|
+
".cs": "csharp",
|
|
5712
|
+
".java": "java",
|
|
5713
|
+
".c": "c",
|
|
5714
|
+
".h": "c",
|
|
5715
|
+
".cpp": "cpp",
|
|
5716
|
+
".cc": "cpp",
|
|
5717
|
+
".hpp": "cpp",
|
|
5718
|
+
".rb": "ruby",
|
|
5719
|
+
".php": "php",
|
|
5720
|
+
".kt": "kotlin",
|
|
5721
|
+
".swift": "swift"
|
|
5722
|
+
};
|
|
4861
5723
|
}
|
|
4862
5724
|
});
|
|
4863
5725
|
|
|
@@ -4885,11 +5747,18 @@ function closureTypeOf(snapshot, identifier) {
|
|
|
4885
5747
|
if (matches.length === 1) return matches[0];
|
|
4886
5748
|
return matches.find((def) => nameKey(def.id) === nameKey(ref));
|
|
4887
5749
|
}
|
|
5750
|
+
function renamedRefs(expr, rename) {
|
|
5751
|
+
const args = expr.args.map((a) => renamedRefs(a, rename));
|
|
5752
|
+
return expr.form === "named" || expr.form === "applied" ? { ...expr, name: rename(expr.name), args } : { ...expr, args };
|
|
5753
|
+
}
|
|
4888
5754
|
function canonicalTypeRef(snapshot, typeExpr) {
|
|
5755
|
+
const rename = (identifier) => closureTypeOf(snapshot, identifier)?.id ?? identifier;
|
|
5756
|
+
const parse = parseTypeExpression(typeExpr, "returns");
|
|
5757
|
+
if (parse.expression) return canonicalTypeText(renamedRefs(parse.expression, rename));
|
|
4889
5758
|
return typeExpr.replace(TYPE_IDENTIFIER, (identifier) => {
|
|
4890
5759
|
if (!/[A-Za-z]/.test(identifier)) return identifier;
|
|
4891
|
-
if (
|
|
4892
|
-
return
|
|
5760
|
+
if (isTypeVocabulary(identifier)) return identifier.toLowerCase();
|
|
5761
|
+
return rename(identifier);
|
|
4893
5762
|
});
|
|
4894
5763
|
}
|
|
4895
5764
|
function typeShape(snapshot, def) {
|
|
@@ -4901,7 +5770,9 @@ function typeShape(snapshot, def) {
|
|
|
4901
5770
|
...def.kind === "signature" ? {
|
|
4902
5771
|
params: (def.params ?? []).map((p) => ({ type: canonicalTypeRef(snapshot, p.type), optional: p.optional === true })),
|
|
4903
5772
|
returns: canonicalTypeRef(snapshot, def.returns ?? "unknown")
|
|
4904
|
-
} : {}
|
|
5773
|
+
} : {},
|
|
5774
|
+
...def.kind === "enum" ? { values: (def.values ?? []).map((v) => v.name) } : {},
|
|
5775
|
+
...def.holds !== void 0 ? { holds: canonicalTypeRef(snapshot, def.holds) } : {}
|
|
4905
5776
|
};
|
|
4906
5777
|
}
|
|
4907
5778
|
function typeDefExprs(def) {
|
|
@@ -4978,6 +5849,7 @@ var init_surface_references = __esm({
|
|
|
4978
5849
|
"use strict";
|
|
4979
5850
|
import_crypto = require("crypto");
|
|
4980
5851
|
init_type_references();
|
|
5852
|
+
init_type_grammar();
|
|
4981
5853
|
init_canonical_json();
|
|
4982
5854
|
TYPE_IDENTIFIER = /(?:::)?[A-Za-z0-9_][A-Za-z0-9_-]*(?:(?:::|\.)[A-Za-z0-9_][A-Za-z0-9_-]*)*/g;
|
|
4983
5855
|
}
|
|
@@ -5191,7 +6063,7 @@ var init_project_family = __esm({
|
|
|
5191
6063
|
// src/models/validation-options.ts
|
|
5192
6064
|
function selectsFamily(options, declaresMembers) {
|
|
5193
6065
|
if (options?.family) return true;
|
|
5194
|
-
return declaresMembers && options?.
|
|
6066
|
+
return declaresMembers && options?.memberDepth !== 0;
|
|
5195
6067
|
}
|
|
5196
6068
|
var init_validation_options = __esm({
|
|
5197
6069
|
"src/models/validation-options.ts"() {
|
|
@@ -5210,6 +6082,8 @@ var init_models = __esm({
|
|
|
5210
6082
|
init_template();
|
|
5211
6083
|
init_specs();
|
|
5212
6084
|
init_type_references();
|
|
6085
|
+
init_type_grammar();
|
|
6086
|
+
init_type_dialects();
|
|
5213
6087
|
init_step_graph();
|
|
5214
6088
|
init_step_config();
|
|
5215
6089
|
init_code_model();
|
|
@@ -5959,17 +6833,23 @@ function buildCanvasModel(issues = [], relations) {
|
|
|
5959
6833
|
})),
|
|
5960
6834
|
methods: t.methods.map((m) => ({ name: m.name, signature: m.signature, returns: m.returns, ...m.description ? { description: m.description } : {} })),
|
|
5961
6835
|
...t.kind === "signature" ? { signature: deriveTypeSignature(t) } : {},
|
|
6836
|
+
...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
|
|
6837
|
+
...t.holds !== void 0 ? { holds: t.holds } : {},
|
|
5962
6838
|
usedBy: usedByFor(t),
|
|
5963
6839
|
...t.componentClass ? { componentClass: t.componentClass } : {},
|
|
5964
6840
|
...t.database ? { database: t.database } : {},
|
|
5965
6841
|
...t.table ? { table: t.table } : {},
|
|
5966
6842
|
...t.linkedEntity ? { linkedEntity: t.linkedEntity } : {}
|
|
5967
6843
|
}));
|
|
5968
|
-
const
|
|
6844
|
+
const multiplicity = (field) => {
|
|
6845
|
+
const expression = parseTypeExpression(field.type, "field").expression;
|
|
6846
|
+
if (expression && typeIsMany(expression)) return "*";
|
|
6847
|
+
return field.optional || expression?.form === "optional" ? "0..1" : "1";
|
|
6848
|
+
};
|
|
5969
6849
|
const typeEdges = [];
|
|
5970
6850
|
for (const t of typeSpecs) {
|
|
5971
6851
|
for (const field of t.fields) {
|
|
5972
|
-
const refs = new Set(
|
|
6852
|
+
const refs = new Set(writtenTypeRefs(field.type, "field"));
|
|
5973
6853
|
if (field.references) {
|
|
5974
6854
|
const refStr = field.references;
|
|
5975
6855
|
refs.add(refStr);
|
|
@@ -5984,8 +6864,8 @@ function buildCanvasModel(issues = [], relations) {
|
|
|
5984
6864
|
const qualified = other.subsystem && !other.id.startsWith(`${other.subsystem}::`) ? `${other.subsystem}::${other.id}` : other.id;
|
|
5985
6865
|
return matchTypeRef(ref, qualified);
|
|
5986
6866
|
});
|
|
5987
|
-
if (target && target.id !== t.id) {
|
|
5988
|
-
const card =
|
|
6867
|
+
if (target && target.id !== t.id && target.kind !== "enum" && target.holds === void 0) {
|
|
6868
|
+
const card = multiplicity(field);
|
|
5989
6869
|
if (!typeEdges.some((e) => e.from === t.id && e.to === target.id && e.field === field.name)) {
|
|
5990
6870
|
typeEdges.push({ from: t.id, to: target.id, field: field.name, card });
|
|
5991
6871
|
}
|
|
@@ -7659,7 +8539,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
7659
8539
|
return '';
|
|
7660
8540
|
}
|
|
7661
8541
|
function visibleFields(t) {
|
|
7662
|
-
if (det === 'names') return [];
|
|
8542
|
+
if (det === 'names' || t.values || t.holds) return [];
|
|
7663
8543
|
if (det === 'keys') return t.fields.filter(function (f) { return markerOf(t, f) !== ''; });
|
|
7664
8544
|
return t.fields;
|
|
7665
8545
|
}
|
|
@@ -7704,15 +8584,19 @@ var MODEL = __MODEL_JSON__;
|
|
|
7704
8584
|
var meths = det === 'full' ? t.methods : [];
|
|
7705
8585
|
// A signature type is drawn with its derived text in place of a field list.
|
|
7706
8586
|
var sig = t.signature && det !== 'names' ? t.signature : '';
|
|
7707
|
-
|
|
7708
|
-
var
|
|
8587
|
+
// An enum is drawn with its values in place of a field list.
|
|
8588
|
+
var vals = t.values && det !== 'names' ? t.values : [];
|
|
8589
|
+
// A named scalar is drawn compactly: its name and the primitive it holds.
|
|
8590
|
+
var head = t.name + (t.holds ? ' = ' + t.holds : '') + ' \\u00AB' + t.kind + '\\u00BB';
|
|
8591
|
+
var rows = (sig ? [sig] : []).concat(vals.map(function (v) { return '\\u2022 ' + v.name; }))
|
|
8592
|
+
.concat(fields.map(function (f) { return rowText(t, f); }))
|
|
7709
8593
|
.concat(meths.map(function (m) { return '\\u0192 ' + m.name + '(): ' + m.returns; }));
|
|
7710
8594
|
var longest = head.length + 4;
|
|
7711
8595
|
rows.forEach(function (r) { if (r.length > longest) longest = r.length; });
|
|
7712
8596
|
var plain = rows.length === 0;
|
|
7713
8597
|
var pw = Math.max(170, head.length * 6.8 + 26);
|
|
7714
8598
|
var W = Math.max(210, Math.min(400, longest * 6.6 + 30));
|
|
7715
|
-
return { fields: fields, meths: meths, sig: sig, head: head, plain: plain, w: plain ? pw : W, h: plain ? 40 : TH_H + (sig ? ROW_H : 0) + fields.length * ROW_H + meths.length * ROW_H };
|
|
8599
|
+
return { fields: fields, meths: meths, sig: sig, vals: vals, head: head, plain: plain, w: plain ? pw : W, h: plain ? 40 : TH_H + (sig ? ROW_H : 0) + vals.length * ROW_H + fields.length * ROW_H + meths.length * ROW_H };
|
|
7716
8600
|
}
|
|
7717
8601
|
|
|
7718
8602
|
// Emit one type table with its top-left at (ax, ay); returns its size.
|
|
@@ -7743,6 +8627,13 @@ var MODEL = __MODEL_JSON__;
|
|
|
7743
8627
|
});
|
|
7744
8628
|
ry += ROW_H;
|
|
7745
8629
|
}
|
|
8630
|
+
sh.vals.forEach(function (v, vi) {
|
|
8631
|
+
eles.push({
|
|
8632
|
+
data: { id: 'TV~' + t.id + '~' + vi, parent: 'T~' + t.id, label: '\\u2022 ' + v.name, w: sh.w, h: ROW_H, tw: sh.w - 14 },
|
|
8633
|
+
position: { x: ax + sh.w / 2, y: ry + ROW_H / 2 }, classes: 'typeRow' + (dim ? ' dimmed' : ''), grabbable: false,
|
|
8634
|
+
});
|
|
8635
|
+
ry += ROW_H;
|
|
8636
|
+
});
|
|
7746
8637
|
sh.fields.forEach(function (f) {
|
|
7747
8638
|
var rid = 'TF~' + t.id + '~' + f.name;
|
|
7748
8639
|
rowIds[rid] = 1;
|
|
@@ -10276,6 +11167,17 @@ var MODEL = __MODEL_JSON__;
|
|
|
10276
11167
|
: '<span class="desc">no fields</span>';
|
|
10277
11168
|
if (ty.signature) {
|
|
10278
11169
|
body += section('Signature', 1, '<div class="method"><code>' + esc(ty.signature) + '</code></div>', true);
|
|
11170
|
+
} else if (ty.holds) {
|
|
11171
|
+
body += section('Holds', 1, '<div class="method"><code>' + esc(ty.holds) + '</code>'
|
|
11172
|
+
+ '<div class="mdesc">A named scalar: one ' + esc(ty.holds) + ' under this name.</div></div>', true);
|
|
11173
|
+
} else if (ty.values) {
|
|
11174
|
+
body += section('Values', ty.values.length, ty.values.length
|
|
11175
|
+
? ty.values.map(function (v) {
|
|
11176
|
+
return '<div class="method"><div class="mname">' + esc(v.name) + '</div>'
|
|
11177
|
+
+ (v.description ? '<div class="mdesc">' + esc(v.description) + '</div>' : '')
|
|
11178
|
+
+ '</div>';
|
|
11179
|
+
}).join('')
|
|
11180
|
+
: '<span class="desc">no values</span>', true);
|
|
10279
11181
|
} else {
|
|
10280
11182
|
body += section('Fields', ty.fields.length, fieldsInner, true);
|
|
10281
11183
|
}
|
|
@@ -10602,21 +11504,66 @@ var init_externals = __esm({
|
|
|
10602
11504
|
});
|
|
10603
11505
|
|
|
10604
11506
|
// src/core/openapi.ts
|
|
10605
|
-
function
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
11507
|
+
function expressionOf(typeRef) {
|
|
11508
|
+
return parseTypeExpression(typeRef.trim(), "returns").expression;
|
|
11509
|
+
}
|
|
11510
|
+
function closureHit(name, closureIds) {
|
|
11511
|
+
const local = name.split(/::|\./).pop().toLowerCase().replace(/[^a-z0-9_-]/g, "");
|
|
11512
|
+
return [...closureIds].find((id) => id.toLowerCase() === local);
|
|
11513
|
+
}
|
|
11514
|
+
function schemaOfExpression(expr, closureIds) {
|
|
11515
|
+
switch (expr.form) {
|
|
11516
|
+
case "primitive":
|
|
11517
|
+
return { ...PRIMITIVE_SCHEMAS[expr.name ?? ""] ?? {} };
|
|
11518
|
+
case "named":
|
|
11519
|
+
case "applied": {
|
|
11520
|
+
const hit = closureHit(expr.name ?? "", closureIds);
|
|
11521
|
+
return hit ? { $ref: `#/components/schemas/${hit}` } : { description: `Unresolved type: ${expr.name}` };
|
|
11522
|
+
}
|
|
11523
|
+
case "list":
|
|
11524
|
+
return { type: "array", items: schemaOfExpression(expr.args[0], closureIds) };
|
|
11525
|
+
case "set":
|
|
11526
|
+
return { type: "array", uniqueItems: true, items: schemaOfExpression(expr.args[0], closureIds) };
|
|
11527
|
+
case "map": {
|
|
11528
|
+
const key = expr.args[0];
|
|
11529
|
+
const keyHit = key.form === "named" ? closureHit(key.name ?? "", closureIds) : void 0;
|
|
11530
|
+
const propertyNames = keyHit ? { propertyNames: { $ref: `#/components/schemas/${keyHit}` } } : key.form === "primitive" && key.name === "int" ? { propertyNames: { pattern: "^-?[0-9]+$" } } : {};
|
|
11531
|
+
return { type: "object", ...propertyNames, additionalProperties: schemaOfExpression(expr.args[1], closureIds) };
|
|
11532
|
+
}
|
|
11533
|
+
case "optional": {
|
|
11534
|
+
const inner2 = schemaOfExpression(expr.args[0], closureIds);
|
|
11535
|
+
if (Object.keys(inner2).length === 0) return inner2;
|
|
11536
|
+
if (typeof inner2.type === "string") return { ...inner2, type: [inner2.type, "null"] };
|
|
11537
|
+
return { anyOf: [inner2, { type: "null" }] };
|
|
11538
|
+
}
|
|
11539
|
+
case "union":
|
|
11540
|
+
return { oneOf: expr.args.map((member) => schemaOfExpression(member, closureIds)) };
|
|
11541
|
+
case "async":
|
|
11542
|
+
return schemaOfExpression(expr.args[0], closureIds);
|
|
10610
11543
|
}
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
11544
|
+
}
|
|
11545
|
+
function schemaFor(typeRef, closureIds) {
|
|
11546
|
+
const expr = expressionOf(typeRef);
|
|
11547
|
+
if (!expr) return { description: `Not a canonical type expression: ${typeRef.trim()}` };
|
|
11548
|
+
return schemaOfExpression(expr, closureIds);
|
|
11549
|
+
}
|
|
11550
|
+
function returnsNothing(returns) {
|
|
11551
|
+
const expr = expressionOf(returns);
|
|
11552
|
+
const inner2 = expr?.form === "async" ? expr.args[0] : expr;
|
|
11553
|
+
return inner2?.form === "primitive" && inner2.name === "void";
|
|
11554
|
+
}
|
|
11555
|
+
function enumDescription(values) {
|
|
11556
|
+
return ["Values:", ...values.map((v) => `- \`${v.name}\`${v.description ? `: ${v.description}` : ""}`)].join("\n");
|
|
11557
|
+
}
|
|
11558
|
+
function enumValuesFrom(schema) {
|
|
11559
|
+
const described = /* @__PURE__ */ new Map();
|
|
11560
|
+
if (typeof schema.description === "string") {
|
|
11561
|
+
for (const line2 of schema.description.split("\n")) {
|
|
11562
|
+
const m = /^- `([^`]+)`: (.+)$/.exec(line2.trim());
|
|
11563
|
+
if (m) described.set(m[1], m[2]);
|
|
11564
|
+
}
|
|
10615
11565
|
}
|
|
10616
|
-
|
|
10617
|
-
const hit = [...closureIds].find((id) => id.toLowerCase() === local);
|
|
10618
|
-
if (hit) return { $ref: `#/components/schemas/${hit}` };
|
|
10619
|
-
return { type: "object", description: `Unresolved type: ${trimmed}` };
|
|
11566
|
+
return schema.enum.filter((v) => typeof v === "string" && v.length > 0).map((name) => ({ name, ...described.has(name) ? { description: described.get(name) } : {} }));
|
|
10620
11567
|
}
|
|
10621
11568
|
function operationFor(method2, closureIds) {
|
|
10622
11569
|
const endpoint = method2.endpoint;
|
|
@@ -10629,7 +11576,7 @@ function operationFor(method2, closureIds) {
|
|
|
10629
11576
|
responses: {
|
|
10630
11577
|
"200": {
|
|
10631
11578
|
description: method2.returns || "Success",
|
|
10632
|
-
...method2.returns && method2.returns
|
|
11579
|
+
...method2.returns && !returnsNothing(method2.returns) ? { content: { "application/json": { schema: schemaFor(method2.returns, closureIds) } } } : {}
|
|
10633
11580
|
}
|
|
10634
11581
|
}
|
|
10635
11582
|
};
|
|
@@ -10664,7 +11611,7 @@ function operationFor(method2, closureIds) {
|
|
|
10664
11611
|
}
|
|
10665
11612
|
function signatureComponent(t, closureIds) {
|
|
10666
11613
|
const params = t.params ?? [];
|
|
10667
|
-
const returns = t.returns ?? "
|
|
11614
|
+
const returns = t.returns ?? "any";
|
|
10668
11615
|
const text3 = `(${params.map((p) => `${p.name}${p.optional ? "?" : ""}: ${p.type}`).join(", ")}): ${returns}`;
|
|
10669
11616
|
return {
|
|
10670
11617
|
title: t.name,
|
|
@@ -10689,9 +11636,7 @@ function signatureFromComponent(id, schema) {
|
|
|
10689
11636
|
const ext = raw;
|
|
10690
11637
|
const typeOf = (entry) => {
|
|
10691
11638
|
if (typeof entry.type === "string" && entry.type.trim()) return entry.type;
|
|
10692
|
-
|
|
10693
|
-
if (schema2 && typeof schema2 === "object" && Object.keys(schema2).length === 0) return "unknown";
|
|
10694
|
-
return typeRefFromSchema(schema2);
|
|
11639
|
+
return typeRefFromSchema(entry.schema);
|
|
10695
11640
|
};
|
|
10696
11641
|
const params = (Array.isArray(ext.params) ? ext.params : []).filter((p) => !!p && typeof p === "object" && typeof p.name === "string").map((p) => ({
|
|
10697
11642
|
name: p.name,
|
|
@@ -10699,7 +11644,7 @@ function signatureFromComponent(id, schema) {
|
|
|
10699
11644
|
...p.optional === true ? { optional: true } : {},
|
|
10700
11645
|
...typeof p.description === "string" ? { description: p.description } : {}
|
|
10701
11646
|
}));
|
|
10702
|
-
const returns = ext.returns && typeof ext.returns === "object" && !Array.isArray(ext.returns) ? typeOf(ext.returns) : "
|
|
11647
|
+
const returns = ext.returns && typeof ext.returns === "object" && !Array.isArray(ext.returns) ? typeOf(ext.returns) : "any";
|
|
10703
11648
|
return { id, name: typeof schema.title === "string" ? schema.title : id, kind: "signature", fields: [], params, returns };
|
|
10704
11649
|
}
|
|
10705
11650
|
function securitySchemeObject(auth) {
|
|
@@ -10773,6 +11718,15 @@ function renderDoc(snapshot, entries, closureIds, opts = {}) {
|
|
|
10773
11718
|
}
|
|
10774
11719
|
const schemas = {};
|
|
10775
11720
|
for (const t of snapshot.types) {
|
|
11721
|
+
if (t.kind === "enum") {
|
|
11722
|
+
const values = t.values ?? [];
|
|
11723
|
+
schemas[t.id] = { type: "string", title: t.name, enum: values.map((v) => v.name), description: enumDescription(values) };
|
|
11724
|
+
continue;
|
|
11725
|
+
}
|
|
11726
|
+
if (t.holds !== void 0) {
|
|
11727
|
+
schemas[t.id] = { ...schemaFor(t.holds, closureIds), title: t.name };
|
|
11728
|
+
continue;
|
|
11729
|
+
}
|
|
10776
11730
|
schemas[t.id] = t.kind === "signature" ? signatureComponent(t, closureIds) : {
|
|
10777
11731
|
type: "object",
|
|
10778
11732
|
title: t.name,
|
|
@@ -10824,17 +11778,73 @@ function isOpenApiDocument(body) {
|
|
|
10824
11778
|
return false;
|
|
10825
11779
|
}
|
|
10826
11780
|
}
|
|
11781
|
+
function isNullSchema(schema) {
|
|
11782
|
+
return !!schema && typeof schema === "object" && schema.type === "null";
|
|
11783
|
+
}
|
|
11784
|
+
function isTopLevelUnion(text3) {
|
|
11785
|
+
let depth = 0;
|
|
11786
|
+
for (const ch of text3) {
|
|
11787
|
+
if (ch === "<" || ch === "(") depth++;
|
|
11788
|
+
else if (ch === ">" || ch === ")") depth--;
|
|
11789
|
+
else if (ch === "|" && depth === 0) return true;
|
|
11790
|
+
}
|
|
11791
|
+
return false;
|
|
11792
|
+
}
|
|
10827
11793
|
function typeRefFromSchema(schema) {
|
|
10828
|
-
if (!schema) return "
|
|
11794
|
+
if (!schema || typeof schema !== "object") return "any";
|
|
10829
11795
|
const ref = schema.$ref;
|
|
10830
|
-
if (typeof ref === "string") return ref.split("/").pop() ?? "
|
|
10831
|
-
|
|
10832
|
-
|
|
11796
|
+
if (typeof ref === "string") return ref.split("/").pop() ?? "any";
|
|
11797
|
+
for (const key of ["anyOf", "oneOf"]) {
|
|
11798
|
+
const members = schema[key];
|
|
11799
|
+
if (!Array.isArray(members) || members.length === 0) continue;
|
|
11800
|
+
const nullable = members.some(isNullSchema);
|
|
11801
|
+
const texts = members.filter((m) => !isNullSchema(m)).map((m) => typeRefFromSchema(m));
|
|
11802
|
+
if (texts.length === 0 || texts.includes("any")) return "any";
|
|
11803
|
+
const text3 = texts.join(" | ");
|
|
11804
|
+
if (!nullable) return text3;
|
|
11805
|
+
return isTopLevelUnion(text3) ? `(${text3})?` : `${text3}?`;
|
|
10833
11806
|
}
|
|
10834
11807
|
const t = schema.type;
|
|
11808
|
+
if (Array.isArray(t)) {
|
|
11809
|
+
const types = t.filter((x) => typeof x === "string");
|
|
11810
|
+
const nonNull = types.filter((x) => x !== "null");
|
|
11811
|
+
if (nonNull.length !== 1) return "any";
|
|
11812
|
+
const inner2 = typeRefFromSchema({ ...schema, type: nonNull[0] });
|
|
11813
|
+
return types.includes("null") && inner2 !== "any" ? `${inner2}?` : inner2;
|
|
11814
|
+
}
|
|
11815
|
+
if (t === "array") {
|
|
11816
|
+
const elem = typeRefFromSchema(schema.items);
|
|
11817
|
+
return schema.uniqueItems === true ? `set<${elem}>` : `list<${elem}>`;
|
|
11818
|
+
}
|
|
10835
11819
|
if (t === "integer") return "int";
|
|
10836
|
-
if (
|
|
10837
|
-
return "
|
|
11820
|
+
if (t === "number") return "float";
|
|
11821
|
+
if (t === "boolean") return "bool";
|
|
11822
|
+
if (t === "string") {
|
|
11823
|
+
if (schema.format === "date") return "date";
|
|
11824
|
+
if (schema.format === "date-time") return "datetime";
|
|
11825
|
+
if (schema.format === "duration") return "duration";
|
|
11826
|
+
if (schema.contentEncoding === "base64" || schema.format === "byte" || schema.format === "binary") return "bytes";
|
|
11827
|
+
return "string";
|
|
11828
|
+
}
|
|
11829
|
+
if (t === "object" || t === void 0) {
|
|
11830
|
+
const additional = schema.additionalProperties;
|
|
11831
|
+
if (additional && typeof additional === "object") {
|
|
11832
|
+
const names = schema.propertyNames;
|
|
11833
|
+
const key = names && typeof names.$ref === "string" ? typeRefFromSchema(names) : names && typeof names.pattern === "string" && names.pattern.includes("[0-9]") ? "int" : "string";
|
|
11834
|
+
return `map<${key}, ${typeRefFromSchema(additional)}>`;
|
|
11835
|
+
}
|
|
11836
|
+
if (additional === true) return "map<string, any>";
|
|
11837
|
+
}
|
|
11838
|
+
return "any";
|
|
11839
|
+
}
|
|
11840
|
+
function inlineEnumNote(schema) {
|
|
11841
|
+
if (!schema || schema.$ref !== void 0 || !Array.isArray(schema.enum)) return void 0;
|
|
11842
|
+
const values = schema.enum.filter((v) => typeof v === "string" || typeof v === "number");
|
|
11843
|
+
return values.length ? `One of: ${values.join(", ")}.` : void 0;
|
|
11844
|
+
}
|
|
11845
|
+
function describedWith(description, note) {
|
|
11846
|
+
const text3 = [description, note].filter((x) => !!x).join(" ");
|
|
11847
|
+
return text3 ? { description: text3 } : {};
|
|
10838
11848
|
}
|
|
10839
11849
|
function authFromSecurityScheme(scheme) {
|
|
10840
11850
|
const desc = typeof scheme.description === "string" ? { description: scheme.description } : {};
|
|
@@ -10889,11 +11899,12 @@ function fromOpenApi(document, projectName) {
|
|
|
10889
11899
|
const params = [];
|
|
10890
11900
|
for (const p of op.parameters ?? []) {
|
|
10891
11901
|
if (typeof p.name !== "string") continue;
|
|
11902
|
+
const schema = p.schema;
|
|
10892
11903
|
params.push({
|
|
10893
11904
|
name: p.name,
|
|
10894
|
-
type: typeRefFromSchema(
|
|
11905
|
+
type: typeRefFromSchema(schema),
|
|
10895
11906
|
...p.required === true ? {} : { optional: true },
|
|
10896
|
-
...typeof p.description === "string" ?
|
|
11907
|
+
...describedWith(typeof p.description === "string" ? p.description : void 0, inlineEnumNote(schema))
|
|
10897
11908
|
});
|
|
10898
11909
|
}
|
|
10899
11910
|
const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
|
|
@@ -10902,7 +11913,12 @@ function fromOpenApi(document, projectName) {
|
|
|
10902
11913
|
const required = new Set(bodySchema.required ?? []);
|
|
10903
11914
|
if (Object.keys(props).length) {
|
|
10904
11915
|
for (const [pname, pschema] of Object.entries(props)) {
|
|
10905
|
-
params.push({
|
|
11916
|
+
params.push({
|
|
11917
|
+
name: pname,
|
|
11918
|
+
type: typeRefFromSchema(pschema),
|
|
11919
|
+
...required.has(pname) ? {} : { optional: true },
|
|
11920
|
+
...describedWith(typeof pschema.description === "string" ? pschema.description : void 0, inlineEnumNote(pschema))
|
|
11921
|
+
});
|
|
10906
11922
|
}
|
|
10907
11923
|
} else {
|
|
10908
11924
|
params.push({ name: "body", type: typeRefFromSchema(bodySchema) });
|
|
@@ -10938,6 +11954,14 @@ function fromOpenApi(document, projectName) {
|
|
|
10938
11954
|
types.push(signature);
|
|
10939
11955
|
continue;
|
|
10940
11956
|
}
|
|
11957
|
+
if (schema.type === "string" && Array.isArray(schema.enum)) {
|
|
11958
|
+
types.push({ id, name: typeof schema.title === "string" ? schema.title : id, kind: "enum", fields: [], values: enumValuesFrom(schema) });
|
|
11959
|
+
continue;
|
|
11960
|
+
}
|
|
11961
|
+
if (typeof schema.type === "string" && SCALAR_SCHEMA_TYPES.has(schema.type) && schema.properties === void 0) {
|
|
11962
|
+
types.push({ id, name: typeof schema.title === "string" ? schema.title : id, kind: "value-object", fields: [], holds: typeRefFromSchema(schema) });
|
|
11963
|
+
continue;
|
|
11964
|
+
}
|
|
10941
11965
|
const props = schema.properties ?? {};
|
|
10942
11966
|
const required = new Set(schema.required ?? []);
|
|
10943
11967
|
types.push({
|
|
@@ -10974,31 +11998,26 @@ function fromOpenApi(document, projectName) {
|
|
|
10974
11998
|
types
|
|
10975
11999
|
});
|
|
10976
12000
|
}
|
|
10977
|
-
var yaml2,
|
|
12001
|
+
var yaml2, PRIMITIVE_SCHEMAS, SIGNATURE_EXTENSION, SCALAR_SCHEMA_TYPES;
|
|
10978
12002
|
var init_openapi = __esm({
|
|
10979
12003
|
"src/core/openapi.ts"() {
|
|
10980
12004
|
"use strict";
|
|
10981
12005
|
yaml2 = __toESM(require("js-yaml"));
|
|
10982
12006
|
init_models();
|
|
10983
|
-
|
|
12007
|
+
PRIMITIVE_SCHEMAS = {
|
|
10984
12008
|
string: { type: "string" },
|
|
10985
|
-
number: { type: "number" },
|
|
10986
|
-
float: { type: "number" },
|
|
10987
|
-
decimal: { type: "number" },
|
|
10988
12009
|
int: { type: "integer" },
|
|
10989
|
-
|
|
10990
|
-
boolean: { type: "boolean" },
|
|
12010
|
+
float: { type: "number" },
|
|
10991
12011
|
bool: { type: "boolean" },
|
|
10992
|
-
|
|
12012
|
+
bytes: { type: "string", contentEncoding: "base64" },
|
|
12013
|
+
date: { type: "string", format: "date" },
|
|
10993
12014
|
datetime: { type: "string", format: "date-time" },
|
|
10994
|
-
|
|
10995
|
-
json: { type: "object" },
|
|
10996
|
-
object: { type: "object" },
|
|
12015
|
+
duration: { type: "string", format: "duration" },
|
|
10997
12016
|
any: {},
|
|
10998
|
-
unknown: {},
|
|
10999
12017
|
void: {}
|
|
11000
12018
|
};
|
|
11001
12019
|
SIGNATURE_EXTENSION = "x-wairon-signature";
|
|
12020
|
+
SCALAR_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "integer", "number", "boolean"]);
|
|
11002
12021
|
}
|
|
11003
12022
|
});
|
|
11004
12023
|
|
|
@@ -11027,7 +12046,7 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
11027
12046
|
queue.push(key);
|
|
11028
12047
|
};
|
|
11029
12048
|
const enqueueRef = (ref) => {
|
|
11030
|
-
if (
|
|
12049
|
+
if (isTypeVocabulary(ref)) return;
|
|
11031
12050
|
for (const spec of types) {
|
|
11032
12051
|
if (matchTypeRef(ref, qualifiedTypeId2(spec))) include(spec);
|
|
11033
12052
|
}
|
|
@@ -11041,13 +12060,13 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
11041
12060
|
while (queue.length) {
|
|
11042
12061
|
const spec = included.get(queue.shift());
|
|
11043
12062
|
for (const field of spec.fields) {
|
|
11044
|
-
for (const ref of
|
|
12063
|
+
for (const ref of writtenTypeRefs(field.type, "field")) enqueueRef(ref);
|
|
11045
12064
|
}
|
|
11046
12065
|
for (const param of spec.params ?? []) {
|
|
11047
|
-
for (const ref of
|
|
12066
|
+
for (const ref of writtenTypeRefs(param.type, "signature-param")) enqueueRef(ref);
|
|
11048
12067
|
}
|
|
11049
12068
|
if (spec.returns) {
|
|
11050
|
-
for (const ref of
|
|
12069
|
+
for (const ref of writtenTypeRefs(spec.returns, "signature-returns")) enqueueRef(ref);
|
|
11051
12070
|
}
|
|
11052
12071
|
}
|
|
11053
12072
|
const usedIds = /* @__PURE__ */ new Set();
|
|
@@ -11066,7 +12085,11 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
11066
12085
|
kind: t.kind,
|
|
11067
12086
|
fields: t.fields.map(describe3),
|
|
11068
12087
|
// A signature type travels complete: its params and returns with it.
|
|
11069
|
-
...t.kind === "signature" ? { params: (t.params ?? []).map(describe3), returns: t.returns ?? "
|
|
12088
|
+
...t.kind === "signature" ? { params: (t.params ?? []).map(describe3), returns: t.returns ?? "any" } : {},
|
|
12089
|
+
// An enum travels with its values, in declared order.
|
|
12090
|
+
...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
|
|
12091
|
+
// A named scalar travels with the primitive it holds.
|
|
12092
|
+
...t.holds !== void 0 ? { holds: t.holds } : {}
|
|
11070
12093
|
};
|
|
11071
12094
|
});
|
|
11072
12095
|
}
|
|
@@ -11810,7 +12833,7 @@ function depthOf(family, node) {
|
|
|
11810
12833
|
return depth;
|
|
11811
12834
|
}
|
|
11812
12835
|
function selectProjects(family, options) {
|
|
11813
|
-
const limit =
|
|
12836
|
+
const limit = options.memberDepth ?? Infinity;
|
|
11814
12837
|
const nodes = family.nodes.filter((n) => depthOf(family, n) <= limit);
|
|
11815
12838
|
const scope = options.scopeSubsystem;
|
|
11816
12839
|
if (!scope) return nodes.map((node) => ({ node }));
|
|
@@ -12617,7 +13640,7 @@ function globalPacksEnabled(config) {
|
|
|
12617
13640
|
return config.extensions?.useGlobalPacks ?? GLOBAL_PACKS_DEFAULT;
|
|
12618
13641
|
}
|
|
12619
13642
|
function emptyExtensions() {
|
|
12620
|
-
return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
|
|
13643
|
+
return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [], deprecations: [] };
|
|
12621
13644
|
}
|
|
12622
13645
|
function globalPacksDir() {
|
|
12623
13646
|
return process.env.WAIRON_PACKS_DIR ?? path19.join(os4.homedir(), ".wairon", "packs");
|
|
@@ -12678,11 +13701,11 @@ function mergePack(out, pack, ref, scope, packDir) {
|
|
|
12678
13701
|
Object.assign(out.profiles, pack.profiles);
|
|
12679
13702
|
for (const [lang, def] of Object.entries(pack.languages)) {
|
|
12680
13703
|
const key = lang.toLowerCase();
|
|
13704
|
+
if (def.foreignBuiltins !== void 0) {
|
|
13705
|
+
out.deprecations.push(`${pack.name}: languages.${lang}.foreignBuiltins \u2014 ${FOREIGN_BUILTINS_RETIRED}`);
|
|
13706
|
+
}
|
|
12681
13707
|
const existing = out.languages[key];
|
|
12682
|
-
out.languages[key] = existing
|
|
12683
|
-
unsupportedFlow: { ...existing.unsupportedFlow, ...def.unsupportedFlow },
|
|
12684
|
-
foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
|
|
12685
|
-
} : def;
|
|
13708
|
+
out.languages[key] = { unsupportedFlow: { ...existing?.unsupportedFlow, ...def.unsupportedFlow } };
|
|
12686
13709
|
}
|
|
12687
13710
|
for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path19.resolve(packDir, s.source) });
|
|
12688
13711
|
for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
|
|
@@ -12973,7 +13996,7 @@ function findBundledPack(projectRoot2, selection) {
|
|
|
12973
13996
|
}
|
|
12974
13997
|
return best?.dir ?? null;
|
|
12975
13998
|
}
|
|
12976
|
-
var fs14, os4, path19, import_module, import_zod9, ProfileDefSchema, LanguagePackDefSchema, PackSkillSchema, PackInstructionBlockSchema, PackInstructionsSchema, PatternDefSchema, AssertionSelectorSchema, assertionBase, PackAssertionSchema, DeclarativePackSchema, EXTENDABLE_BUILTIN_SKILLS, GLOBAL_PACKS_DEFAULT, PACK_DIR_ENTRIES, isYamlPath;
|
|
13999
|
+
var fs14, os4, path19, import_module, import_zod9, ProfileDefSchema, LanguagePackDefSchema, PackSkillSchema, PackInstructionBlockSchema, PackInstructionsSchema, PatternDefSchema, AssertionSelectorSchema, assertionBase, PackAssertionSchema, DeclarativePackSchema, EXTENDABLE_BUILTIN_SKILLS, GLOBAL_PACKS_DEFAULT, FOREIGN_BUILTINS_RETIRED, PACK_DIR_ENTRIES, isYamlPath;
|
|
12977
14000
|
var init_extensions = __esm({
|
|
12978
14001
|
"src/core/extensions.ts"() {
|
|
12979
14002
|
"use strict";
|
|
@@ -13012,7 +14035,7 @@ var init_extensions = __esm({
|
|
|
13012
14035
|
});
|
|
13013
14036
|
LanguagePackDefSchema = import_zod9.z.object({
|
|
13014
14037
|
unsupportedFlow: import_zod9.z.record(import_zod9.z.string()).default({}),
|
|
13015
|
-
foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).
|
|
14038
|
+
foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).optional()
|
|
13016
14039
|
});
|
|
13017
14040
|
PackSkillSchema = import_zod9.z.object({
|
|
13018
14041
|
/** A NEW skill, installed namespaced as `<pack-id>-<id>`. Mutually exclusive with `extends`. */
|
|
@@ -13126,6 +14149,7 @@ var init_extensions = __esm({
|
|
|
13126
14149
|
});
|
|
13127
14150
|
EXTENDABLE_BUILTIN_SKILLS = ["sdd-architect", "sdd-narrative", "sdd-auditor", "sdd-implement", "sdd-delegate"];
|
|
13128
14151
|
GLOBAL_PACKS_DEFAULT = false;
|
|
14152
|
+
FOREIGN_BUILTINS_RETIRED = "nothing replaces it: contracts are written in the neutral type grammar and a language is chosen at L4, so the foreign-builtin check it fed is retired";
|
|
13129
14153
|
PACK_DIR_ENTRIES = ["pack.yaml", "pack.yml", "pack.cjs", "pack.js", "index.cjs", "index.js"];
|
|
13130
14154
|
isYamlPath = (p) => /\.ya?ml$/i.test(p);
|
|
13131
14155
|
}
|
|
@@ -13446,7 +14470,7 @@ function buildImplementationMethods(ctx) {
|
|
|
13446
14470
|
const component = ctx.componentMap.get(contract.component);
|
|
13447
14471
|
if (!component) continue;
|
|
13448
14472
|
if (ctx.isInChainedSubproject(component.subsystem)) continue;
|
|
13449
|
-
const
|
|
14473
|
+
const draftContext4 = ctx.isImplementationDraft(impl);
|
|
13450
14474
|
for (const method2 of impl.methods) {
|
|
13451
14475
|
const sourceFile = methodSourceFile(method2, impl.sourcePath);
|
|
13452
14476
|
out.push({
|
|
@@ -13454,7 +14478,7 @@ function buildImplementationMethods(ctx) {
|
|
|
13454
14478
|
method: method2,
|
|
13455
14479
|
component,
|
|
13456
14480
|
...sourceFile !== void 0 ? { sourceFile } : {},
|
|
13457
|
-
draftContext:
|
|
14481
|
+
draftContext: draftContext4
|
|
13458
14482
|
});
|
|
13459
14483
|
}
|
|
13460
14484
|
}
|
|
@@ -13736,7 +14760,7 @@ var init_type_declarations = __esm({
|
|
|
13736
14760
|
typeDeclarationsRule = {
|
|
13737
14761
|
name: "type-declarations",
|
|
13738
14762
|
judges: "design",
|
|
13739
|
-
description: "A type owned by a subsystem must reference an existing one, and a type declaring neither fields nor methods is a placeholder that can inform neither implementers nor the ERD.",
|
|
14763
|
+
description: "A type owned by a subsystem must reference an existing one, and a type declaring neither fields nor methods (nor, for an enum, values, nor, for a signature type, returns, nor, for a named scalar, the primitive it holds) is a placeholder that can inform neither implementers nor the ERD.",
|
|
13740
14764
|
codes: [
|
|
13741
14765
|
{ code: "INVALID_SUBSYSTEM_REFERENCE", defaultSeverity: "error", summary: "Type references a non-existent owning subsystem" },
|
|
13742
14766
|
{ code: "HOLLOW_TYPE", defaultSeverity: "warning", summary: "Type declares no fields and no methods \u2014 a placeholder that informs neither implementers nor the ERD" }
|
|
@@ -13754,7 +14778,8 @@ var init_type_declarations = __esm({
|
|
|
13754
14778
|
isDraftCtx
|
|
13755
14779
|
);
|
|
13756
14780
|
}
|
|
13757
|
-
|
|
14781
|
+
const models = (t.fields?.length ?? 0) > 0 || (t.methods?.length ?? 0) > 0 || (t.values?.length ?? 0) > 0 || t.returns !== void 0 || t.holds !== void 0;
|
|
14782
|
+
if (!models) {
|
|
13758
14783
|
ctx.addIssue(
|
|
13759
14784
|
"warning",
|
|
13760
14785
|
"HOLLOW_TYPE",
|
|
@@ -14018,6 +15043,7 @@ var init_signature_types = __esm({
|
|
|
14018
15043
|
);
|
|
14019
15044
|
continue;
|
|
14020
15045
|
}
|
|
15046
|
+
if (t.kind === "enum") continue;
|
|
14021
15047
|
const stated = [...t.params !== void 0 ? ["params"] : [], ...t.returns !== void 0 ? ["returns"] : []];
|
|
14022
15048
|
if (stated.length === 0) continue;
|
|
14023
15049
|
ctx.addIssue(
|
|
@@ -14072,6 +15098,204 @@ var init_signature_text = __esm({
|
|
|
14072
15098
|
}
|
|
14073
15099
|
});
|
|
14074
15100
|
|
|
15101
|
+
// src/core/rules/integrity/type-expressions.ts
|
|
15102
|
+
function draftContext3(ctx, specId, kind) {
|
|
15103
|
+
if (kind === "interface") {
|
|
15104
|
+
const intf = ctx.interfaceMap.get(specId);
|
|
15105
|
+
return !!intf && (ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design");
|
|
15106
|
+
}
|
|
15107
|
+
const type = ctx.types.find((t) => t.id === specId);
|
|
15108
|
+
const sub = type?.subsystem ? ctx.subsystems.find((s) => s.id === type.subsystem) : void 0;
|
|
15109
|
+
return !!sub && (sub.status === "draft" || sub.status === "design");
|
|
15110
|
+
}
|
|
15111
|
+
function siteOf(path92) {
|
|
15112
|
+
const [head2, name] = path92.split(".");
|
|
15113
|
+
return (head2 === "methods" || head2 === "fields") && name ? name : path92;
|
|
15114
|
+
}
|
|
15115
|
+
function located(kind, specId, path92) {
|
|
15116
|
+
return `${path92 ? `"${path92}" of ` : ""}${kind ?? "spec"} "${specId}"`;
|
|
15117
|
+
}
|
|
15118
|
+
function problemMessage(problem, specId) {
|
|
15119
|
+
const where = located(problem.kind, specId, problem.path);
|
|
15120
|
+
const replacement = problem.replacement ? ` Write ${problem.replacement} instead.` : "";
|
|
15121
|
+
switch (problem.code) {
|
|
15122
|
+
case "TYPE_EXPRESSION_INVALID":
|
|
15123
|
+
return `The type at ${where} does not parse under the type grammar: ${problem.detail}.${replacement} Every reader treats the position as opaque any until it does.`;
|
|
15124
|
+
case "TYPE_POSITION_INVALID":
|
|
15125
|
+
return `The type at ${where} breaks a position rule: ${problem.detail}.${replacement}`;
|
|
15126
|
+
case "TYPE_FORM_UNSUPPORTED":
|
|
15127
|
+
return `The type at ${where} uses a form the type grammar leaves out: ${problem.detail}.${replacement} Every reader treats the position as opaque any until it is remodelled; the writer refuses it in a new write.`;
|
|
15128
|
+
case "TYPE_NOT_NEUTRAL": {
|
|
15129
|
+
if (problem.replacement === "int or float") {
|
|
15130
|
+
const proposal = typeProblemIntProposal({ ...problem, specId }) ? ` Its name says a whole number, so \`wairon doctor\` proposes int here \u2014 confirm it by writing int, or write float.` : " Write int or float.";
|
|
15131
|
+
return `The type at ${where} is "${problem.written}": number does not say whether it holds an integer \u2014 int or float?${proposal} Until then it is read as float.`;
|
|
15132
|
+
}
|
|
15133
|
+
return `The type at ${where} is "${problem.written}": ${problem.detail}, so it is read as any.${replacement}`;
|
|
15134
|
+
}
|
|
15135
|
+
}
|
|
15136
|
+
}
|
|
15137
|
+
var typeExpressionsRule;
|
|
15138
|
+
var init_type_expressions = __esm({
|
|
15139
|
+
"src/core/rules/integrity/type-expressions.ts"() {
|
|
15140
|
+
"use strict";
|
|
15141
|
+
init_models();
|
|
15142
|
+
typeExpressionsRule = {
|
|
15143
|
+
name: "type-expressions",
|
|
15144
|
+
judges: "design",
|
|
15145
|
+
description: "Reports what the scan's type canonicalisation recorded (ctx.typeSpellingFacts), one finding per position, located by spec and path: a stored text that does not parse (TYPE_EXPRESSION_INVALID); one that breaks a position rule \u2014 void or async out of place, a map key that is not string, int or an enum, a named scalar's holds that is not one primitive other than void and any, `T??` (TYPE_POSITION_INVALID); one using a form the grammar leaves out \u2014 an inline object shape, an inline function type, a string-literal union, a union mixing in a primitive or a collection, an intersection, a utility type or a tuple (TYPE_FORM_UNSUPPORTED); one naming `number` or a legacy builtin with no neutral meaning (TYPE_NOT_NEUTRAL); and one that is an alias of its canonical spelling (TYPE_SPELLING_STALE, which any save or doctor --fix repairs). Every message names the replacement: `number` asks \"int or float?\" (and says when the doctor repair proposes int), a function type names a signature type, a literal union an enum, an inline object or a mixed union a named value-object. The writer refuses all but the stale spelling at write time; these findings are how a tree that held them before the grammar existed is told, while it still loads and its consumers read the position as opaque any \u2014 which is why only what no real tree holds (a text that does not parse, a broken position rule) is an error. No finding when the run carries no facts (a candidate run).",
|
|
15146
|
+
codes: [
|
|
15147
|
+
{ code: "TYPE_EXPRESSION_INVALID", defaultSeverity: "error", summary: "A structured type position does not parse under the type grammar" },
|
|
15148
|
+
{ code: "TYPE_POSITION_INVALID", defaultSeverity: "error", summary: "A type position breaks a position rule: void or async out of place, a non-scalar map key, or T??" },
|
|
15149
|
+
{ code: "TYPE_FORM_UNSUPPORTED", defaultSeverity: "warning", summary: "A type position uses a form the grammar leaves out \u2014 inline object, inline function type, string-literal union, union mixing in a primitive or collection, intersection, utility type or tuple \u2014 and the message names its named replacement" },
|
|
15150
|
+
{ code: "TYPE_NOT_NEUTRAL", defaultSeverity: "warning", summary: "A type position names number (int or float?) or a legacy builtin with no neutral meaning, and the message names the replacement" },
|
|
15151
|
+
{ code: "TYPE_SPELLING_STALE", defaultSeverity: "warning", summary: "A stored type position is an alias of its canonical spelling; any save or doctor --fix rewrites it" }
|
|
15152
|
+
],
|
|
15153
|
+
check(ctx) {
|
|
15154
|
+
const facts = ctx.typeSpellingFacts;
|
|
15155
|
+
if (!facts) return;
|
|
15156
|
+
for (const problem of facts.problems) {
|
|
15157
|
+
if (problem.specId === void 0 || !ctx.isSpecInScope(problem.specId)) continue;
|
|
15158
|
+
const severity = problem.code === "TYPE_EXPRESSION_INVALID" || problem.code === "TYPE_POSITION_INVALID" ? "error" : "warning";
|
|
15159
|
+
ctx.addIssue(
|
|
15160
|
+
severity,
|
|
15161
|
+
problem.code,
|
|
15162
|
+
problemMessage(problem, problem.specId),
|
|
15163
|
+
problem.specId,
|
|
15164
|
+
draftContext3(ctx, problem.specId, problem.kind),
|
|
15165
|
+
void 0,
|
|
15166
|
+
problem.path ? { at: siteOf(problem.path) } : void 0
|
|
15167
|
+
);
|
|
15168
|
+
}
|
|
15169
|
+
for (const respelling of facts.respellings) {
|
|
15170
|
+
if (!ctx.isSpecInScope(respelling.specId)) continue;
|
|
15171
|
+
ctx.addIssue(
|
|
15172
|
+
"warning",
|
|
15173
|
+
"TYPE_SPELLING_STALE",
|
|
15174
|
+
`The type at ${located(respelling.kind, respelling.specId, respelling.path)} is stored as "${respelling.written}", an alias of its canonical spelling "${respelling.stored}" \u2014 which is what every reader is shown. Any save of the spec writes the canonical text, and \`wairon doctor --fix\` rewrites every stale spelling at once.`,
|
|
15175
|
+
respelling.specId,
|
|
15176
|
+
draftContext3(ctx, respelling.specId, respelling.kind),
|
|
15177
|
+
void 0,
|
|
15178
|
+
{ at: siteOf(respelling.path) }
|
|
15179
|
+
);
|
|
15180
|
+
}
|
|
15181
|
+
}
|
|
15182
|
+
};
|
|
15183
|
+
}
|
|
15184
|
+
});
|
|
15185
|
+
|
|
15186
|
+
// src/core/rules/integrity/enum-types.ts
|
|
15187
|
+
var enumTypesRule;
|
|
15188
|
+
var init_enum_types = __esm({
|
|
15189
|
+
"src/core/rules/integrity/enum-types.ts"() {
|
|
15190
|
+
"use strict";
|
|
15191
|
+
init_models();
|
|
15192
|
+
enumTypesRule = {
|
|
15193
|
+
name: "enum-types",
|
|
15194
|
+
judges: "design",
|
|
15195
|
+
description: "An enum is a closed, ordered set of named values with optional pure methods, nothing else: an enum without values, with two values equal by reference_resolution.nameKey (every language derives one identifier from both), or carrying fields, params, returns, invariants, componentClass, database, table or linkedEntity is reported; so are values on a type of any other kind, where they mean nothing.",
|
|
15196
|
+
codes: [
|
|
15197
|
+
{ code: "ENUM_MEMBERS", defaultSeverity: "error", summary: "An enum has no values, two values equal by nameKey, or a member it cannot carry; or a type of another kind carries values" }
|
|
15198
|
+
],
|
|
15199
|
+
check(ctx) {
|
|
15200
|
+
for (const t of ctx.types) {
|
|
15201
|
+
if (!ctx.isSpecInScope(t.id)) continue;
|
|
15202
|
+
const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
|
|
15203
|
+
const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
|
|
15204
|
+
if (t.kind === "enum") {
|
|
15205
|
+
const values = t.values ?? [];
|
|
15206
|
+
const problems = [];
|
|
15207
|
+
if (values.length === 0) problems.push("lists no values");
|
|
15208
|
+
const seen = /* @__PURE__ */ new Map();
|
|
15209
|
+
for (const value of values) {
|
|
15210
|
+
const key = nameKey(value.name);
|
|
15211
|
+
const earlier = seen.get(key);
|
|
15212
|
+
if (earlier !== void 0) problems.push(`lists "${earlier}" and "${value.name}", which every language derives one identifier from`);
|
|
15213
|
+
else seen.set(key, value.name);
|
|
15214
|
+
}
|
|
15215
|
+
const members = [
|
|
15216
|
+
...t.fields.length > 0 ? ["fields"] : [],
|
|
15217
|
+
...t.params !== void 0 ? ["params"] : [],
|
|
15218
|
+
...t.returns !== void 0 ? ["returns"] : [],
|
|
15219
|
+
...(t.invariants?.length ?? 0) > 0 ? ["invariants"] : [],
|
|
15220
|
+
...t.componentClass !== void 0 ? ["componentClass"] : [],
|
|
15221
|
+
...t.database !== void 0 ? ["database"] : [],
|
|
15222
|
+
...t.table !== void 0 ? ["table"] : [],
|
|
15223
|
+
...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
|
|
15224
|
+
];
|
|
15225
|
+
if (members.length > 0) problems.push(`carries ${members.join(", ")}`);
|
|
15226
|
+
if (problems.length === 0) continue;
|
|
15227
|
+
ctx.addIssue(
|
|
15228
|
+
"error",
|
|
15229
|
+
"ENUM_MEMBERS",
|
|
15230
|
+
`Enum type "${t.id}" ${problems.join("; ")}. An enum is a closed, ordered set of named values, unique by name ignoring case and separators, with optional pure methods and nothing else.`,
|
|
15231
|
+
t.id,
|
|
15232
|
+
isDraft
|
|
15233
|
+
);
|
|
15234
|
+
continue;
|
|
15235
|
+
}
|
|
15236
|
+
if (t.values === void 0) continue;
|
|
15237
|
+
ctx.addIssue(
|
|
15238
|
+
"error",
|
|
15239
|
+
"ENUM_MEMBERS",
|
|
15240
|
+
`Type "${t.id}" is ${t.kind === "entity" ? "an entity" : `a ${t.kind}`} and carries values, which only an enum has. Make it kind enum, or drop them.`,
|
|
15241
|
+
t.id,
|
|
15242
|
+
isDraft
|
|
15243
|
+
);
|
|
15244
|
+
}
|
|
15245
|
+
}
|
|
15246
|
+
};
|
|
15247
|
+
}
|
|
15248
|
+
});
|
|
15249
|
+
|
|
15250
|
+
// src/core/rules/integrity/named-scalar-types.ts
|
|
15251
|
+
var namedScalarTypesRule;
|
|
15252
|
+
var init_named_scalar_types = __esm({
|
|
15253
|
+
"src/core/rules/integrity/named-scalar-types.ts"() {
|
|
15254
|
+
"use strict";
|
|
15255
|
+
namedScalarTypesRule = {
|
|
15256
|
+
name: "named-scalar-types",
|
|
15257
|
+
judges: "design",
|
|
15258
|
+
description: "A named scalar is a value-object that declares `holds: <primitive>` in place of fields \u2014 a newtype or type alias in every language. It models its value and nothing else beside its pure methods and invariants: holds beside fields, componentClass, database, table or linkedEntity is reported, and so is holds on an entity, an enum or a signature type, where it means nothing. Whether holds names one of the primitives is the type-expressions rule's question (TYPE_POSITION_INVALID on the holds position), never a second voice here. Mirrors enum-types and signature-types: judged at validate time, on the type's own fields.",
|
|
15259
|
+
codes: [
|
|
15260
|
+
{ code: "NAMED_SCALAR_MEMBERS", defaultSeverity: "error", summary: "A named scalar (a value-object holding a primitive) carries fields or a member it cannot carry; or a type of another kind declares holds" }
|
|
15261
|
+
],
|
|
15262
|
+
check(ctx) {
|
|
15263
|
+
for (const t of ctx.types) {
|
|
15264
|
+
if (!ctx.isSpecInScope(t.id)) continue;
|
|
15265
|
+
if (t.holds === void 0) continue;
|
|
15266
|
+
const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
|
|
15267
|
+
const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
|
|
15268
|
+
if (t.kind !== "value-object") {
|
|
15269
|
+
ctx.addIssue(
|
|
15270
|
+
"error",
|
|
15271
|
+
"NAMED_SCALAR_MEMBERS",
|
|
15272
|
+
`Type "${t.id}" is ${t.kind === "entity" ? "an entity" : `a ${t.kind}`} and declares holds, which only a value-object has: a named scalar is a value-object holding one primitive. Make it a value-object, or drop holds.`,
|
|
15273
|
+
t.id,
|
|
15274
|
+
isDraft
|
|
15275
|
+
);
|
|
15276
|
+
continue;
|
|
15277
|
+
}
|
|
15278
|
+
const members = [
|
|
15279
|
+
...t.fields.length > 0 ? ["fields"] : [],
|
|
15280
|
+
...t.componentClass !== void 0 ? ["componentClass"] : [],
|
|
15281
|
+
...t.database !== void 0 ? ["database"] : [],
|
|
15282
|
+
...t.table !== void 0 ? ["table"] : [],
|
|
15283
|
+
...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
|
|
15284
|
+
];
|
|
15285
|
+
if (members.length === 0) continue;
|
|
15286
|
+
ctx.addIssue(
|
|
15287
|
+
"error",
|
|
15288
|
+
"NAMED_SCALAR_MEMBERS",
|
|
15289
|
+
`Named scalar "${t.id}" holds ${t.holds} and carries ${members.join(", ")}. A named scalar is one primitive under a name, with optional pure methods and invariants and nothing else: drop ${members.length === 1 ? "it" : "them"}, or drop holds and model the value-object's fields.`,
|
|
15290
|
+
t.id,
|
|
15291
|
+
isDraft
|
|
15292
|
+
);
|
|
15293
|
+
}
|
|
15294
|
+
}
|
|
15295
|
+
};
|
|
15296
|
+
}
|
|
15297
|
+
});
|
|
15298
|
+
|
|
14075
15299
|
// src/core/rules/integrity/public-surface-binding.ts
|
|
14076
15300
|
var publicSurfaceBindingRule;
|
|
14077
15301
|
var init_public_surface_binding = __esm({
|
|
@@ -15661,11 +16885,11 @@ var init_detail_sufficiency = __esm({
|
|
|
15661
16885
|
const contract = ctx.interfaceMap.get(impl.contract);
|
|
15662
16886
|
if (!contract) continue;
|
|
15663
16887
|
const component = ctx.componentMap.get(contract.component);
|
|
15664
|
-
const
|
|
16888
|
+
const draftContext4 = ctx.isImplementationDraft(impl);
|
|
15665
16889
|
for (const method2 of impl.methods) {
|
|
15666
16890
|
const detail = effectiveDetail(method2, impl, component);
|
|
15667
16891
|
if (contract.methods.some((m) => m.name === method2.name) && method2.narrative.length === 0 && detail.level !== "full") {
|
|
15668
|
-
dialedDown.push({ implementation: impl, method: method2, component, detail, draftContext:
|
|
16892
|
+
dialedDown.push({ implementation: impl, method: method2, component, detail, draftContext: draftContext4 });
|
|
15669
16893
|
}
|
|
15670
16894
|
}
|
|
15671
16895
|
}
|
|
@@ -17291,6 +18515,31 @@ var init_pack_requirements = __esm({
|
|
|
17291
18515
|
}
|
|
17292
18516
|
});
|
|
17293
18517
|
|
|
18518
|
+
// src/core/rules/extension/pack-deprecations.ts
|
|
18519
|
+
var packDeprecationsRule;
|
|
18520
|
+
var init_pack_deprecations = __esm({
|
|
18521
|
+
"src/core/rules/extension/pack-deprecations.ts"() {
|
|
18522
|
+
"use strict";
|
|
18523
|
+
packDeprecationsRule = {
|
|
18524
|
+
name: "pack-deprecations",
|
|
18525
|
+
judges: "design",
|
|
18526
|
+
description: "A loaded pack still declaring a field wairon has deprecated (ctx.ext.deprecations \u2014 today a language's foreignBuiltins, whose foreign-builtin check is retired because contracts are written in the neutral type grammar) is told so: the field is accepted and ignored for one release and removed in the release after. A notice: it never fails the gate.",
|
|
18527
|
+
codes: [
|
|
18528
|
+
{ code: "PACK_FIELD_DEPRECATED", defaultSeverity: "notice", summary: "A loaded pack declares a deprecated field, accepted and ignored for one release" }
|
|
18529
|
+
],
|
|
18530
|
+
check(ctx) {
|
|
18531
|
+
for (const deprecation of ctx.ext.deprecations) {
|
|
18532
|
+
ctx.addIssue(
|
|
18533
|
+
"notice",
|
|
18534
|
+
"PACK_FIELD_DEPRECATED",
|
|
18535
|
+
`Deprecated pack field \u2014 ${deprecation}. It is accepted and ignored in this release and removed in the next; take it out of the pack.`
|
|
18536
|
+
);
|
|
18537
|
+
}
|
|
18538
|
+
}
|
|
18539
|
+
};
|
|
18540
|
+
}
|
|
18541
|
+
});
|
|
18542
|
+
|
|
17294
18543
|
// src/core/rules/wiring/dependency-cycles.ts
|
|
17295
18544
|
var cyclesRule;
|
|
17296
18545
|
var init_dependency_cycles = __esm({
|
|
@@ -18018,19 +19267,27 @@ var init_durability_round_trip = __esm({
|
|
|
18018
19267
|
});
|
|
18019
19268
|
|
|
18020
19269
|
// src/core/rules/wiring/untyped-seams.ts
|
|
18021
|
-
function
|
|
18022
|
-
return
|
|
19270
|
+
function holdsAny(expr) {
|
|
19271
|
+
return expr.form === "primitive" && expr.name === "any" || expr.args.some(holdsAny);
|
|
19272
|
+
}
|
|
19273
|
+
function tokensUntyped(text3) {
|
|
19274
|
+
return extractTypeIdentifiers(text3).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()));
|
|
19275
|
+
}
|
|
19276
|
+
function positionUntyped(text3, position) {
|
|
19277
|
+
const parse = parseTypePosition(text3, position);
|
|
19278
|
+
if (parse.expression && !parse.problem) return holdsAny(parse.expression);
|
|
19279
|
+
return tokensUntyped(text3);
|
|
18023
19280
|
}
|
|
18024
|
-
var
|
|
19281
|
+
var UNTYPED_SPELLINGS, untypedSeamRule;
|
|
18025
19282
|
var init_untyped_seams = __esm({
|
|
18026
19283
|
"src/core/rules/wiring/untyped-seams.ts"() {
|
|
18027
19284
|
"use strict";
|
|
18028
19285
|
init_models();
|
|
18029
|
-
|
|
19286
|
+
UNTYPED_SPELLINGS = /* @__PURE__ */ new Set(["any", "json", "unknown", "object"]);
|
|
18030
19287
|
untypedSeamRule = {
|
|
18031
19288
|
name: "untyped-seams",
|
|
18032
19289
|
judges: "design",
|
|
18033
|
-
description: "Methods on a subsystem's published components (its public surface) should not take or return
|
|
19290
|
+
description: "Methods on a subsystem's published components (its public surface) should not take or return `any` \u2014 the one untyped type of the grammar, which object, unknown, json and Json are canonicalised to \u2014 judged through each method's named types and parsed expressions so a prose signature is judged like structured params (its tokens still read leniently): cross-subsystem contracts are the swap seam and must be typed. Generic-dispatch portals carry per-capability types via their dispatch table instead.",
|
|
18034
19291
|
codes: [
|
|
18035
19292
|
{ code: "UNTYPED_SEAM", defaultSeverity: "warning", summary: "Bare Json/any/unknown/object parameter or return crossing a subsystem public surface" }
|
|
18036
19293
|
],
|
|
@@ -18048,14 +19305,14 @@ var init_untyped_seams = __esm({
|
|
|
18048
19305
|
const offenders = [];
|
|
18049
19306
|
if (m.params && m.params.length > 0) {
|
|
18050
19307
|
for (const p of m.params) {
|
|
18051
|
-
if (
|
|
19308
|
+
if (positionUntyped(p.type, "param")) {
|
|
18052
19309
|
offenders.push(`param "${p.name}: ${p.type}"`);
|
|
18053
19310
|
}
|
|
18054
19311
|
}
|
|
18055
|
-
if (
|
|
19312
|
+
if (m.returns && positionUntyped(m.returns, "returns")) {
|
|
18056
19313
|
offenders.push(`return "${m.returns}"`);
|
|
18057
19314
|
}
|
|
18058
|
-
} else if (
|
|
19315
|
+
} else if (methodTypeRefs(m).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()))) {
|
|
18059
19316
|
offenders.push(`signature "${m.signature}"`);
|
|
18060
19317
|
}
|
|
18061
19318
|
if (offenders.length) {
|
|
@@ -19423,6 +20680,33 @@ function originOf(shape) {
|
|
|
19423
20680
|
function absence(optional) {
|
|
19424
20681
|
return optional ? "may be absent" : "is always there";
|
|
19425
20682
|
}
|
|
20683
|
+
function judgeNamedScalar(ctx, type, file, facts) {
|
|
20684
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") return;
|
|
20685
|
+
const dialect = dialectOf(facts);
|
|
20686
|
+
const holds = parseTypePosition(type.holds, "holds").expression;
|
|
20687
|
+
if (!dialect || !holds) return;
|
|
20688
|
+
const symbol = type.symbol ?? type.name;
|
|
20689
|
+
const own = (record2) => !!record2 && Object.prototype.hasOwnProperty.call(record2, symbol);
|
|
20690
|
+
let declared;
|
|
20691
|
+
if (own(facts.aliasTypes)) {
|
|
20692
|
+
const annotation = facts.aliasTypes[symbol];
|
|
20693
|
+
if (dialect.agrees(annotation, holds, /* @__PURE__ */ new Map())) return;
|
|
20694
|
+
declared = `an alias of \`${annotation}\``;
|
|
20695
|
+
} else if (own(facts.typeShapes)) {
|
|
20696
|
+
declared = "a record (an object shape)";
|
|
20697
|
+
} else {
|
|
20698
|
+
return;
|
|
20699
|
+
}
|
|
20700
|
+
ctx.addIssue(
|
|
20701
|
+
"warning",
|
|
20702
|
+
"TYPE_HOLDS_MISMATCH",
|
|
20703
|
+
`Named scalar "${type.id}" holds ${type.holds}, but "${file}" declares "${symbol}" as ${declared}. Every reader of a named scalar is told what one value of it is, and the code says otherwise. Make the declaration an alias of the primitive (in TypeScript, \`type ${symbol} = ${dialect.write(holds)}\`), or change what the type holds.`,
|
|
20704
|
+
type.id,
|
|
20705
|
+
void 0,
|
|
20706
|
+
void 0,
|
|
20707
|
+
{ at: symbol }
|
|
20708
|
+
);
|
|
20709
|
+
}
|
|
19426
20710
|
var typeShapeRule;
|
|
19427
20711
|
var init_type_shape = __esm({
|
|
19428
20712
|
"src/core/rules/conformance/type-shape.ts"() {
|
|
@@ -19431,7 +20715,7 @@ var init_type_shape = __esm({
|
|
|
19431
20715
|
typeShapeRule = {
|
|
19432
20716
|
name: "type-shape",
|
|
19433
20717
|
judges: "code",
|
|
19434
|
-
description: "Code-to-contract for the DATA: a type spec's `fields` are compared, name by name, against the shape its `sourcePath` actually declares. `typeRealization` asks whether a type EXISTS in code; nothing asked whether it is the shape the spec claims, so a type spec could describe two fields of a six-field record \u2014 and call the two that are optional required \u2014 straight through a lock and a CI gate, while the ERD, the agent briefs and every implementer read it as truth. That is the worst of the code-to-spec gaps, because a wrong signature eventually breaks at a call site and a type spec that lies is only ever read by humans and agents. Two origins answer at exact grade: a DECLARED shape, whose members the file lists, and a DERIVED one, an alias followed one hop to the object literal its schema is built from, where the keys are the members \u2014 and on through a composition the same file writes out (`Base.extend({\u2026})` on a schema constant it declares), the extension's keys laid over the base's. A shape that extends another is judged on what it shows and never on what it omits, since its inherited members are not in this file to count.",
|
|
20718
|
+
description: "Code-to-contract for the DATA: a type spec's `fields` are compared, name by name, against the shape its `sourcePath` actually declares. `typeRealization` asks whether a type EXISTS in code; nothing asked whether it is the shape the spec claims, so a type spec could describe two fields of a six-field record \u2014 and call the two that are optional required \u2014 straight through a lock and a CI gate, while the ERD, the agent briefs and every implementer read it as truth. That is the worst of the code-to-spec gaps, because a wrong signature eventually breaks at a call site and a type spec that lies is only ever read by humans and agents. Two origins answer at exact grade: a DECLARED shape, whose members the file lists, and a DERIVED one, an alias followed one hop to the object literal its schema is built from, where the keys are the members \u2014 and on through a composition the same file writes out (`Base.extend({\u2026})` on a schema constant it declares), the extension's keys laid over the base's. A shape that extends another is judged on what it shows and never on what it omits, since its inherited members are not in this file to count. A NAMED SCALAR (a value-object declaring `holds`) has no field list: its shape is the primitive it holds, compared with the right side of the type alias the file declares under its name, read through the file's dialect (`type PackPath = string` agrees with holds string); an object shape under that name, or an alias the dialect does not read as that primitive, is TYPE_HOLDS_MISMATCH.",
|
|
19435
20719
|
codes: [
|
|
19436
20720
|
{
|
|
19437
20721
|
code: "UNREALIZED_TYPE_FIELD",
|
|
@@ -19447,6 +20731,12 @@ var init_type_shape = __esm({
|
|
|
19447
20731
|
summary: "The shape at a type's sourcePath carries a field the type spec does not declare \u2014 data the design never described, so no diagram draws it and no brief hands it to an implementer",
|
|
19448
20732
|
carryable: true
|
|
19449
20733
|
},
|
|
20734
|
+
{
|
|
20735
|
+
code: "TYPE_HOLDS_MISMATCH",
|
|
20736
|
+
defaultSeverity: "warning",
|
|
20737
|
+
summary: "A named scalar's holds disagrees with what its sourcePath declares under its name \u2014 an alias of another type, or a record \u2014 so every reader is told one value of it is something the code says it is not",
|
|
20738
|
+
carryable: true
|
|
20739
|
+
},
|
|
19450
20740
|
{
|
|
19451
20741
|
code: "TYPE_FIELD_OPTIONALITY",
|
|
19452
20742
|
defaultSeverity: "warning",
|
|
@@ -19461,6 +20751,10 @@ var init_type_shape = __esm({
|
|
|
19461
20751
|
if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
|
|
19462
20752
|
const file = pathKey(type.sourcePath);
|
|
19463
20753
|
const facts = code.factsAt(file);
|
|
20754
|
+
if (type.holds !== void 0) {
|
|
20755
|
+
judgeNamedScalar(ctx, type, file, facts);
|
|
20756
|
+
continue;
|
|
20757
|
+
}
|
|
19464
20758
|
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
19465
20759
|
const symbol = type.symbol ?? type.name;
|
|
19466
20760
|
const shapes = facts.typeShapes;
|
|
@@ -19517,6 +20811,74 @@ var init_type_shape = __esm({
|
|
|
19517
20811
|
}
|
|
19518
20812
|
});
|
|
19519
20813
|
|
|
20814
|
+
// src/core/rules/conformance/enum-values.ts
|
|
20815
|
+
var enumValuesRule;
|
|
20816
|
+
var init_enum_values = __esm({
|
|
20817
|
+
"src/core/rules/conformance/enum-values.ts"() {
|
|
20818
|
+
"use strict";
|
|
20819
|
+
init_models();
|
|
20820
|
+
enumValuesRule = {
|
|
20821
|
+
name: "enum-values",
|
|
20822
|
+
judges: "code",
|
|
20823
|
+
description: "Code-to-contract for an ENUM: an enum type's values are compared, name by name, with the values the declaration at its sourcePath holds \u2014 a string-literal union alias, the array a z.enum constant holds, or a string enum's member values (source_file_facts.enumValues). `typeRealization` already asks whether the declaration exists; nothing asked whether it holds the values the design lists, and an enum is read by every diagram, OpenAPI document and brief as the closed set it claims. Exact grade only; a declaration the analyzer reads no values from is typeRealization's question, never this rule's. Order is not judged: languages differ on whether declaration order is observable.",
|
|
20824
|
+
codes: [
|
|
20825
|
+
{
|
|
20826
|
+
code: "UNREALIZED_ENUM_VALUE",
|
|
20827
|
+
defaultSeverity: "warning",
|
|
20828
|
+
summary: "An enum type lists a value the declaration at its sourcePath does not hold \u2014 the design promises a value the code would reject",
|
|
20829
|
+
carryable: true
|
|
20830
|
+
},
|
|
20831
|
+
{
|
|
20832
|
+
code: "UNDECLARED_ENUM_VALUE",
|
|
20833
|
+
defaultSeverity: "warning",
|
|
20834
|
+
summary: "The declaration at an enum type's sourcePath holds a value the enum does not list \u2014 a value the design never described",
|
|
20835
|
+
carryable: true
|
|
20836
|
+
}
|
|
20837
|
+
],
|
|
20838
|
+
check(ctx) {
|
|
20839
|
+
const code = ctx.codeIndex();
|
|
20840
|
+
for (const type of ctx.types) {
|
|
20841
|
+
if (type.kind !== "enum" || !type.sourcePath) continue;
|
|
20842
|
+
if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
|
|
20843
|
+
const file = pathKey(type.sourcePath);
|
|
20844
|
+
const facts = code.factsAt(file);
|
|
20845
|
+
const symbol = type.symbol ?? type.name;
|
|
20846
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
20847
|
+
const declared = facts.enumValues;
|
|
20848
|
+
if (!declared || !Object.prototype.hasOwnProperty.call(declared, symbol)) continue;
|
|
20849
|
+
const held = new Set(declared[symbol]);
|
|
20850
|
+
const listed = (type.values ?? []).map((value) => value.name);
|
|
20851
|
+
const listedSet = new Set(listed);
|
|
20852
|
+
const unrealized = listed.filter((value) => !held.has(value));
|
|
20853
|
+
if (unrealized.length > 0) {
|
|
20854
|
+
ctx.addIssue(
|
|
20855
|
+
"warning",
|
|
20856
|
+
"UNREALIZED_ENUM_VALUE",
|
|
20857
|
+
`Enum type "${type.id}" lists ${unrealized.length} value(s) the declaration "${symbol}" in "${file}" does not hold \u2014 ${unrealized.map((value) => `"${value}"`).join(", ")}. The design promises a value the code would reject, and every diagram, OpenAPI document and brief offers it. Add it to the declaration, or drop it from the enum (values compare exactly: a value is data).`,
|
|
20858
|
+
type.id,
|
|
20859
|
+
void 0,
|
|
20860
|
+
void 0,
|
|
20861
|
+
{ at: symbol, covers: unrealized }
|
|
20862
|
+
);
|
|
20863
|
+
}
|
|
20864
|
+
const undeclared = declared[symbol].filter((value) => !listedSet.has(value));
|
|
20865
|
+
if (undeclared.length > 0) {
|
|
20866
|
+
ctx.addIssue(
|
|
20867
|
+
"warning",
|
|
20868
|
+
"UNDECLARED_ENUM_VALUE",
|
|
20869
|
+
`The declaration "${symbol}" in "${file}" holds ${undeclared.length} value(s) enum type "${type.id}" does not list \u2014 ${undeclared.map((value) => `"${value}"`).join(", ")}. A value the design never described is one no diagram shows and no brief hands an implementer. List it on the enum, or take it out of the code.`,
|
|
20870
|
+
type.id,
|
|
20871
|
+
void 0,
|
|
20872
|
+
void 0,
|
|
20873
|
+
{ at: symbol, covers: undeclared }
|
|
20874
|
+
);
|
|
20875
|
+
}
|
|
20876
|
+
}
|
|
20877
|
+
}
|
|
20878
|
+
};
|
|
20879
|
+
}
|
|
20880
|
+
});
|
|
20881
|
+
|
|
19520
20882
|
// src/core/rules/conformance/param-conformance.ts
|
|
19521
20883
|
function omittable(optional) {
|
|
19522
20884
|
return optional ? "may be left out" : "is required";
|
|
@@ -19572,7 +20934,7 @@ var init_param_conformance = __esm({
|
|
|
19572
20934
|
paramConformanceRule = {
|
|
19573
20935
|
name: "param-conformance",
|
|
19574
20936
|
judges: "code",
|
|
19575
|
-
description: "Code-to-contract for the SIGNATURE, the last of the three readings a spec-driven gate never made: a contract declares `params`, and nothing ever compared them to the parameters of the function that realizes the method. A contract could promise an argument the code does not take, take one the contract never mentions \u2014 including a secret \u2014 or name the same argument two different things, and the brief handed to an implementer would carry the contract's version. Parameters are matched by POSITION against the tail of the realization's list, and the declared type is what tells a rename from a dropped argument: `seed(config: HostConfig)` realized as `bootstrapInstance(cfg: HostConfig)` is one parameter under two names, which anything matching on names alone reads as a parameter the code lost. What a realization takes BEFORE the contract's own parameters is wiring, and it is declared on the implementation as `injectedParams` rather than inferred, because an inferred prefix cannot be told from a renamed first argument. A method the named file only CALLS is left to `methodRealization`, which already reports that the body is not here.",
|
|
20937
|
+
description: "Code-to-contract for the SIGNATURE, the last of the three readings a spec-driven gate never made: a contract declares `params`, and nothing ever compared them to the parameters of the function that realizes the method. A contract could promise an argument the code does not take, take one the contract never mentions \u2014 including a secret \u2014 or name the same argument two different things, and the brief handed to an implementer would carry the contract's version. Parameters are matched by POSITION against the tail of the realization's list, and the declared type is what tells a rename from a dropped argument: `seed(config: HostConfig)` realized as `bootstrapInstance(cfg: HostConfig)` is one parameter under two names, which anything matching on names alone reads as a parameter the code lost. Types agree when the code's annotation, read through the dialect of the language the file was analyzed as (type_dialect.agrees), is the contract's canonical type \u2014 so `string[]` in the code agrees with `list<string>` in the contract, TypeScript's `number` with int and float alike, and an annotation the dialect cannot read agrees with nothing. What a realization takes BEFORE the contract's own parameters is wiring, and it is declared on the implementation as `injectedParams` rather than inferred, because an inferred prefix cannot be told from a renamed first argument. A method the named file only CALLS is left to `methodRealization`, which already reports that the body is not here.",
|
|
19576
20938
|
codes: [
|
|
19577
20939
|
{
|
|
19578
20940
|
code: "UNREALIZED_PARAM",
|
|
@@ -19609,13 +20971,13 @@ var init_param_conformance = __esm({
|
|
|
19609
20971
|
codeNameOf.set(type.id, named2);
|
|
19610
20972
|
if (type.subsystem) codeNameOf.set(`${type.subsystem}.${type.id}`, named2);
|
|
19611
20973
|
}
|
|
19612
|
-
const
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
return
|
|
20974
|
+
const typeAgreesIn = (dialect) => (declared, realized) => {
|
|
20975
|
+
if (!realized.type || !dialect) return false;
|
|
20976
|
+
const stated = parseTypePosition(declared.type, "param", !!declared.optional);
|
|
20977
|
+
if (!stated.expression) return false;
|
|
20978
|
+
return dialect.agrees(realized.type, stated.expression, codeNameOf);
|
|
19617
20979
|
};
|
|
19618
|
-
for (const { implementation, method: method2, sourceFile, draftContext:
|
|
20980
|
+
for (const { implementation, method: method2, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
19619
20981
|
const contract = ctx.interfaceMap.get(implementation.contract);
|
|
19620
20982
|
const declared = contract?.methods.find((m) => m.name === method2.name)?.params ?? [];
|
|
19621
20983
|
if (declared.length === 0 || !sourceFile) continue;
|
|
@@ -19628,6 +20990,7 @@ var init_param_conformance = __esm({
|
|
|
19628
20990
|
const candidates = signatures[symbol];
|
|
19629
20991
|
if (candidates.length === 0) continue;
|
|
19630
20992
|
const injected = new Set(implementation.injectedParams ?? []);
|
|
20993
|
+
const typeAgrees = typeAgreesIn(dialectOf(facts));
|
|
19631
20994
|
const judgements = candidates.map((realized) => judge(declared, realized, injected, typeAgrees));
|
|
19632
20995
|
const subject = candidates.length > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
|
|
19633
20996
|
const opening = subject.charAt(0).toUpperCase() + subject.slice(1);
|
|
@@ -19638,7 +21001,7 @@ var init_param_conformance = __esm({
|
|
|
19638
21001
|
"UNREALIZED_PARAM",
|
|
19639
21002
|
`Method "${method2.name}" of contract "${implementation.contract}" declares ${unrealized.length} parameter(s) ${subject} does not take \u2014 ${unrealized.map((found) => found.told).join(", ")}. The contract is promising an argument that would go nowhere, and nothing breaks at a call site to correct it: every brief and every caller built from the contract passes one. Take the parameter in the code, or drop it from the contract.`,
|
|
19640
21003
|
implementation.id,
|
|
19641
|
-
|
|
21004
|
+
draftContext4,
|
|
19642
21005
|
void 0,
|
|
19643
21006
|
{ at: method2.name, covers: unrealized.map((found) => found.unit) }
|
|
19644
21007
|
);
|
|
@@ -19650,7 +21013,7 @@ var init_param_conformance = __esm({
|
|
|
19650
21013
|
"UNDECLARED_PARAM",
|
|
19651
21014
|
`${opening} realizing method "${method2.name}" of contract "${implementation.contract}" takes ${undeclared.length} parameter(s) the contract does not declare and no declared injection accounts for \u2014 ${undeclared.map((found) => found.told).join(", ")}. An argument a caller must supply that the design never mentions is how a credential ends up in a signature nobody has read against its contract. Declare it on the contract, name it in the implementation's \`injectedParams\` when whatever wires this component up supplies it (a LEADING run only), or take it out of the signature.`,
|
|
19652
21015
|
implementation.id,
|
|
19653
|
-
|
|
21016
|
+
draftContext4,
|
|
19654
21017
|
void 0,
|
|
19655
21018
|
{ at: method2.name, covers: undeclared.map((found) => found.unit) }
|
|
19656
21019
|
);
|
|
@@ -19662,7 +21025,7 @@ var init_param_conformance = __esm({
|
|
|
19662
21025
|
"PARAM_NAME_MISMATCH",
|
|
19663
21026
|
`Method "${method2.name}" of contract "${implementation.contract}" and ${subject} agree on position and type but not on name for ${renamed.length} parameter(s) \u2014 ${renamed.map((f) => f.told).join("; ")}. The contract, the ERD and every brief carry one word and the code answers to another, which is a rename nobody recorded rather than a different argument \u2014 the declared type agreeing is what says so. Rename one side to the other.`,
|
|
19664
21027
|
implementation.id,
|
|
19665
|
-
|
|
21028
|
+
draftContext4,
|
|
19666
21029
|
void 0,
|
|
19667
21030
|
{ at: method2.name, covers: renamed.map((found) => found.unit) }
|
|
19668
21031
|
);
|
|
@@ -19674,7 +21037,7 @@ var init_param_conformance = __esm({
|
|
|
19674
21037
|
"PARAM_OPTIONALITY",
|
|
19675
21038
|
`Method "${method2.name}" of contract "${implementation.contract}" and ${subject} disagree about whether ${disagreed.length} parameter(s) may be left out \u2014 ${disagreed.map((f) => f.told).join("; ")}. One of them is telling a caller an argument is required when it is not, or the reverse. Omittable is the code's word for it: a default value and a rest parameter make an argument omittable exactly as a question mark does.`,
|
|
19676
21039
|
implementation.id,
|
|
19677
|
-
|
|
21040
|
+
draftContext4,
|
|
19678
21041
|
void 0,
|
|
19679
21042
|
{ at: method2.name, covers: disagreed.map((found) => found.unit) }
|
|
19680
21043
|
);
|
|
@@ -19685,6 +21048,69 @@ var init_param_conformance = __esm({
|
|
|
19685
21048
|
}
|
|
19686
21049
|
});
|
|
19687
21050
|
|
|
21051
|
+
// src/core/rules/conformance/async-conformance.ts
|
|
21052
|
+
var asyncConformanceRule;
|
|
21053
|
+
var init_async_conformance = __esm({
|
|
21054
|
+
"src/core/rules/conformance/async-conformance.ts"() {
|
|
21055
|
+
"use strict";
|
|
21056
|
+
init_models();
|
|
21057
|
+
asyncConformanceRule = {
|
|
21058
|
+
name: "async-conformance",
|
|
21059
|
+
judges: "code",
|
|
21060
|
+
description: "Code-to-contract for ASYNC: a contract method whose returns is `async T` is realized by a function that completes later, and one whose returns is not, by one that completes now \u2014 every caller in every language with async/await is shaped by the difference, so a contract that hides it misleads every implementer and translation built from it. Compared with source_file_facts.asyncFunctions for the method's realizing function (under its `symbol`), at exact grade only; where a name has several bodies only what they all agree on is reported, as param-conformance does. A method whose file only calls the function is methodRealization's finding.",
|
|
21061
|
+
codes: [
|
|
21062
|
+
{
|
|
21063
|
+
code: "ASYNC_MISMATCH",
|
|
21064
|
+
defaultSeverity: "warning",
|
|
21065
|
+
summary: "A contract method and the function realizing it disagree about whether the call completes later: the returns says `async T` and the code completes now, or the code is async and the returns does not say so",
|
|
21066
|
+
carryable: true
|
|
21067
|
+
}
|
|
21068
|
+
],
|
|
21069
|
+
check(ctx) {
|
|
21070
|
+
const code = ctx.codeIndex();
|
|
21071
|
+
for (const { implementation, method: method2, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
21072
|
+
const contractMethod = ctx.interfaceMap.get(implementation.contract)?.methods.find((m) => m.name === method2.name);
|
|
21073
|
+
if (!contractMethod || typeof contractMethod.returns !== "string" || !sourceFile) continue;
|
|
21074
|
+
const file = pathKey(sourceFile);
|
|
21075
|
+
const facts = code.factsAt(file);
|
|
21076
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
21077
|
+
const symbol = method2.symbol ?? method2.name;
|
|
21078
|
+
const signatures = facts.functionParams;
|
|
21079
|
+
if (!signatures || !Object.prototype.hasOwnProperty.call(signatures, symbol)) continue;
|
|
21080
|
+
const bodies = signatures[symbol].length;
|
|
21081
|
+
if (bodies === 0) continue;
|
|
21082
|
+
const returns = parseTypeExpression(contractMethod.returns, "returns");
|
|
21083
|
+
if (!returns.expression) continue;
|
|
21084
|
+
const contractAsync = returns.expression.form === "async";
|
|
21085
|
+
const asyncBodies = (facts.asyncFunctions ?? []).filter((name) => name === symbol).length;
|
|
21086
|
+
const subject = bodies > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
|
|
21087
|
+
if (contractAsync && asyncBodies === 0) {
|
|
21088
|
+
ctx.addIssue(
|
|
21089
|
+
"warning",
|
|
21090
|
+
"ASYNC_MISMATCH",
|
|
21091
|
+
`Method "${method2.name}" of contract "${implementation.contract}" returns "${contractMethod.returns}", which completes later, but ${subject} completes now \u2014 it is neither declared async nor annotated to return a Promise. Every caller is told to await a call that answers at once. Make the code async, or drop \`async\` from the returns.`,
|
|
21092
|
+
implementation.id,
|
|
21093
|
+
draftContext4,
|
|
21094
|
+
void 0,
|
|
21095
|
+
{ at: method2.name }
|
|
21096
|
+
);
|
|
21097
|
+
} else if (!contractAsync && asyncBodies === bodies) {
|
|
21098
|
+
ctx.addIssue(
|
|
21099
|
+
"warning",
|
|
21100
|
+
"ASYNC_MISMATCH",
|
|
21101
|
+
`Method "${method2.name}" of contract "${implementation.contract}" returns "${contractMethod.returns}", which completes now, but ${subject} completes later (declared async, or annotated to return a Promise). Every caller built from the contract forgets to await it. Write the returns as "async ${contractMethod.returns}" \u2014 or, if the code is async by accident, make it complete now.`,
|
|
21102
|
+
implementation.id,
|
|
21103
|
+
draftContext4,
|
|
21104
|
+
void 0,
|
|
21105
|
+
{ at: method2.name }
|
|
21106
|
+
);
|
|
21107
|
+
}
|
|
21108
|
+
}
|
|
21109
|
+
}
|
|
21110
|
+
};
|
|
21111
|
+
}
|
|
21112
|
+
});
|
|
21113
|
+
|
|
19688
21114
|
// src/core/rules/conformance/route-coverage.ts
|
|
19689
21115
|
function liesUnder2(path92, prefix) {
|
|
19690
21116
|
return path92 === prefix || path92.startsWith(prefix + "/");
|
|
@@ -19758,7 +21184,7 @@ var init_route_coverage = __esm({
|
|
|
19758
21184
|
const routes = code.factsAt(file).functionRoutes;
|
|
19759
21185
|
return routes && Object.prototype.hasOwnProperty.call(routes, via) ? routes[via] : [];
|
|
19760
21186
|
});
|
|
19761
|
-
const
|
|
21187
|
+
const draftContext4 = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
|
|
19762
21188
|
const where = holders.map((file) => `"${file}"`).join(", ");
|
|
19763
21189
|
if (read2.length === 0) {
|
|
19764
21190
|
ctx.addIssue(
|
|
@@ -19766,7 +21192,7 @@ var init_route_coverage = __esm({
|
|
|
19766
21192
|
"UNREADABLE_ROUTER",
|
|
19767
21193
|
`Listener "${listener.id}" mounts portal "${portal.id}" through "${via}" in ${where}, but no branch of "${via}" reads as a route \u2014 so none of its routes were checked against the contract at all. Only one idiom is read: an \`if\` whose conditions, together with those of every enclosing \`if\`, compare \`<request>.method\` with a string and \`parts[i]\` / \`parts.length\` with literals. Silence here would read as a clean router; it is only one this analysis cannot see. Write the router in that idiom, or carry this finding with the reason it cannot be.`,
|
|
19768
21194
|
anchor,
|
|
19769
|
-
|
|
21195
|
+
draftContext4,
|
|
19770
21196
|
void 0,
|
|
19771
21197
|
{ at: via }
|
|
19772
21198
|
);
|
|
@@ -19791,7 +21217,7 @@ var init_route_coverage = __esm({
|
|
|
19791
21217
|
"UNDECLARED_ROUTE",
|
|
19792
21218
|
`Portal "${portal.id}"'s router "${via}" (${where}), mounted by listener "${listener.id}", answers ${undeclared.length} route(s) no contract endpoint of "${portal.id}" declares \u2014 ${undeclared.map((key) => `"${key}"`).join(", ")}. A surface the code serves and the design never promised is how a write runs with no contract: no brief, no auth review, no rule reading it. Declare each as a contract method with its endpoint, or take the route out of the router.`,
|
|
19793
21219
|
anchor,
|
|
19794
|
-
|
|
21220
|
+
draftContext4,
|
|
19795
21221
|
void 0,
|
|
19796
21222
|
{ at: via, covers: undeclared }
|
|
19797
21223
|
);
|
|
@@ -19803,7 +21229,7 @@ var init_route_coverage = __esm({
|
|
|
19803
21229
|
"UNROUTED_ENDPOINT",
|
|
19804
21230
|
`Portal "${portal.id}" binds ${unrouted.length} HTTP endpoint(s) under listener "${listener.id}"'s mount that no route of its router "${via}" (${where}) answers \u2014 ${unrouted.map((key) => `"${key}"`).join(", ")}. The contract promises a route no request can reach. Route it in the router, or drop the endpoint from the contract.`,
|
|
19805
21231
|
anchor,
|
|
19806
|
-
|
|
21232
|
+
draftContext4,
|
|
19807
21233
|
void 0,
|
|
19808
21234
|
{ at: via, covers: unrouted }
|
|
19809
21235
|
);
|
|
@@ -19920,7 +21346,7 @@ var init_export_conformance = __esm({
|
|
|
19920
21346
|
}
|
|
19921
21347
|
}
|
|
19922
21348
|
}
|
|
19923
|
-
for (const { implementation, method: method2, sourceFile, draftContext:
|
|
21349
|
+
for (const { implementation, method: method2, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
19924
21350
|
const handle = method2.exportedVia;
|
|
19925
21351
|
if (!handle || !sourceFile) continue;
|
|
19926
21352
|
const file = pathKey(sourceFile);
|
|
@@ -19935,7 +21361,7 @@ var init_export_conformance = __esm({
|
|
|
19935
21361
|
"UNREALIZED_EXPORT_HANDLE",
|
|
19936
21362
|
`Method "${method2.name}" in implementation "${implementation.id}" declares exportedVia "${handle}", but "${file}" exports no such name. A handle names the export a consumer imports to REACH the method \u2014 the value that composes it, which \`symbol\` cannot name because \`symbol\` names the function inside \u2014 so one the file does not publish promises a route nobody can import. It allows nothing either: every export of this file is still read against the contracts. Name the binding the file actually exports, export it, or drop the handle.`,
|
|
19937
21363
|
implementation.id,
|
|
19938
|
-
|
|
21364
|
+
draftContext4
|
|
19939
21365
|
);
|
|
19940
21366
|
}
|
|
19941
21367
|
for (const listener of ctx.components) {
|
|
@@ -20330,89 +21756,6 @@ var init_coupling_health = __esm({
|
|
|
20330
21756
|
}
|
|
20331
21757
|
});
|
|
20332
21758
|
|
|
20333
|
-
// src/core/rules/heuristic/signature-language-builtins.ts
|
|
20334
|
-
var LANGUAGE_MARKERS, signatureLanguageBuiltinsRule;
|
|
20335
|
-
var init_signature_language_builtins = __esm({
|
|
20336
|
-
"src/core/rules/heuristic/signature-language-builtins.ts"() {
|
|
20337
|
-
"use strict";
|
|
20338
|
-
init_models();
|
|
20339
|
-
LANGUAGE_MARKERS = {
|
|
20340
|
-
rust: /* @__PURE__ */ new Set([
|
|
20341
|
-
"u8",
|
|
20342
|
-
"u16",
|
|
20343
|
-
"u32",
|
|
20344
|
-
"u64",
|
|
20345
|
-
"u128",
|
|
20346
|
-
"usize",
|
|
20347
|
-
"i8",
|
|
20348
|
-
"i16",
|
|
20349
|
-
"i32",
|
|
20350
|
-
"i64",
|
|
20351
|
-
"i128",
|
|
20352
|
-
"isize",
|
|
20353
|
-
"f32",
|
|
20354
|
-
"f64",
|
|
20355
|
-
"vec",
|
|
20356
|
-
"box",
|
|
20357
|
-
"arc",
|
|
20358
|
-
"rc",
|
|
20359
|
-
"refcell",
|
|
20360
|
-
"cell",
|
|
20361
|
-
"mutex",
|
|
20362
|
-
"rwlock",
|
|
20363
|
-
"str"
|
|
20364
|
-
]),
|
|
20365
|
-
typescript: /* @__PURE__ */ new Set(["any", "unknown", "never", "undefined", "promise", "record"]),
|
|
20366
|
-
javascript: /* @__PURE__ */ new Set(["promise", "undefined"]),
|
|
20367
|
-
python: /* @__PURE__ */ new Set(["dict", "tuple"]),
|
|
20368
|
-
csharp: /* @__PURE__ */ new Set(["task"]),
|
|
20369
|
-
go: /* @__PURE__ */ new Set(["chan", "rune"])
|
|
20370
|
-
};
|
|
20371
|
-
signatureLanguageBuiltinsRule = {
|
|
20372
|
-
name: "signature-language-builtins",
|
|
20373
|
-
judges: "design",
|
|
20374
|
-
description: "Contracts must speak the declared target language: builtin types that unambiguously belong to another language family are flagged in method signatures (e.g. `usize` in a TypeScript system, `Promise` in a Rust one). Set targetLanguage on the system (L0) or override per subsystem (L1).",
|
|
20375
|
-
codes: [
|
|
20376
|
-
{ code: "LANGUAGE_FOREIGN_BUILTIN", defaultSeverity: "warning", summary: "Signature uses a builtin from a different language family" }
|
|
20377
|
-
],
|
|
20378
|
-
check(ctx) {
|
|
20379
|
-
const markersFor = (family) => {
|
|
20380
|
-
const base = LANGUAGE_MARKERS[family];
|
|
20381
|
-
const extra = ctx.ext.languages[family]?.foreignBuiltins;
|
|
20382
|
-
if (!extra?.length) return base;
|
|
20383
|
-
return /* @__PURE__ */ new Set([...base ?? [], ...extra.map((s) => s.toLowerCase())]);
|
|
20384
|
-
};
|
|
20385
|
-
const families = [.../* @__PURE__ */ new Set([...Object.keys(LANGUAGE_MARKERS), ...Object.keys(ctx.ext.languages)])];
|
|
20386
|
-
const scans = [];
|
|
20387
|
-
for (const intf of ctx.interfaces) {
|
|
20388
|
-
const comp = ctx.componentMap.get(intf.component);
|
|
20389
|
-
const lang = ctx.targetLanguageFor(comp?.subsystem);
|
|
20390
|
-
if (!lang) continue;
|
|
20391
|
-
const ownMarkers = markersFor(lang);
|
|
20392
|
-
if (!ownMarkers || ownMarkers.size === 0) continue;
|
|
20393
|
-
const draft = ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design";
|
|
20394
|
-
for (const method2 of intf.methods) {
|
|
20395
|
-
for (const ref of methodTypeRefs(method2)) scans.push({ intf, method: method2, ref, lang, ownMarkers, draft });
|
|
20396
|
-
}
|
|
20397
|
-
}
|
|
20398
|
-
for (const scan of scans) {
|
|
20399
|
-
const refLower = scan.ref.toLowerCase();
|
|
20400
|
-
if (scan.ownMarkers.has(refLower)) continue;
|
|
20401
|
-
const foreign = families.find((family) => family !== scan.lang && markersFor(family)?.has(refLower));
|
|
20402
|
-
if (!foreign) continue;
|
|
20403
|
-
ctx.addIssue(
|
|
20404
|
-
"warning",
|
|
20405
|
-
"LANGUAGE_FOREIGN_BUILTIN",
|
|
20406
|
-
`Method "${scan.method.name}" on interface "${scan.intf.id}" uses "${scan.ref}", a ${foreign} builtin, but the target language here is ${scan.lang}. Use the ${scan.lang} equivalent so implementers generate idiomatic code.`,
|
|
20407
|
-
scan.intf.id,
|
|
20408
|
-
scan.draft
|
|
20409
|
-
);
|
|
20410
|
-
}
|
|
20411
|
-
}
|
|
20412
|
-
};
|
|
20413
|
-
}
|
|
20414
|
-
});
|
|
20415
|
-
|
|
20416
21759
|
// src/core/rules/heuristic/narrative-language-constructs.ts
|
|
20417
21760
|
function constructsOf(step) {
|
|
20418
21761
|
const constructs = [
|
|
@@ -21413,6 +22756,9 @@ var init_repository = __esm({
|
|
|
21413
22756
|
init_signature_sources();
|
|
21414
22757
|
init_signature_types();
|
|
21415
22758
|
init_signature_text();
|
|
22759
|
+
init_type_expressions();
|
|
22760
|
+
init_enum_types();
|
|
22761
|
+
init_named_scalar_types();
|
|
21416
22762
|
init_public_surface_binding();
|
|
21417
22763
|
init_public_surface_consumers();
|
|
21418
22764
|
init_public_surface_declared_type();
|
|
@@ -21465,6 +22811,7 @@ var init_repository = __esm({
|
|
|
21465
22811
|
init_pack_resolution();
|
|
21466
22812
|
init_pack_reproducibility();
|
|
21467
22813
|
init_pack_requirements();
|
|
22814
|
+
init_pack_deprecations();
|
|
21468
22815
|
init_dependency_cycles();
|
|
21469
22816
|
init_dispatch_table_bindings();
|
|
21470
22817
|
init_dispatch_step_routing();
|
|
@@ -21493,13 +22840,14 @@ var init_repository = __esm({
|
|
|
21493
22840
|
init_integration_sim_coverage();
|
|
21494
22841
|
init_type_realization();
|
|
21495
22842
|
init_type_shape();
|
|
22843
|
+
init_enum_values();
|
|
21496
22844
|
init_param_conformance();
|
|
22845
|
+
init_async_conformance();
|
|
21497
22846
|
init_route_coverage();
|
|
21498
22847
|
init_unclaimed_source();
|
|
21499
22848
|
init_export_conformance();
|
|
21500
22849
|
init_carried_debt();
|
|
21501
22850
|
init_coupling_health();
|
|
21502
|
-
init_signature_language_builtins();
|
|
21503
22851
|
init_narrative_language_constructs();
|
|
21504
22852
|
init_technology_binding();
|
|
21505
22853
|
init_technology_boundaries();
|
|
@@ -21530,6 +22878,11 @@ var init_repository = __esm({
|
|
|
21530
22878
|
signatureSourcesRule,
|
|
21531
22879
|
signatureTypesRule,
|
|
21532
22880
|
signatureTextRule,
|
|
22881
|
+
// The type grammar beside the signatures: how each stored type position is
|
|
22882
|
+
// spelled, then what an enum and a named scalar may hold.
|
|
22883
|
+
typeExpressionsRule,
|
|
22884
|
+
enumTypesRule,
|
|
22885
|
+
namedScalarTypesRule,
|
|
21533
22886
|
// Contracts and the targets narratives name, in four questions with one
|
|
21534
22887
|
// owner each: does the implementation mirror its contract, does a target
|
|
21535
22888
|
// inside this tree resolve, does a target that leaves it pin to exactly one
|
|
@@ -21694,14 +23047,17 @@ var init_repository = __esm({
|
|
|
21694
23047
|
// others named.
|
|
21695
23048
|
typeRealizationRule,
|
|
21696
23049
|
typeShapeRule,
|
|
23050
|
+
// An enum's values beside the data shape, and whether the call completes
|
|
23051
|
+
// later beside the signature: the same readings, of their own facts.
|
|
23052
|
+
enumValuesRule,
|
|
21697
23053
|
paramConformanceRule,
|
|
23054
|
+
asyncConformanceRule,
|
|
21698
23055
|
routeCoverageRule,
|
|
21699
23056
|
unclaimedSourceRule,
|
|
21700
23057
|
exportConformanceRule,
|
|
21701
23058
|
couplingRule,
|
|
21702
|
-
// Target-language fit
|
|
21703
|
-
//
|
|
21704
|
-
signatureLanguageBuiltinsRule,
|
|
23059
|
+
// Target-language fit: what a NARRATIVE may describe. What a contract may
|
|
23060
|
+
// name is the neutral type grammar's (type-expressions), not a language's.
|
|
21705
23061
|
narrativeLanguageConstructsRule,
|
|
21706
23062
|
// The declaration before the consequences: which stereotype may bind a
|
|
21707
23063
|
// technology at all, then where its name may appear.
|
|
@@ -21725,6 +23081,9 @@ var init_repository = __esm({
|
|
|
21725
23081
|
// stage): configuration too, and the family run cannot judge a member against
|
|
21726
23082
|
// a requirement that does not parse.
|
|
21727
23083
|
packRequirementsRule,
|
|
23084
|
+
// The fields a loaded pack still declares that wairon has deprecated: about
|
|
23085
|
+
// the packs' configuration too, and only ever a notice.
|
|
23086
|
+
packDeprecationsRule,
|
|
21728
23087
|
// MUST run last, in this order: each audits what the earlier rules did
|
|
21729
23088
|
// with a declared exception. The debt register first (which carried
|
|
21730
23089
|
// findings the conformance family actually matched), then the allows
|
|
@@ -21871,6 +23230,9 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
21871
23230
|
const typeShapes = /* @__PURE__ */ new Map();
|
|
21872
23231
|
const functionParams = /* @__PURE__ */ new Map();
|
|
21873
23232
|
const functionRoutes = /* @__PURE__ */ new Map();
|
|
23233
|
+
const asyncFunctions = [];
|
|
23234
|
+
const enumValues = /* @__PURE__ */ new Map();
|
|
23235
|
+
const aliasTypes = /* @__PURE__ */ new Map();
|
|
21874
23236
|
const mutableBindings = /* @__PURE__ */ new Set();
|
|
21875
23237
|
const schemaConstants = /* @__PURE__ */ new Map();
|
|
21876
23238
|
const derivedAliases = [];
|
|
@@ -22085,6 +23447,48 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
22085
23447
|
if (fn.body) walk2(fn.body, []);
|
|
22086
23448
|
return routes;
|
|
22087
23449
|
};
|
|
23450
|
+
const completesLater = (fn) => {
|
|
23451
|
+
const mods = fn.modifiers;
|
|
23452
|
+
if (mods?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) return true;
|
|
23453
|
+
const returned = fn.type;
|
|
23454
|
+
return !!returned && ts.isTypeReferenceNode(returned) && ts.isIdentifier(returned.typeName) && returned.typeName.text === "Promise";
|
|
23455
|
+
};
|
|
23456
|
+
const stringLiteralUnion = (type) => {
|
|
23457
|
+
const members = ts.isUnionTypeNode(type) ? [...type.types] : [type];
|
|
23458
|
+
const values = [];
|
|
23459
|
+
for (const member of members) {
|
|
23460
|
+
if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return void 0;
|
|
23461
|
+
values.push(member.literal.text);
|
|
23462
|
+
}
|
|
23463
|
+
return values;
|
|
23464
|
+
};
|
|
23465
|
+
const zodEnumValues = (expression) => {
|
|
23466
|
+
const strings = (array, hops) => {
|
|
23467
|
+
let node2 = array;
|
|
23468
|
+
while (node2 && (ts.isAsExpression(node2) || ts.isParenthesizedExpression(node2) || ts.isSatisfiesExpression(node2))) node2 = node2.expression;
|
|
23469
|
+
if (node2 && ts.isIdentifier(node2) && hops > 0) return strings(schemaConstants.get(node2.text), hops - 1);
|
|
23470
|
+
if (!node2 || !ts.isArrayLiteralExpression(node2) || node2.elements.length === 0) return void 0;
|
|
23471
|
+
const values = [];
|
|
23472
|
+
for (const element of node2.elements) {
|
|
23473
|
+
if (!ts.isStringLiteral(element) && !ts.isNoSubstitutionTemplateLiteral(element)) return void 0;
|
|
23474
|
+
values.push(element.text);
|
|
23475
|
+
}
|
|
23476
|
+
return values;
|
|
23477
|
+
};
|
|
23478
|
+
let node = expression;
|
|
23479
|
+
const walked = /* @__PURE__ */ new Set();
|
|
23480
|
+
while (node && !walked.has(node)) {
|
|
23481
|
+
walked.add(node);
|
|
23482
|
+
if (ts.isCallExpression(node)) {
|
|
23483
|
+
const callee = node.expression;
|
|
23484
|
+
if (ts.isPropertyAccessExpression(callee) && callee.name.text === "enum") return strings(node.arguments[0], 1);
|
|
23485
|
+
node = callee;
|
|
23486
|
+
} else if (ts.isPropertyAccessExpression(node)) {
|
|
23487
|
+
node = node.expression;
|
|
23488
|
+
} else break;
|
|
23489
|
+
}
|
|
23490
|
+
return void 0;
|
|
23491
|
+
};
|
|
22088
23492
|
const visit = (node) => {
|
|
22089
23493
|
const fnName = namedFunctionName(node);
|
|
22090
23494
|
if (fnName && node.body) {
|
|
@@ -22096,6 +23500,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
22096
23500
|
const signatures = functionParams.get(fnName) ?? [];
|
|
22097
23501
|
signatures.push(declaredParameters(node));
|
|
22098
23502
|
functionParams.set(fnName, signatures);
|
|
23503
|
+
if (completesLater(node)) asyncFunctions.push(fnName);
|
|
22099
23504
|
const routes = collectRoutes(node);
|
|
22100
23505
|
if (routes.size > 0) {
|
|
22101
23506
|
const known = functionRoutes.get(fnName) ?? /* @__PURE__ */ new Map();
|
|
@@ -22118,10 +23523,17 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
22118
23523
|
} else if (ts.isTypeAliasDeclaration(node)) {
|
|
22119
23524
|
if (ts.isTypeLiteralNode(node.type)) recordDeclaredShape(node.name.text, node.type.members, false);
|
|
22120
23525
|
else {
|
|
23526
|
+
if (!aliasTypes.has(node.name.text)) aliasTypes.set(node.name.text, node.type.getText(sf));
|
|
22121
23527
|
const constant = inferredSchemaConstant(node.type);
|
|
22122
23528
|
if (constant) derivedAliases.push({ name: node.name.text, constant });
|
|
23529
|
+
const literals = stringLiteralUnion(node.type);
|
|
23530
|
+
if (literals) enumValues.set(node.name.text, literals);
|
|
22123
23531
|
}
|
|
22124
23532
|
}
|
|
23533
|
+
if (ts.isEnumDeclaration(node)) {
|
|
23534
|
+
const values = node.members.map((member) => member.initializer && (ts.isStringLiteral(member.initializer) || ts.isNoSubstitutionTemplateLiteral(member.initializer)) ? member.initializer.text : void 0);
|
|
23535
|
+
if (values.length > 0 && values.every((v) => v !== void 0)) enumValues.set(node.name.text, values);
|
|
23536
|
+
}
|
|
22125
23537
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && !schemaConstants.has(node.name.text)) {
|
|
22126
23538
|
schemaConstants.set(node.name.text, node.initializer);
|
|
22127
23539
|
}
|
|
@@ -22243,8 +23655,17 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
22243
23655
|
if (!fields) continue;
|
|
22244
23656
|
typeShapes.set(alias.name, { origin: "derived", fields, methods: [] });
|
|
22245
23657
|
}
|
|
23658
|
+
for (const [name, initializer] of schemaConstants) {
|
|
23659
|
+
const values = zodEnumValues(initializer);
|
|
23660
|
+
if (values) enumValues.set(name, values);
|
|
23661
|
+
}
|
|
23662
|
+
for (const alias of derivedAliases) {
|
|
23663
|
+
if (enumValues.has(alias.name)) continue;
|
|
23664
|
+
const values = enumValues.get(alias.constant);
|
|
23665
|
+
if (values && schemaConstants.has(alias.constant)) enumValues.set(alias.name, values);
|
|
23666
|
+
}
|
|
22246
23667
|
const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
|
|
22247
|
-
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, mutableBindings, reexportOnly };
|
|
23668
|
+
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, asyncFunctions, enumValues, aliasTypes, mutableBindings, reexportOnly };
|
|
22248
23669
|
}
|
|
22249
23670
|
function resolveRelativeModule(fromFile, specifier) {
|
|
22250
23671
|
if (!specifier.startsWith(".")) return null;
|
|
@@ -22323,7 +23744,7 @@ function walkDeclaredRoots(roots, exclude, projectRoot2) {
|
|
|
22323
23744
|
const record2 = (absolute) => {
|
|
22324
23745
|
const key = pathKey(path20.relative(projectRoot2, absolute));
|
|
22325
23746
|
if (seen.has(key) || isExcluded(key)) return;
|
|
22326
|
-
if (!
|
|
23747
|
+
if (!languageOfSourcePath(key)) return;
|
|
22327
23748
|
seen.add(key);
|
|
22328
23749
|
found.push(key);
|
|
22329
23750
|
};
|
|
@@ -22405,7 +23826,7 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
22405
23826
|
continue;
|
|
22406
23827
|
}
|
|
22407
23828
|
const text3 = buffer.toString("utf8");
|
|
22408
|
-
const language =
|
|
23829
|
+
const language = languageOfSourcePath(sourcePath);
|
|
22409
23830
|
let analyzed;
|
|
22410
23831
|
if (language === "typescript" || language === "javascript") {
|
|
22411
23832
|
const ts = resolveTypeScript(projectRoot2);
|
|
@@ -22433,6 +23854,9 @@ function buildCodeModel(implementations, types, projectRoot2, sourceRoots = [],
|
|
|
22433
23854
|
typeShapes: Object.fromEntries(facts.typeShapes),
|
|
22434
23855
|
functionParams: Object.fromEntries(facts.functionParams),
|
|
22435
23856
|
functionRoutes: Object.fromEntries([...facts.functionRoutes].map(([k, v]) => [k, [...v.values()]])),
|
|
23857
|
+
asyncFunctions: [...facts.asyncFunctions],
|
|
23858
|
+
enumValues: Object.fromEntries(facts.enumValues),
|
|
23859
|
+
aliasTypes: Object.fromEntries(facts.aliasTypes),
|
|
22436
23860
|
topLevelMutableBindings: [...facts.mutableBindings],
|
|
22437
23861
|
reexportOnly: facts.reexportOnly
|
|
22438
23862
|
};
|
|
@@ -22585,7 +24009,7 @@ function findTestsReferencing(methods, projectRoot2, testRoots) {
|
|
|
22585
24009
|
}
|
|
22586
24010
|
return found;
|
|
22587
24011
|
}
|
|
22588
|
-
var fs15, path20, import_module2,
|
|
24012
|
+
var fs15, path20, import_module2, C_FAMILY_COMMENTS, NAMED_IMPORT_BINDINGS_RE, JS_PATTERNS, LANGUAGE_PATTERNS, PATTERN_ANALYSIS_MAX_BYTES, IDENTIFIER_RE, STRING_RE, tsResolutionCache, TS_RESOLUTION_RETRY_MS, IMPORT_FROM_RE, DYNAMIC_IMPORT_RE, IDENTIFIER_ONLY_RE, NAMED_REEXPORT_RE, STAR_REEXPORT_RE;
|
|
22589
24013
|
var init_source_analysis = __esm({
|
|
22590
24014
|
"src/core/source-analysis.ts"() {
|
|
22591
24015
|
"use strict";
|
|
@@ -22593,30 +24017,6 @@ var init_source_analysis = __esm({
|
|
|
22593
24017
|
path20 = __toESM(require("path"));
|
|
22594
24018
|
import_module2 = require("module");
|
|
22595
24019
|
init_models();
|
|
22596
|
-
EXTENSION_LANGUAGE = {
|
|
22597
|
-
".ts": "typescript",
|
|
22598
|
-
".tsx": "typescript",
|
|
22599
|
-
".mts": "typescript",
|
|
22600
|
-
".cts": "typescript",
|
|
22601
|
-
".js": "javascript",
|
|
22602
|
-
".jsx": "javascript",
|
|
22603
|
-
".mjs": "javascript",
|
|
22604
|
-
".cjs": "javascript",
|
|
22605
|
-
".py": "python",
|
|
22606
|
-
".rs": "rust",
|
|
22607
|
-
".go": "go",
|
|
22608
|
-
".cs": "csharp",
|
|
22609
|
-
".java": "java",
|
|
22610
|
-
".c": "c",
|
|
22611
|
-
".h": "c",
|
|
22612
|
-
".cpp": "cpp",
|
|
22613
|
-
".cc": "cpp",
|
|
22614
|
-
".hpp": "cpp",
|
|
22615
|
-
".rb": "ruby",
|
|
22616
|
-
".php": "php",
|
|
22617
|
-
".kt": "kotlin",
|
|
22618
|
-
".swift": "swift"
|
|
22619
|
-
};
|
|
22620
24020
|
C_FAMILY_COMMENTS = { lineComments: ["//"], blockComments: [["/*", "*/"]] };
|
|
22621
24021
|
NAMED_IMPORT_BINDINGS_RE = /\bimport\s*\{([^}]*)\}/g;
|
|
22622
24022
|
JS_PATTERNS = {
|
|
@@ -22920,7 +24320,7 @@ function buildRuleContext(opts) {
|
|
|
22920
24320
|
const authoredTypeRefs = new Set((family?.authoredReferences ?? []).filter((r) => r.position === "type" && r.binding !== "local" && memberOf(r.specId) === void 0).map((r) => r.authored));
|
|
22921
24321
|
const isTypeResolved = (ref, generics) => {
|
|
22922
24322
|
const refLower = ref.toLowerCase();
|
|
22923
|
-
if (
|
|
24323
|
+
if (isTypeVocabulary(refLower)) return true;
|
|
22924
24324
|
if (generics.has(refLower)) return true;
|
|
22925
24325
|
if (ownTypes.some((spec) => typeMatchesRef(spec, ref))) return true;
|
|
22926
24326
|
const [first, ...rest] = ref.split(/::|\./);
|
|
@@ -23134,7 +24534,7 @@ function buildRuleContext(opts) {
|
|
|
23134
24534
|
}
|
|
23135
24535
|
return projectNaming;
|
|
23136
24536
|
};
|
|
23137
|
-
const isBuiltinType = (ref) =>
|
|
24537
|
+
const isBuiltinType = (ref) => isTypeVocabulary(ref);
|
|
23138
24538
|
const getRuleSeverity = (ruleCode, defaultSeverity, isDraftContext, subsystemId) => {
|
|
23139
24539
|
if (rules?.sddRuleSeverity?.[ruleCode]) {
|
|
23140
24540
|
return rules.sddRuleSeverity[ruleCode];
|
|
@@ -23312,7 +24712,7 @@ function buildRuleContext(opts) {
|
|
|
23312
24712
|
documentationConfigFor,
|
|
23313
24713
|
namingConfigFor,
|
|
23314
24714
|
isBuiltinType,
|
|
23315
|
-
ext: { profiles: extensions.profiles, languages: extensions.languages, patterns: extensions.patterns, guarantees: extensions.guarantees, assertions: extensions.assertions, packSelections: opts.packSelections ?? [], selectionFailures: extensions.selectionFailures ?? [], packRequirements: opts.packRequirements ?? [] },
|
|
24715
|
+
ext: { profiles: extensions.profiles, languages: extensions.languages, patterns: extensions.patterns, guarantees: extensions.guarantees, assertions: extensions.assertions, packSelections: opts.packSelections ?? [], selectionFailures: extensions.selectionFailures ?? [], packRequirements: opts.packRequirements ?? [], deprecations: extensions.deprecations ?? [] },
|
|
23316
24716
|
variants: opts.variants ?? [],
|
|
23317
24717
|
surfaceSnapshots,
|
|
23318
24718
|
...opts.projectIdentity ? { projectIdentity: opts.projectIdentity } : {},
|
|
@@ -23321,6 +24721,7 @@ function buildRuleContext(opts) {
|
|
|
23321
24721
|
...opts.projectFamily ? { projectFamily: opts.projectFamily } : {},
|
|
23322
24722
|
...opts.exportUsages ? { exportUsages: opts.exportUsages } : {},
|
|
23323
24723
|
...opts.signatureFacts ? { signatureFacts: opts.signatureFacts } : {},
|
|
24724
|
+
...opts.typeSpellingFacts ? { typeSpellingFacts: opts.typeSpellingFacts } : {},
|
|
23324
24725
|
pinnedExternals,
|
|
23325
24726
|
codeModel: opts.codeModel ?? emptyCodeModel(),
|
|
23326
24727
|
roundTripIssues: opts.roundTripIssues,
|
|
@@ -23829,7 +25230,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
23829
25230
|
let extensions;
|
|
23830
25231
|
let treatAllAsComplete = false;
|
|
23831
25232
|
let packSelections;
|
|
23832
|
-
if (rulesOrOptions && ("scopeSubsystem" in rulesOrOptions || "
|
|
25233
|
+
if (rulesOrOptions && ("scopeSubsystem" in rulesOrOptions || "memberDepth" in rulesOrOptions || "rules" in rulesOrOptions || "projectType" in rulesOrOptions || "extensions" in rulesOrOptions || "treatAllAsComplete" in rulesOrOptions || "family" in rulesOrOptions || "packSelections" in rulesOrOptions)) {
|
|
23833
25234
|
const opts = rulesOrOptions;
|
|
23834
25235
|
rules = opts.rules;
|
|
23835
25236
|
projectType = opts.projectType ?? "backend";
|
|
@@ -23839,7 +25240,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
23839
25240
|
packSelections = opts.packSelections;
|
|
23840
25241
|
}
|
|
23841
25242
|
extensions ??= loadProjectExtensions();
|
|
23842
|
-
scanAllSpecs(
|
|
25243
|
+
scanAllSpecs();
|
|
23843
25244
|
const issues = [];
|
|
23844
25245
|
clearLoaderIssues();
|
|
23845
25246
|
const boundConfig = boundConfiguration();
|
|
@@ -23917,6 +25318,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
23917
25318
|
const producers = new Set(family.references.filter((r) => r.consumer === "").map((r) => r.producer));
|
|
23918
25319
|
const exportUsages = [...producers].map((producer) => exportUsage("", producer));
|
|
23919
25320
|
const signatures = signatureFacts();
|
|
25321
|
+
const typeSpellings = typeSpellingFacts();
|
|
23920
25322
|
const ctx = buildRuleContext({
|
|
23921
25323
|
system,
|
|
23922
25324
|
subsystems,
|
|
@@ -23939,6 +25341,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
23939
25341
|
projectFamily: family,
|
|
23940
25342
|
exportUsages,
|
|
23941
25343
|
signatureFacts: signatures,
|
|
25344
|
+
typeSpellingFacts: typeSpellings,
|
|
23942
25345
|
pinnedExternals,
|
|
23943
25346
|
// By-name selections only: a legacy path ref pins nothing to check. A dry
|
|
23944
25347
|
// run supplies its candidate's; otherwise the stored ones.
|
|
@@ -24058,7 +25461,12 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
24058
25461
|
issues.push(issue("warning", "EXTERNAL_CHECK_UNAVAILABLE", `"${by}" names "${key}", which neither this part nor its pinned excerpt of "${parentId}" holds \u2014 used since the pin: re-pin with \`wairon externals pin\` while the parent is on disk.`, by));
|
|
24059
25462
|
}
|
|
24060
25463
|
const ownSignatures = signatureFacts();
|
|
24061
|
-
const
|
|
25464
|
+
const ownTypeSpellings = typeSpellingFacts();
|
|
25465
|
+
const partTypeSpellings = {
|
|
25466
|
+
respellings: ownTypeSpellings.respellings.filter((r) => isOwn(r.specId)),
|
|
25467
|
+
problems: ownTypeSpellings.problems.filter((p) => p.specId === void 0 || isOwn(p.specId))
|
|
25468
|
+
};
|
|
25469
|
+
const resolved = resolveSignatures(
|
|
24062
25470
|
[...own.interfaces, ...context.interfaces],
|
|
24063
25471
|
[...own.components, ...context.components],
|
|
24064
25472
|
[...own.types, ...context.types]
|
|
@@ -24097,6 +25505,7 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
24097
25505
|
projectFamily: graph(),
|
|
24098
25506
|
exportUsages: [],
|
|
24099
25507
|
signatureFacts: partSignatures,
|
|
25508
|
+
typeSpellingFacts: partTypeSpellings,
|
|
24100
25509
|
pinnedExternals: [],
|
|
24101
25510
|
packSelections: packs.filter((p) => typeof p !== "string"),
|
|
24102
25511
|
packRequirements: [],
|
|
@@ -24184,7 +25593,7 @@ function builtinProjectKinds() {
|
|
|
24184
25593
|
return [...PROJECT_KINDS];
|
|
24185
25594
|
}
|
|
24186
25595
|
function computeGateStateId() {
|
|
24187
|
-
scanAllSpecs(
|
|
25596
|
+
scanAllSpecs();
|
|
24188
25597
|
const content = computeOwnStateId();
|
|
24189
25598
|
const extensions = loadProjectExtensions();
|
|
24190
25599
|
let gate = {};
|
|
@@ -24873,16 +26282,16 @@ function bindReferencedMembers(node, root) {
|
|
|
24873
26282
|
out.push({ ...base, sourceKind: "hosted", hosted: member.source.hosted });
|
|
24874
26283
|
continue;
|
|
24875
26284
|
}
|
|
24876
|
-
const
|
|
26285
|
+
const located2 = root.referenced.find((r) => r.alias === member.alias);
|
|
24877
26286
|
const sourceKind = member.storage === "git" ? "git" : "path";
|
|
24878
|
-
const directory =
|
|
24879
|
-
const commit3 =
|
|
26287
|
+
const directory = located2?.directory ?? (member.storage === "path" ? path22.resolve(node.directory, member.source.path ?? "") : void 0);
|
|
26288
|
+
const commit3 = located2?.commit ?? member.source.commit;
|
|
24880
26289
|
out.push({
|
|
24881
26290
|
...base,
|
|
24882
26291
|
sourceKind,
|
|
24883
26292
|
...directory !== void 0 ? { directory } : {},
|
|
24884
26293
|
...commit3 !== void 0 ? { commit: commit3 } : {},
|
|
24885
|
-
...
|
|
26294
|
+
...located2?.availability === "unavailable" ? { problem: located2.reason } : {}
|
|
24886
26295
|
});
|
|
24887
26296
|
}
|
|
24888
26297
|
return out;
|
|
@@ -25720,7 +27129,8 @@ function emptyIndex() {
|
|
|
25720
27129
|
type: {},
|
|
25721
27130
|
group: {}
|
|
25722
27131
|
},
|
|
25723
|
-
signatures: { sources: [], staleTexts: [] }
|
|
27132
|
+
signatures: { sources: [], staleTexts: [] },
|
|
27133
|
+
typeSpellings: emptyTypeSpellingFacts()
|
|
25724
27134
|
};
|
|
25725
27135
|
}
|
|
25726
27136
|
function isWithin(dir, file) {
|
|
@@ -26075,7 +27485,7 @@ function bareRawReferences(kind, spec) {
|
|
|
26075
27485
|
const out = [];
|
|
26076
27486
|
const seen = /* @__PURE__ */ new Set();
|
|
26077
27487
|
const add2 = (position, value, generics = /* @__PURE__ */ new Set()) => {
|
|
26078
|
-
if (!value || value.includes("::") ||
|
|
27488
|
+
if (!value || value.includes("::") || isTypeVocabulary(value) || generics.has(value.toLowerCase())) return;
|
|
26079
27489
|
const k = `${position}|${value}`;
|
|
26080
27490
|
if (seen.has(k)) return;
|
|
26081
27491
|
seen.add(k);
|
|
@@ -26495,6 +27905,49 @@ function bindImport(raw, suppliers, p) {
|
|
|
26495
27905
|
}
|
|
26496
27906
|
};
|
|
26497
27907
|
}
|
|
27908
|
+
function typePositionText(spec, at) {
|
|
27909
|
+
const [head2, name, member, param] = at.split(".");
|
|
27910
|
+
const named2 = (list2, key) => Array.isArray(list2) ? list2.find((x) => x?.name === key) : void 0;
|
|
27911
|
+
if (head2 === "returns") return spec.returns;
|
|
27912
|
+
if (head2 === "params") return named2(spec.params, name)?.type;
|
|
27913
|
+
if (head2 === "fields") return named2(spec.fields, name)?.type;
|
|
27914
|
+
if (head2 !== "methods") return void 0;
|
|
27915
|
+
const method2 = named2(spec.methods, name);
|
|
27916
|
+
return member === "returns" ? method2?.returns : named2(method2?.params, param)?.type;
|
|
27917
|
+
}
|
|
27918
|
+
function writtenSignatureTexts(raws) {
|
|
27919
|
+
const texts = /* @__PURE__ */ new Map();
|
|
27920
|
+
const record2 = (kind, specId, methods) => {
|
|
27921
|
+
for (const m of methods) {
|
|
27922
|
+
if (m.signatureFrom !== void 0) continue;
|
|
27923
|
+
const derived = deriveMethodSignature(m);
|
|
27924
|
+
if (derived !== void 0) texts.set(`${kind}|${specId}|${m.name}`, derived);
|
|
27925
|
+
}
|
|
27926
|
+
};
|
|
27927
|
+
for (const raw of raws) {
|
|
27928
|
+
for (const intf of raw.index.interfaces) record2("interface", intf.id, intf.methods ?? []);
|
|
27929
|
+
for (const type of raw.index.types) record2("type", type.id, type.methods ?? []);
|
|
27930
|
+
}
|
|
27931
|
+
return texts;
|
|
27932
|
+
}
|
|
27933
|
+
function canonicalizeRootTypes(raws) {
|
|
27934
|
+
const facts = emptyTypeSpellingFacts();
|
|
27935
|
+
for (const raw of raws) {
|
|
27936
|
+
raw.index.interfaces = raw.index.interfaces.map((intf) => {
|
|
27937
|
+
const read2 = interfaceCanonicalTypes(intf);
|
|
27938
|
+
facts.respellings.push(...read2.respellings);
|
|
27939
|
+
facts.problems.push(...read2.problems);
|
|
27940
|
+
return read2.spec;
|
|
27941
|
+
});
|
|
27942
|
+
raw.index.types = raw.index.types.map((type) => {
|
|
27943
|
+
const read2 = typeCanonicalTypes(type);
|
|
27944
|
+
facts.respellings.push(...read2.respellings);
|
|
27945
|
+
facts.problems.push(...read2.problems);
|
|
27946
|
+
return read2.spec;
|
|
27947
|
+
});
|
|
27948
|
+
}
|
|
27949
|
+
return facts;
|
|
27950
|
+
}
|
|
26498
27951
|
function bindRootReferences(raw, raws, readables) {
|
|
26499
27952
|
const bound2 = /* @__PURE__ */ new Map();
|
|
26500
27953
|
for (const p of raw.pending) {
|
|
@@ -26587,7 +28040,8 @@ function specKind(raw) {
|
|
|
26587
28040
|
if ("component" in raw && Array.isArray(raw.methods)) return "interface";
|
|
26588
28041
|
if ("contract" in raw && Array.isArray(raw.methods)) return "implementation";
|
|
26589
28042
|
if ("kind" in raw && Array.isArray(raw.fields)) return "type";
|
|
26590
|
-
if (raw.kind === "signature") return "type";
|
|
28043
|
+
if (raw.kind === "signature" || raw.kind === "enum") return "type";
|
|
28044
|
+
if ("kind" in raw && typeof raw.holds === "string") return "type";
|
|
26591
28045
|
return void 0;
|
|
26592
28046
|
}
|
|
26593
28047
|
function rewriteSpecRefs(raw, remap) {
|
|
@@ -26883,12 +28337,12 @@ function pairSteps(before, after) {
|
|
|
26883
28337
|
const gapBefore = before.slice(oi + 1, oj).map((step, k) => ({ step, at: oi + 1 + k }));
|
|
26884
28338
|
const gapAfter = after.slice(ni + 1, nj).map((step, k) => ({ step, at: ni + 1 + k }));
|
|
26885
28339
|
const similar = commonRun(gapBefore, gapAfter, (x, y) => recognisablySame(x.step, y.step)).map(([x, y]) => [gapBefore[x].at, gapAfter[y].at]);
|
|
26886
|
-
const
|
|
26887
|
-
for (let k = 0; k <
|
|
26888
|
-
const [a0, b0] =
|
|
26889
|
-
const [a1, b1] =
|
|
28340
|
+
const inner2 = [[oi, ni], ...similar, [oj, nj]];
|
|
28341
|
+
for (let k = 0; k < inner2.length - 1; k++) {
|
|
28342
|
+
const [a0, b0] = inner2[k];
|
|
28343
|
+
const [a1, b1] = inner2[k + 1];
|
|
26890
28344
|
if (a1 - a0 === b1 - b0) for (let d = 1; d < a1 - a0; d++) pairs.push([a0 + d, b0 + d]);
|
|
26891
|
-
if (k <
|
|
28345
|
+
if (k < inner2.length - 2) pairs.push(inner2[k + 1]);
|
|
26892
28346
|
}
|
|
26893
28347
|
if (g < bounds2.length - 2) pairs.push(bounds2[g + 1]);
|
|
26894
28348
|
}
|
|
@@ -27173,6 +28627,7 @@ function moveChangeReports(edits, dryRun) {
|
|
|
27173
28627
|
changes,
|
|
27174
28628
|
ineffective: [],
|
|
27175
28629
|
notices: [],
|
|
28630
|
+
respellings: [],
|
|
27176
28631
|
testsToRevisit: [],
|
|
27177
28632
|
summary: edit4.before === null ? `${dryRun ? "Would create" : "Created"} ${edit4.kind} "${edit4.id}" to receive the moved methods.` : `${dryRun ? "Would move" : "Moved"} into ${edit4.kind} "${edit4.id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
|
|
27178
28633
|
}));
|
|
@@ -27462,6 +28917,9 @@ function snapshotSpecFiles() {
|
|
|
27462
28917
|
function signatureFacts() {
|
|
27463
28918
|
return current().signatureFacts();
|
|
27464
28919
|
}
|
|
28920
|
+
function typeSpellingFacts() {
|
|
28921
|
+
return current().typeSpellingFacts();
|
|
28922
|
+
}
|
|
27465
28923
|
function findLegacySpecFiles() {
|
|
27466
28924
|
return current().findLegacySpecFiles();
|
|
27467
28925
|
}
|
|
@@ -27559,7 +29017,7 @@ var init_specs2 = __esm({
|
|
|
27559
29017
|
SpecWorkspace = class {
|
|
27560
29018
|
constructor(rootDir) {
|
|
27561
29019
|
this.cachedIndex = null;
|
|
27562
|
-
this.
|
|
29020
|
+
this.cachedDepth = null;
|
|
27563
29021
|
this.cachedSpecDirs = [];
|
|
27564
29022
|
this.cachedSignature = null;
|
|
27565
29023
|
this.lastSignatureCheckMs = 0;
|
|
@@ -27588,7 +29046,7 @@ var init_specs2 = __esm({
|
|
|
27588
29046
|
}
|
|
27589
29047
|
invalidate() {
|
|
27590
29048
|
this.cachedIndex = null;
|
|
27591
|
-
this.
|
|
29049
|
+
this.cachedDepth = null;
|
|
27592
29050
|
this.cachedSpecDirs = [];
|
|
27593
29051
|
this.cachedConfigFiles = [];
|
|
27594
29052
|
this.cachedRoots = [];
|
|
@@ -27603,8 +29061,8 @@ var init_specs2 = __esm({
|
|
|
27603
29061
|
// Scanning
|
|
27604
29062
|
// -------------------------------------------------------------------------
|
|
27605
29063
|
scanAll(options) {
|
|
27606
|
-
const
|
|
27607
|
-
if (this.cachedIndex && this.
|
|
29064
|
+
const maxDepth = options?.memberDepth ?? Infinity;
|
|
29065
|
+
if (this.cachedIndex && this.cachedDepth === maxDepth) {
|
|
27608
29066
|
const now = Date.now();
|
|
27609
29067
|
if (now - this.lastSignatureCheckMs <= SIGNATURE_TTL_MS) return this.cachedIndex;
|
|
27610
29068
|
this.lastSignatureCheckMs = now;
|
|
@@ -27612,10 +29070,9 @@ var init_specs2 = __esm({
|
|
|
27612
29070
|
this.invalidate();
|
|
27613
29071
|
}
|
|
27614
29072
|
this.loaderIssues = [];
|
|
27615
|
-
this.
|
|
29073
|
+
this.cachedDepth = maxDepth;
|
|
27616
29074
|
this.scanVisitedSpecDirs = [];
|
|
27617
29075
|
this.scanVisitedConfigFiles = [];
|
|
27618
|
-
const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
|
|
27619
29076
|
const scan = this.scanFamily(maxDepth);
|
|
27620
29077
|
this.cachedIndex = scan.index;
|
|
27621
29078
|
this.cachedRoots = scan.raws.map((raw) => raw.record);
|
|
@@ -27656,6 +29113,8 @@ var init_specs2 = __esm({
|
|
|
27656
29113
|
raws.forEach((raw) => this.bindAliases(raw, raws));
|
|
27657
29114
|
const readables = raws.map((raw) => readableOf(raw));
|
|
27658
29115
|
resolveFamilyTables(raws);
|
|
29116
|
+
const writtenTexts = writtenSignatureTexts(raws);
|
|
29117
|
+
const typeSpellings = canonicalizeRootTypes(raws);
|
|
27659
29118
|
raws.forEach((raw) => bindRootReferences(raw, raws, readables));
|
|
27660
29119
|
const index = emptyIndex();
|
|
27661
29120
|
for (const raw of raws) {
|
|
@@ -27670,7 +29129,11 @@ var init_specs2 = __esm({
|
|
|
27670
29129
|
const signatures = resolveTree(index.interfaces, index.components, index.types, raws.flatMap((r) => r.record.authoredReferences));
|
|
27671
29130
|
index.interfaces = signatures.interfaces;
|
|
27672
29131
|
index.types = signatures.types;
|
|
27673
|
-
index.signatures =
|
|
29132
|
+
index.signatures = {
|
|
29133
|
+
...signatures.facts,
|
|
29134
|
+
staleTexts: signatures.facts.staleTexts.filter((stale) => writtenTexts.get(`${stale.kind}|${stale.specId}|${stale.method}`) !== stale.stored)
|
|
29135
|
+
};
|
|
29136
|
+
index.typeSpellings = typeSpellings;
|
|
27674
29137
|
return { index, raws, readables };
|
|
27675
29138
|
}
|
|
27676
29139
|
/**
|
|
@@ -27816,26 +29279,26 @@ var init_specs2 = __esm({
|
|
|
27816
29279
|
decl.kind = "project";
|
|
27817
29280
|
return;
|
|
27818
29281
|
}
|
|
27819
|
-
const
|
|
27820
|
-
if (
|
|
27821
|
-
if ("unavailable" in
|
|
29282
|
+
const located2 = this.memberRoot(raw, decl);
|
|
29283
|
+
if (located2 === null) return;
|
|
29284
|
+
if ("unavailable" in located2) {
|
|
27822
29285
|
if (asserted === "project" || pinnedAsMember(raw.dir, decl.alias)) {
|
|
27823
29286
|
decl.kind = "project";
|
|
27824
|
-
raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason:
|
|
29287
|
+
raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
|
|
27825
29288
|
return;
|
|
27826
29289
|
}
|
|
27827
29290
|
decl.kind = "part";
|
|
27828
|
-
this.memberProblem(raw, "part-unavailable", decl.alias,
|
|
27829
|
-
raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason:
|
|
29291
|
+
this.memberProblem(raw, "part-unavailable", decl.alias, located2.unavailable);
|
|
29292
|
+
raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
|
|
27830
29293
|
return;
|
|
27831
29294
|
}
|
|
27832
|
-
const kind = projectContentAt(
|
|
29295
|
+
const kind = projectContentAt(located2.dir) ? "project" : "part";
|
|
27833
29296
|
decl.kind = kind;
|
|
27834
29297
|
if (asserted !== void 0 && asserted !== kind) {
|
|
27835
29298
|
this.memberProblem(raw, "kind-mismatch", decl.alias, `the member "${decl.alias}" is asserted \`as: ${asserted}\`, but its content makes it a ${kind}: ${kind === "project" ? "its tree declares an id, holds an L0 or carries a lock \u2014 drop the `as`, or remove that content with `wairon member demote`" : "its tree declares no id, holds no L0 and carries no lock \u2014 drop the `as`, or create the project content with `wairon member promote`"}`);
|
|
27836
29299
|
}
|
|
27837
|
-
if (kind === "part") this.readPart(raw, decl,
|
|
27838
|
-
else if (decl.storage !== "contained") this.recordReferenced(raw, decl,
|
|
29300
|
+
if (kind === "part") this.readPart(raw, decl, located2.dir, located2.commit);
|
|
29301
|
+
else if (decl.storage !== "contained") this.recordReferenced(raw, decl, located2.dir, located2.commit);
|
|
27839
29302
|
}
|
|
27840
29303
|
/**
|
|
27841
29304
|
* A referenced project member (stage 8): where its root is — the sibling
|
|
@@ -28734,7 +30197,8 @@ var init_specs2 = __esm({
|
|
|
28734
30197
|
* the owning project.
|
|
28735
30198
|
*/
|
|
28736
30199
|
prepareInterfaceForWrite(spec) {
|
|
28737
|
-
const
|
|
30200
|
+
const canonical3 = interfaceCanonicalTypes(spec).spec;
|
|
30201
|
+
const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedMethodSignature(m)) };
|
|
28738
30202
|
return this.relativizeSpec("interface", stored);
|
|
28739
30203
|
}
|
|
28740
30204
|
prepareImplementationForWrite(spec, carry = true) {
|
|
@@ -28745,9 +30209,14 @@ var init_specs2 = __esm({
|
|
|
28745
30209
|
const partDir = this.partHolding(this.getImplementationPath(spec.id, spec.contract))?.part.directory;
|
|
28746
30210
|
return partDir ? partRelativeFilePaths(relative26, this.rootDir, partDir) : relative26;
|
|
28747
30211
|
}
|
|
28748
|
-
/**
|
|
30212
|
+
/**
|
|
30213
|
+
* A type written in its stored form — every type position canonical (one
|
|
30214
|
+
* that is not canonical written as it stands), every params-bearing method's
|
|
30215
|
+
* text derived from them — relative to the owning project.
|
|
30216
|
+
*/
|
|
28749
30217
|
prepareTypeForWrite(spec) {
|
|
28750
|
-
const
|
|
30218
|
+
const canonical3 = typeCanonicalTypes(spec).spec;
|
|
30219
|
+
const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedTypeMethod(m)) };
|
|
28751
30220
|
return this.relativizeSpec("type", stored);
|
|
28752
30221
|
}
|
|
28753
30222
|
prepareGroupForWrite(spec) {
|
|
@@ -28958,7 +30427,7 @@ var init_specs2 = __esm({
|
|
|
28958
30427
|
if (!pathExists(p)) return null;
|
|
28959
30428
|
try {
|
|
28960
30429
|
const raw = readSpecFile(p);
|
|
28961
|
-
return resolveTree([InterfaceSpecSchema.parse(raw)], index.components, index.types).interfaces[0];
|
|
30430
|
+
return resolveTree([interfaceCanonicalTypes(InterfaceSpecSchema.parse(raw)).spec], index.components, index.types).interfaces[0];
|
|
28962
30431
|
} catch (e) {
|
|
28963
30432
|
this.loaderIssues.push({
|
|
28964
30433
|
severity: "error",
|
|
@@ -29534,6 +31003,33 @@ var init_specs2 = __esm({
|
|
|
29534
31003
|
index.listProjectRoots();
|
|
29535
31004
|
return this.cachedIndex.signatures;
|
|
29536
31005
|
}
|
|
31006
|
+
/**
|
|
31007
|
+
* A delta's merged spec with every type position canonical, IN PLACE (an
|
|
31008
|
+
* interface or a type; nothing else holds type positions). Answers the
|
|
31009
|
+
* respellings the write applies: each alias the merge holds — written by the
|
|
31010
|
+
* delta — and each alias the stored file still holds at a position the merge
|
|
31011
|
+
* kept, which the scan recorded and the save rewrites with it. A position
|
|
31012
|
+
* that is not canonical stays as written.
|
|
31013
|
+
*/
|
|
31014
|
+
canonicalizeMerged(kind, merged) {
|
|
31015
|
+
if (kind !== "interface" && kind !== "type") return [];
|
|
31016
|
+
const read2 = kind === "interface" ? interfaceCanonicalTypes(merged) : typeCanonicalTypes(merged);
|
|
31017
|
+
Object.assign(merged, read2.spec);
|
|
31018
|
+
const respelled = new Set(read2.respellings.map((r) => r.path));
|
|
31019
|
+
const fromFile = this.scanAll().typeSpellings.respellings.filter((r) => r.specId === merged.id && r.kind === kind && !respelled.has(r.path) && typePositionText(merged, r.path) === r.stored);
|
|
31020
|
+
return [...read2.respellings, ...fromFile];
|
|
31021
|
+
}
|
|
31022
|
+
/**
|
|
31023
|
+
* ispec_index.typeSpellingFacts — what the current scan's type
|
|
31024
|
+
* canonicalisation recorded: every stored type position that is an alias of
|
|
31025
|
+
* its canonical spelling, and every one that is not canonical at all. Read
|
|
31026
|
+
* from the cached scan, rescanning first when the tree changed.
|
|
31027
|
+
*/
|
|
31028
|
+
typeSpellingFacts() {
|
|
31029
|
+
const index = this;
|
|
31030
|
+
index.listProjectRoots();
|
|
31031
|
+
return this.cachedIndex.typeSpellings;
|
|
31032
|
+
}
|
|
29537
31033
|
snapshotSpecFiles() {
|
|
29538
31034
|
const index = this.scanAll();
|
|
29539
31035
|
const snapshot = /* @__PURE__ */ new Map();
|
|
@@ -30144,6 +31640,7 @@ var init_specs2 = __esm({
|
|
|
30144
31640
|
const qualifiedDelta = qualifyDeltaRefs(mergeableDelta);
|
|
30145
31641
|
const mergedResult = mergeDelta(result, qualifiedDelta);
|
|
30146
31642
|
for (const field of unsetFields) delete mergedResult[field];
|
|
31643
|
+
const respellings = this.canonicalizeMerged(kind, mergedResult);
|
|
30147
31644
|
deriveMergedTexts(kind, mergedResult);
|
|
30148
31645
|
const withDefaults = deltaSchema.safeParse(mergedResult);
|
|
30149
31646
|
if (withDefaults.success) {
|
|
@@ -30184,6 +31681,7 @@ var init_specs2 = __esm({
|
|
|
30184
31681
|
changes,
|
|
30185
31682
|
ineffective,
|
|
30186
31683
|
notices,
|
|
31684
|
+
respellings: [],
|
|
30187
31685
|
testsToRevisit: [],
|
|
30188
31686
|
summary: `No change to ${kind} "${id}" \u2014 the delta matches what is stored, so nothing ${dryRun ? "would be" : "was"} written.`
|
|
30189
31687
|
};
|
|
@@ -30200,6 +31698,7 @@ var init_specs2 = __esm({
|
|
|
30200
31698
|
changes,
|
|
30201
31699
|
ineffective,
|
|
30202
31700
|
notices,
|
|
31701
|
+
respellings,
|
|
30203
31702
|
testsToRevisit: [],
|
|
30204
31703
|
...stripped.length ? { strippedKeys: stripped } : {},
|
|
30205
31704
|
summary: `Dry run on ${kind} "${id}": ${changes.length} change${changes.length === 1 ? "" : "s"} would be made. Nothing was written.`
|
|
@@ -30218,6 +31717,7 @@ var init_specs2 = __esm({
|
|
|
30218
31717
|
changes,
|
|
30219
31718
|
ineffective,
|
|
30220
31719
|
notices,
|
|
31720
|
+
respellings,
|
|
30221
31721
|
// The store never searches for tests: it holds the tree and knows
|
|
30222
31722
|
// nothing about the rule engine that reads code. The GATED write above
|
|
30223
31723
|
// it fills this in, which is also the only write path a human drives.
|
|
@@ -33579,6 +35079,19 @@ function composeAgentBrief(agentId) {
|
|
|
33579
35079
|
## Project guidance
|
|
33580
35080
|
|
|
33581
35081
|
${guidance.trim()}
|
|
35082
|
+
`;
|
|
35083
|
+
}
|
|
35084
|
+
const language = implementationLanguage(record2);
|
|
35085
|
+
const dialect = language ? typeDialectFor(language) : null;
|
|
35086
|
+
const typeMapping = dialect ? dialect.mappingLines() : void 0;
|
|
35087
|
+
if (typeMapping) {
|
|
35088
|
+
instructions = `${instructions.trimEnd()}
|
|
35089
|
+
|
|
35090
|
+
## Types in ${language}
|
|
35091
|
+
|
|
35092
|
+
Contracts speak wairon's neutral type grammar; write each type in ${language} as:
|
|
35093
|
+
|
|
35094
|
+
${typeMapping.map((line2) => `- ${line2}`).join("\n")}
|
|
33582
35095
|
`;
|
|
33583
35096
|
}
|
|
33584
35097
|
const profile = deriveExecutionProfile(record2);
|
|
@@ -33592,10 +35105,28 @@ ${guidance.trim()}
|
|
|
33592
35105
|
readPaths: record2.readPaths,
|
|
33593
35106
|
instructions,
|
|
33594
35107
|
variantGuidance: record2.variantGuidance || void 0,
|
|
35108
|
+
...typeMapping ? { typeMapping } : {},
|
|
33595
35109
|
profile: budget ? profile : void 0,
|
|
33596
35110
|
budget
|
|
33597
35111
|
};
|
|
33598
35112
|
}
|
|
35113
|
+
function implementationLanguage(record2) {
|
|
35114
|
+
const owned = new Set(record2.ownedPaths);
|
|
35115
|
+
const implementations = loadImplementationSpecs().filter((impl) => implementationSourceFiles(impl).some((file) => owned.has(file)));
|
|
35116
|
+
for (const impl of implementations) {
|
|
35117
|
+
for (const technology of impl.technologies ?? []) {
|
|
35118
|
+
const name = typeof technology === "string" ? technology : technology.name;
|
|
35119
|
+
if (typeDialectFor(name)) return name.toLowerCase();
|
|
35120
|
+
}
|
|
35121
|
+
}
|
|
35122
|
+
for (const impl of implementations) {
|
|
35123
|
+
for (const file of implementationSourceFiles(impl)) {
|
|
35124
|
+
const language = languageOfSourcePath(file);
|
|
35125
|
+
if (language) return language;
|
|
35126
|
+
}
|
|
35127
|
+
}
|
|
35128
|
+
return void 0;
|
|
35129
|
+
}
|
|
33599
35130
|
function memberHop(agentId) {
|
|
33600
35131
|
const at = agentId.indexOf("::");
|
|
33601
35132
|
if (at < 0) return null;
|
|
@@ -33641,6 +35172,8 @@ var init_agent_resolver = __esm({
|
|
|
33641
35172
|
init_budget_policy();
|
|
33642
35173
|
init_specs2();
|
|
33643
35174
|
init_specs();
|
|
35175
|
+
init_code_model();
|
|
35176
|
+
init_type_dialects();
|
|
33644
35177
|
init_variants();
|
|
33645
35178
|
projectFilesCache = /* @__PURE__ */ new Map();
|
|
33646
35179
|
UnknownAgentError = class extends WaironError {
|
|
@@ -36845,7 +38378,6 @@ var require_dist = __commonJS({
|
|
|
36845
38378
|
"# languages:",
|
|
36846
38379
|
"# rust:",
|
|
36847
38380
|
"# unsupportedFlow: {}",
|
|
36848
|
-
"# foreignBuiltins: []",
|
|
36849
38381
|
"languages: {}",
|
|
36850
38382
|
"",
|
|
36851
38383
|
"# Reusable, versioned architecture patterns:",
|
|
@@ -37072,12 +38604,12 @@ var require_dist = __commonJS({
|
|
|
37072
38604
|
const suggestedFileName = `${sealed.name}-${sealed.version}.wpack`;
|
|
37073
38605
|
return { archive: archiveBytes, info, suggestedFileName };
|
|
37074
38606
|
}
|
|
37075
|
-
function inspectArchive3(
|
|
37076
|
-
const entries = listEntries(
|
|
38607
|
+
function inspectArchive3(archive) {
|
|
38608
|
+
const entries = listEntries(archive);
|
|
37077
38609
|
if (!entries.some((entry) => entry.path === ENVELOPE_FILENAME)) {
|
|
37078
38610
|
throw new Error("not a .wpack archive (missing wairon-pack.yaml envelope)");
|
|
37079
38611
|
}
|
|
37080
|
-
const envelopeBytes = inflateEntry(
|
|
38612
|
+
const envelopeBytes = inflateEntry(archive, ENVELOPE_FILENAME);
|
|
37081
38613
|
const manifest = parseManifest(decode(envelopeBytes));
|
|
37082
38614
|
const compatible = checkCompatibility(manifest, SDK_VERSION);
|
|
37083
38615
|
const fileEntries = entries.filter((entry) => entry.kind === "file");
|
|
@@ -37095,13 +38627,13 @@ var require_dist = __commonJS({
|
|
|
37095
38627
|
if (manifest.minWaironVersion !== void 0) info.minWaironVersion = manifest.minWaironVersion;
|
|
37096
38628
|
return info;
|
|
37097
38629
|
}
|
|
37098
|
-
function extractPack3(
|
|
38630
|
+
function extractPack3(archive, destDir, limits) {
|
|
37099
38631
|
const effectiveLimits = limits === void 0 ? defaultLimits() : limits;
|
|
37100
|
-
const entries = listEntries(
|
|
38632
|
+
const entries = listEntries(archive);
|
|
37101
38633
|
const plan7 = planExtraction(entries, effectiveLimits);
|
|
37102
38634
|
const files = [];
|
|
37103
38635
|
for (const approvedPath of plan7.paths) {
|
|
37104
|
-
const contents = inflateEntry(
|
|
38636
|
+
const contents = inflateEntry(archive, approvedPath);
|
|
37105
38637
|
files.push({ path: approvedPath, contents });
|
|
37106
38638
|
}
|
|
37107
38639
|
const envelope = files.find((file) => file.path === ENVELOPE_FILENAME);
|
|
@@ -37158,28 +38690,28 @@ var require_dist = __commonJS({
|
|
|
37158
38690
|
const suggestedFileName = `${slugify2(projectName)}.waitree`;
|
|
37159
38691
|
return { archive: archiveBytes, manifest: sealed, suggestedFileName, fileCount: files.length };
|
|
37160
38692
|
}
|
|
37161
|
-
function inspectTreeArchive3(
|
|
37162
|
-
const entries = listEntries(
|
|
38693
|
+
function inspectTreeArchive3(archive) {
|
|
38694
|
+
const entries = listEntries(archive);
|
|
37163
38695
|
if (!entries.some((entry) => entry.path === TREE_ENVELOPE_FILENAME)) {
|
|
37164
38696
|
throw new Error("not a .waitree archive (missing wairon-tree.yaml envelope)");
|
|
37165
38697
|
}
|
|
37166
|
-
const envelopeBytes = inflateEntry(
|
|
38698
|
+
const envelopeBytes = inflateEntry(archive, TREE_ENVELOPE_FILENAME);
|
|
37167
38699
|
const manifest = parseTreeManifest(decode(envelopeBytes));
|
|
37168
38700
|
const compatible = checkTreeCompatibility(manifest, SDK_VERSION);
|
|
37169
38701
|
const fileEntries = entries.filter((entry) => entry.kind === "file");
|
|
37170
38702
|
const totalUncompressedBytes = entries.reduce((sum, entry) => sum + entry.uncompressedSize, 0);
|
|
37171
38703
|
return { manifest, entryCount: fileEntries.length, totalUncompressedBytes, compatible };
|
|
37172
38704
|
}
|
|
37173
|
-
function extractTreeArchive3(
|
|
38705
|
+
function extractTreeArchive3(archive, destDir, limits, refuseExecutableEntries) {
|
|
37174
38706
|
const effectiveLimits = limits === void 0 ? defaultTreeLimits() : limits;
|
|
37175
|
-
const entries = listEntries(
|
|
38707
|
+
const entries = listEntries(archive);
|
|
37176
38708
|
const plan7 = planTreeExtraction(entries, effectiveLimits);
|
|
37177
38709
|
if (refuseExecutableEntries === true) {
|
|
37178
38710
|
assertPortableTreePaths(plan7.paths);
|
|
37179
38711
|
}
|
|
37180
38712
|
const files = [];
|
|
37181
38713
|
for (const approvedPath of plan7.paths) {
|
|
37182
|
-
const contents = inflateEntry(
|
|
38714
|
+
const contents = inflateEntry(archive, approvedPath);
|
|
37183
38715
|
files.push({ path: approvedPath, contents });
|
|
37184
38716
|
}
|
|
37185
38717
|
const envelope = files.find((file) => file.path === TREE_ENVELOPE_FILENAME);
|
|
@@ -37212,9 +38744,9 @@ var require_dist = __commonJS({
|
|
|
37212
38744
|
}
|
|
37213
38745
|
function readInnerIdentity(files, manifest) {
|
|
37214
38746
|
const innerPath = manifest.kind === "code" ? "package.json" : manifest.entry;
|
|
37215
|
-
const
|
|
37216
|
-
if (!
|
|
37217
|
-
const parsed = manifest.kind === "code" ? JSON.parse(decode(
|
|
38747
|
+
const inner2 = files.find((file) => file.path === innerPath);
|
|
38748
|
+
if (!inner2) throw new Error(`pack build: inner pack manifest "${innerPath}" is missing`);
|
|
38749
|
+
const parsed = manifest.kind === "code" ? JSON.parse(decode(inner2.contents)) : (0, import_js_yaml3.load)(decode(inner2.contents));
|
|
37218
38750
|
const name = parsed?.name;
|
|
37219
38751
|
const version = parsed?.version;
|
|
37220
38752
|
if (typeof name !== "string" || typeof version !== "string") {
|
|
@@ -37628,6 +39160,59 @@ var init_signature_repair = __esm({
|
|
|
37628
39160
|
}
|
|
37629
39161
|
});
|
|
37630
39162
|
|
|
39163
|
+
// src/core/type-spelling-repair.ts
|
|
39164
|
+
function repairTypeSpellings(apply4) {
|
|
39165
|
+
const facts = typeSpellingFacts();
|
|
39166
|
+
const held = new Set(signatureFacts().sources.filter((f) => f.outcome === "restated" && f.differs).map((f) => f.interfaceId));
|
|
39167
|
+
const repairs = /* @__PURE__ */ new Map();
|
|
39168
|
+
const repairOf = (specId, kind) => {
|
|
39169
|
+
const key = `${kind}:${specId}`;
|
|
39170
|
+
let repair = repairs.get(key);
|
|
39171
|
+
if (!repair) {
|
|
39172
|
+
repair = { specId, kind, rewritten: [], proposals: [], authorNeeded: [] };
|
|
39173
|
+
repairs.set(key, repair);
|
|
39174
|
+
}
|
|
39175
|
+
return repair;
|
|
39176
|
+
};
|
|
39177
|
+
const own = (specId) => !specId.includes("::");
|
|
39178
|
+
for (const respelling of facts.respellings) {
|
|
39179
|
+
if (!own(respelling.specId)) continue;
|
|
39180
|
+
if (respelling.kind === "interface" && held.has(respelling.specId)) continue;
|
|
39181
|
+
repairOf(respelling.specId, respelling.kind).rewritten.push(respelling);
|
|
39182
|
+
}
|
|
39183
|
+
for (const problem of facts.problems) {
|
|
39184
|
+
if (problem.specId === void 0 || problem.kind === void 0 || !own(problem.specId)) continue;
|
|
39185
|
+
const repair = repairOf(problem.specId, problem.kind);
|
|
39186
|
+
const proposal = typeProblemIntProposal(problem);
|
|
39187
|
+
if (proposal) repair.proposals.push(proposal);
|
|
39188
|
+
else repair.authorNeeded.push(problem);
|
|
39189
|
+
}
|
|
39190
|
+
const planned = [...repairs.values()];
|
|
39191
|
+
const rewriting = planned.filter((repair) => repair.rewritten.length > 0);
|
|
39192
|
+
if (apply4 && rewriting.length > 0) {
|
|
39193
|
+
const interfaces = new Map(loadInterfaceSpecs().map((i) => [i.id, i]));
|
|
39194
|
+
const types = new Map(loadTypeSpecs().map((t) => [t.id, t]));
|
|
39195
|
+
for (const repair of rewriting) {
|
|
39196
|
+
if (repair.kind === "interface") {
|
|
39197
|
+
const intf = interfaces.get(repair.specId);
|
|
39198
|
+
if (intf) saveInterfaceSpec(intf);
|
|
39199
|
+
continue;
|
|
39200
|
+
}
|
|
39201
|
+
const type = types.get(repair.specId);
|
|
39202
|
+
if (type) saveSpec("type", type);
|
|
39203
|
+
}
|
|
39204
|
+
invalidateSpecCache();
|
|
39205
|
+
}
|
|
39206
|
+
return planned;
|
|
39207
|
+
}
|
|
39208
|
+
var init_type_spelling_repair = __esm({
|
|
39209
|
+
"src/core/type-spelling-repair.ts"() {
|
|
39210
|
+
"use strict";
|
|
39211
|
+
init_specs2();
|
|
39212
|
+
init_models();
|
|
39213
|
+
}
|
|
39214
|
+
});
|
|
39215
|
+
|
|
37631
39216
|
// src/models/lock.ts
|
|
37632
39217
|
function describeApprover(who) {
|
|
37633
39218
|
const label7 = who.name ? `${who.name} (${who.id})` : who.id;
|
|
@@ -38210,7 +39795,7 @@ function parentPinState(parent) {
|
|
|
38210
39795
|
}
|
|
38211
39796
|
function getStatusReport(options = {}, decor) {
|
|
38212
39797
|
const mark = fillDecor(decor);
|
|
38213
|
-
scanAllSpecs({
|
|
39798
|
+
scanAllSpecs({ memberDepth: options.memberDepth });
|
|
38214
39799
|
const system = loadSystemSpec();
|
|
38215
39800
|
const loaderErrors = getLoaderIssues();
|
|
38216
39801
|
if (loaderErrors.length > 0) {
|
|
@@ -38412,6 +39997,11 @@ var init_status = __esm({
|
|
|
38412
39997
|
});
|
|
38413
39998
|
|
|
38414
39999
|
// src/core/index.ts
|
|
40000
|
+
function resolveSignatures(interfaces, components, types) {
|
|
40001
|
+
const canonicalInterfaces = interfaces.map((intf) => interfaceCanonicalTypes(intf).spec);
|
|
40002
|
+
const canonicalTypes = types.map((type) => typeCanonicalTypes(type).spec);
|
|
40003
|
+
return resolveTree(canonicalInterfaces, components, canonicalTypes);
|
|
40004
|
+
}
|
|
38415
40005
|
function resolveDomains2() {
|
|
38416
40006
|
return resolveDomains();
|
|
38417
40007
|
}
|
|
@@ -38433,9 +40023,10 @@ var init_core = __esm({
|
|
|
38433
40023
|
init_project_config();
|
|
38434
40024
|
init_domain_projector();
|
|
38435
40025
|
init_domain_curator();
|
|
40026
|
+
init_models();
|
|
40027
|
+
init_signature_sources2();
|
|
38436
40028
|
init_rules();
|
|
38437
40029
|
init_specs2();
|
|
38438
|
-
init_signature_sources2();
|
|
38439
40030
|
init_external_producers();
|
|
38440
40031
|
init_part_context();
|
|
38441
40032
|
init_provision();
|
|
@@ -38457,6 +40048,7 @@ var init_core = __esm({
|
|
|
38457
40048
|
init_stereotype_migration();
|
|
38458
40049
|
init_narrative_repair();
|
|
38459
40050
|
init_signature_repair();
|
|
40051
|
+
init_type_spelling_repair();
|
|
38460
40052
|
init_approval();
|
|
38461
40053
|
init_approver();
|
|
38462
40054
|
init_specs2();
|
|
@@ -38863,12 +40455,14 @@ function noticesFrom(verdict) {
|
|
|
38863
40455
|
...verdict.notices.map((n) => `${n.code} (notice): ${n.message}`)
|
|
38864
40456
|
];
|
|
38865
40457
|
}
|
|
38866
|
-
function componentCandidateGate(options = candidateOptions(), storedOwner) {
|
|
40458
|
+
function componentCandidateGate(options = candidateOptions(), storedOwner, stored) {
|
|
38867
40459
|
return {
|
|
38868
40460
|
gate: (kind, merged) => {
|
|
38869
40461
|
refuseUnknownOwner(kind, merged, storedOwner);
|
|
38870
40462
|
const restated = kind === "interface" ? restatedSources(merged.methods) : [];
|
|
38871
40463
|
if (restated.length) throw new Error(`${restatedSourceRefusal(String(merged.id), restated)} Nothing was written.`);
|
|
40464
|
+
const written = deltaWrittenTypeProblems(kind, merged, stored ?? null);
|
|
40465
|
+
if (written.length) throw new Error(`${typeProblemRefusal(kind, String(merged.id), written)} Nothing was written.`);
|
|
38872
40466
|
if (kind !== "component") return;
|
|
38873
40467
|
const verdict = validateComponentCandidate(merged, options);
|
|
38874
40468
|
if (verdict.errors.length) throw new Error(formatCandidateRefusal(verdict));
|
|
@@ -38876,6 +40470,22 @@ function componentCandidateGate(options = candidateOptions(), storedOwner) {
|
|
|
38876
40470
|
}
|
|
38877
40471
|
};
|
|
38878
40472
|
}
|
|
40473
|
+
function canonicalTypesOf(kind, spec) {
|
|
40474
|
+
if (!spec || typeof spec !== "object") return null;
|
|
40475
|
+
if (kind === "interface") return interfaceCanonicalTypes(spec);
|
|
40476
|
+
if (kind === "type") return typeCanonicalTypes(spec);
|
|
40477
|
+
return null;
|
|
40478
|
+
}
|
|
40479
|
+
function deltaWrittenTypeProblems(kind, merged, stored) {
|
|
40480
|
+
const now = canonicalTypesOf(kind, merged)?.problems ?? [];
|
|
40481
|
+
if (now.length === 0) return [];
|
|
40482
|
+
const before = new Set((canonicalTypesOf(kind, stored)?.problems ?? []).map((p) => `${p.path}|${p.written}`));
|
|
40483
|
+
return now.filter((p) => !before.has(`${p.path}|${p.written}`));
|
|
40484
|
+
}
|
|
40485
|
+
function typeProblemRefusal(kind, id, problems) {
|
|
40486
|
+
const lines = problems.map((p) => `${p.code} at ${p.path}: ${p.detail}${p.replacement ? ` \u2014 write ${p.replacement} instead` : ""}.`);
|
|
40487
|
+
return `Refusing to write ${kind} "${id}": ${problems.length === 1 ? "a type position is" : `${problems.length} type positions are`} not in the neutral type grammar. ${lines.join(" ")} Aliases (string[], T | null, boolean, Promise<T>, ...) are accepted and respelled; these forms have no canonical spelling.`;
|
|
40488
|
+
}
|
|
38879
40489
|
function restatedSources(methods) {
|
|
38880
40490
|
if (!Array.isArray(methods)) return [];
|
|
38881
40491
|
return methods.filter((m) => m && typeof m === "object" && m.signatureFrom !== void 0 && (m.params !== void 0 || m.returns !== void 0)).map((m) => String(m.name));
|
|
@@ -38962,6 +40572,11 @@ function applyRestatement(restatement, loaded, parent) {
|
|
|
38962
40572
|
`Refusing to write ${restatement.kind} "${String(candidate.id)}": ${unsigned.map((n) => `"${n}"`).join(", ")} ${unsigned.length === 1 ? "states" : "state"} neither params${restatement.kind === "interface" ? ", a signatureFrom" : ""} nor a prose signature, so nothing says what the method takes. Nothing was written.`
|
|
38963
40573
|
);
|
|
38964
40574
|
}
|
|
40575
|
+
const types = canonicalTypesOf(restatement.kind, candidate);
|
|
40576
|
+
if (types && types.problems.length) {
|
|
40577
|
+
return refused(restatement, replacedExisting, `${typeProblemRefusal(restatement.kind, String(candidate.id), types.problems)} Nothing was written.`);
|
|
40578
|
+
}
|
|
40579
|
+
if (types) Object.assign(candidate, types.spec);
|
|
38965
40580
|
const derivedNotices = deriveStatedTexts(restatement.kind, candidate);
|
|
38966
40581
|
const labelErrors = resolveLabelsOf(restatement.kind, candidate);
|
|
38967
40582
|
if (labelErrors.length) {
|
|
@@ -38975,7 +40590,8 @@ function applyRestatement(restatement, loaded, parent) {
|
|
|
38975
40590
|
...status2.status ? { status: status2.status } : {},
|
|
38976
40591
|
replacedExisting,
|
|
38977
40592
|
notices: [...existing ? rewriteNotices(restatement.kind, existing, candidate, carried, cleared) : [], ...derivedNotices],
|
|
38978
|
-
changedMethods: changedMethodsOf(restatement.kind, existing, candidate)
|
|
40593
|
+
changedMethods: changedMethodsOf(restatement.kind, existing, candidate),
|
|
40594
|
+
respellings: types?.respellings ?? []
|
|
38979
40595
|
};
|
|
38980
40596
|
}
|
|
38981
40597
|
function parseCandidate(kind, candidate) {
|
|
@@ -39006,7 +40622,7 @@ function parseCandidate(kind, candidate) {
|
|
|
39006
40622
|
};
|
|
39007
40623
|
}
|
|
39008
40624
|
function refused(restatement, replacedExisting, refusal2) {
|
|
39009
|
-
return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [] };
|
|
40625
|
+
return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [], respellings: [] };
|
|
39010
40626
|
}
|
|
39011
40627
|
function statusForCreate(restatement, existing) {
|
|
39012
40628
|
if (!STATUSED_KINDS.has(restatement.kind)) return {};
|
|
@@ -39146,6 +40762,7 @@ function writeSpec(restatement) {
|
|
|
39146
40762
|
replacedExisting: application.replacedExisting,
|
|
39147
40763
|
...application.status ? { status: application.status } : {},
|
|
39148
40764
|
notices: [...gateNotices, ...persisted.notices, ...application.notices],
|
|
40765
|
+
respellings: application.respellings,
|
|
39149
40766
|
testsToRevisit
|
|
39150
40767
|
};
|
|
39151
40768
|
}
|
|
@@ -39201,7 +40818,7 @@ function updateSpecGated(kind, id, delta, dryRun) {
|
|
|
39201
40818
|
const bound2 = candidateOptions();
|
|
39202
40819
|
const testRoots = bound2.rules?.conformance?.testRoots ?? [];
|
|
39203
40820
|
const stored = loadSpec(kind, id);
|
|
39204
|
-
const gate = componentCandidateGate(bound2, stored?.subsystem);
|
|
40821
|
+
const gate = componentCandidateGate(bound2, stored?.subsystem, stored);
|
|
39205
40822
|
const report3 = updateSpec(kind, id, delta, gate, dryRun);
|
|
39206
40823
|
const changed = changedMethods(report3);
|
|
39207
40824
|
if (changed.length > 0 && testRoots.length > 0) {
|
|
@@ -39249,6 +40866,7 @@ var init_authoring = __esm({
|
|
|
39249
40866
|
"src/core/authoring.ts"() {
|
|
39250
40867
|
"use strict";
|
|
39251
40868
|
init_specs();
|
|
40869
|
+
init_type_grammar();
|
|
39252
40870
|
init_authoring_core();
|
|
39253
40871
|
init_authoring_validator();
|
|
39254
40872
|
init_candidate2();
|
|
@@ -42950,6 +44568,7 @@ function renderChangeReport(report3) {
|
|
|
42950
44568
|
if (report3.strippedKeys?.length) {
|
|
42951
44569
|
lines.push("", `DROPPED FROM THE STORED FILE (${report3.dryRun ? "would be " : ""}removed \u2014 the schema does not know them):`, ...report3.strippedKeys.map((k) => `- ${k}`));
|
|
42952
44570
|
}
|
|
44571
|
+
lines.push(...renderRespellings(report3.respellings));
|
|
42953
44572
|
lines.push(...renderTestsToRevisit(report3.testsToRevisit));
|
|
42954
44573
|
return lines.join("\n");
|
|
42955
44574
|
}
|
|
@@ -42966,13 +44585,19 @@ function renderTestsToRevisit(entries) {
|
|
|
42966
44585
|
}
|
|
42967
44586
|
return lines;
|
|
42968
44587
|
}
|
|
44588
|
+
function renderRespellings(entries) {
|
|
44589
|
+
if (!entries.length) return [];
|
|
44590
|
+
return ["", "RESPELLED (stored canonical):", ...entries.map((r) => `- ${r.path}: "${r.written}" \u2192 "${r.stored}"`)];
|
|
44591
|
+
}
|
|
42969
44592
|
function writeReceipt(sentence, receipt) {
|
|
42970
44593
|
const noticeBlock = receipt.notices.length ? `
|
|
42971
44594
|
|
|
42972
44595
|
NOTICE:
|
|
42973
44596
|
- ${receipt.notices.join("\n- ")}` : "";
|
|
44597
|
+
const respelledBlock = renderRespellings(receipt.respellings).join("\n");
|
|
42974
44598
|
const testsBlock = renderTestsToRevisit(receipt.testsToRevisit).join("\n");
|
|
42975
|
-
return structured(`${sentence}${noticeBlock}${
|
|
44599
|
+
return structured(`${sentence}${noticeBlock}${respelledBlock ? `
|
|
44600
|
+
${respelledBlock}` : ""}${testsBlock ? `
|
|
42976
44601
|
${testsBlock}` : ""}`, receipt);
|
|
42977
44602
|
}
|
|
42978
44603
|
function describeMemberPacks(creation) {
|
|
@@ -43030,46 +44655,46 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
|
|
|
43030
44655
|
const known = seen.get(schema);
|
|
43031
44656
|
if (known !== void 0) return { ref: known };
|
|
43032
44657
|
seen.set(schema, seen.size);
|
|
43033
|
-
const
|
|
44658
|
+
const inner2 = (s) => schemaShape(s, seen);
|
|
43034
44659
|
const kind = String(def.typeName);
|
|
43035
44660
|
switch (kind) {
|
|
43036
44661
|
case "ZodObject": {
|
|
43037
44662
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
43038
44663
|
return {
|
|
43039
44664
|
kind,
|
|
43040
|
-
keys: Object.keys(shape).sort().map((key) => [key,
|
|
44665
|
+
keys: Object.keys(shape).sort().map((key) => [key, inner2(shape[key])]),
|
|
43041
44666
|
unknownKeys: def.unknownKeys,
|
|
43042
|
-
catchall:
|
|
44667
|
+
catchall: inner2(def.catchall)
|
|
43043
44668
|
};
|
|
43044
44669
|
}
|
|
43045
44670
|
case "ZodArray":
|
|
43046
|
-
return { kind, of:
|
|
44671
|
+
return { kind, of: inner2(def.type), min: def.minLength?.value, max: def.maxLength?.value };
|
|
43047
44672
|
case "ZodOptional":
|
|
43048
44673
|
case "ZodNullable":
|
|
43049
44674
|
case "ZodReadonly":
|
|
43050
44675
|
case "ZodBranded":
|
|
43051
44676
|
case "ZodCatch":
|
|
43052
|
-
return { kind, of:
|
|
44677
|
+
return { kind, of: inner2(def.innerType ?? def.type) };
|
|
43053
44678
|
case "ZodDefault":
|
|
43054
|
-
return { kind, of:
|
|
44679
|
+
return { kind, of: inner2(def.innerType), default: JSON.stringify(def.defaultValue?.()) };
|
|
43055
44680
|
case "ZodEffects":
|
|
43056
|
-
return { kind, effect: def.effect?.type, of:
|
|
44681
|
+
return { kind, effect: def.effect?.type, of: inner2(def.schema) };
|
|
43057
44682
|
case "ZodLazy":
|
|
43058
|
-
return { kind, of:
|
|
44683
|
+
return { kind, of: inner2(def.getter()) };
|
|
43059
44684
|
case "ZodUnion":
|
|
43060
44685
|
case "ZodDiscriminatedUnion": {
|
|
43061
44686
|
const options = def.options instanceof Map ? [...def.options.values()] : def.options;
|
|
43062
|
-
return { kind, discriminator: def.discriminator, of: options.map(
|
|
44687
|
+
return { kind, discriminator: def.discriminator, of: options.map(inner2) };
|
|
43063
44688
|
}
|
|
43064
44689
|
case "ZodIntersection":
|
|
43065
|
-
return { kind, left:
|
|
44690
|
+
return { kind, left: inner2(def.left), right: inner2(def.right) };
|
|
43066
44691
|
case "ZodTuple":
|
|
43067
|
-
return { kind, of: def.items.map(
|
|
44692
|
+
return { kind, of: def.items.map(inner2), rest: inner2(def.rest) };
|
|
43068
44693
|
case "ZodRecord":
|
|
43069
44694
|
case "ZodMap":
|
|
43070
|
-
return { kind, key:
|
|
44695
|
+
return { kind, key: inner2(def.keyType), value: inner2(def.valueType) };
|
|
43071
44696
|
case "ZodSet":
|
|
43072
|
-
return { kind, of:
|
|
44697
|
+
return { kind, of: inner2(def.valueType) };
|
|
43073
44698
|
case "ZodEnum":
|
|
43074
44699
|
return { kind, values: def.values };
|
|
43075
44700
|
case "ZodNativeEnum":
|
|
@@ -43077,7 +44702,7 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
|
|
|
43077
44702
|
case "ZodLiteral":
|
|
43078
44703
|
return { kind, value: def.value };
|
|
43079
44704
|
case "ZodPipeline":
|
|
43080
|
-
return { kind, in:
|
|
44705
|
+
return { kind, in: inner2(def.in), out: inner2(def.out) };
|
|
43081
44706
|
default:
|
|
43082
44707
|
return { kind, checks: def.checks?.map((c) => [c.kind, c.value ?? null]) ?? [] };
|
|
43083
44708
|
}
|
|
@@ -43878,7 +45503,7 @@ ${renderChangeReport(report3)}`,
|
|
|
43878
45503
|
type: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
|
|
43879
45504
|
description: import_zod11.z.string().optional(),
|
|
43880
45505
|
optional: import_zod11.z.boolean().optional().describe(
|
|
43881
|
-
'Whether the parameter may be OMITTED by a caller. It is not nullability: a parameter that must be passed but may be passed as nothing is a required parameter whose type
|
|
45506
|
+
'Whether the parameter may be OMITTED by a caller. It is not nullability: a parameter that must be passed but may be passed as nothing is a required parameter whose type says so \u2014 "ProjectConfig?". Say whichever is true; they are different contracts (both together: may be left out, and may be none).'
|
|
43882
45507
|
)
|
|
43883
45508
|
}).strict();
|
|
43884
45509
|
const interfaceMethodShape = {
|
|
@@ -44127,7 +45752,7 @@ ${renderChangeReport(report3)}`,
|
|
|
44127
45752
|
}
|
|
44128
45753
|
);
|
|
44129
45754
|
const typeInput = {
|
|
44130
|
-
kind: import_zod11.z.enum(["entity", "value-object", "signature"]).describe("entity (owned by a subsystem), value-object (often system-level shared),
|
|
45755
|
+
kind: import_zod11.z.enum(["entity", "value-object", "signature", "enum"]).describe("entity (owned by a subsystem), value-object (often system-level shared), signature \u2014 a named function type: params and returns, nothing else \u2014 or enum: a closed, ordered set of named values"),
|
|
44131
45756
|
id: import_zod11.z.string().describe("Lowercase identifier"),
|
|
44132
45757
|
name: import_zod11.z.string().describe("Human-readable name"),
|
|
44133
45758
|
description: import_zod11.z.string().optional(),
|
|
@@ -44161,18 +45786,23 @@ ${renderChangeReport(report3)}`,
|
|
|
44161
45786
|
sourcePath: import_zod11.z.string().optional().describe("Source file holding the declaration of this type (project-relative). Naming one turns the type into a claim on code: the file must resolve and the declaration must be anchored in it (UNREALIZED_TYPE)"),
|
|
44162
45787
|
symbol: import_zod11.z.string().optional().describe('Code-level name realizing the declaration when it differs from name, e.g. a type named "Invoice Line" declared as InvoiceLine'),
|
|
44163
45788
|
params: import_zod11.z.array(methodParamItem).optional().describe("kind signature only: the function type's parameters, in declared order (SIGNATURE_TYPE_MEMBERS on any other kind)"),
|
|
44164
|
-
returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output"))
|
|
45789
|
+
returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output")),
|
|
45790
|
+
values: import_zod11.z.array(import_zod11.z.object({
|
|
45791
|
+
name: import_zod11.z.string().min(1).describe(`The value's name, exactly as data carries it ("stable", "local_only")`),
|
|
45792
|
+
description: import_zod11.z.string().optional().describe("What the value means")
|
|
45793
|
+
}).strict()).optional().describe("kind enum only, and required there: the values in declared order \u2014 the order is part of the design (a narrowest-first track list means something). Unique by name ignoring case and separators; no ordinals and no separate wire value"),
|
|
45794
|
+
holds: import_zod11.z.string().optional().describe('kind value-object only: makes it a NAMED SCALAR \u2014 one primitive under a name (string, int, float, bool, bytes, date, datetime or duration), a newtype or type alias in every language (`type PackPath = string`), declared in place of fields. Not a union, not a named type, not any; fields beside it, or holds on another kind, is NAMED_SCALAR_MEMBERS. Aliases are respelled (boolean \u2192 bool) and number is refused ("int or float?")')
|
|
44165
45795
|
};
|
|
44166
45796
|
const typeInputFields = Object.keys(typeInput);
|
|
44167
45797
|
reg(
|
|
44168
45798
|
server,
|
|
44169
45799
|
"sdd_add_type",
|
|
44170
45800
|
{
|
|
44171
|
-
description: "Define a type: an entity or value-object (the data components operate on),
|
|
45801
|
+
description: "Define a type: an entity or value-object (the data components operate on), a signature \u2014 a named function type \u2014 or an enum: a closed, ordered set of named `values` ({name, description?}, unique by name ignoring case and separators; the name is also the value as data carries it), with optional pure methods and nothing else (no fields, params or returns). A value-object may instead be a NAMED SCALAR: it `holds` one primitive in place of fields (a newtype or type alias in every language). Every type position (a field's type, a method's params and returns, a signature's params and returns, a named scalar's holds) is written in the neutral type grammar; aliases are respelled and listed in the receipt. Entities are owned by a subsystem; shared value objects and signatures omit subsystem (system-level). Fields are data; methods are PURE intrinsic behaviour only \u2014 anything needing a collaborator belongs on a component, taking the entity as an argument \u2014 and a type method may carry structured params, which then derive its signature text as a contract method's do. A signature carries top-level params and returns and nothing else (no fields, methods or invariants \u2014 SIGNATURE_TYPE_MEMBERS); a contract method takes it by naming it as its signatureFrom, and a param may be typed by one (a callback). A type may also CLAIM code: sourcePath names the file holding its declaration (and each method may name its own), symbol binds the code-level name when it differs \u2014 the file must then resolve and the declaration must be anchored in it. An owning subsystem the tree does not have is refused, writing nothing, exactly as a component under an unknown subsystem is. Re-defining an existing id REPLACES fields/methods/invariants and restates sourcePath/symbol (an omitted list or path is CLEARED, and a dropped member is reported); lint/ext are carried forward. The answer carries a write receipt as structured content beside the sentence \u2014 whether a spec already held the id, and the notices a restatement raised, each as its own entry. A type carries no lifecycle status, so the receipt states none.",
|
|
44172
45802
|
inputSchema: typeInput,
|
|
44173
45803
|
outputSchema: specWriteReceiptOutput
|
|
44174
45804
|
},
|
|
44175
|
-
({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns }) => {
|
|
45805
|
+
({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns, values, holds }) => {
|
|
44176
45806
|
try {
|
|
44177
45807
|
const spec = {
|
|
44178
45808
|
kind,
|
|
@@ -44198,7 +45828,9 @@ ${renderChangeReport(report3)}`,
|
|
|
44198
45828
|
...sourcePath ? { sourcePath } : {},
|
|
44199
45829
|
...symbol ? { symbol } : {},
|
|
44200
45830
|
...params ? { params } : {},
|
|
44201
|
-
...returns ? { returns } : {}
|
|
45831
|
+
...returns ? { returns } : {},
|
|
45832
|
+
...values ? { values } : {},
|
|
45833
|
+
...holds ? { holds } : {}
|
|
44202
45834
|
};
|
|
44203
45835
|
const receipt = writeSpec({ kind: "type", spec, fields: typeInputFields });
|
|
44204
45836
|
return writeReceipt(
|
|
@@ -44231,7 +45863,8 @@ ${renderChangeReport(report3)}`,
|
|
|
44231
45863
|
rules: config.rules,
|
|
44232
45864
|
projectType: config.projectType,
|
|
44233
45865
|
scopeSubsystem: subsystem,
|
|
44234
|
-
|
|
45866
|
+
// The tool's flag at the edge: recursive false is a member depth of 0.
|
|
45867
|
+
...recursive === false ? { memberDepth: 0 } : {},
|
|
44235
45868
|
family
|
|
44236
45869
|
};
|
|
44237
45870
|
const result = selectsFamily(options2, declaredMembers(config).length > 0) ? validateFamily(options2) : validateProject(options2);
|
|
@@ -44366,7 +45999,7 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
44366
45999
|
server,
|
|
44367
46000
|
"sdd_update_spec",
|
|
44368
46001
|
{
|
|
44369
|
-
description: "Update/patch an existing SDD specification (subsystem, component, interface, implementation, or type) using a granular delta. Updates fields, appends/merges array elements, or inserts/deletes narrative steps. Answers with exactly what changed, and with every path the delta named that the write did not act on. Pass dryRun to be told what it would do without writing it.",
|
|
46002
|
+
description: "Update/patch an existing SDD specification (subsystem, component, interface, implementation, or type) using a granular delta. Updates fields, appends/merges array elements, or inserts/deletes narrative steps. Answers with exactly what changed, and with every path the delta named that the write did not act on. Type positions (the type of a param, a returns, the type of a field, the params and returns of a signature) are written in the neutral type grammar: an alias the delta writes (string[], T | null, boolean, Promise<T>) is stored canonical and listed under `respellings`, and a stored alias at a position the write keeps is respelled with it; a position the delta writes that has no canonical spelling (number \u2014 int or float?, an inline object or function type, a literal union, a union mixing in a primitive) is refused, naming the replacement, while one the stored spec already held is left alone. Pass dryRun to be told what it would do without writing it.",
|
|
44370
46003
|
inputSchema: {
|
|
44371
46004
|
kind: import_zod11.z.enum(["system", "subsystem", "component", "interface", "implementation", "type"]).describe("The spec kind to update (system = the singleton L0 \u2014 vision, boundaries, globalRequirements, databases, and publicInterfaces: the project export table, each entry a re-export {from, component, interface, typeDef, as, name, type, details, audience: project|department|instance|partner|external} \u2014 from alone re-exports everything a subsystem exports, and a legacy {id, subsystem} reads as {as, from})"),
|
|
44372
46005
|
id: import_zod11.z.string().describe("The ID of the spec to update (namespaced if needed)"),
|
|
@@ -44395,18 +46028,19 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
44395
46028
|
}
|
|
44396
46029
|
},
|
|
44397
46030
|
({ subsystem, recursive }) => {
|
|
46031
|
+
const memberDepth = recursive === false ? 0 : void 0;
|
|
44398
46032
|
const banner = pendingBanner().map((line2) => `\u26A0 TRANSACTION PENDING: ${line2}
|
|
44399
46033
|
`).join("");
|
|
44400
46034
|
try {
|
|
44401
46035
|
let approvals;
|
|
44402
46036
|
try {
|
|
44403
|
-
approvals = familyApprovals(
|
|
46037
|
+
approvals = familyApprovals(memberDepth);
|
|
44404
46038
|
} catch {
|
|
44405
46039
|
approvals = void 0;
|
|
44406
46040
|
}
|
|
44407
46041
|
const report3 = getStatusReport({
|
|
44408
46042
|
subsystem,
|
|
44409
|
-
|
|
46043
|
+
memberDepth,
|
|
44410
46044
|
approvals
|
|
44411
46045
|
});
|
|
44412
46046
|
const family = statusFamilyContext();
|
|
@@ -44623,7 +46257,7 @@ async function startMcpServer() {
|
|
|
44623
46257
|
} catch {
|
|
44624
46258
|
}
|
|
44625
46259
|
}
|
|
44626
|
-
var import_mcp, import_stdio, import_zod11, import_types12, fs30, path50, import_url, crypto10, TYPE_REF_GRAMMAR, staleServerOutput, externalPinsOutput, externalStatusesOutput, SPEC_KINDS, STATUS_VALUES, testsToRevisitOutput, specWriteReceiptOutput, specDeletionOutput, specChangeOutput, specChangeReportOutput, validationIssueOutput, memberCreationOutput, doctrineChangeOutput, impactTotalsOutput, packImpactOutput, validateTreeOutput, getSpecOutput, FINGERPRINT_VERSION, runningFingerprint, RECONNECT, assessedAsChanged, serverBuildStamps, SERVER_BUILD_STAMP, SPEC_WRITE_TOOLS, listChangedEmitters, statusInput, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
|
|
46260
|
+
var import_mcp, import_stdio, import_zod11, import_types12, fs30, path50, import_url, crypto10, TYPE_REF_GRAMMAR, staleServerOutput, externalPinsOutput, externalStatusesOutput, SPEC_KINDS, STATUS_VALUES, testsToRevisitOutput, typeRespellingOutput, specWriteReceiptOutput, specDeletionOutput, specChangeOutput, specChangeReportOutput, validationIssueOutput, memberCreationOutput, doctrineChangeOutput, impactTotalsOutput, packImpactOutput, validateTreeOutput, getSpecOutput, FINGERPRINT_VERSION, runningFingerprint, RECONNECT, assessedAsChanged, serverBuildStamps, SERVER_BUILD_STAMP, SPEC_WRITE_TOOLS, listChangedEmitters, statusInput, SKILL_RESOURCE_MIME, AGENT_BRIEF_SCHEME;
|
|
44627
46261
|
var init_server = __esm({
|
|
44628
46262
|
"src/mcp/server.ts"() {
|
|
44629
46263
|
"use strict";
|
|
@@ -44652,7 +46286,7 @@ var init_server = __esm({
|
|
|
44652
46286
|
init_project();
|
|
44653
46287
|
init_validation_options();
|
|
44654
46288
|
init_migrations3();
|
|
44655
|
-
TYPE_REF_GRAMMAR = (what) => `${what}: a primitive
|
|
46289
|
+
TYPE_REF_GRAMMAR = (what) => `${what}, in the neutral type grammar: a primitive (string, int, float, bool, bytes, date, datetime, duration, any; void only as a whole returns), a defined type id ("billing.Invoice", "alias::name"), list<T>, set<T>, map<K, V> (K is string, int or an enum), T? (T or no value), a union of NAMED types ("Invoice | Receipt"), and on a returns only, async T ("async void"). Every named type must resolve. TypeScript spellings are accepted and respelled \u2014 "Invoice[]" \u2192 list<Invoice>, "Invoice | null" \u2192 Invoice?, boolean \u2192 bool, Record<string, V> \u2192 map<string, V>, Promise<T> \u2192 async T \u2014 and the answer lists each respelling. Refused, naming the replacement: number ("int or float?"), inline object or function types (name a value-object or a signature type), string-literal unions (name an enum), and unions mixing in a primitive or a collection.`;
|
|
44656
46290
|
staleServerOutput = {
|
|
44657
46291
|
staleServer: import_zod11.z.boolean().optional().describe(
|
|
44658
46292
|
"True when the wairon build on disk changed after this server started \u2014 the structured twin of the text answer's STALE SERVER banner. When the rebuild left the spec and tool schemas alone, writes still go through; reconnect to run the new code."
|
|
@@ -44702,6 +46336,13 @@ var init_server = __esm({
|
|
|
44702
46336
|
})).describe(
|
|
44703
46337
|
"The tests that encode a method this write changed or deleted, one entry per such method. Empty when the write touched no method, when the project declares no `rules.conformance.testRoots`, or when nothing references them. Read it before promising that existing tests still pass."
|
|
44704
46338
|
);
|
|
46339
|
+
typeRespellingOutput = import_zod11.z.object({
|
|
46340
|
+
specId: import_zod11.z.string().describe("The interface or type holding the position."),
|
|
46341
|
+
kind: import_zod11.z.enum(["interface", "type"]).describe("interface | type."),
|
|
46342
|
+
path: import_zod11.z.string().describe("Where in the spec: methods.save.params.key, methods.save.returns, fields.createdAt, params.listener."),
|
|
46343
|
+
written: import_zod11.z.string().describe("The text the input (or the stored file) held."),
|
|
46344
|
+
stored: import_zod11.z.string().describe("The canonical spelling, which is what is stored and shown.")
|
|
46345
|
+
});
|
|
44705
46346
|
specWriteReceiptOutput = {
|
|
44706
46347
|
kind: import_zod11.z.enum(SPEC_KINDS).describe("The spec kind written."),
|
|
44707
46348
|
id: import_zod11.z.string().describe('The id the spec is stored under; "system" for the L0 singleton.'),
|
|
@@ -44715,6 +46356,9 @@ var init_server = __esm({
|
|
|
44715
46356
|
notices: import_zod11.z.array(import_zod11.z.string()).describe(
|
|
44716
46357
|
"The notice lines the text answer lists, one per entry: what was carried forward, what a restatement removed, what an omission cleared, and every gate warning the write raised. Empty for a clean create."
|
|
44717
46358
|
),
|
|
46359
|
+
respellings: import_zod11.z.array(typeRespellingOutput).describe(
|
|
46360
|
+
"Each type position the write normalised: what the input wrote against the canonical spelling stored. Aliases are accepted, never refused, and this list is how an author learns the canonical form. Empty when every position was already canonical."
|
|
46361
|
+
),
|
|
44718
46362
|
testsToRevisit: testsToRevisitOutput,
|
|
44719
46363
|
...staleServerOutput
|
|
44720
46364
|
};
|
|
@@ -44747,6 +46391,9 @@ var init_server = __esm({
|
|
|
44747
46391
|
"Every path the delta named that the write did not act on, each with why. Read it: a nested typo the permissive delta cannot refuse shows up here and nowhere else."
|
|
44748
46392
|
),
|
|
44749
46393
|
notices: import_zod11.z.array(import_zod11.z.string()).describe("Store placement notices, gate warnings and delta notices."),
|
|
46394
|
+
respellings: import_zod11.z.array(typeRespellingOutput).describe(
|
|
46395
|
+
"Each type position the write normalised (or, on a dry run, would): what the delta or the stored file wrote against the canonical spelling stored. Aliases are accepted and respelled, never refused \u2014 this is how the canonical form is taught. Empty when every position was already canonical."
|
|
46396
|
+
),
|
|
44750
46397
|
summary: import_zod11.z.string().describe("One line for people."),
|
|
44751
46398
|
testsToRevisit: testsToRevisitOutput,
|
|
44752
46399
|
strippedKeys: import_zod11.z.array(import_zod11.z.string()).optional().describe(
|
|
@@ -45147,7 +46794,7 @@ function planMcpInstall(options) {
|
|
|
45147
46794
|
upToDate
|
|
45148
46795
|
}));
|
|
45149
46796
|
}
|
|
45150
|
-
|
|
46797
|
+
function runMcpInstall(options = {}) {
|
|
45151
46798
|
for (const target of resolveInstallTargets(options)) {
|
|
45152
46799
|
const agentLabel = target.backend === "gemini" ? "Antigravity" : "Claude";
|
|
45153
46800
|
if (target.upToDate) {
|
|
@@ -45188,7 +46835,7 @@ function reportInstalled(target, agentLabel) {
|
|
|
45188
46835
|
}
|
|
45189
46836
|
logger.blank();
|
|
45190
46837
|
}
|
|
45191
|
-
|
|
46838
|
+
function runMcpStatus() {
|
|
45192
46839
|
assertProjectInitialized();
|
|
45193
46840
|
const projectConfig = loadProjectConfig();
|
|
45194
46841
|
if (!projectConfig) throw new ProjectNotInitializedError();
|
|
@@ -45998,7 +47645,7 @@ async function executeInit(projectName, projectConfig, guidePlan) {
|
|
|
45998
47645
|
if (targetTypes.includes("claude")) {
|
|
45999
47646
|
try {
|
|
46000
47647
|
const { runMcpInstall: runMcpInstall2 } = (init_mcp(), __toCommonJS(mcp_exports));
|
|
46001
|
-
|
|
47648
|
+
runMcpInstall2({ global: false, backend: "claude" });
|
|
46002
47649
|
} catch (err) {
|
|
46003
47650
|
logger.warn(`Failed to automatically register MCP server for Claude: ${err}`);
|
|
46004
47651
|
}
|
|
@@ -46006,7 +47653,7 @@ async function executeInit(projectName, projectConfig, guidePlan) {
|
|
|
46006
47653
|
if (targetTypes.includes("gemini") || targetTypes.includes("agy")) {
|
|
46007
47654
|
try {
|
|
46008
47655
|
const { runMcpInstall: runMcpInstall2 } = (init_mcp(), __toCommonJS(mcp_exports));
|
|
46009
|
-
|
|
47656
|
+
runMcpInstall2({ backend: "gemini", global: false });
|
|
46010
47657
|
} catch (err) {
|
|
46011
47658
|
logger.warn(`Failed to automatically register MCP server for Antigravity: ${err}`);
|
|
46012
47659
|
}
|
|
@@ -46700,7 +48347,8 @@ async function runValidate(options = {}) {
|
|
|
46700
48347
|
rules: projectConfig.rules,
|
|
46701
48348
|
projectType: projectConfig.projectType,
|
|
46702
48349
|
scopeSubsystem: options.subsystem,
|
|
46703
|
-
|
|
48350
|
+
// The flag at the edge: --no-recursive is a member depth of 0, the default every level.
|
|
48351
|
+
...options.recursive === false ? { memberDepth: 0 } : {},
|
|
46704
48352
|
family: options.family
|
|
46705
48353
|
};
|
|
46706
48354
|
const family = selectsFamily(sddOptions, declaredMembers(projectConfig).length > 0);
|
|
@@ -47234,16 +48882,12 @@ function refuseUnreadableTree(explanation) {
|
|
|
47234
48882
|
function withoutTrailingNewline(text3) {
|
|
47235
48883
|
return text3.endsWith("\n") ? text3.slice(0, -1) : text3;
|
|
47236
48884
|
}
|
|
47237
|
-
function depthOf2(recursive) {
|
|
47238
|
-
if (recursive === false) return 0;
|
|
47239
|
-
return typeof recursive === "number" ? recursive : void 0;
|
|
47240
|
-
}
|
|
47241
48885
|
async function runStatus(options = {}) {
|
|
47242
48886
|
assertProjectInitialized();
|
|
47243
48887
|
printPendingTransactions();
|
|
47244
48888
|
let approvals;
|
|
47245
48889
|
try {
|
|
47246
|
-
approvals = familyApprovals(
|
|
48890
|
+
approvals = familyApprovals(options.memberDepth);
|
|
47247
48891
|
} catch {
|
|
47248
48892
|
approvals = void 0;
|
|
47249
48893
|
}
|
|
@@ -47649,7 +49293,7 @@ async function runDomainsRemove(id) {
|
|
|
47649
49293
|
var import_chalk11 = __toESM(require("chalk"));
|
|
47650
49294
|
init_logger();
|
|
47651
49295
|
init_paths();
|
|
47652
|
-
|
|
49296
|
+
function runSkillsList() {
|
|
47653
49297
|
assertProjectInitialized();
|
|
47654
49298
|
const names = listSkillNames();
|
|
47655
49299
|
logger.header(`SDD Skills (${names.length})`);
|
|
@@ -47658,7 +49302,7 @@ async function runSkillsList() {
|
|
|
47658
49302
|
console.log(` ${import_chalk11.default.bold(n)}`);
|
|
47659
49303
|
}
|
|
47660
49304
|
}
|
|
47661
|
-
|
|
49305
|
+
function runSkillsInstall() {
|
|
47662
49306
|
assertProjectInitialized();
|
|
47663
49307
|
const result = exportSddSkills();
|
|
47664
49308
|
if (result.destinations.length === 0) {
|
|
@@ -47998,6 +49642,34 @@ async function runDoctor(options = {}) {
|
|
|
47998
49642
|
} catch (e) {
|
|
47999
49643
|
line(tally, "warn", `Could not plan the signature repair: ${e instanceof Error ? e.message : String(e)}`);
|
|
48000
49644
|
}
|
|
49645
|
+
try {
|
|
49646
|
+
const spellings = repairTypeSpellings(false);
|
|
49647
|
+
const rewriting = spellings.filter((repair) => repair.rewritten.length > 0);
|
|
49648
|
+
const proposals = spellings.flatMap((repair) => repair.proposals);
|
|
49649
|
+
const authorNeeded = spellings.flatMap((repair) => repair.authorNeeded);
|
|
49650
|
+
if (spellings.length > 0) console.log(import_chalk12.default.bold("Type spellings"));
|
|
49651
|
+
if (rewriting.length > 0) {
|
|
49652
|
+
for (const repair of rewriting) {
|
|
49653
|
+
line(tally, "warn", `${repair.kind} ${repair.specId}: ${repair.rewritten.length} position(s) to respell (${describeRespellings(repair.rewritten)})`);
|
|
49654
|
+
}
|
|
49655
|
+
line(tally, "warn", "Run `wairon doctor --fix` to write them in their canonical spelling (any save of the spec does too).");
|
|
49656
|
+
}
|
|
49657
|
+
if (proposals.length > 0) {
|
|
49658
|
+
console.log(` ${import_chalk12.default.gray("int proposed \u2014 never written: confirm by writing int, or write float")}`);
|
|
49659
|
+
for (const proposal of proposals) {
|
|
49660
|
+
line(tally, "warn", `${proposal.kind} ${proposal.specId} ${proposal.path}: "${proposal.written}" \u2192 ${proposal.stored} (proposed)`);
|
|
49661
|
+
}
|
|
49662
|
+
}
|
|
49663
|
+
if (authorNeeded.length > 0) {
|
|
49664
|
+
console.log(` ${import_chalk12.default.gray("needs an author \u2014 no rewrite can settle these")}`);
|
|
49665
|
+
for (const problem of authorNeeded) {
|
|
49666
|
+
line(tally, "warn", `${problem.kind} ${problem.specId} ${problem.path ?? ""}: "${problem.written}" \u2014 ${problem.replacement ? `write ${problem.replacement}` : problem.detail}`);
|
|
49667
|
+
}
|
|
49668
|
+
}
|
|
49669
|
+
if (spellings.length > 0) logger.blank();
|
|
49670
|
+
} catch (e) {
|
|
49671
|
+
line(tally, "warn", `Could not plan the type-spelling repair: ${e instanceof Error ? e.message : String(e)}`);
|
|
49672
|
+
}
|
|
48001
49673
|
try {
|
|
48002
49674
|
const planned = plan5({ verb: "chaining", rehearse: false });
|
|
48003
49675
|
const pending4 = planned.chaining;
|
|
@@ -48229,6 +49901,28 @@ async function applyFixes(options, tally) {
|
|
|
48229
49901
|
} catch (e) {
|
|
48230
49902
|
console.log(` ${icon("error")} Signature repair failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
48231
49903
|
}
|
|
49904
|
+
try {
|
|
49905
|
+
const spellings = repairTypeSpellings(true);
|
|
49906
|
+
const rewritten = spellings.filter((repair) => repair.rewritten.length > 0);
|
|
49907
|
+
if (rewritten.length > 0) {
|
|
49908
|
+
const positions = rewritten.reduce((n, repair) => n + repair.rewritten.length, 0);
|
|
49909
|
+
console.log(` ${icon("ok")} Rewrote ${positions} type position(s) in ${rewritten.length} spec(s) into their canonical spelling.`);
|
|
49910
|
+
}
|
|
49911
|
+
const proposals = spellings.flatMap((repair) => repair.proposals);
|
|
49912
|
+
if (proposals.length > 0) {
|
|
49913
|
+
console.log(` ${icon("warn")} ${proposals.length} number position(s) with int proposed \u2014 not written; confirm by writing int, or write float:`);
|
|
49914
|
+
for (const proposal of proposals) console.log(` ${proposal.kind} ${proposal.specId} ${proposal.path}: "${proposal.written}" \u2192 ${proposal.stored} (proposed)`);
|
|
49915
|
+
}
|
|
49916
|
+
const authorNeeded = spellings.flatMap((repair) => repair.authorNeeded);
|
|
49917
|
+
if (authorNeeded.length > 0) {
|
|
49918
|
+
console.log(` ${icon("warn")} ${authorNeeded.length} type position(s) need an author \u2014 no rewrite can settle them:`);
|
|
49919
|
+
for (const problem of authorNeeded) {
|
|
49920
|
+
console.log(` ${problem.kind} ${problem.specId} ${problem.path ?? ""}: "${problem.written}" \u2014 ${problem.replacement ? `write ${problem.replacement}` : problem.detail}`);
|
|
49921
|
+
}
|
|
49922
|
+
}
|
|
49923
|
+
} catch (e) {
|
|
49924
|
+
console.log(` ${icon("error")} Type-spelling repair failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
49925
|
+
}
|
|
48232
49926
|
await migrateChaining(options, tally);
|
|
48233
49927
|
await repairMcpRegistration(options, targets);
|
|
48234
49928
|
logger.blank();
|
|
@@ -48248,18 +49942,18 @@ async function repairMcpRegistration(options, targets) {
|
|
|
48248
49942
|
continue;
|
|
48249
49943
|
}
|
|
48250
49944
|
if (writes.some((w) => w.outsideProject && !w.upToDate)) outside.push({ install, writes });
|
|
48251
|
-
else
|
|
49945
|
+
else installMcp(install);
|
|
48252
49946
|
}
|
|
48253
49947
|
const plugin = gemini ? findLegacyPlugin() : null;
|
|
48254
49948
|
if (outside.length === 0 && !plugin) return;
|
|
48255
49949
|
printOutsideWrites(outside, plugin);
|
|
48256
49950
|
if (!await confirmOutsideWrites(options)) return;
|
|
48257
|
-
for (const planned of outside)
|
|
49951
|
+
for (const planned of outside) installMcp(planned.install);
|
|
48258
49952
|
if (plugin) retireLegacyPlugin();
|
|
48259
49953
|
}
|
|
48260
|
-
|
|
49954
|
+
function installMcp(install) {
|
|
48261
49955
|
try {
|
|
48262
|
-
|
|
49956
|
+
runMcpInstall(install);
|
|
48263
49957
|
} catch (e) {
|
|
48264
49958
|
console.log(` ${icon("warn")} MCP install for ${install.backend} failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
48265
49959
|
}
|
|
@@ -48451,6 +50145,11 @@ function describeSignatureRepair(repair) {
|
|
|
48451
50145
|
if (repair.dropped.length > 0) parts.push(`drops the restated signature of ${repair.dropped.join(", ")}`);
|
|
48452
50146
|
return parts.join("; ");
|
|
48453
50147
|
}
|
|
50148
|
+
function describeRespellings(respellings) {
|
|
50149
|
+
const shown2 = respellings.slice(0, 3).map((r) => `${r.written} \u2192 ${r.stored}`);
|
|
50150
|
+
const more = respellings.length - shown2.length;
|
|
50151
|
+
return more > 0 ? `${shown2.join("; ")}; and ${more} more` : shown2.join("; ");
|
|
50152
|
+
}
|
|
48454
50153
|
function pendingCount(migration) {
|
|
48455
50154
|
return migration.rewrites.length + migration.projects.reduce((n, p) => n + (p.idToWrite ? 1 : 0) + (p.createsSystem ? 1 : 0) + p.exports.length + p.externals.length + p.imports.length + p.pins.length + p.members.length + p.supersededPins.length + p.locations.length, 0);
|
|
48456
50155
|
}
|
|
@@ -48689,7 +50388,7 @@ var import_chalk13 = __toESM(require("chalk"));
|
|
|
48689
50388
|
init_logger();
|
|
48690
50389
|
init_validation();
|
|
48691
50390
|
init_core();
|
|
48692
|
-
|
|
50391
|
+
function listRules3() {
|
|
48693
50392
|
let overrides = {};
|
|
48694
50393
|
if (projectConfigExists()) {
|
|
48695
50394
|
try {
|
|
@@ -48743,7 +50442,7 @@ SDD conformance rules (${active.length})
|
|
|
48743
50442
|
var import_chalk14 = __toESM(require("chalk"));
|
|
48744
50443
|
init_logger();
|
|
48745
50444
|
init_core();
|
|
48746
|
-
|
|
50445
|
+
function listPatterns() {
|
|
48747
50446
|
const ext = loadProjectExtensions();
|
|
48748
50447
|
console.log(import_chalk14.default.bold(`
|
|
48749
50448
|
Reusable patterns (${ext.patterns.length})
|
|
@@ -48768,7 +50467,7 @@ Reusable patterns (${ext.patterns.length})
|
|
|
48768
50467
|
var import_chalk15 = __toESM(require("chalk"));
|
|
48769
50468
|
init_logger();
|
|
48770
50469
|
init_core();
|
|
48771
|
-
|
|
50470
|
+
function listVariants() {
|
|
48772
50471
|
const variants = loadProjectVariants();
|
|
48773
50472
|
console.log(import_chalk15.default.bold(`
|
|
48774
50473
|
Component variants (${variants.length})
|
|
@@ -48948,7 +50647,7 @@ async function addPackFromArchive(source, options) {
|
|
|
48948
50647
|
}
|
|
48949
50648
|
logger.info(`${describe2(probe2)} \u2014 commit .wai/ so CI and every clone enforce it.`);
|
|
48950
50649
|
}
|
|
48951
|
-
|
|
50650
|
+
function initPack(name, options = {}) {
|
|
48952
50651
|
const kind = options.kind === "code" ? "code" : "declarative";
|
|
48953
50652
|
const targetDir = options.dir ?? `./${name}`;
|
|
48954
50653
|
const request = { name, kind, targetDir };
|
|
@@ -48961,7 +50660,7 @@ async function initPack(name, options = {}) {
|
|
|
48961
50660
|
logger.blank();
|
|
48962
50661
|
logger.info(`Next: cd ${targetDir} && wairon pack build`);
|
|
48963
50662
|
}
|
|
48964
|
-
|
|
50663
|
+
function buildPack(source, options = {}) {
|
|
48965
50664
|
const sourceDir = source && source.length > 0 ? source : ".";
|
|
48966
50665
|
const result = (0, import_sdk.buildPack)(sourceDir);
|
|
48967
50666
|
const outPath = options.out ?? result.suggestedFileName;
|
|
@@ -49108,7 +50807,7 @@ function extractArchiveToTemp(source) {
|
|
|
49108
50807
|
return null;
|
|
49109
50808
|
}
|
|
49110
50809
|
}
|
|
49111
|
-
|
|
50810
|
+
function uninstallStorePack(spec) {
|
|
49112
50811
|
const { name, version } = parseNameAtVersion(spec);
|
|
49113
50812
|
if (!uninstallPack(name, version)) {
|
|
49114
50813
|
logger.error(`No pack "${spec}" is installed in the store (${packStoreDir()}).`);
|
|
@@ -49118,7 +50817,7 @@ async function uninstallStorePack(spec) {
|
|
|
49118
50817
|
logger.success(`Uninstalled ${version ? `${name} v${version}` : `every version of ${name}`} from the pack store.`);
|
|
49119
50818
|
logger.info("A project that still SELECTS it will now fail its gate with PACK_NOT_INSTALLED \u2014 reinstall it or drop the selection.");
|
|
49120
50819
|
}
|
|
49121
|
-
|
|
50820
|
+
function whichPack(spec) {
|
|
49122
50821
|
const { name, version } = parseNameAtVersion(spec);
|
|
49123
50822
|
const resolved = resolveInstalledPack(name, version);
|
|
49124
50823
|
if (!resolved) {
|
|
@@ -49276,7 +50975,7 @@ function writeBundle(root, resolved) {
|
|
|
49276
50975
|
fs37.cpSync(resolved.path, dest, { recursive: true });
|
|
49277
50976
|
return dest;
|
|
49278
50977
|
}
|
|
49279
|
-
|
|
50978
|
+
function bundlePack(name, options = {}) {
|
|
49280
50979
|
if (!projectConfigExists()) {
|
|
49281
50980
|
logger.error("Not inside a wairon project \u2014 run `wairon init` first.");
|
|
49282
50981
|
process.exitCode = 1;
|
|
@@ -49341,7 +51040,7 @@ function parseNameAtVersion(spec) {
|
|
|
49341
51040
|
if (at <= 0) return { name: spec };
|
|
49342
51041
|
return { name: spec.slice(0, at), version: spec.slice(at + 1) };
|
|
49343
51042
|
}
|
|
49344
|
-
|
|
51043
|
+
function listPacks() {
|
|
49345
51044
|
const inProject = projectConfigExists();
|
|
49346
51045
|
const config = inProject ? loadProjectConfig() : null;
|
|
49347
51046
|
if (inProject && !config) throw new ProjectNotInitializedError();
|
|
@@ -49508,7 +51207,7 @@ function printImpact(impact) {
|
|
|
49508
51207
|
After: ${totals3(impact.after)}`);
|
|
49509
51208
|
logger.blank();
|
|
49510
51209
|
}
|
|
49511
|
-
|
|
51210
|
+
function impactPack(spec) {
|
|
49512
51211
|
if (!projectConfigExists()) {
|
|
49513
51212
|
logger.error("Not inside a wairon project \u2014 run `wairon init` first.");
|
|
49514
51213
|
process.exitCode = 1;
|
|
@@ -56320,7 +58019,7 @@ function referencedTypeNames(methods) {
|
|
|
56320
58019
|
const names = /* @__PURE__ */ new Set();
|
|
56321
58020
|
for (const m of methods) {
|
|
56322
58021
|
for (const ref of methodTypeRefs(m)) {
|
|
56323
|
-
if (!
|
|
58022
|
+
if (!isTypeVocabulary(ref)) names.add(ref.split(/::|\./).pop());
|
|
56324
58023
|
}
|
|
56325
58024
|
}
|
|
56326
58025
|
return [...names];
|
|
@@ -56871,7 +58570,7 @@ function scopeOf2(grant) {
|
|
|
56871
58570
|
if (!grant.projectId || grant.projectId === "*") return { scopeKind: "instance" };
|
|
56872
58571
|
return { scopeKind: "project", scopeId: grant.projectId };
|
|
56873
58572
|
}
|
|
56874
|
-
function
|
|
58573
|
+
function readRaw2(file) {
|
|
56875
58574
|
try {
|
|
56876
58575
|
return JSON.parse(fs57.readFileSync(file, "utf8"));
|
|
56877
58576
|
} catch {
|
|
@@ -56912,7 +58611,7 @@ function migratePermissionModel(dataDir, apply4) {
|
|
|
56912
58611
|
const found = (area, detail) => {
|
|
56913
58612
|
findings.push({ area, detail });
|
|
56914
58613
|
};
|
|
56915
|
-
const grid =
|
|
58614
|
+
const grid = readRaw2(
|
|
56916
58615
|
path79.join(dataDir, "permissions.json")
|
|
56917
58616
|
) ?? [];
|
|
56918
58617
|
if (!getInstanceIdentity(dataDir)) {
|
|
@@ -56920,7 +58619,7 @@ function migratePermissionModel(dataDir, apply4) {
|
|
|
56920
58619
|
if (apply4) ensureInstanceIdentity(dataDir);
|
|
56921
58620
|
}
|
|
56922
58621
|
const orgPath = path79.join(dataDir, "organization.json");
|
|
56923
|
-
const org =
|
|
58622
|
+
const org = readRaw2(orgPath);
|
|
56924
58623
|
if (org?.units?.length) {
|
|
56925
58624
|
const units = org.units;
|
|
56926
58625
|
const byId = new Map(units.map((u) => [u.id, u]));
|
|
@@ -56974,7 +58673,7 @@ function migratePermissionModel(dataDir, apply4) {
|
|
|
56974
58673
|
}
|
|
56975
58674
|
}
|
|
56976
58675
|
const usersPath = path79.join(dataDir, "users.json");
|
|
56977
|
-
const users =
|
|
58676
|
+
const users = readRaw2(usersPath);
|
|
56978
58677
|
if (users) {
|
|
56979
58678
|
let changed = false;
|
|
56980
58679
|
for (const user of users) {
|
|
@@ -57001,7 +58700,7 @@ function migratePermissionModel(dataDir, apply4) {
|
|
|
57001
58700
|
if (apply4 && changed) writeRaw(usersPath, users);
|
|
57002
58701
|
}
|
|
57003
58702
|
const keysPath = path79.join(dataDir, "auth", "credentials.json");
|
|
57004
|
-
const keys =
|
|
58703
|
+
const keys = readRaw2(keysPath);
|
|
57005
58704
|
if (keys) {
|
|
57006
58705
|
let changed = false;
|
|
57007
58706
|
for (const key of keys) {
|
|
@@ -57051,7 +58750,7 @@ function migratePermissionModel(dataDir, apply4) {
|
|
|
57051
58750
|
if (apply4 && changed) writeRaw(keysPath, keys);
|
|
57052
58751
|
}
|
|
57053
58752
|
const sessionsPath = path79.join(dataDir, "web-sessions.json");
|
|
57054
|
-
const sessions =
|
|
58753
|
+
const sessions = readRaw2(sessionsPath);
|
|
57055
58754
|
if (sessions) {
|
|
57056
58755
|
let changed = false;
|
|
57057
58756
|
const kept = sessions.filter((s) => {
|
|
@@ -59270,9 +60969,9 @@ function serveMembershipTool(cfg, principal, binding, body) {
|
|
|
59270
60969
|
return answer(relocationResult("adopt", adopt(cfg, principal, binding, String(call.args.alias ?? ""), String(call.args.path ?? ""), apply4), apply4));
|
|
59271
60970
|
default: {
|
|
59272
60971
|
const named2 = call.name === "sdd_rename_project" ? String(call.args.project ?? "") : call.name === "sdd_externalize_subsystem" ? String(call.args.subsystem ?? "") : String(call.args.alias ?? "");
|
|
59273
|
-
const
|
|
60972
|
+
const located2 = typeof call.args.source === "string" ? call.args.source : typeof call.args.path === "string" ? call.args.path : void 0;
|
|
59274
60973
|
const newId = call.name === "sdd_promote_member" && typeof call.args.id === "string" && call.args.id ? call.args.id : void 0;
|
|
59275
|
-
const screened = screen(cfg.dataDir, binding, call.name, named2,
|
|
60974
|
+
const screened = screen(cfg.dataDir, binding, call.name, named2, located2, newId);
|
|
59276
60975
|
if (screened.refusal !== void 0) return answer({ content: [{ type: "text", text: screened.refusal }], isError: true });
|
|
59277
60976
|
return { screen: screened };
|
|
59278
60977
|
}
|
|
@@ -66016,7 +67715,7 @@ async function statusCommand(opts) {
|
|
|
66016
67715
|
`);
|
|
66017
67716
|
return;
|
|
66018
67717
|
}
|
|
66019
|
-
await runStatus({ subsystem: opts.subsystem,
|
|
67718
|
+
await runStatus({ subsystem: opts.subsystem, ...opts.recursive === false ? { memberDepth: 0 } : {} });
|
|
66020
67719
|
}
|
|
66021
67720
|
async function lockCheckCommand(options) {
|
|
66022
67721
|
const verdict = checkApproval(options.strict === true);
|
|
@@ -66041,34 +67740,34 @@ program.command("status").description("Show a hierarchical completeness graph of
|
|
|
66041
67740
|
program.command("doctor").description("Health check: flags stale generated guides/skills, an unregistered MCP server, spec-tree issues and the chaining migration still pending").option("--fix", "regenerate stale in-project guides/context/skills, register the MCP server, then apply the chaining migration once confirmed").option("--report <section>", "print one section's report and nothing else, writing nothing (chaining | composed-validation); never combines with --fix").option("-y, --yes", "answer the chaining migration's confirmation (for a non-interactive --fix); a write outside the project root also needs --global").option("--global", "consent to the --fix writes outside the project root (a machine-wide MCP config, the legacy global plugin); with --yes it answers their confirmation, and each replaced file is backed up beside itself").action(async (opts) => {
|
|
66042
67741
|
await runDoctor({ fix: opts.fix, report: opts.report, yes: opts.yes, global: opts.global === true });
|
|
66043
67742
|
});
|
|
66044
|
-
|
|
66045
|
-
|
|
67743
|
+
function runRules() {
|
|
67744
|
+
listRules3();
|
|
66046
67745
|
}
|
|
66047
|
-
|
|
66048
|
-
|
|
67746
|
+
function runPatterns() {
|
|
67747
|
+
listPatterns();
|
|
66049
67748
|
}
|
|
66050
|
-
|
|
66051
|
-
|
|
67749
|
+
function runVariants() {
|
|
67750
|
+
listVariants();
|
|
66052
67751
|
}
|
|
66053
67752
|
async function runPacks(action, arg, options = {}) {
|
|
66054
67753
|
if (action === "add") await addPack(arg, options.global);
|
|
66055
|
-
else if (action === "list")
|
|
67754
|
+
else if (action === "list") listPacks();
|
|
66056
67755
|
else if (action === "remove") await removePack(arg, options.global);
|
|
66057
67756
|
}
|
|
66058
67757
|
async function runPack(action, arg, options = {}) {
|
|
66059
|
-
if (action === "init")
|
|
66060
|
-
else if (action === "build")
|
|
67758
|
+
if (action === "init") initPack(arg, { kind: options.kind === "code" ? "code" : "declarative", dir: options.dir, skill: options.skill });
|
|
67759
|
+
else if (action === "build") buildPack(arg ?? ".", { out: options.out });
|
|
66061
67760
|
else if (action === "add") await addPack(arg, options.global, options.yes);
|
|
66062
|
-
else if (action === "list")
|
|
67761
|
+
else if (action === "list") listPacks();
|
|
66063
67762
|
else if (action === "remove") await removePack(arg, options.global, options.yes);
|
|
66064
67763
|
else if (action === "install") await installPack(arg, options.yes);
|
|
66065
|
-
else if (action === "uninstall")
|
|
66066
|
-
else if (action === "which")
|
|
67764
|
+
else if (action === "uninstall") uninstallStorePack(arg);
|
|
67765
|
+
else if (action === "which") whichPack(arg);
|
|
66067
67766
|
else if (action === "use") await usePack(arg, { source: options.source, bundle: options.bundle, pin: options.pin, yes: options.yes });
|
|
66068
67767
|
else if (action === "unuse") await unusePack(arg, options.yes);
|
|
66069
|
-
else if (action === "bundle")
|
|
67768
|
+
else if (action === "bundle") bundlePack(arg, { all: options.all });
|
|
66070
67769
|
else if (action === "sync") await syncPacks();
|
|
66071
|
-
else if (action === "impact")
|
|
67770
|
+
else if (action === "impact") impactPack(arg);
|
|
66072
67771
|
else throw new WaironError("unknown pack action (expected init | build | install | uninstall | which | use | unuse | impact | bundle | sync | add | list | remove)");
|
|
66073
67772
|
}
|
|
66074
67773
|
var executionCmd = program.command("execution").description("Execution budgets: what each agent's work is like and the model/turn/tool allowance it earns");
|
|
@@ -66237,9 +67936,9 @@ var mcpCmd = program.command("mcp").description("MCP (Model Context Protocol) se
|
|
|
66237
67936
|
mcpCmd.command("serve").description("Start the wairon MCP server (stdio transport \u2014 use in mcpServers config)").action(async () => {
|
|
66238
67937
|
await runMcpServe();
|
|
66239
67938
|
});
|
|
66240
|
-
|
|
67939
|
+
function mcpInstallCommand(opts) {
|
|
66241
67940
|
const hostedToken = opts.hosted ? opts.token ?? storedCredentialFor(String(opts.hosted).replace(/\/+$/, "")) ?? void 0 : void 0;
|
|
66242
|
-
|
|
67941
|
+
runMcpInstall({
|
|
66243
67942
|
global: opts.global,
|
|
66244
67943
|
configDir: opts.configDir,
|
|
66245
67944
|
backend: opts.backend,
|
|
@@ -66249,8 +67948,8 @@ async function mcpInstallCommand(opts) {
|
|
|
66249
67948
|
});
|
|
66250
67949
|
}
|
|
66251
67950
|
mcpCmd.command("install").description("Register the wairon MCP server in the Claude Code settings.json or Antigravity mcp_config.json").option("--global", "install into the global/home config instead of the project (respects CLAUDE_CONFIG_DIR / GEMINI_CONFIG_DIR)").option("--config-dir <path>", "explicit config dir to install into (validated for the agent; requires --backend). Reliable alternative to relying on the shell's CLAUDE_CONFIG_DIR").option("--backend <type>", "target AI assistant: claude | gemini (aliases: agy, antigravity \u2192 gemini)").option("--hosted <url>", "register a HOSTED entry against this instance instead of the local stdio server").option("--project <id>", "hosted: the project the agent should be bound to").option("--token <token>", "hosted: the bearer to carry (else the credential stored by `wairon login`)").action(mcpInstallCommand);
|
|
66252
|
-
mcpCmd.command("status").description("Show whether the wairon MCP server is registered in Claude Code and Antigravity settings").action(
|
|
66253
|
-
|
|
67951
|
+
mcpCmd.command("status").description("Show whether the wairon MCP server is registered in Claude Code and Antigravity settings").action(() => {
|
|
67952
|
+
runMcpStatus();
|
|
66254
67953
|
});
|
|
66255
67954
|
program.command("produce <target>").description("project the local project's specs to a producer target (notion | miro)").option("--page <id>", "parent page/board id in the target").option("--token <token>", "integration token (else env, else interactive prompt)").action(async (target, opts) => {
|
|
66256
67955
|
await runProduce(target, { page: opts.page, token: opts.token });
|
|
@@ -66413,11 +68112,11 @@ domainsCmd.command("remove <id>").alias("rm").description("Remove a free-standin
|
|
|
66413
68112
|
await runDomainsRemove(id);
|
|
66414
68113
|
});
|
|
66415
68114
|
var skillsCmd = program.command("skills").description("Manage the SDD skills installed into your AI tools");
|
|
66416
|
-
skillsCmd.command("list").alias("ls").description("List the built-in SDD skills").action(
|
|
66417
|
-
|
|
68115
|
+
skillsCmd.command("list").alias("ls").description("List the built-in SDD skills").action(() => {
|
|
68116
|
+
runSkillsList();
|
|
66418
68117
|
});
|
|
66419
|
-
skillsCmd.command("install").alias("sync").description("Install/refresh the SDD skills into each active target tool").action(
|
|
66420
|
-
|
|
68118
|
+
skillsCmd.command("install").alias("sync").description("Install/refresh the SDD skills into each active target tool").action(() => {
|
|
68119
|
+
runSkillsInstall();
|
|
66421
68120
|
});
|
|
66422
68121
|
async function main() {
|
|
66423
68122
|
try {
|