@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/index.js
CHANGED
|
@@ -2959,7 +2959,6 @@ var require_dist = __commonJS({
|
|
|
2959
2959
|
"# languages:",
|
|
2960
2960
|
"# rust:",
|
|
2961
2961
|
"# unsupportedFlow: {}",
|
|
2962
|
-
"# foreignBuiltins: []",
|
|
2963
2962
|
"languages: {}",
|
|
2964
2963
|
"",
|
|
2965
2964
|
"# Reusable, versioned architecture patterns:",
|
|
@@ -3186,12 +3185,12 @@ var require_dist = __commonJS({
|
|
|
3186
3185
|
const suggestedFileName = `${sealed.name}-${sealed.version}.wpack`;
|
|
3187
3186
|
return { archive: archiveBytes, info, suggestedFileName };
|
|
3188
3187
|
}
|
|
3189
|
-
function inspectArchive(
|
|
3190
|
-
const entries = listEntries(
|
|
3188
|
+
function inspectArchive(archive) {
|
|
3189
|
+
const entries = listEntries(archive);
|
|
3191
3190
|
if (!entries.some((entry) => entry.path === ENVELOPE_FILENAME)) {
|
|
3192
3191
|
throw new Error("not a .wpack archive (missing wairon-pack.yaml envelope)");
|
|
3193
3192
|
}
|
|
3194
|
-
const envelopeBytes = inflateEntry(
|
|
3193
|
+
const envelopeBytes = inflateEntry(archive, ENVELOPE_FILENAME);
|
|
3195
3194
|
const manifest = parseManifest(decode(envelopeBytes));
|
|
3196
3195
|
const compatible = checkCompatibility(manifest, SDK_VERSION);
|
|
3197
3196
|
const fileEntries = entries.filter((entry) => entry.kind === "file");
|
|
@@ -3209,13 +3208,13 @@ var require_dist = __commonJS({
|
|
|
3209
3208
|
if (manifest.minWaironVersion !== void 0) info.minWaironVersion = manifest.minWaironVersion;
|
|
3210
3209
|
return info;
|
|
3211
3210
|
}
|
|
3212
|
-
function extractPack(
|
|
3211
|
+
function extractPack(archive, destDir, limits) {
|
|
3213
3212
|
const effectiveLimits = limits === void 0 ? defaultLimits() : limits;
|
|
3214
|
-
const entries = listEntries(
|
|
3213
|
+
const entries = listEntries(archive);
|
|
3215
3214
|
const plan6 = planExtraction(entries, effectiveLimits);
|
|
3216
3215
|
const files = [];
|
|
3217
3216
|
for (const approvedPath of plan6.paths) {
|
|
3218
|
-
const contents = inflateEntry(
|
|
3217
|
+
const contents = inflateEntry(archive, approvedPath);
|
|
3219
3218
|
files.push({ path: approvedPath, contents });
|
|
3220
3219
|
}
|
|
3221
3220
|
const envelope = files.find((file) => file.path === ENVELOPE_FILENAME);
|
|
@@ -3272,28 +3271,28 @@ var require_dist = __commonJS({
|
|
|
3272
3271
|
const suggestedFileName = `${slugify(projectName)}.waitree`;
|
|
3273
3272
|
return { archive: archiveBytes, manifest: sealed, suggestedFileName, fileCount: files.length };
|
|
3274
3273
|
}
|
|
3275
|
-
function inspectTreeArchive3(
|
|
3276
|
-
const entries = listEntries(
|
|
3274
|
+
function inspectTreeArchive3(archive) {
|
|
3275
|
+
const entries = listEntries(archive);
|
|
3277
3276
|
if (!entries.some((entry) => entry.path === TREE_ENVELOPE_FILENAME)) {
|
|
3278
3277
|
throw new Error("not a .waitree archive (missing wairon-tree.yaml envelope)");
|
|
3279
3278
|
}
|
|
3280
|
-
const envelopeBytes = inflateEntry(
|
|
3279
|
+
const envelopeBytes = inflateEntry(archive, TREE_ENVELOPE_FILENAME);
|
|
3281
3280
|
const manifest = parseTreeManifest(decode(envelopeBytes));
|
|
3282
3281
|
const compatible = checkTreeCompatibility(manifest, SDK_VERSION);
|
|
3283
3282
|
const fileEntries = entries.filter((entry) => entry.kind === "file");
|
|
3284
3283
|
const totalUncompressedBytes = entries.reduce((sum, entry) => sum + entry.uncompressedSize, 0);
|
|
3285
3284
|
return { manifest, entryCount: fileEntries.length, totalUncompressedBytes, compatible };
|
|
3286
3285
|
}
|
|
3287
|
-
function extractTreeArchive3(
|
|
3286
|
+
function extractTreeArchive3(archive, destDir, limits, refuseExecutableEntries) {
|
|
3288
3287
|
const effectiveLimits = limits === void 0 ? defaultTreeLimits() : limits;
|
|
3289
|
-
const entries = listEntries(
|
|
3288
|
+
const entries = listEntries(archive);
|
|
3290
3289
|
const plan6 = planTreeExtraction(entries, effectiveLimits);
|
|
3291
3290
|
if (refuseExecutableEntries === true) {
|
|
3292
3291
|
assertPortableTreePaths(plan6.paths);
|
|
3293
3292
|
}
|
|
3294
3293
|
const files = [];
|
|
3295
3294
|
for (const approvedPath of plan6.paths) {
|
|
3296
|
-
const contents = inflateEntry(
|
|
3295
|
+
const contents = inflateEntry(archive, approvedPath);
|
|
3297
3296
|
files.push({ path: approvedPath, contents });
|
|
3298
3297
|
}
|
|
3299
3298
|
const envelope = files.find((file) => file.path === TREE_ENVELOPE_FILENAME);
|
|
@@ -3326,9 +3325,9 @@ var require_dist = __commonJS({
|
|
|
3326
3325
|
}
|
|
3327
3326
|
function readInnerIdentity(files, manifest) {
|
|
3328
3327
|
const innerPath = manifest.kind === "code" ? "package.json" : manifest.entry;
|
|
3329
|
-
const
|
|
3330
|
-
if (!
|
|
3331
|
-
const parsed = manifest.kind === "code" ? JSON.parse(decode(
|
|
3328
|
+
const inner2 = files.find((file) => file.path === innerPath);
|
|
3329
|
+
if (!inner2) throw new Error(`pack build: inner pack manifest "${innerPath}" is missing`);
|
|
3330
|
+
const parsed = manifest.kind === "code" ? JSON.parse(decode(inner2.contents)) : (0, import_js_yaml3.load)(decode(inner2.contents));
|
|
3332
3331
|
const name = parsed?.name;
|
|
3333
3332
|
const version = parsed?.version;
|
|
3334
3333
|
if (typeof name !== "string" || typeof version !== "string") {
|
|
@@ -3394,7 +3393,6 @@ __export(src_exports, {
|
|
|
3394
3393
|
AgentTemplateSchema: () => AgentTemplateSchema,
|
|
3395
3394
|
BACKEND_COMMANDS: () => BACKEND_COMMANDS,
|
|
3396
3395
|
BUILTIN_PROFILES: () => BUILTIN_PROFILES,
|
|
3397
|
-
BUILTIN_TYPES: () => BUILTIN_TYPES,
|
|
3398
3396
|
BoundaryItemSchema: () => BoundaryItemSchema,
|
|
3399
3397
|
BuiltinTargetConfigSchema: () => BuiltinTargetConfigSchema,
|
|
3400
3398
|
BuiltinTargetSchema: () => BuiltinTargetSchema,
|
|
@@ -3428,6 +3426,7 @@ __export(src_exports, {
|
|
|
3428
3426
|
DurabilitySchema: () => DurabilitySchema,
|
|
3429
3427
|
EXTERNAL_ALIAS_RE: () => EXTERNAL_ALIAS_RE,
|
|
3430
3428
|
EndpointSchema: () => EndpointSchema,
|
|
3429
|
+
EnumValueSchema: () => EnumValueSchema,
|
|
3431
3430
|
EventBindingSchema: () => EventBindingSchema,
|
|
3432
3431
|
ExtDataSchema: () => ExtDataSchema,
|
|
3433
3432
|
ExternalDeclarationSchema: () => ExternalDeclarationSchema,
|
|
@@ -3442,6 +3441,7 @@ __export(src_exports, {
|
|
|
3442
3441
|
GeminiExporter: () => GeminiExporter,
|
|
3443
3442
|
GroupSpecSchema: () => GroupSpecSchema,
|
|
3444
3443
|
GuaranteeSchema: () => GuaranteeSchema,
|
|
3444
|
+
HOLDABLE_PRIMITIVES: () => HOLDABLE_PRIMITIVES,
|
|
3445
3445
|
HttpMethodSchema: () => HttpMethodSchema,
|
|
3446
3446
|
ImplementationSpecSchema: () => ImplementationSpecSchema,
|
|
3447
3447
|
InterfaceSpecSchema: () => InterfaceSpecSchema,
|
|
@@ -3461,6 +3461,7 @@ __export(src_exports, {
|
|
|
3461
3461
|
NarrativeStepTypeSchema: () => NarrativeStepTypeSchema,
|
|
3462
3462
|
OutputTargetSchema: () => OutputTargetSchema,
|
|
3463
3463
|
PATTERN_TYPES: () => PATTERN_TYPES,
|
|
3464
|
+
PRIMITIVE_TYPES: () => PRIMITIVE_TYPES,
|
|
3464
3465
|
PROJECT_ID_RE: () => PROJECT_ID_RE,
|
|
3465
3466
|
PROJECT_KINDS: () => PROJECT_KINDS,
|
|
3466
3467
|
PUBLIC_NAME_RE: () => PUBLIC_NAME_RE,
|
|
@@ -3548,6 +3549,7 @@ __export(src_exports, {
|
|
|
3548
3549
|
buildRuleContext: () => buildRuleContext,
|
|
3549
3550
|
callSitesOf: () => callSitesOf,
|
|
3550
3551
|
canonicalTypeRef: () => canonicalTypeRef,
|
|
3552
|
+
canonicalTypeText: () => canonicalTypeText,
|
|
3551
3553
|
captureApprovedSpecs: () => captureApprovedSpecs,
|
|
3552
3554
|
checkDeclarativePack: () => checkDeclarativePack,
|
|
3553
3555
|
clearLoaderIssues: () => clearLoaderIssues,
|
|
@@ -3592,6 +3594,7 @@ __export(src_exports, {
|
|
|
3592
3594
|
detectDomainCandidates: () => detectDomainCandidates,
|
|
3593
3595
|
diagnoseProjectPacks: () => diagnoseProjectPacks,
|
|
3594
3596
|
diagramSetIndex: () => diagramSetIndex,
|
|
3597
|
+
dialectOf: () => dialectOf,
|
|
3595
3598
|
diffAgainstApproval: () => diffAgainstApproval,
|
|
3596
3599
|
diffSize: () => diffSize,
|
|
3597
3600
|
discoverPacks: () => discoverPacks,
|
|
@@ -3599,6 +3602,7 @@ __export(src_exports, {
|
|
|
3599
3602
|
effectiveDetail: () => effectiveDetail,
|
|
3600
3603
|
effectiveProjectId: () => effectiveProjectId,
|
|
3601
3604
|
emptyExtensions: () => emptyExtensions,
|
|
3605
|
+
emptyTypeSpellingFacts: () => emptyTypeSpellingFacts,
|
|
3602
3606
|
ensureDir: () => ensureDir,
|
|
3603
3607
|
ensureProjectInitialized: () => ensureProjectInitialized,
|
|
3604
3608
|
excerptParent: () => excerpt,
|
|
@@ -3645,6 +3649,7 @@ __export(src_exports, {
|
|
|
3645
3649
|
importSpecTree: () => importSpecTree,
|
|
3646
3650
|
injectGuide: () => injectGuide,
|
|
3647
3651
|
installPackFromDirectory: () => installPackFromDirectory,
|
|
3652
|
+
interfaceCanonicalTypes: () => interfaceCanonicalTypes,
|
|
3648
3653
|
interfaceGenericParameters: () => interfaceGenericParameters,
|
|
3649
3654
|
internalizeMember: () => internalizeMember,
|
|
3650
3655
|
isDraftSubsystem: () => isDraftSubsystem,
|
|
@@ -3656,9 +3661,11 @@ __export(src_exports, {
|
|
|
3656
3661
|
isProjectInitialized: () => isProjectInitialized,
|
|
3657
3662
|
isProvidedBy: () => isProvidedBy,
|
|
3658
3663
|
isRetired: () => isRetired,
|
|
3664
|
+
isTypeVocabulary: () => isTypeVocabulary,
|
|
3659
3665
|
judgesCode: () => judgesCode,
|
|
3660
3666
|
keyIn: () => keyIn,
|
|
3661
3667
|
landReference: () => landReference,
|
|
3668
|
+
languageOfSourcePath: () => languageOfSourcePath,
|
|
3662
3669
|
listDirectChainedSubprojects: () => listDirectChainedSubprojects,
|
|
3663
3670
|
listFiles: () => listFiles,
|
|
3664
3671
|
listFilesRecursive: () => listFilesRecursive,
|
|
@@ -3701,6 +3708,7 @@ __export(src_exports, {
|
|
|
3701
3708
|
moveMethods: () => moveMethods,
|
|
3702
3709
|
moveMountToMembers: () => moveMountToMembers,
|
|
3703
3710
|
nameKey: () => nameKey,
|
|
3711
|
+
namesAnInteger: () => namesAnInteger,
|
|
3704
3712
|
narrativeStepForeignFields: () => narrativeStepForeignFields,
|
|
3705
3713
|
normalizeReferences: () => normalizeReferences2,
|
|
3706
3714
|
ownerOf: () => ownerOf,
|
|
@@ -3712,6 +3720,8 @@ __export(src_exports, {
|
|
|
3712
3720
|
parseDeclarativePack: () => parseDeclarativePack,
|
|
3713
3721
|
parseDeclaredCall: () => parseDeclaredCall,
|
|
3714
3722
|
parseMemberSource: () => parseMemberSource,
|
|
3723
|
+
parseTypeExpression: () => parseTypeExpression,
|
|
3724
|
+
parseTypePosition: () => parseTypePosition,
|
|
3715
3725
|
parseYaml: () => parseYaml,
|
|
3716
3726
|
passesIntentFloor: () => passesIntentFloor,
|
|
3717
3727
|
pathExists: () => pathExists,
|
|
@@ -3725,6 +3735,7 @@ __export(src_exports, {
|
|
|
3725
3735
|
provisionProject: () => provisionProject,
|
|
3726
3736
|
qualifiedTypeId: () => qualifiedTypeId,
|
|
3727
3737
|
rangeProblem: () => rangeProblem,
|
|
3738
|
+
readCodeAnnotation: () => readCodeAnnotation,
|
|
3728
3739
|
readFileOrNull: () => readFileOrNull,
|
|
3729
3740
|
readJsonFile: () => readJsonFile,
|
|
3730
3741
|
readLockRecord: () => readLockRecord,
|
|
@@ -3747,6 +3758,7 @@ __export(src_exports, {
|
|
|
3747
3758
|
renderDiagram: () => renderDiagram,
|
|
3748
3759
|
repairForeignStepFields: () => repairForeignStepFields,
|
|
3749
3760
|
repairSignatures: () => repairSignatures,
|
|
3761
|
+
repairTypeSpellings: () => repairTypeSpellings,
|
|
3750
3762
|
repointExternal: () => repointExternal,
|
|
3751
3763
|
requiredPolicies: () => requiredPolicies,
|
|
3752
3764
|
resolveAgentTopology: () => resolveAgentTopology,
|
|
@@ -3758,7 +3770,7 @@ __export(src_exports, {
|
|
|
3758
3770
|
resolveImport: () => resolveImport,
|
|
3759
3771
|
resolveInstalledPack: () => resolveInstalledPack,
|
|
3760
3772
|
resolveProjectExports: () => resolveProjectExports,
|
|
3761
|
-
resolveSignatures: () =>
|
|
3773
|
+
resolveSignatures: () => resolveSignatures,
|
|
3762
3774
|
resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
|
|
3763
3775
|
resolveSubsystemExports: () => resolveSubsystemExports,
|
|
3764
3776
|
resolveVariantGuidance: () => resolveVariantGuidance,
|
|
@@ -3794,9 +3806,15 @@ __export(src_exports, {
|
|
|
3794
3806
|
technologyTokens: () => technologyTokens,
|
|
3795
3807
|
toMarkdown: () => toMarkdown,
|
|
3796
3808
|
typeBindingOf: () => typeBindingOf,
|
|
3809
|
+
typeCanonicalTypes: () => typeCanonicalTypes,
|
|
3810
|
+
typeDialectFor: () => typeDialectFor,
|
|
3797
3811
|
typeGenericParameters: () => typeGenericParameters,
|
|
3812
|
+
typeIsMany: () => typeIsMany,
|
|
3798
3813
|
typeMatchesRef: () => typeMatchesRef,
|
|
3814
|
+
typeNamedRefs: () => typeNamedRefs,
|
|
3815
|
+
typeProblemIntProposal: () => typeProblemIntProposal,
|
|
3799
3816
|
typeSourceFiles: () => typeSourceFiles,
|
|
3817
|
+
typeSpellingFacts: () => typeSpellingFacts,
|
|
3800
3818
|
uninstallPack: () => uninstallPack,
|
|
3801
3819
|
updateMember: () => updateMember,
|
|
3802
3820
|
updateSpec: () => updateSpec,
|
|
@@ -3811,7 +3829,8 @@ __export(src_exports, {
|
|
|
3811
3829
|
writeReachDenials: () => writeReachDenials,
|
|
3812
3830
|
writeReachPermits: () => writeReachPermits,
|
|
3813
3831
|
writeRootGuideDelegator: () => writeRootGuideDelegator,
|
|
3814
|
-
writeYamlFile: () => writeYamlFile
|
|
3832
|
+
writeYamlFile: () => writeYamlFile,
|
|
3833
|
+
writtenTypeRefs: () => writtenTypeRefs
|
|
3815
3834
|
});
|
|
3816
3835
|
module.exports = __toCommonJS(src_exports);
|
|
3817
3836
|
|
|
@@ -4260,6 +4279,14 @@ var AgentBriefSchema = import_zod2.z.object({
|
|
|
4260
4279
|
instructions: import_zod2.z.string(),
|
|
4261
4280
|
/** Rendered variant guidance, also folded into instructions */
|
|
4262
4281
|
variantGuidance: import_zod2.z.string().optional(),
|
|
4282
|
+
/**
|
|
4283
|
+
* How the neutral types of the contracts this agent implements are spelled
|
|
4284
|
+
* in its language: the write table (type_dialect.mappingLines) of the dialect
|
|
4285
|
+
* for the language its implementations are written in, also folded into
|
|
4286
|
+
* instructions. Absent when no dialect is shipped for that language or the
|
|
4287
|
+
* agent implements nothing.
|
|
4288
|
+
*/
|
|
4289
|
+
typeMapping: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
4263
4290
|
/**
|
|
4264
4291
|
* Set only on a brief for a member's agent (an id qualified `<alias>::`): the
|
|
4265
4292
|
* member's directory relative to the root the brief was asked from. The
|
|
@@ -5272,14 +5299,16 @@ function locateScalar(tokens, path49) {
|
|
|
5272
5299
|
const base = Math.min(...region.map((t) => t.col));
|
|
5273
5300
|
const last = k === path49.length - 1;
|
|
5274
5301
|
let at;
|
|
5275
|
-
|
|
5302
|
+
const items = region.map((t, i) => ({ t, i })).filter(({ t }) => t.kind === "item" && t.col === base);
|
|
5303
|
+
if (items.length === 0) {
|
|
5276
5304
|
at = region.findIndex((t) => t.kind === "key" && t.col === base && t.name === segment);
|
|
5277
5305
|
if (at < 0) return `no block key "${segment}" at ${path49.slice(0, k).join(".") || "the document root"}`;
|
|
5278
5306
|
if (last) return region[at].valueStart !== void 0 ? region[at] : `"${segment}" holds no inline scalar`;
|
|
5279
5307
|
} else {
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5308
|
+
if (!/^\d+$/.test(segment)) return `"${segment}" is not a sequence index at ${path49.slice(0, k).join(".") || "the document root"}`;
|
|
5309
|
+
const index = Number(segment);
|
|
5310
|
+
if (index >= items.length) return `no block sequence item ${segment} at ${path49.slice(0, k).join(".")}`;
|
|
5311
|
+
at = items[index].i;
|
|
5283
5312
|
if (last) {
|
|
5284
5313
|
const value = region[at + 1];
|
|
5285
5314
|
return value && value.kind === "scalar" && value.line === region[at].line ? value : `item ${segment} holds no inline scalar`;
|
|
@@ -5751,7 +5780,7 @@ function registryOver(store, root) {
|
|
|
5751
5780
|
const at = typeof entry.at === "string" ? entry.at : void 0;
|
|
5752
5781
|
const covers = Array.isArray(entry.covers) ? entry.covers.filter((u) => typeof u === "string") : void 0;
|
|
5753
5782
|
const next = rekeyAnchor(rename, { spec: entry.spec, at, covers });
|
|
5754
|
-
const base = ["rules", "conformance", "carried", g, "findings", f];
|
|
5783
|
+
const base = ["rules", "conformance", "carried", String(g), "findings", String(f)];
|
|
5755
5784
|
const named2 = { code: String(entry.code), spec: entry.spec, at: at ?? "" };
|
|
5756
5785
|
const change = (path49, field, from, to) => {
|
|
5757
5786
|
if (from === to) return;
|
|
@@ -5760,7 +5789,7 @@ function registryOver(store, root) {
|
|
|
5760
5789
|
};
|
|
5761
5790
|
change(["spec"], "spec", entry.spec, next.spec);
|
|
5762
5791
|
if (at !== void 0) change(["at"], "at", at, next.at);
|
|
5763
|
-
(covers ?? []).forEach((unit, u) => change(["covers", u], "covers", unit, next.covers[u]));
|
|
5792
|
+
(covers ?? []).forEach((unit, u) => change(["covers", String(u)], "covers", unit, next.covers[u]));
|
|
5764
5793
|
});
|
|
5765
5794
|
});
|
|
5766
5795
|
store.rewriteScalars(edits, dryRun);
|
|
@@ -7087,11 +7116,10 @@ var GuaranteeSchema = import_zod8.z.string().min(1);
|
|
|
7087
7116
|
var MethodParamSchema = import_zod8.z.object({
|
|
7088
7117
|
name: import_zod8.z.string(),
|
|
7089
7118
|
/**
|
|
7090
|
-
* A
|
|
7091
|
-
*
|
|
7092
|
-
* `
|
|
7093
|
-
*
|
|
7094
|
-
* src/models/type-references.ts.
|
|
7119
|
+
* A type expression in the neutral type grammar (src/models/type-grammar.ts):
|
|
7120
|
+
* a primitive, a named type (`billing.Invoice`, `alias::name`), `list<T>`,
|
|
7121
|
+
* `set<T>`, `map<K, V>`, `T?`, a union of named types. Stored canonical; an
|
|
7122
|
+
* alias (`Invoice[]`, `Invoice | null`, `boolean`) is normalised on write.
|
|
7095
7123
|
*/
|
|
7096
7124
|
type: import_zod8.z.string(),
|
|
7097
7125
|
description: import_zod8.z.string().optional(),
|
|
@@ -7110,8 +7138,9 @@ var MethodSignatureSchema = import_zod8.z.object({
|
|
|
7110
7138
|
description: import_zod8.z.string(),
|
|
7111
7139
|
signature: import_zod8.z.string().optional(),
|
|
7112
7140
|
// e.g. "save(key: string, data: Buffer): Promise<void>"
|
|
7113
|
-
//
|
|
7114
|
-
//
|
|
7141
|
+
// A type expression in the neutral grammar, at the returns position — the only
|
|
7142
|
+
// one `async T` and `void` may stand in: "async void", "Invoice?". Stored
|
|
7143
|
+
// canonical; see src/models/type-grammar.ts.
|
|
7115
7144
|
returns: import_zod8.z.string().optional(),
|
|
7116
7145
|
/** Structured parameters (authoritative for type checking when present). */
|
|
7117
7146
|
params: import_zod8.z.array(MethodParamSchema).optional(),
|
|
@@ -7587,12 +7616,12 @@ function implementationSourceFiles(impl) {
|
|
|
7587
7616
|
for (const method of impl.methods ?? []) add2(method.sourcePath);
|
|
7588
7617
|
return files;
|
|
7589
7618
|
}
|
|
7590
|
-
var TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature"]);
|
|
7619
|
+
var TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature", "enum"]);
|
|
7591
7620
|
var TypeFieldSchema = import_zod8.z.object({
|
|
7592
7621
|
name: import_zod8.z.string(),
|
|
7593
|
-
// A
|
|
7594
|
-
// "billing.Invoice")
|
|
7595
|
-
//
|
|
7622
|
+
// A type expression in the neutral grammar (src/models/type-grammar.ts): a
|
|
7623
|
+
// primitive, a named type ("billing.Invoice"), list/set/map, `T?`, a union
|
|
7624
|
+
// of named types. Stored canonical.
|
|
7596
7625
|
type: import_zod8.z.string(),
|
|
7597
7626
|
description: import_zod8.z.string().optional(),
|
|
7598
7627
|
optional: import_zod8.z.boolean().default(false),
|
|
@@ -7646,9 +7675,13 @@ var InvariantSchema = import_zod8.z.object({
|
|
|
7646
7675
|
/** The property that must hold, stated precisely enough to test against. */
|
|
7647
7676
|
description: import_zod8.z.string().min(1)
|
|
7648
7677
|
});
|
|
7678
|
+
var EnumValueSchema = import_zod8.z.object({
|
|
7679
|
+
name: import_zod8.z.string().min(1),
|
|
7680
|
+
description: import_zod8.z.string().optional()
|
|
7681
|
+
});
|
|
7649
7682
|
var TypeSpecSchema = import_zod8.z.object({
|
|
7650
7683
|
kind: TypeKindSchema,
|
|
7651
|
-
// discriminator — entity | value-object | signature
|
|
7684
|
+
// discriminator — entity | value-object | signature | enum
|
|
7652
7685
|
id: SpecIdSchema,
|
|
7653
7686
|
name: import_zod8.z.string(),
|
|
7654
7687
|
description: import_zod8.z.string().optional(),
|
|
@@ -7711,6 +7744,20 @@ var TypeSpecSchema = import_zod8.z.object({
|
|
|
7711
7744
|
params: import_zod8.z.array(MethodParamSchema).optional(),
|
|
7712
7745
|
/** A signature's one output type; required on kind signature and only there (SIGNATURE_TYPE_MEMBERS). */
|
|
7713
7746
|
returns: import_zod8.z.string().optional(),
|
|
7747
|
+
/**
|
|
7748
|
+
* An enum's values, in declared order (the order is part of the design),
|
|
7749
|
+
* unique by nameKey; required and non-empty on kind enum and only there
|
|
7750
|
+
* (ENUM_MEMBERS).
|
|
7751
|
+
*/
|
|
7752
|
+
values: import_zod8.z.array(EnumValueSchema).optional(),
|
|
7753
|
+
/**
|
|
7754
|
+
* A named scalar's one primitive (string, int, float, bool, bytes, date,
|
|
7755
|
+
* datetime or duration), in place of fields: a value-object that is a
|
|
7756
|
+
* newtype or type alias in every language. Read as a type position (the
|
|
7757
|
+
* grammar's `holds` position); only on a value-object and never beside
|
|
7758
|
+
* fields (NAMED_SCALAR_MEMBERS).
|
|
7759
|
+
*/
|
|
7760
|
+
holds: import_zod8.z.string().optional(),
|
|
7714
7761
|
createdAt: import_zod8.z.string().datetime(),
|
|
7715
7762
|
updatedAt: import_zod8.z.string().datetime()
|
|
7716
7763
|
});
|
|
@@ -7753,7 +7800,11 @@ var SurfaceTypeDefSchema = import_zod8.z.object({
|
|
|
7753
7800
|
optional: import_zod8.z.boolean().optional()
|
|
7754
7801
|
})).optional(),
|
|
7755
7802
|
/** A signature's one output type; only on kind signature. */
|
|
7756
|
-
returns: import_zod8.z.string().optional()
|
|
7803
|
+
returns: import_zod8.z.string().optional(),
|
|
7804
|
+
/** An enum's values in declared order; only on kind enum. */
|
|
7805
|
+
values: import_zod8.z.array(EnumValueSchema).optional(),
|
|
7806
|
+
/** A named scalar's one primitive, in place of fields; only on a value-object that declares it. */
|
|
7807
|
+
holds: import_zod8.z.string().optional()
|
|
7757
7808
|
});
|
|
7758
7809
|
var SurfaceTypeExportSchema = import_zod8.z.object({
|
|
7759
7810
|
/** The type's public name in the producer's export table. */
|
|
@@ -7862,80 +7913,767 @@ var GroupSpecSchema = import_zod8.z.object({
|
|
|
7862
7913
|
updatedAt: import_zod8.z.string().datetime()
|
|
7863
7914
|
});
|
|
7864
7915
|
|
|
7865
|
-
// src/models/type-
|
|
7866
|
-
var
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
"boolean",
|
|
7871
|
-
"
|
|
7872
|
-
"
|
|
7873
|
-
"
|
|
7874
|
-
"int",
|
|
7875
|
-
"
|
|
7876
|
-
"
|
|
7877
|
-
"
|
|
7878
|
-
"
|
|
7879
|
-
"
|
|
7880
|
-
"
|
|
7881
|
-
"
|
|
7882
|
-
"
|
|
7883
|
-
"
|
|
7884
|
-
"
|
|
7885
|
-
"
|
|
7886
|
-
"
|
|
7887
|
-
"
|
|
7888
|
-
"
|
|
7889
|
-
"
|
|
7890
|
-
"
|
|
7891
|
-
"
|
|
7916
|
+
// src/models/type-grammar.ts
|
|
7917
|
+
var PRIMITIVE_TYPES = ["string", "int", "float", "bool", "bytes", "date", "datetime", "duration", "void", "any"];
|
|
7918
|
+
var PRIMITIVES = new Set(PRIMITIVE_TYPES);
|
|
7919
|
+
var HOLDABLE_PRIMITIVES = PRIMITIVE_TYPES.filter((p) => p !== "void" && p !== "any");
|
|
7920
|
+
var PRIMITIVE_ALIASES = /* @__PURE__ */ new Map([
|
|
7921
|
+
["boolean", "bool"],
|
|
7922
|
+
["integer", "int"],
|
|
7923
|
+
["long", "int"],
|
|
7924
|
+
["i8", "int"],
|
|
7925
|
+
["i16", "int"],
|
|
7926
|
+
["i32", "int"],
|
|
7927
|
+
["i64", "int"],
|
|
7928
|
+
["i128", "int"],
|
|
7929
|
+
["isize", "int"],
|
|
7930
|
+
["u8", "int"],
|
|
7931
|
+
["u16", "int"],
|
|
7932
|
+
["u32", "int"],
|
|
7933
|
+
["u64", "int"],
|
|
7934
|
+
["u128", "int"],
|
|
7935
|
+
["usize", "int"],
|
|
7936
|
+
["double", "float"],
|
|
7937
|
+
["f32", "float"],
|
|
7938
|
+
["f64", "float"],
|
|
7939
|
+
["Buffer", "bytes"],
|
|
7940
|
+
["Uint8Array", "bytes"],
|
|
7941
|
+
["Date", "datetime"],
|
|
7942
|
+
["timestamp", "datetime"],
|
|
7943
|
+
["object", "any"],
|
|
7944
|
+
["unknown", "any"],
|
|
7945
|
+
["json", "any"],
|
|
7946
|
+
["Json", "any"],
|
|
7947
|
+
["str", "string"]
|
|
7948
|
+
]);
|
|
7949
|
+
var GENERIC_ALIASES = /* @__PURE__ */ new Map([
|
|
7950
|
+
["list", { form: "list", arity: 1 }],
|
|
7951
|
+
["Array", { form: "list", arity: 1 }],
|
|
7952
|
+
["ReadonlyArray", { form: "list", arity: 1 }],
|
|
7953
|
+
["List", { form: "list", arity: 1 }],
|
|
7954
|
+
["vec", { form: "list", arity: 1 }],
|
|
7955
|
+
["vector", { form: "list", arity: 1 }],
|
|
7956
|
+
["set", { form: "set", arity: 1 }],
|
|
7957
|
+
["Set", { form: "set", arity: 1 }],
|
|
7958
|
+
["ReadonlySet", { form: "set", arity: 1 }],
|
|
7959
|
+
["map", { form: "map", arity: 2 }],
|
|
7960
|
+
["Map", { form: "map", arity: 2 }],
|
|
7961
|
+
["Record", { form: "map", arity: 2 }],
|
|
7962
|
+
["ReadonlyMap", { form: "map", arity: 2 }],
|
|
7963
|
+
["dict", { form: "map", arity: 2 }],
|
|
7964
|
+
["dictionary", { form: "map", arity: 2 }],
|
|
7965
|
+
["HashMap", { form: "map", arity: 2 }],
|
|
7966
|
+
["Option", { form: "optional", arity: 1 }],
|
|
7967
|
+
["Optional", { form: "optional", arity: 1 }],
|
|
7968
|
+
["Promise", { form: "async", arity: 1 }]
|
|
7969
|
+
]);
|
|
7970
|
+
var NOT_NEUTRAL = /* @__PURE__ */ new Map([
|
|
7971
|
+
["uuid", "a named value-object holding a string (e.g. order_id)"],
|
|
7972
|
+
["decimal", "a named value-object (e.g. money), or float"],
|
|
7973
|
+
["char", "string"],
|
|
7974
|
+
["byte", "int, or bytes for binary data"],
|
|
7975
|
+
["time", "datetime for an instant, or duration for an elapsed time"],
|
|
7976
|
+
["tuple", "a named value-object"],
|
|
7977
|
+
["result", "the success type as the returns (failures as findings or throws), or a named value-object"],
|
|
7978
|
+
["error", "a named value-object"],
|
|
7979
|
+
["never", "void"],
|
|
7980
|
+
["box", "the inner type (ownership is an implementation detail)"],
|
|
7981
|
+
["arc", "the inner type (ownership is an implementation detail)"],
|
|
7982
|
+
["rc", "the inner type (ownership is an implementation detail)"],
|
|
7983
|
+
["ref", "the inner type (ownership is an implementation detail)"],
|
|
7984
|
+
["cell", "the inner type (ownership is an implementation detail)"],
|
|
7985
|
+
["refcell", "the inner type (ownership is an implementation detail)"],
|
|
7986
|
+
["mutex", "the inner type (synchronisation is an implementation detail)"],
|
|
7987
|
+
["rwlock", "the inner type (synchronisation is an implementation detail)"],
|
|
7988
|
+
["std", "a named type"],
|
|
7989
|
+
["mcpserver", "a named type"]
|
|
7990
|
+
]);
|
|
7991
|
+
var UTILITY_TYPES = /* @__PURE__ */ new Set([
|
|
7992
|
+
"Partial",
|
|
7993
|
+
"Required",
|
|
7994
|
+
"Readonly",
|
|
7995
|
+
"Pick",
|
|
7996
|
+
"Omit",
|
|
7997
|
+
"Exclude",
|
|
7998
|
+
"Extract",
|
|
7999
|
+
"NonNullable",
|
|
8000
|
+
"ReturnType",
|
|
8001
|
+
"Parameters",
|
|
8002
|
+
"InstanceType",
|
|
8003
|
+
"Awaited",
|
|
8004
|
+
"ConstructorParameters",
|
|
8005
|
+
"ThisType",
|
|
8006
|
+
"Uppercase",
|
|
8007
|
+
"Lowercase"
|
|
8008
|
+
]);
|
|
8009
|
+
var NONES = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
8010
|
+
var LOWER_PRIMITIVE = new Map([
|
|
8011
|
+
...PRIMITIVE_TYPES.map((p) => [p, p]),
|
|
8012
|
+
...[...PRIMITIVE_ALIASES].map(([k, v]) => [k.toLowerCase(), v])
|
|
8013
|
+
]);
|
|
8014
|
+
var LOWER_GENERIC = new Map([...GENERIC_ALIASES].map(([k, v]) => [k.toLowerCase(), v]));
|
|
8015
|
+
function isTypeVocabulary(name) {
|
|
8016
|
+
const lower = name.toLowerCase();
|
|
8017
|
+
return LOWER_PRIMITIVE.has(lower) || LOWER_GENERIC.has(lower) || NOT_NEUTRAL.has(lower) || NONES.has(lower) || lower === "true" || lower === "false" || lower === "number";
|
|
8018
|
+
}
|
|
8019
|
+
function primitiveOf(name) {
|
|
8020
|
+
if (PRIMITIVES.has(name)) return name;
|
|
8021
|
+
const exact = PRIMITIVE_ALIASES.get(name);
|
|
8022
|
+
if (exact) return exact;
|
|
8023
|
+
return LOWER_PRIMITIVE.get(name.toLowerCase());
|
|
8024
|
+
}
|
|
8025
|
+
function genericOf(name) {
|
|
8026
|
+
return GENERIC_ALIASES.get(name) ?? LOWER_GENERIC.get(name.toLowerCase());
|
|
8027
|
+
}
|
|
8028
|
+
var TypeSyntaxError = class extends Error {
|
|
8029
|
+
};
|
|
8030
|
+
var PUNCTUATION = ["...", "::", "=>", "<", ">", ",", "|", "?", "(", ")", "[", "]", "{", "}", ":", "&", ";", "."];
|
|
8031
|
+
function tokenize2(text3) {
|
|
8032
|
+
const out = [];
|
|
8033
|
+
let i = 0;
|
|
8034
|
+
while (i < text3.length) {
|
|
8035
|
+
const c = text3[i];
|
|
8036
|
+
if (/\s/.test(c)) {
|
|
8037
|
+
i++;
|
|
8038
|
+
continue;
|
|
8039
|
+
}
|
|
8040
|
+
if (/[A-Za-z_$]/.test(c)) {
|
|
8041
|
+
let j = i + 1;
|
|
8042
|
+
while (j < text3.length && /[A-Za-z0-9_$-]/.test(text3[j])) j++;
|
|
8043
|
+
while (text3[j - 1] === "-") j--;
|
|
8044
|
+
out.push({ t: "id", v: text3.slice(i, j) });
|
|
8045
|
+
i = j;
|
|
8046
|
+
continue;
|
|
8047
|
+
}
|
|
8048
|
+
if (/[0-9]/.test(c)) {
|
|
8049
|
+
let j = i + 1;
|
|
8050
|
+
while (j < text3.length && /[0-9.]/.test(text3[j])) j++;
|
|
8051
|
+
out.push({ t: "num", v: text3.slice(i, j) });
|
|
8052
|
+
i = j;
|
|
8053
|
+
continue;
|
|
8054
|
+
}
|
|
8055
|
+
if (c === "'" || c === '"' || c === "`") {
|
|
8056
|
+
let j = i + 1;
|
|
8057
|
+
while (j < text3.length && text3[j] !== c) j += text3[j] === "\\" ? 2 : 1;
|
|
8058
|
+
if (j >= text3.length) throw new TypeSyntaxError(`an unterminated string literal at "${text3.slice(i)}"`);
|
|
8059
|
+
out.push({ t: "str", v: text3.slice(i, j + 1) });
|
|
8060
|
+
i = j + 1;
|
|
8061
|
+
continue;
|
|
8062
|
+
}
|
|
8063
|
+
const punct = PUNCTUATION.find((p) => text3.startsWith(p, i));
|
|
8064
|
+
if (!punct) throw new TypeSyntaxError(`"${c}" is not part of any type spelling`);
|
|
8065
|
+
out.push({ t: "p", v: punct });
|
|
8066
|
+
i += punct.length;
|
|
8067
|
+
}
|
|
8068
|
+
return out;
|
|
8069
|
+
}
|
|
8070
|
+
var RawParser = class {
|
|
8071
|
+
constructor(tokens) {
|
|
8072
|
+
this.tokens = tokens;
|
|
8073
|
+
this.at = 0;
|
|
8074
|
+
}
|
|
8075
|
+
/** type-position: an optional `async` prefix, one type, and nothing after it. */
|
|
8076
|
+
position() {
|
|
8077
|
+
if (this.tokens.length === 0) throw new TypeSyntaxError("the position is empty");
|
|
8078
|
+
const node = this.isAsyncPrefix() ? (this.at++, { k: "async", inner: this.type() }) : this.type();
|
|
8079
|
+
if (this.at < this.tokens.length) throw new TypeSyntaxError(`"${this.rest()}" is left over after the type`);
|
|
8080
|
+
return node;
|
|
8081
|
+
}
|
|
8082
|
+
isAsyncPrefix() {
|
|
8083
|
+
const first = this.tokens[0];
|
|
8084
|
+
const next = this.tokens[1];
|
|
8085
|
+
if (!first || first.t !== "id" || first.v !== "async" || !next) return false;
|
|
8086
|
+
return next.t !== "p" || ["(", "{", "[", "::"].includes(next.v);
|
|
8087
|
+
}
|
|
8088
|
+
rest() {
|
|
8089
|
+
return this.tokens.slice(this.at).map((t) => t.v).join(" ");
|
|
8090
|
+
}
|
|
8091
|
+
peek(offset = 0) {
|
|
8092
|
+
return this.tokens[this.at + offset];
|
|
8093
|
+
}
|
|
8094
|
+
isP(v, offset = 0) {
|
|
8095
|
+
const t = this.peek(offset);
|
|
8096
|
+
return !!t && t.t === "p" && t.v === v;
|
|
8097
|
+
}
|
|
8098
|
+
expect(v) {
|
|
8099
|
+
if (!this.isP(v)) {
|
|
8100
|
+
const got = this.peek();
|
|
8101
|
+
throw new TypeSyntaxError(got ? `expected "${v}" but found "${got.v}"` : `expected "${v}" but the text ended`);
|
|
8102
|
+
}
|
|
8103
|
+
this.at++;
|
|
8104
|
+
}
|
|
8105
|
+
type() {
|
|
8106
|
+
if (this.isP("|")) this.at++;
|
|
8107
|
+
const members = [this.intersection()];
|
|
8108
|
+
while (this.isP("|")) {
|
|
8109
|
+
this.at++;
|
|
8110
|
+
members.push(this.intersection());
|
|
8111
|
+
}
|
|
8112
|
+
return members.length === 1 ? members[0] : { k: "union", members };
|
|
8113
|
+
}
|
|
8114
|
+
intersection() {
|
|
8115
|
+
const members = [this.postfix()];
|
|
8116
|
+
while (this.isP("&")) {
|
|
8117
|
+
this.at++;
|
|
8118
|
+
members.push(this.postfix());
|
|
8119
|
+
}
|
|
8120
|
+
return members.length === 1 ? members[0] : { k: "intersection", members };
|
|
8121
|
+
}
|
|
8122
|
+
postfix() {
|
|
8123
|
+
let node = this.primary();
|
|
8124
|
+
for (; ; ) {
|
|
8125
|
+
if (this.isP("[") && this.isP("]", 1)) {
|
|
8126
|
+
this.at += 2;
|
|
8127
|
+
node = { k: "array", elem: node };
|
|
8128
|
+
} else if (this.isP("?")) {
|
|
8129
|
+
this.at++;
|
|
8130
|
+
node = { k: "opt", inner: node };
|
|
8131
|
+
} else {
|
|
8132
|
+
return node;
|
|
8133
|
+
}
|
|
8134
|
+
}
|
|
8135
|
+
}
|
|
8136
|
+
primary() {
|
|
8137
|
+
const tok = this.peek();
|
|
8138
|
+
if (!tok) throw new TypeSyntaxError("a type was expected but the text ended");
|
|
8139
|
+
if (tok.t === "str" || tok.t === "num") {
|
|
8140
|
+
this.at++;
|
|
8141
|
+
return { k: "literal", text: tok.v };
|
|
8142
|
+
}
|
|
8143
|
+
if (tok.t === "id" && (tok.v === "keyof" || tok.v === "typeof" || tok.v === "unique") && this.peek(1)?.t === "id") {
|
|
8144
|
+
this.at++;
|
|
8145
|
+
return { k: "operator", op: tok.v, inner: this.postfix() };
|
|
8146
|
+
}
|
|
8147
|
+
const next = this.peek(1);
|
|
8148
|
+
if (tok.t === "id" && tok.v === "readonly" && next && (next.t === "id" || next.t === "p" && (next.v === "(" || next.v === "["))) {
|
|
8149
|
+
this.at++;
|
|
8150
|
+
return this.postfix();
|
|
8151
|
+
}
|
|
8152
|
+
if (tok.t === "id" || tok.t === "p" && tok.v === "::") return this.named();
|
|
8153
|
+
if (tok.t === "p" && tok.v === "(") return this.parenOrFunction();
|
|
8154
|
+
if (tok.t === "p" && tok.v === "{") return this.objectShape();
|
|
8155
|
+
if (tok.t === "p" && tok.v === "[") return this.tuple();
|
|
8156
|
+
throw new TypeSyntaxError(`"${tok.v}" cannot start a type`);
|
|
8157
|
+
}
|
|
8158
|
+
ident() {
|
|
8159
|
+
const tok = this.peek();
|
|
8160
|
+
if (!tok || tok.t !== "id") throw new TypeSyntaxError(tok ? `expected a name but found "${tok.v}"` : "expected a name but the text ended");
|
|
8161
|
+
this.at++;
|
|
8162
|
+
return tok.v;
|
|
8163
|
+
}
|
|
8164
|
+
named() {
|
|
8165
|
+
let name = "";
|
|
8166
|
+
if (this.isP("::")) {
|
|
8167
|
+
this.at++;
|
|
8168
|
+
name = "::";
|
|
8169
|
+
}
|
|
8170
|
+
name += this.ident();
|
|
8171
|
+
while (this.isP("::") || this.isP(".")) {
|
|
8172
|
+
const sep14 = this.peek().v;
|
|
8173
|
+
this.at++;
|
|
8174
|
+
name += sep14 + this.ident();
|
|
8175
|
+
}
|
|
8176
|
+
if (!this.isP("<")) return { k: "name", name };
|
|
8177
|
+
this.at++;
|
|
8178
|
+
const args = [this.type()];
|
|
8179
|
+
while (this.isP(",")) {
|
|
8180
|
+
this.at++;
|
|
8181
|
+
args.push(this.type());
|
|
8182
|
+
}
|
|
8183
|
+
this.expect(">");
|
|
8184
|
+
return { k: "name", name, args };
|
|
8185
|
+
}
|
|
8186
|
+
/** The index of the `)` closing the `(` at the cursor, or -1. */
|
|
8187
|
+
closingParen() {
|
|
8188
|
+
let depth = 0;
|
|
8189
|
+
for (let i = this.at; i < this.tokens.length; i++) {
|
|
8190
|
+
const t = this.tokens[i];
|
|
8191
|
+
if (t.t !== "p") continue;
|
|
8192
|
+
if (t.v === "(") depth++;
|
|
8193
|
+
else if (t.v === ")" && --depth === 0) return i;
|
|
8194
|
+
}
|
|
8195
|
+
return -1;
|
|
8196
|
+
}
|
|
8197
|
+
parenOrFunction() {
|
|
8198
|
+
const close2 = this.closingParen();
|
|
8199
|
+
const after = close2 === -1 ? void 0 : this.tokens[close2 + 1];
|
|
8200
|
+
if (!after || after.t !== "p" || after.v !== "=>") {
|
|
8201
|
+
this.expect("(");
|
|
8202
|
+
const inner2 = this.type();
|
|
8203
|
+
this.expect(")");
|
|
8204
|
+
return { k: "paren", inner: inner2 };
|
|
8205
|
+
}
|
|
8206
|
+
this.expect("(");
|
|
8207
|
+
const params = [];
|
|
8208
|
+
while (!this.isP(")")) {
|
|
8209
|
+
if (this.isP("...")) this.at++;
|
|
8210
|
+
this.ident();
|
|
8211
|
+
if (this.isP("?")) this.at++;
|
|
8212
|
+
if (this.isP(":")) {
|
|
8213
|
+
this.at++;
|
|
8214
|
+
params.push(this.type());
|
|
8215
|
+
}
|
|
8216
|
+
if (!this.isP(",")) break;
|
|
8217
|
+
this.at++;
|
|
8218
|
+
}
|
|
8219
|
+
this.expect(")");
|
|
8220
|
+
this.expect("=>");
|
|
8221
|
+
return { k: "function", params, ret: this.type() };
|
|
8222
|
+
}
|
|
8223
|
+
objectShape() {
|
|
8224
|
+
this.expect("{");
|
|
8225
|
+
const members = [];
|
|
8226
|
+
while (!this.isP("}")) {
|
|
8227
|
+
if (this.isP("[")) {
|
|
8228
|
+
this.at++;
|
|
8229
|
+
this.ident();
|
|
8230
|
+
this.expect(":");
|
|
8231
|
+
members.push(this.type());
|
|
8232
|
+
this.expect("]");
|
|
8233
|
+
} else {
|
|
8234
|
+
if (this.peek()?.t === "id" && this.peek().v === "readonly" && this.peek(1)?.t === "id") this.at++;
|
|
8235
|
+
const key = this.peek();
|
|
8236
|
+
if (!key || key.t !== "id" && key.t !== "str" && key.t !== "num") throw new TypeSyntaxError("an inline object member has no name");
|
|
8237
|
+
this.at++;
|
|
8238
|
+
if (this.isP("?")) this.at++;
|
|
8239
|
+
if (this.isP("(")) {
|
|
8240
|
+
members.push(this.parenOrFunctionMember());
|
|
8241
|
+
this.skipSeparator();
|
|
8242
|
+
continue;
|
|
8243
|
+
}
|
|
8244
|
+
}
|
|
8245
|
+
this.expect(":");
|
|
8246
|
+
members.push(this.type());
|
|
8247
|
+
this.skipSeparator();
|
|
8248
|
+
}
|
|
8249
|
+
this.expect("}");
|
|
8250
|
+
return { k: "object", members };
|
|
8251
|
+
}
|
|
8252
|
+
/** A method member of an inline object: (params): returns. */
|
|
8253
|
+
parenOrFunctionMember() {
|
|
8254
|
+
this.expect("(");
|
|
8255
|
+
const params = [];
|
|
8256
|
+
while (!this.isP(")")) {
|
|
8257
|
+
if (this.isP("...")) this.at++;
|
|
8258
|
+
this.ident();
|
|
8259
|
+
if (this.isP("?")) this.at++;
|
|
8260
|
+
if (this.isP(":")) {
|
|
8261
|
+
this.at++;
|
|
8262
|
+
params.push(this.type());
|
|
8263
|
+
}
|
|
8264
|
+
if (!this.isP(",")) break;
|
|
8265
|
+
this.at++;
|
|
8266
|
+
}
|
|
8267
|
+
this.expect(")");
|
|
8268
|
+
this.expect(":");
|
|
8269
|
+
return { k: "function", params, ret: this.type() };
|
|
8270
|
+
}
|
|
8271
|
+
skipSeparator() {
|
|
8272
|
+
if (this.isP(";") || this.isP(",")) this.at++;
|
|
8273
|
+
}
|
|
8274
|
+
tuple() {
|
|
8275
|
+
this.expect("[");
|
|
8276
|
+
const elems = [];
|
|
8277
|
+
while (!this.isP("]")) {
|
|
8278
|
+
elems.push(this.type());
|
|
8279
|
+
if (!this.isP(",")) break;
|
|
8280
|
+
this.at++;
|
|
8281
|
+
}
|
|
8282
|
+
this.expect("]");
|
|
8283
|
+
return { k: "tuple", elems };
|
|
8284
|
+
}
|
|
8285
|
+
};
|
|
8286
|
+
function readRaw(text3) {
|
|
8287
|
+
return new RawParser(tokenize2(text3)).position();
|
|
8288
|
+
}
|
|
8289
|
+
var TypeProblemError = class extends Error {
|
|
8290
|
+
constructor(code, detail, replacement) {
|
|
8291
|
+
super(detail);
|
|
8292
|
+
this.code = code;
|
|
8293
|
+
this.detail = detail;
|
|
8294
|
+
this.replacement = replacement;
|
|
8295
|
+
}
|
|
8296
|
+
};
|
|
8297
|
+
var RETURNS_POSITIONS = /* @__PURE__ */ new Set(["returns", "type-method-returns", "signature-returns"]);
|
|
8298
|
+
var LOOSE_NUMBER = "number";
|
|
8299
|
+
function primitive(name) {
|
|
8300
|
+
return { form: "primitive", name, args: [] };
|
|
8301
|
+
}
|
|
8302
|
+
function optionalOf(inner2) {
|
|
8303
|
+
if (inner2.form === "primitive" && inner2.name === "any") return inner2;
|
|
8304
|
+
if (inner2.form === "optional") throw new TypeProblemError("TYPE_POSITION_INVALID", "a type is made optional twice (T??)", "T?");
|
|
8305
|
+
if (inner2.form === "primitive" && inner2.name === "void") throw new TypeProblemError("TYPE_POSITION_INVALID", "void cannot be optional (void?)", "void");
|
|
8306
|
+
return { form: "optional", args: [inner2] };
|
|
8307
|
+
}
|
|
8308
|
+
function inner(ctx) {
|
|
8309
|
+
return { ...ctx, top: false, voidAllowed: false, omittable: false };
|
|
8310
|
+
}
|
|
8311
|
+
function normalise(node, ctx, notes) {
|
|
8312
|
+
switch (node.k) {
|
|
8313
|
+
case "paren":
|
|
8314
|
+
return normalise(node.inner, ctx, notes);
|
|
8315
|
+
case "async":
|
|
8316
|
+
return asyncOf(node.inner, ctx, notes, "async");
|
|
8317
|
+
case "array":
|
|
8318
|
+
return { form: "list", args: [normalise(node.elem, inner(ctx), notes)] };
|
|
8319
|
+
case "opt":
|
|
8320
|
+
return optionalOf(normalise(node.inner, inner(ctx), notes));
|
|
8321
|
+
case "union":
|
|
8322
|
+
return unionOf(node.members, ctx, notes);
|
|
8323
|
+
case "name":
|
|
8324
|
+
return node.args === void 0 ? bareName(node.name, ctx, notes) : appliedName(node.name, node.args, ctx, notes);
|
|
8325
|
+
case "literal":
|
|
8326
|
+
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");
|
|
8327
|
+
case "object":
|
|
8328
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline object shape is not in the grammar", "a named value-object");
|
|
8329
|
+
case "function":
|
|
8330
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline function type is not in the grammar", "a signature type");
|
|
8331
|
+
case "intersection":
|
|
8332
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an intersection (A & B) is not in the grammar", "a named type");
|
|
8333
|
+
case "tuple":
|
|
8334
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a tuple is not in the grammar", "a named value-object");
|
|
8335
|
+
case "operator":
|
|
8336
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${node.op}" is TypeScript's type algebra, not in the grammar`, "a named type");
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
function asyncOf(innerNode, ctx, notes, spelled) {
|
|
8340
|
+
if (!ctx.top || !RETURNS_POSITIONS.has(ctx.position)) {
|
|
8341
|
+
throw new TypeProblemError("TYPE_POSITION_INVALID", `${spelled} may stand only at the top of a returns, not in a ${ctx.position}`);
|
|
8342
|
+
}
|
|
8343
|
+
const read2 = normalise(innerNode, { ...inner(ctx), voidAllowed: true }, notes);
|
|
8344
|
+
return { form: "async", args: [read2] };
|
|
8345
|
+
}
|
|
8346
|
+
function bareName(name, ctx, notes) {
|
|
8347
|
+
const lower = name.toLowerCase();
|
|
8348
|
+
if (NONES.has(name)) {
|
|
8349
|
+
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");
|
|
8350
|
+
}
|
|
8351
|
+
if (lower === "true" || lower === "false") {
|
|
8352
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `${name} is a literal value, not a type`, "bool, or an enum type naming the values");
|
|
8353
|
+
}
|
|
8354
|
+
if (name === "number" || lower === "number") {
|
|
8355
|
+
if (ctx.looseNumber) return primitive(LOOSE_NUMBER);
|
|
8356
|
+
notes.notNeutral ??= { detail: '"number" does not say whether it holds an integer \u2014 int or float?', replacement: "int or float" };
|
|
8357
|
+
return primitive("float");
|
|
8358
|
+
}
|
|
8359
|
+
const prim = primitiveOf(name);
|
|
8360
|
+
if (prim !== void 0) {
|
|
8361
|
+
if (prim === "void" && !ctx.voidAllowed) {
|
|
8362
|
+
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"}`);
|
|
8363
|
+
}
|
|
8364
|
+
return primitive(prim);
|
|
8365
|
+
}
|
|
8366
|
+
if (genericOf(name) !== void 0) {
|
|
8367
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" needs its type arguments`, `${genericOf(name)?.form ?? "list"}<...>`);
|
|
8368
|
+
}
|
|
8369
|
+
const legacy = NOT_NEUTRAL.get(lower);
|
|
8370
|
+
if (legacy !== void 0) {
|
|
8371
|
+
notes.notNeutral ??= { detail: `"${name}" has no neutral meaning`, replacement: legacy };
|
|
8372
|
+
return primitive("any");
|
|
8373
|
+
}
|
|
8374
|
+
return { form: "named", name, args: [] };
|
|
8375
|
+
}
|
|
8376
|
+
function appliedName(name, args, ctx, notes) {
|
|
8377
|
+
const alias = genericOf(name);
|
|
8378
|
+
if (alias !== void 0) {
|
|
8379
|
+
if (args.length !== alias.arity) {
|
|
8380
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes ${alias.arity} type argument${alias.arity === 1 ? "" : "s"}, ${args.length} given`);
|
|
8381
|
+
}
|
|
8382
|
+
if (alias.form === "async") return asyncOf(args[0], ctx, notes, `${name}<...>`);
|
|
8383
|
+
if (alias.form === "optional") return optionalOf(normalise(args[0], inner(ctx), notes));
|
|
8384
|
+
const read2 = args.map((a) => normalise(a, inner(ctx), notes));
|
|
8385
|
+
if (alias.form === "map") assertMapKey(read2[0], args[0]);
|
|
8386
|
+
return { form: alias.form, args: read2 };
|
|
8387
|
+
}
|
|
8388
|
+
if (UTILITY_TYPES.has(name)) {
|
|
8389
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${name}<...>" is a TypeScript utility type, not in the grammar`, "a named type");
|
|
8390
|
+
}
|
|
8391
|
+
if (primitiveOf(name) !== void 0 || NONES.has(name)) {
|
|
8392
|
+
throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes no type arguments`);
|
|
8393
|
+
}
|
|
8394
|
+
const legacy = NOT_NEUTRAL.get(name.toLowerCase());
|
|
8395
|
+
if (legacy !== void 0) {
|
|
8396
|
+
args.forEach((a) => normalise(a, { ...inner(ctx), voidAllowed: true }, notes));
|
|
8397
|
+
notes.notNeutral ??= { detail: `"${name}<...>" has no neutral meaning`, replacement: legacy };
|
|
8398
|
+
return primitive("any");
|
|
8399
|
+
}
|
|
8400
|
+
return { form: "applied", name, args: args.map((a) => normalise(a, inner(ctx), notes)) };
|
|
8401
|
+
}
|
|
8402
|
+
function assertHoldable(expression) {
|
|
8403
|
+
if (expression.form === "primitive" && HOLDABLE_PRIMITIVES.includes(expression.name ?? "")) return;
|
|
8404
|
+
throw new TypeProblemError(
|
|
8405
|
+
"TYPE_POSITION_INVALID",
|
|
8406
|
+
`a named scalar holds one primitive (${HOLDABLE_PRIMITIVES.join(", ")}), not ${canonicalTypeText(expression)}`,
|
|
8407
|
+
"one of those primitives, or fields for a value-object that holds more than one value"
|
|
8408
|
+
);
|
|
8409
|
+
}
|
|
8410
|
+
function assertMapKey(key, written) {
|
|
8411
|
+
if (key.form === "named") return;
|
|
8412
|
+
if (key.form === "primitive" && (key.name === "string" || key.name === "int" || key.name === LOOSE_NUMBER)) return;
|
|
8413
|
+
if (key.form === "primitive" && key.name === "float" && written.k === "name" && written.name.toLowerCase() === "number") return;
|
|
8414
|
+
throw new TypeProblemError("TYPE_POSITION_INVALID", "a map key must be string, int or an enum", "map<string, V>");
|
|
8415
|
+
}
|
|
8416
|
+
function unionOf(members, ctx, notes) {
|
|
8417
|
+
const nones = members.filter((m) => m.k === "name" && m.args === void 0 && NONES.has(m.name));
|
|
8418
|
+
const rest = members.filter((m) => !(m.k === "name" && m.args === void 0 && NONES.has(m.name)));
|
|
8419
|
+
if (rest.length === 0) throw new TypeProblemError("TYPE_EXPRESSION_INVALID", "a union of nones names no type");
|
|
8420
|
+
if (rest.some((m) => m.k === "literal" || m.k === "name" && m.args === void 0 && /^(true|false)$/i.test(m.name))) {
|
|
8421
|
+
throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a union of literal values is not in the grammar", "an enum type naming the values");
|
|
8422
|
+
}
|
|
8423
|
+
const memberCtx = inner(ctx);
|
|
8424
|
+
let hasNone = nones.length > 0;
|
|
8425
|
+
const read2 = rest.map((m) => {
|
|
8426
|
+
const e = normalise(m, memberCtx, notes);
|
|
8427
|
+
if (e.form !== "optional") return e;
|
|
8428
|
+
hasNone = true;
|
|
8429
|
+
return e.args[0];
|
|
8430
|
+
});
|
|
8431
|
+
let base;
|
|
8432
|
+
if (read2.length === 1) {
|
|
8433
|
+
base = read2[0];
|
|
8434
|
+
} else {
|
|
8435
|
+
const loose = read2.find((e) => e.form !== "named" && e.form !== "applied");
|
|
8436
|
+
if (loose) {
|
|
8437
|
+
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");
|
|
8438
|
+
}
|
|
8439
|
+
base = { form: "union", args: read2 };
|
|
8440
|
+
}
|
|
8441
|
+
if (!hasNone) return base;
|
|
8442
|
+
const onlyUndefined = nones.length > 0 && nones.every((n) => n.name === "undefined") && read2.length === rest.length && !rest.some((m) => m.k === "opt");
|
|
8443
|
+
if (ctx.omittable && ctx.top && onlyUndefined) return base;
|
|
8444
|
+
return optionalOf(base);
|
|
8445
|
+
}
|
|
8446
|
+
function canonicalTypeText(expr) {
|
|
8447
|
+
switch (expr.form) {
|
|
8448
|
+
case "primitive":
|
|
8449
|
+
case "named":
|
|
8450
|
+
return expr.name ?? "";
|
|
8451
|
+
case "list":
|
|
8452
|
+
case "set":
|
|
8453
|
+
return `${expr.form}<${canonicalTypeText(expr.args[0])}>`;
|
|
8454
|
+
case "map":
|
|
8455
|
+
return `map<${canonicalTypeText(expr.args[0])}, ${canonicalTypeText(expr.args[1])}>`;
|
|
8456
|
+
case "optional": {
|
|
8457
|
+
const innerText = canonicalTypeText(expr.args[0]);
|
|
8458
|
+
return expr.args[0].form === "union" ? `(${innerText})?` : `${innerText}?`;
|
|
8459
|
+
}
|
|
8460
|
+
case "union":
|
|
8461
|
+
return expr.args.map(canonicalTypeText).join(" | ");
|
|
8462
|
+
case "async":
|
|
8463
|
+
return `async ${canonicalTypeText(expr.args[0])}`;
|
|
8464
|
+
case "applied":
|
|
8465
|
+
return `${expr.name}<${expr.args.map(canonicalTypeText).join(", ")}>`;
|
|
8466
|
+
}
|
|
8467
|
+
}
|
|
8468
|
+
function typeNamedRefs(expr) {
|
|
8469
|
+
if (expr.form === "named") return [expr.name];
|
|
8470
|
+
const own = expr.form === "applied" ? [expr.name] : [];
|
|
8471
|
+
return [...own, ...expr.args.flatMap(typeNamedRefs)];
|
|
8472
|
+
}
|
|
8473
|
+
function typeIsMany(expr) {
|
|
8474
|
+
if (expr.form === "list" || expr.form === "set" || expr.form === "map") return true;
|
|
8475
|
+
if (expr.form === "optional" || expr.form === "async") return typeIsMany(expr.args[0]);
|
|
8476
|
+
return false;
|
|
8477
|
+
}
|
|
8478
|
+
function contextFor(position, omittable2, looseNumber = false) {
|
|
8479
|
+
return { position, top: true, voidAllowed: RETURNS_POSITIONS.has(position), omittable: omittable2, looseNumber };
|
|
8480
|
+
}
|
|
8481
|
+
function parseTypePosition(text3, position, omittable2 = false) {
|
|
8482
|
+
let raw;
|
|
8483
|
+
try {
|
|
8484
|
+
raw = readRaw(text3);
|
|
8485
|
+
} catch (e) {
|
|
8486
|
+
if (!(e instanceof TypeSyntaxError)) throw e;
|
|
8487
|
+
return { expression: null, canonical: text3, problem: { code: "TYPE_EXPRESSION_INVALID", written: text3, detail: `"${text3}" does not parse as a type: ${e.message}` } };
|
|
8488
|
+
}
|
|
8489
|
+
const notes = {};
|
|
8490
|
+
try {
|
|
8491
|
+
const expression = normalise(raw, contextFor(position, omittable2), notes);
|
|
8492
|
+
if (position === "holds") assertHoldable(expression);
|
|
8493
|
+
const problem = notes.notNeutral ? { code: "TYPE_NOT_NEUTRAL", written: text3, detail: notes.notNeutral.detail, replacement: notes.notNeutral.replacement } : null;
|
|
8494
|
+
return { expression, canonical: canonicalTypeText(expression), problem };
|
|
8495
|
+
} catch (e) {
|
|
8496
|
+
if (!(e instanceof TypeProblemError)) throw e;
|
|
8497
|
+
return {
|
|
8498
|
+
expression: null,
|
|
8499
|
+
canonical: text3,
|
|
8500
|
+
problem: { code: e.code, written: text3, detail: `"${text3}": ${e.detail}`, ...e.replacement ? { replacement: e.replacement } : {} }
|
|
8501
|
+
};
|
|
8502
|
+
}
|
|
8503
|
+
}
|
|
8504
|
+
function parseTypeExpression(text3, position) {
|
|
8505
|
+
return parseTypePosition(text3, position);
|
|
8506
|
+
}
|
|
8507
|
+
function readCodeAnnotation(annotation, looseNumber) {
|
|
8508
|
+
let raw;
|
|
8509
|
+
try {
|
|
8510
|
+
raw = readRaw(annotation);
|
|
8511
|
+
} catch (e) {
|
|
8512
|
+
if (e instanceof TypeSyntaxError) return null;
|
|
8513
|
+
throw e;
|
|
8514
|
+
}
|
|
8515
|
+
try {
|
|
8516
|
+
return normalise(raw, contextFor("returns", false, looseNumber), {});
|
|
8517
|
+
} catch (e) {
|
|
8518
|
+
if (e instanceof TypeProblemError) return null;
|
|
8519
|
+
throw e;
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8522
|
+
function writtenTypeRefs(text3, position) {
|
|
8523
|
+
const parse = parseTypePosition(text3, position);
|
|
8524
|
+
if (parse.expression && !parse.problem) return typeNamedRefs(parse.expression);
|
|
8525
|
+
try {
|
|
8526
|
+
return rawRefs(readRaw(text3));
|
|
8527
|
+
} catch (e) {
|
|
8528
|
+
if (e instanceof TypeSyntaxError) return [];
|
|
8529
|
+
throw e;
|
|
8530
|
+
}
|
|
8531
|
+
}
|
|
8532
|
+
function rawRefs(node) {
|
|
8533
|
+
switch (node.k) {
|
|
8534
|
+
case "name": {
|
|
8535
|
+
const own = isTypeVocabulary(node.name) || UTILITY_TYPES.has(node.name) ? [] : [node.name];
|
|
8536
|
+
return [...own, ...(node.args ?? []).flatMap(rawRefs)];
|
|
8537
|
+
}
|
|
8538
|
+
case "array":
|
|
8539
|
+
return rawRefs(node.elem);
|
|
8540
|
+
case "opt":
|
|
8541
|
+
case "paren":
|
|
8542
|
+
case "async":
|
|
8543
|
+
case "operator":
|
|
8544
|
+
return rawRefs(node.inner);
|
|
8545
|
+
case "union":
|
|
8546
|
+
case "intersection":
|
|
8547
|
+
case "object":
|
|
8548
|
+
return node.members.flatMap(rawRefs);
|
|
8549
|
+
case "tuple":
|
|
8550
|
+
return node.elems.flatMap(rawRefs);
|
|
8551
|
+
case "function":
|
|
8552
|
+
return [...node.params.flatMap(rawRefs), ...rawRefs(node.ret)];
|
|
8553
|
+
case "literal":
|
|
8554
|
+
return [];
|
|
8555
|
+
}
|
|
8556
|
+
}
|
|
8557
|
+
var Canonicalizer = class {
|
|
8558
|
+
constructor(specId, kind) {
|
|
8559
|
+
this.specId = specId;
|
|
8560
|
+
this.kind = kind;
|
|
8561
|
+
this.respellings = [];
|
|
8562
|
+
this.problems = [];
|
|
8563
|
+
}
|
|
8564
|
+
/** One position: its canonical text when it has one, else the text as written, recorded either way. */
|
|
8565
|
+
read(text3, position, path49, omittable2 = false) {
|
|
8566
|
+
const parse = parseTypePosition(text3, position, omittable2);
|
|
8567
|
+
if (parse.problem) {
|
|
8568
|
+
this.problems.push({ ...parse.problem, specId: this.specId, kind: this.kind, path: path49 });
|
|
8569
|
+
return text3;
|
|
8570
|
+
}
|
|
8571
|
+
if (parse.canonical !== text3) this.respellings.push({ specId: this.specId, kind: this.kind, path: path49, written: text3, stored: parse.canonical });
|
|
8572
|
+
return parse.canonical;
|
|
8573
|
+
}
|
|
8574
|
+
params(params, position, prefix) {
|
|
8575
|
+
return params.map((p) => ({ ...p, type: this.read(p.type, position, `${prefix}.${p.name}`, !!p.optional) }));
|
|
8576
|
+
}
|
|
8577
|
+
};
|
|
8578
|
+
function interfaceCanonicalTypes(intf) {
|
|
8579
|
+
const reader = new Canonicalizer(intf.id, "interface");
|
|
8580
|
+
const methods = (intf.methods ?? []).map((m) => {
|
|
8581
|
+
if (m.signatureFrom !== void 0) return m;
|
|
8582
|
+
const out = { ...m };
|
|
8583
|
+
if (m.params !== void 0) out.params = reader.params(m.params, "param", `methods.${m.name}.params`);
|
|
8584
|
+
if (typeof m.returns === "string") out.returns = reader.read(m.returns, "returns", `methods.${m.name}.returns`);
|
|
8585
|
+
return out;
|
|
8586
|
+
});
|
|
8587
|
+
return { spec: { ...intf, methods }, respellings: reader.respellings, problems: reader.problems };
|
|
8588
|
+
}
|
|
8589
|
+
function typeCanonicalTypes(type) {
|
|
8590
|
+
const reader = new Canonicalizer(type.id, "type");
|
|
8591
|
+
const out = { ...type };
|
|
8592
|
+
if (Array.isArray(type.fields)) {
|
|
8593
|
+
out.fields = type.fields.map((f) => ({ ...f, type: reader.read(f.type, "field", `fields.${f.name}`, !!f.optional) }));
|
|
8594
|
+
}
|
|
8595
|
+
if (Array.isArray(type.methods)) {
|
|
8596
|
+
out.methods = type.methods.map((m) => {
|
|
8597
|
+
const method = { ...m };
|
|
8598
|
+
if (m.params !== void 0) method.params = reader.params(m.params, "type-method-param", `methods.${m.name}.params`);
|
|
8599
|
+
if (typeof m.returns === "string") method.returns = reader.read(m.returns, "type-method-returns", `methods.${m.name}.returns`);
|
|
8600
|
+
return method;
|
|
8601
|
+
});
|
|
8602
|
+
}
|
|
8603
|
+
if (type.params !== void 0) out.params = reader.params(type.params, "signature-param", "params");
|
|
8604
|
+
if (typeof type.holds === "string") out.holds = reader.read(type.holds, "holds", "holds");
|
|
8605
|
+
if (typeof type.returns === "string") out.returns = reader.read(type.returns, "signature-returns", "returns");
|
|
8606
|
+
return { spec: out, respellings: reader.respellings, problems: reader.problems };
|
|
8607
|
+
}
|
|
8608
|
+
var INTEGER_WORDS = /* @__PURE__ */ new Set([
|
|
8609
|
+
"count",
|
|
8610
|
+
"counts",
|
|
8611
|
+
"size",
|
|
8612
|
+
"sizes",
|
|
8613
|
+
"length",
|
|
8614
|
+
"len",
|
|
8615
|
+
"limit",
|
|
8616
|
+
"limits",
|
|
8617
|
+
"port",
|
|
8618
|
+
"step",
|
|
8619
|
+
"steps",
|
|
8620
|
+
"index",
|
|
8621
|
+
"idx",
|
|
8622
|
+
"depth",
|
|
8623
|
+
"level",
|
|
8624
|
+
"levels",
|
|
8625
|
+
"days",
|
|
8626
|
+
"day",
|
|
8627
|
+
"hours",
|
|
8628
|
+
"minutes",
|
|
8629
|
+
"seconds",
|
|
8630
|
+
"ms",
|
|
8631
|
+
"millis",
|
|
8632
|
+
"milliseconds",
|
|
7892
8633
|
"bytes",
|
|
7893
|
-
"
|
|
7894
|
-
"
|
|
7895
|
-
"
|
|
7896
|
-
"
|
|
7897
|
-
"
|
|
7898
|
-
"
|
|
7899
|
-
"
|
|
7900
|
-
"
|
|
7901
|
-
"
|
|
7902
|
-
"
|
|
7903
|
-
"
|
|
7904
|
-
"
|
|
7905
|
-
"
|
|
7906
|
-
"
|
|
7907
|
-
"
|
|
7908
|
-
"
|
|
7909
|
-
"
|
|
7910
|
-
"vec",
|
|
7911
|
-
"array",
|
|
7912
|
-
"map",
|
|
7913
|
-
"set",
|
|
7914
|
-
"dict",
|
|
7915
|
-
"dictionary",
|
|
7916
|
-
"hashmap",
|
|
7917
|
-
"tuple",
|
|
7918
|
-
"result",
|
|
7919
|
-
"option",
|
|
7920
|
-
"box",
|
|
7921
|
-
"arc",
|
|
7922
|
-
"rc",
|
|
7923
|
-
"ref",
|
|
7924
|
-
"cell",
|
|
7925
|
-
"refcell",
|
|
7926
|
-
"mutex",
|
|
7927
|
-
"rwlock",
|
|
7928
|
-
"std",
|
|
7929
|
-
"promise",
|
|
7930
|
-
"record",
|
|
7931
|
-
"json",
|
|
7932
|
-
"unknown",
|
|
7933
|
-
"never",
|
|
7934
|
-
"error",
|
|
7935
|
-
"mcpserver"
|
|
8634
|
+
"version",
|
|
8635
|
+
"total",
|
|
8636
|
+
"offset",
|
|
8637
|
+
"page",
|
|
8638
|
+
"pages",
|
|
8639
|
+
"retries",
|
|
8640
|
+
"attempts",
|
|
8641
|
+
"number",
|
|
8642
|
+
"num",
|
|
8643
|
+
"line",
|
|
8644
|
+
"lines",
|
|
8645
|
+
"column",
|
|
8646
|
+
"columns",
|
|
8647
|
+
"max",
|
|
8648
|
+
"min",
|
|
8649
|
+
"width",
|
|
8650
|
+
"height"
|
|
7936
8651
|
]);
|
|
8652
|
+
function namesAnInteger(name) {
|
|
8653
|
+
const words2 = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[\s_\-.]+/).filter(Boolean);
|
|
8654
|
+
return words2.some((word) => INTEGER_WORDS.has(word));
|
|
8655
|
+
}
|
|
8656
|
+
function positionNameOf(path49) {
|
|
8657
|
+
const segments = path49.split(".");
|
|
8658
|
+
const last = segments[segments.length - 1];
|
|
8659
|
+
return last === "returns" && segments.length >= 3 ? segments[segments.length - 2] : last;
|
|
8660
|
+
}
|
|
8661
|
+
var NUMBER_NAME = /(?<![\w:.-])number(?![\w:.-])/g;
|
|
8662
|
+
function typeProblemIntProposal(problem) {
|
|
8663
|
+
if (problem.code !== "TYPE_NOT_NEUTRAL" || problem.replacement !== "int or float") return null;
|
|
8664
|
+
if (problem.specId === void 0 || problem.kind === void 0 || problem.path === void 0) return null;
|
|
8665
|
+
if (!namesAnInteger(positionNameOf(problem.path))) return null;
|
|
8666
|
+
const parse = parseTypePosition(problem.written.replace(NUMBER_NAME, "int"), "returns");
|
|
8667
|
+
if (!parse.expression || parse.problem) return null;
|
|
8668
|
+
return { specId: problem.specId, kind: problem.kind, path: problem.path, written: problem.written, stored: parse.canonical };
|
|
8669
|
+
}
|
|
8670
|
+
function emptyTypeSpellingFacts() {
|
|
8671
|
+
return { respellings: [], problems: [] };
|
|
8672
|
+
}
|
|
8673
|
+
|
|
8674
|
+
// src/models/type-references.ts
|
|
7937
8675
|
function extractTypeIdentifiers(typeStr) {
|
|
7938
|
-
let cleaned = typeStr.replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
8676
|
+
let cleaned = typeStr.replace(/^\s*async\s+(?=\S)/, "").replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
7939
8677
|
cleaned = cleaned.replace(/(?<=\S)\s*\([^)]*\)\s*$/, "");
|
|
7940
8678
|
cleaned = cleaned.replace(/(?<=\S)\s+[-—:]\s+[a-z\s_-]+$/, "");
|
|
7941
8679
|
cleaned = cleaned.replace(/(["'`])(?:\\.|[^\\])*?\1/g, " ");
|
|
@@ -8021,16 +8759,19 @@ function methodTypeRefs(m) {
|
|
|
8021
8759
|
if (m.params && m.params.length > 0) {
|
|
8022
8760
|
const refs = [];
|
|
8023
8761
|
for (const p of m.params) {
|
|
8024
|
-
refs.push(...
|
|
8762
|
+
refs.push(...writtenTypeRefs(p.type, "param"));
|
|
8025
8763
|
}
|
|
8026
|
-
refs.push(...
|
|
8764
|
+
if (m.returns !== void 0) refs.push(...writtenTypeRefs(m.returns, "returns"));
|
|
8027
8765
|
return Array.from(new Set(refs));
|
|
8028
8766
|
}
|
|
8029
8767
|
return extractTypesFromSignature(m.signature ?? "", m.returns ?? "");
|
|
8030
8768
|
}
|
|
8031
8769
|
function signatureTypeRefs(type) {
|
|
8032
8770
|
if (type.kind !== "signature") return [];
|
|
8033
|
-
const refs = [
|
|
8771
|
+
const refs = [
|
|
8772
|
+
...(type.params ?? []).flatMap((p) => writtenTypeRefs(p.type, "signature-param")),
|
|
8773
|
+
...type.returns !== void 0 ? writtenTypeRefs(type.returns, "signature-returns") : []
|
|
8774
|
+
];
|
|
8034
8775
|
return Array.from(new Set(refs));
|
|
8035
8776
|
}
|
|
8036
8777
|
function methodGenericParameters(method) {
|
|
@@ -8065,12 +8806,108 @@ function typeGenericParameters(type) {
|
|
|
8065
8806
|
}
|
|
8066
8807
|
function fieldTypeRefs(type, fieldType) {
|
|
8067
8808
|
const generics = new Set(Array.from(typeGenericParameters(type)).map((g) => g.toLowerCase()));
|
|
8068
|
-
return
|
|
8809
|
+
return writtenTypeRefs(fieldType, "field").filter((ref) => !generics.has(ref.toLowerCase()));
|
|
8069
8810
|
}
|
|
8070
8811
|
function interfaceGenericParameters(intf) {
|
|
8071
8812
|
return extractTypeGenerics(intf.name);
|
|
8072
8813
|
}
|
|
8073
8814
|
|
|
8815
|
+
// src/models/type-dialects.ts
|
|
8816
|
+
function lastSegment(name) {
|
|
8817
|
+
return name.split(/::|\./).filter(Boolean).pop() ?? name;
|
|
8818
|
+
}
|
|
8819
|
+
function sameType(code, spec, codeNames) {
|
|
8820
|
+
if (code.form === "primitive" && code.name === "number") return spec.form === "primitive" && (spec.name === "int" || spec.name === "float");
|
|
8821
|
+
if (code.form === "named" && (spec.form === "named" || spec.form === "applied")) {
|
|
8822
|
+
if (spec.form === "applied") return false;
|
|
8823
|
+
return namesAgree(code.name, spec.name, codeNames);
|
|
8824
|
+
}
|
|
8825
|
+
if (code.form !== spec.form) return false;
|
|
8826
|
+
if (code.form === "primitive") return code.name === spec.name;
|
|
8827
|
+
if (code.form === "applied" && !namesAgree(code.name, spec.name, codeNames)) return false;
|
|
8828
|
+
if (code.args.length !== spec.args.length) return false;
|
|
8829
|
+
return code.args.every((arg, i) => sameType(arg, spec.args[i], codeNames));
|
|
8830
|
+
}
|
|
8831
|
+
function namesAgree(codeName, specName, codeNames) {
|
|
8832
|
+
if (codeName === specName) return true;
|
|
8833
|
+
const mapped = codeNames.get(specName) ?? codeNames.get(lastSegment(specName));
|
|
8834
|
+
return mapped === codeName || mapped === lastSegment(codeName);
|
|
8835
|
+
}
|
|
8836
|
+
function writeTypeScript(expr) {
|
|
8837
|
+
switch (expr.form) {
|
|
8838
|
+
case "primitive":
|
|
8839
|
+
return TS_PRIMITIVES[expr.name ?? ""] ?? expr.name ?? "unknown";
|
|
8840
|
+
case "named":
|
|
8841
|
+
return expr.name ?? "unknown";
|
|
8842
|
+
case "list": {
|
|
8843
|
+
const elem = writeTypeScript(expr.args[0]);
|
|
8844
|
+
return /[|\s]/.test(elem) ? `(${elem})[]` : `${elem}[]`;
|
|
8845
|
+
}
|
|
8846
|
+
case "set":
|
|
8847
|
+
return `Set<${writeTypeScript(expr.args[0])}>`;
|
|
8848
|
+
case "map":
|
|
8849
|
+
return `Record<${writeTypeScript(expr.args[0])}, ${writeTypeScript(expr.args[1])}>`;
|
|
8850
|
+
case "optional":
|
|
8851
|
+
return `${writeTypeScript(expr.args[0])} | null`;
|
|
8852
|
+
case "union":
|
|
8853
|
+
return expr.args.map(writeTypeScript).join(" | ");
|
|
8854
|
+
case "async":
|
|
8855
|
+
return `Promise<${writeTypeScript(expr.args[0])}>`;
|
|
8856
|
+
case "applied":
|
|
8857
|
+
return `${expr.name}<${expr.args.map(writeTypeScript).join(", ")}>`;
|
|
8858
|
+
}
|
|
8859
|
+
}
|
|
8860
|
+
var TS_PRIMITIVES = {
|
|
8861
|
+
string: "string",
|
|
8862
|
+
int: "number",
|
|
8863
|
+
float: "number",
|
|
8864
|
+
bool: "boolean",
|
|
8865
|
+
bytes: "Uint8Array",
|
|
8866
|
+
date: "string",
|
|
8867
|
+
datetime: "string",
|
|
8868
|
+
duration: "string",
|
|
8869
|
+
void: "void",
|
|
8870
|
+
any: "unknown"
|
|
8871
|
+
};
|
|
8872
|
+
var typescriptDialect = {
|
|
8873
|
+
language: "typescript",
|
|
8874
|
+
read(annotation) {
|
|
8875
|
+
return readCodeAnnotation(annotation, false);
|
|
8876
|
+
},
|
|
8877
|
+
agrees(annotation, expression, codeNames) {
|
|
8878
|
+
const code = readCodeAnnotation(annotation, true);
|
|
8879
|
+
return code !== null && sameType(code, expression, codeNames);
|
|
8880
|
+
},
|
|
8881
|
+
write(expression) {
|
|
8882
|
+
return writeTypeScript(expression);
|
|
8883
|
+
},
|
|
8884
|
+
mappingLines() {
|
|
8885
|
+
return [
|
|
8886
|
+
"string \u2192 string",
|
|
8887
|
+
"int, float \u2192 number",
|
|
8888
|
+
"bool \u2192 boolean",
|
|
8889
|
+
"bytes \u2192 Uint8Array",
|
|
8890
|
+
"date, datetime, duration \u2192 string (ISO 8601)",
|
|
8891
|
+
"any \u2192 unknown",
|
|
8892
|
+
"list<T> \u2192 T[]",
|
|
8893
|
+
"set<T> \u2192 Set<T>",
|
|
8894
|
+
"map<K, V> \u2192 Record<K, V>",
|
|
8895
|
+
"T? \u2192 T | null",
|
|
8896
|
+
"A | B \u2192 A | B",
|
|
8897
|
+
"async T \u2192 Promise<T>",
|
|
8898
|
+
"an enum E \u2192 type E = 'a' | 'b' (a string-literal union alias)",
|
|
8899
|
+
"a named scalar E holding P \u2192 type E = P (an alias of the primitive)"
|
|
8900
|
+
];
|
|
8901
|
+
}
|
|
8902
|
+
};
|
|
8903
|
+
var DIALECTS = /* @__PURE__ */ new Map([
|
|
8904
|
+
["typescript", typescriptDialect],
|
|
8905
|
+
["javascript", typescriptDialect]
|
|
8906
|
+
]);
|
|
8907
|
+
function typeDialectFor(language) {
|
|
8908
|
+
return DIALECTS.get(language.toLowerCase()) ?? null;
|
|
8909
|
+
}
|
|
8910
|
+
|
|
8074
8911
|
// src/models/step-graph.ts
|
|
8075
8912
|
function stepGraph(method) {
|
|
8076
8913
|
const steps = method.narrative;
|
|
@@ -8365,6 +9202,36 @@ function callSitesOf(facts, fn) {
|
|
|
8365
9202
|
function hasFunctionBody(facts, symbol) {
|
|
8366
9203
|
return callSitesOf(facts, symbol) !== void 0;
|
|
8367
9204
|
}
|
|
9205
|
+
var EXTENSION_LANGUAGE = {
|
|
9206
|
+
".ts": "typescript",
|
|
9207
|
+
".tsx": "typescript",
|
|
9208
|
+
".mts": "typescript",
|
|
9209
|
+
".cts": "typescript",
|
|
9210
|
+
".js": "javascript",
|
|
9211
|
+
".jsx": "javascript",
|
|
9212
|
+
".mjs": "javascript",
|
|
9213
|
+
".cjs": "javascript",
|
|
9214
|
+
".py": "python",
|
|
9215
|
+
".rs": "rust",
|
|
9216
|
+
".go": "go",
|
|
9217
|
+
".cs": "csharp",
|
|
9218
|
+
".java": "java",
|
|
9219
|
+
".c": "c",
|
|
9220
|
+
".h": "c",
|
|
9221
|
+
".cpp": "cpp",
|
|
9222
|
+
".cc": "cpp",
|
|
9223
|
+
".hpp": "cpp",
|
|
9224
|
+
".rb": "ruby",
|
|
9225
|
+
".php": "php",
|
|
9226
|
+
".kt": "kotlin",
|
|
9227
|
+
".swift": "swift"
|
|
9228
|
+
};
|
|
9229
|
+
function languageOfSourcePath(sourcePath) {
|
|
9230
|
+
return EXTENSION_LANGUAGE[path9.extname(sourcePath).toLowerCase()];
|
|
9231
|
+
}
|
|
9232
|
+
function dialectOf(facts) {
|
|
9233
|
+
return facts.language ? typeDialectFor(facts.language) : null;
|
|
9234
|
+
}
|
|
8368
9235
|
function resolveImport(fromFile, specifier, knownPaths) {
|
|
8369
9236
|
if (!specifier.startsWith(".")) return void 0;
|
|
8370
9237
|
const joined = pathKey(path9.posix.normalize(path9.posix.join(path9.posix.dirname(fromFile), specifier)));
|
|
@@ -8410,11 +9277,18 @@ function closureTypeOf(snapshot, identifier) {
|
|
|
8410
9277
|
if (matches.length === 1) return matches[0];
|
|
8411
9278
|
return matches.find((def) => nameKey(def.id) === nameKey(ref));
|
|
8412
9279
|
}
|
|
9280
|
+
function renamedRefs(expr, rename) {
|
|
9281
|
+
const args = expr.args.map((a) => renamedRefs(a, rename));
|
|
9282
|
+
return expr.form === "named" || expr.form === "applied" ? { ...expr, name: rename(expr.name), args } : { ...expr, args };
|
|
9283
|
+
}
|
|
8413
9284
|
function canonicalTypeRef(snapshot, typeExpr) {
|
|
9285
|
+
const rename = (identifier) => closureTypeOf(snapshot, identifier)?.id ?? identifier;
|
|
9286
|
+
const parse = parseTypeExpression(typeExpr, "returns");
|
|
9287
|
+
if (parse.expression) return canonicalTypeText(renamedRefs(parse.expression, rename));
|
|
8414
9288
|
return typeExpr.replace(TYPE_IDENTIFIER, (identifier) => {
|
|
8415
9289
|
if (!/[A-Za-z]/.test(identifier)) return identifier;
|
|
8416
|
-
if (
|
|
8417
|
-
return
|
|
9290
|
+
if (isTypeVocabulary(identifier)) return identifier.toLowerCase();
|
|
9291
|
+
return rename(identifier);
|
|
8418
9292
|
});
|
|
8419
9293
|
}
|
|
8420
9294
|
function typeShape(snapshot, def) {
|
|
@@ -8426,7 +9300,9 @@ function typeShape(snapshot, def) {
|
|
|
8426
9300
|
...def.kind === "signature" ? {
|
|
8427
9301
|
params: (def.params ?? []).map((p) => ({ type: canonicalTypeRef(snapshot, p.type), optional: p.optional === true })),
|
|
8428
9302
|
returns: canonicalTypeRef(snapshot, def.returns ?? "unknown")
|
|
8429
|
-
} : {}
|
|
9303
|
+
} : {},
|
|
9304
|
+
...def.kind === "enum" ? { values: (def.values ?? []).map((v) => v.name) } : {},
|
|
9305
|
+
...def.holds !== void 0 ? { holds: canonicalTypeRef(snapshot, def.holds) } : {}
|
|
8430
9306
|
};
|
|
8431
9307
|
}
|
|
8432
9308
|
function typeDefExprs(def) {
|
|
@@ -8694,7 +9570,7 @@ function shortestPath(from, to, members, edges, rank) {
|
|
|
8694
9570
|
// src/models/validation-options.ts
|
|
8695
9571
|
function selectsFamily(options, declaresMembers) {
|
|
8696
9572
|
if (options?.family) return true;
|
|
8697
|
-
return declaresMembers && options?.
|
|
9573
|
+
return declaresMembers && options?.memberDepth !== 0;
|
|
8698
9574
|
}
|
|
8699
9575
|
|
|
8700
9576
|
// src/core/narrative-labels.ts
|
|
@@ -9423,17 +10299,23 @@ function buildCanvasModel(issues = [], relations) {
|
|
|
9423
10299
|
})),
|
|
9424
10300
|
methods: t.methods.map((m) => ({ name: m.name, signature: m.signature, returns: m.returns, ...m.description ? { description: m.description } : {} })),
|
|
9425
10301
|
...t.kind === "signature" ? { signature: deriveTypeSignature(t) } : {},
|
|
10302
|
+
...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
|
|
10303
|
+
...t.holds !== void 0 ? { holds: t.holds } : {},
|
|
9426
10304
|
usedBy: usedByFor(t),
|
|
9427
10305
|
...t.componentClass ? { componentClass: t.componentClass } : {},
|
|
9428
10306
|
...t.database ? { database: t.database } : {},
|
|
9429
10307
|
...t.table ? { table: t.table } : {},
|
|
9430
10308
|
...t.linkedEntity ? { linkedEntity: t.linkedEntity } : {}
|
|
9431
10309
|
}));
|
|
9432
|
-
const
|
|
10310
|
+
const multiplicity = (field) => {
|
|
10311
|
+
const expression = parseTypeExpression(field.type, "field").expression;
|
|
10312
|
+
if (expression && typeIsMany(expression)) return "*";
|
|
10313
|
+
return field.optional || expression?.form === "optional" ? "0..1" : "1";
|
|
10314
|
+
};
|
|
9433
10315
|
const typeEdges = [];
|
|
9434
10316
|
for (const t of typeSpecs) {
|
|
9435
10317
|
for (const field of t.fields) {
|
|
9436
|
-
const refs = new Set(
|
|
10318
|
+
const refs = new Set(writtenTypeRefs(field.type, "field"));
|
|
9437
10319
|
if (field.references) {
|
|
9438
10320
|
const refStr = field.references;
|
|
9439
10321
|
refs.add(refStr);
|
|
@@ -9448,8 +10330,8 @@ function buildCanvasModel(issues = [], relations) {
|
|
|
9448
10330
|
const qualified = other.subsystem && !other.id.startsWith(`${other.subsystem}::`) ? `${other.subsystem}::${other.id}` : other.id;
|
|
9449
10331
|
return matchTypeRef(ref, qualified);
|
|
9450
10332
|
});
|
|
9451
|
-
if (target && target.id !== t.id) {
|
|
9452
|
-
const card =
|
|
10333
|
+
if (target && target.id !== t.id && target.kind !== "enum" && target.holds === void 0) {
|
|
10334
|
+
const card = multiplicity(field);
|
|
9453
10335
|
if (!typeEdges.some((e) => e.from === t.id && e.to === target.id && e.field === field.name)) {
|
|
9454
10336
|
typeEdges.push({ from: t.id, to: target.id, field: field.name, card });
|
|
9455
10337
|
}
|
|
@@ -11114,7 +11996,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
11114
11996
|
return '';
|
|
11115
11997
|
}
|
|
11116
11998
|
function visibleFields(t) {
|
|
11117
|
-
if (det === 'names') return [];
|
|
11999
|
+
if (det === 'names' || t.values || t.holds) return [];
|
|
11118
12000
|
if (det === 'keys') return t.fields.filter(function (f) { return markerOf(t, f) !== ''; });
|
|
11119
12001
|
return t.fields;
|
|
11120
12002
|
}
|
|
@@ -11159,15 +12041,19 @@ var MODEL = __MODEL_JSON__;
|
|
|
11159
12041
|
var meths = det === 'full' ? t.methods : [];
|
|
11160
12042
|
// A signature type is drawn with its derived text in place of a field list.
|
|
11161
12043
|
var sig = t.signature && det !== 'names' ? t.signature : '';
|
|
11162
|
-
|
|
11163
|
-
var
|
|
12044
|
+
// An enum is drawn with its values in place of a field list.
|
|
12045
|
+
var vals = t.values && det !== 'names' ? t.values : [];
|
|
12046
|
+
// A named scalar is drawn compactly: its name and the primitive it holds.
|
|
12047
|
+
var head = t.name + (t.holds ? ' = ' + t.holds : '') + ' \\u00AB' + t.kind + '\\u00BB';
|
|
12048
|
+
var rows = (sig ? [sig] : []).concat(vals.map(function (v) { return '\\u2022 ' + v.name; }))
|
|
12049
|
+
.concat(fields.map(function (f) { return rowText(t, f); }))
|
|
11164
12050
|
.concat(meths.map(function (m) { return '\\u0192 ' + m.name + '(): ' + m.returns; }));
|
|
11165
12051
|
var longest = head.length + 4;
|
|
11166
12052
|
rows.forEach(function (r) { if (r.length > longest) longest = r.length; });
|
|
11167
12053
|
var plain = rows.length === 0;
|
|
11168
12054
|
var pw = Math.max(170, head.length * 6.8 + 26);
|
|
11169
12055
|
var W = Math.max(210, Math.min(400, longest * 6.6 + 30));
|
|
11170
|
-
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 };
|
|
12056
|
+
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 };
|
|
11171
12057
|
}
|
|
11172
12058
|
|
|
11173
12059
|
// Emit one type table with its top-left at (ax, ay); returns its size.
|
|
@@ -11198,6 +12084,13 @@ var MODEL = __MODEL_JSON__;
|
|
|
11198
12084
|
});
|
|
11199
12085
|
ry += ROW_H;
|
|
11200
12086
|
}
|
|
12087
|
+
sh.vals.forEach(function (v, vi) {
|
|
12088
|
+
eles.push({
|
|
12089
|
+
data: { id: 'TV~' + t.id + '~' + vi, parent: 'T~' + t.id, label: '\\u2022 ' + v.name, w: sh.w, h: ROW_H, tw: sh.w - 14 },
|
|
12090
|
+
position: { x: ax + sh.w / 2, y: ry + ROW_H / 2 }, classes: 'typeRow' + (dim ? ' dimmed' : ''), grabbable: false,
|
|
12091
|
+
});
|
|
12092
|
+
ry += ROW_H;
|
|
12093
|
+
});
|
|
11201
12094
|
sh.fields.forEach(function (f) {
|
|
11202
12095
|
var rid = 'TF~' + t.id + '~' + f.name;
|
|
11203
12096
|
rowIds[rid] = 1;
|
|
@@ -13731,6 +14624,17 @@ var MODEL = __MODEL_JSON__;
|
|
|
13731
14624
|
: '<span class="desc">no fields</span>';
|
|
13732
14625
|
if (ty.signature) {
|
|
13733
14626
|
body += section('Signature', 1, '<div class="method"><code>' + esc(ty.signature) + '</code></div>', true);
|
|
14627
|
+
} else if (ty.holds) {
|
|
14628
|
+
body += section('Holds', 1, '<div class="method"><code>' + esc(ty.holds) + '</code>'
|
|
14629
|
+
+ '<div class="mdesc">A named scalar: one ' + esc(ty.holds) + ' under this name.</div></div>', true);
|
|
14630
|
+
} else if (ty.values) {
|
|
14631
|
+
body += section('Values', ty.values.length, ty.values.length
|
|
14632
|
+
? ty.values.map(function (v) {
|
|
14633
|
+
return '<div class="method"><div class="mname">' + esc(v.name) + '</div>'
|
|
14634
|
+
+ (v.description ? '<div class="mdesc">' + esc(v.description) + '</div>' : '')
|
|
14635
|
+
+ '</div>';
|
|
14636
|
+
}).join('')
|
|
14637
|
+
: '<span class="desc">no values</span>', true);
|
|
13734
14638
|
} else {
|
|
13735
14639
|
body += section('Fields', ty.fields.length, fieldsInner, true);
|
|
13736
14640
|
}
|
|
@@ -14056,7 +14960,7 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
14056
14960
|
queue.push(key);
|
|
14057
14961
|
};
|
|
14058
14962
|
const enqueueRef = (ref) => {
|
|
14059
|
-
if (
|
|
14963
|
+
if (isTypeVocabulary(ref)) return;
|
|
14060
14964
|
for (const spec of types) {
|
|
14061
14965
|
if (matchTypeRef(ref, qualifiedTypeId2(spec))) include(spec);
|
|
14062
14966
|
}
|
|
@@ -14070,13 +14974,13 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
14070
14974
|
while (queue.length) {
|
|
14071
14975
|
const spec = included.get(queue.shift());
|
|
14072
14976
|
for (const field of spec.fields) {
|
|
14073
|
-
for (const ref of
|
|
14977
|
+
for (const ref of writtenTypeRefs(field.type, "field")) enqueueRef(ref);
|
|
14074
14978
|
}
|
|
14075
14979
|
for (const param of spec.params ?? []) {
|
|
14076
|
-
for (const ref of
|
|
14980
|
+
for (const ref of writtenTypeRefs(param.type, "signature-param")) enqueueRef(ref);
|
|
14077
14981
|
}
|
|
14078
14982
|
if (spec.returns) {
|
|
14079
|
-
for (const ref of
|
|
14983
|
+
for (const ref of writtenTypeRefs(spec.returns, "signature-returns")) enqueueRef(ref);
|
|
14080
14984
|
}
|
|
14081
14985
|
}
|
|
14082
14986
|
const usedIds = /* @__PURE__ */ new Set();
|
|
@@ -14095,7 +14999,11 @@ function computeTypeClosure(entries, types, exported = []) {
|
|
|
14095
14999
|
kind: t.kind,
|
|
14096
15000
|
fields: t.fields.map(describe2),
|
|
14097
15001
|
// A signature type travels complete: its params and returns with it.
|
|
14098
|
-
...t.kind === "signature" ? { params: (t.params ?? []).map(describe2), returns: t.returns ?? "
|
|
15002
|
+
...t.kind === "signature" ? { params: (t.params ?? []).map(describe2), returns: t.returns ?? "any" } : {},
|
|
15003
|
+
// An enum travels with its values, in declared order.
|
|
15004
|
+
...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
|
|
15005
|
+
// A named scalar travels with the primitive it holds.
|
|
15006
|
+
...t.holds !== void 0 ? { holds: t.holds } : {}
|
|
14099
15007
|
};
|
|
14100
15008
|
});
|
|
14101
15009
|
}
|
|
@@ -14714,7 +15622,7 @@ function depthOf(family, node) {
|
|
|
14714
15622
|
return depth;
|
|
14715
15623
|
}
|
|
14716
15624
|
function selectProjects(family, options) {
|
|
14717
|
-
const limit =
|
|
15625
|
+
const limit = options.memberDepth ?? Infinity;
|
|
14718
15626
|
const nodes = family.nodes.filter((n) => depthOf(family, n) <= limit);
|
|
14719
15627
|
const scope = options.scopeSubsystem;
|
|
14720
15628
|
if (!scope) return nodes.map((node) => ({ node }));
|
|
@@ -15242,7 +16150,7 @@ function defaultTargetConfig(type) {
|
|
|
15242
16150
|
enabled: true
|
|
15243
16151
|
};
|
|
15244
16152
|
}
|
|
15245
|
-
var WAIRON_VERSION = "5.1.1-dev.
|
|
16153
|
+
var WAIRON_VERSION = "5.1.1-dev.96";
|
|
15246
16154
|
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
15247
16155
|
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
15248
16156
|
var ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -15469,7 +16377,7 @@ var ProfileDefSchema = import_zod9.z.object({
|
|
|
15469
16377
|
});
|
|
15470
16378
|
var LanguagePackDefSchema = import_zod9.z.object({
|
|
15471
16379
|
unsupportedFlow: import_zod9.z.record(import_zod9.z.string()).default({}),
|
|
15472
|
-
foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).
|
|
16380
|
+
foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).optional()
|
|
15473
16381
|
});
|
|
15474
16382
|
var PackSkillSchema = import_zod9.z.object({
|
|
15475
16383
|
/** A NEW skill, installed namespaced as `<pack-id>-<id>`. Mutually exclusive with `extends`. */
|
|
@@ -15603,8 +16511,9 @@ function globalPacksEnabled(config) {
|
|
|
15603
16511
|
return config.extensions?.useGlobalPacks ?? GLOBAL_PACKS_DEFAULT;
|
|
15604
16512
|
}
|
|
15605
16513
|
function emptyExtensions() {
|
|
15606
|
-
return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
|
|
16514
|
+
return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [], deprecations: [] };
|
|
15607
16515
|
}
|
|
16516
|
+
var 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";
|
|
15608
16517
|
function globalPacksDir() {
|
|
15609
16518
|
return process.env.WAIRON_PACKS_DIR ?? path17.join(os3.homedir(), ".wairon", "packs");
|
|
15610
16519
|
}
|
|
@@ -15665,11 +16574,11 @@ function mergePack(out, pack, ref, scope, packDir) {
|
|
|
15665
16574
|
Object.assign(out.profiles, pack.profiles);
|
|
15666
16575
|
for (const [lang, def] of Object.entries(pack.languages)) {
|
|
15667
16576
|
const key = lang.toLowerCase();
|
|
16577
|
+
if (def.foreignBuiltins !== void 0) {
|
|
16578
|
+
out.deprecations.push(`${pack.name}: languages.${lang}.foreignBuiltins \u2014 ${FOREIGN_BUILTINS_RETIRED}`);
|
|
16579
|
+
}
|
|
15668
16580
|
const existing = out.languages[key];
|
|
15669
|
-
out.languages[key] = existing
|
|
15670
|
-
unsupportedFlow: { ...existing.unsupportedFlow, ...def.unsupportedFlow },
|
|
15671
|
-
foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
|
|
15672
|
-
} : def;
|
|
16581
|
+
out.languages[key] = { unsupportedFlow: { ...existing?.unsupportedFlow, ...def.unsupportedFlow } };
|
|
15673
16582
|
}
|
|
15674
16583
|
for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path17.resolve(packDir, s.source) });
|
|
15675
16584
|
for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
|
|
@@ -16275,7 +17184,7 @@ function buildImplementationMethods(ctx) {
|
|
|
16275
17184
|
const component = ctx.componentMap.get(contract.component);
|
|
16276
17185
|
if (!component) continue;
|
|
16277
17186
|
if (ctx.isInChainedSubproject(component.subsystem)) continue;
|
|
16278
|
-
const
|
|
17187
|
+
const draftContext4 = ctx.isImplementationDraft(impl);
|
|
16279
17188
|
for (const method of impl.methods) {
|
|
16280
17189
|
const sourceFile = methodSourceFile(method, impl.sourcePath);
|
|
16281
17190
|
out.push({
|
|
@@ -16283,7 +17192,7 @@ function buildImplementationMethods(ctx) {
|
|
|
16283
17192
|
method,
|
|
16284
17193
|
component,
|
|
16285
17194
|
...sourceFile !== void 0 ? { sourceFile } : {},
|
|
16286
|
-
draftContext:
|
|
17195
|
+
draftContext: draftContext4
|
|
16287
17196
|
});
|
|
16288
17197
|
}
|
|
16289
17198
|
}
|
|
@@ -16521,7 +17430,7 @@ var roundtripRule = {
|
|
|
16521
17430
|
var typeDeclarationsRule = {
|
|
16522
17431
|
name: "type-declarations",
|
|
16523
17432
|
judges: "design",
|
|
16524
|
-
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.",
|
|
17433
|
+
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.",
|
|
16525
17434
|
codes: [
|
|
16526
17435
|
{ code: "INVALID_SUBSYSTEM_REFERENCE", defaultSeverity: "error", summary: "Type references a non-existent owning subsystem" },
|
|
16527
17436
|
{ code: "HOLLOW_TYPE", defaultSeverity: "warning", summary: "Type declares no fields and no methods \u2014 a placeholder that informs neither implementers nor the ERD" }
|
|
@@ -16539,7 +17448,8 @@ var typeDeclarationsRule = {
|
|
|
16539
17448
|
isDraftCtx
|
|
16540
17449
|
);
|
|
16541
17450
|
}
|
|
16542
|
-
|
|
17451
|
+
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;
|
|
17452
|
+
if (!models) {
|
|
16543
17453
|
ctx.addIssue(
|
|
16544
17454
|
"warning",
|
|
16545
17455
|
"HOLLOW_TYPE",
|
|
@@ -16776,6 +17686,7 @@ var signatureTypesRule = {
|
|
|
16776
17686
|
);
|
|
16777
17687
|
continue;
|
|
16778
17688
|
}
|
|
17689
|
+
if (t.kind === "enum") continue;
|
|
16779
17690
|
const stated = [...t.params !== void 0 ? ["params"] : [], ...t.returns !== void 0 ? ["returns"] : []];
|
|
16780
17691
|
if (stated.length === 0) continue;
|
|
16781
17692
|
ctx.addIssue(
|
|
@@ -16822,6 +17733,184 @@ var signatureTextRule = {
|
|
|
16822
17733
|
}
|
|
16823
17734
|
};
|
|
16824
17735
|
|
|
17736
|
+
// src/core/rules/integrity/type-expressions.ts
|
|
17737
|
+
function draftContext3(ctx, specId, kind) {
|
|
17738
|
+
if (kind === "interface") {
|
|
17739
|
+
const intf = ctx.interfaceMap.get(specId);
|
|
17740
|
+
return !!intf && (ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design");
|
|
17741
|
+
}
|
|
17742
|
+
const type = ctx.types.find((t) => t.id === specId);
|
|
17743
|
+
const sub = type?.subsystem ? ctx.subsystems.find((s) => s.id === type.subsystem) : void 0;
|
|
17744
|
+
return !!sub && (sub.status === "draft" || sub.status === "design");
|
|
17745
|
+
}
|
|
17746
|
+
function siteOf(path49) {
|
|
17747
|
+
const [head2, name] = path49.split(".");
|
|
17748
|
+
return (head2 === "methods" || head2 === "fields") && name ? name : path49;
|
|
17749
|
+
}
|
|
17750
|
+
function located(kind, specId, path49) {
|
|
17751
|
+
return `${path49 ? `"${path49}" of ` : ""}${kind ?? "spec"} "${specId}"`;
|
|
17752
|
+
}
|
|
17753
|
+
function problemMessage(problem, specId) {
|
|
17754
|
+
const where = located(problem.kind, specId, problem.path);
|
|
17755
|
+
const replacement = problem.replacement ? ` Write ${problem.replacement} instead.` : "";
|
|
17756
|
+
switch (problem.code) {
|
|
17757
|
+
case "TYPE_EXPRESSION_INVALID":
|
|
17758
|
+
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.`;
|
|
17759
|
+
case "TYPE_POSITION_INVALID":
|
|
17760
|
+
return `The type at ${where} breaks a position rule: ${problem.detail}.${replacement}`;
|
|
17761
|
+
case "TYPE_FORM_UNSUPPORTED":
|
|
17762
|
+
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.`;
|
|
17763
|
+
case "TYPE_NOT_NEUTRAL": {
|
|
17764
|
+
if (problem.replacement === "int or float") {
|
|
17765
|
+
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.";
|
|
17766
|
+
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.`;
|
|
17767
|
+
}
|
|
17768
|
+
return `The type at ${where} is "${problem.written}": ${problem.detail}, so it is read as any.${replacement}`;
|
|
17769
|
+
}
|
|
17770
|
+
}
|
|
17771
|
+
}
|
|
17772
|
+
var typeExpressionsRule = {
|
|
17773
|
+
name: "type-expressions",
|
|
17774
|
+
judges: "design",
|
|
17775
|
+
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).",
|
|
17776
|
+
codes: [
|
|
17777
|
+
{ code: "TYPE_EXPRESSION_INVALID", defaultSeverity: "error", summary: "A structured type position does not parse under the type grammar" },
|
|
17778
|
+
{ 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??" },
|
|
17779
|
+
{ 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" },
|
|
17780
|
+
{ 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" },
|
|
17781
|
+
{ 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" }
|
|
17782
|
+
],
|
|
17783
|
+
check(ctx) {
|
|
17784
|
+
const facts = ctx.typeSpellingFacts;
|
|
17785
|
+
if (!facts) return;
|
|
17786
|
+
for (const problem of facts.problems) {
|
|
17787
|
+
if (problem.specId === void 0 || !ctx.isSpecInScope(problem.specId)) continue;
|
|
17788
|
+
const severity = problem.code === "TYPE_EXPRESSION_INVALID" || problem.code === "TYPE_POSITION_INVALID" ? "error" : "warning";
|
|
17789
|
+
ctx.addIssue(
|
|
17790
|
+
severity,
|
|
17791
|
+
problem.code,
|
|
17792
|
+
problemMessage(problem, problem.specId),
|
|
17793
|
+
problem.specId,
|
|
17794
|
+
draftContext3(ctx, problem.specId, problem.kind),
|
|
17795
|
+
void 0,
|
|
17796
|
+
problem.path ? { at: siteOf(problem.path) } : void 0
|
|
17797
|
+
);
|
|
17798
|
+
}
|
|
17799
|
+
for (const respelling of facts.respellings) {
|
|
17800
|
+
if (!ctx.isSpecInScope(respelling.specId)) continue;
|
|
17801
|
+
ctx.addIssue(
|
|
17802
|
+
"warning",
|
|
17803
|
+
"TYPE_SPELLING_STALE",
|
|
17804
|
+
`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.`,
|
|
17805
|
+
respelling.specId,
|
|
17806
|
+
draftContext3(ctx, respelling.specId, respelling.kind),
|
|
17807
|
+
void 0,
|
|
17808
|
+
{ at: siteOf(respelling.path) }
|
|
17809
|
+
);
|
|
17810
|
+
}
|
|
17811
|
+
}
|
|
17812
|
+
};
|
|
17813
|
+
|
|
17814
|
+
// src/core/rules/integrity/enum-types.ts
|
|
17815
|
+
var enumTypesRule = {
|
|
17816
|
+
name: "enum-types",
|
|
17817
|
+
judges: "design",
|
|
17818
|
+
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.",
|
|
17819
|
+
codes: [
|
|
17820
|
+
{ 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" }
|
|
17821
|
+
],
|
|
17822
|
+
check(ctx) {
|
|
17823
|
+
for (const t of ctx.types) {
|
|
17824
|
+
if (!ctx.isSpecInScope(t.id)) continue;
|
|
17825
|
+
const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
|
|
17826
|
+
const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
|
|
17827
|
+
if (t.kind === "enum") {
|
|
17828
|
+
const values = t.values ?? [];
|
|
17829
|
+
const problems = [];
|
|
17830
|
+
if (values.length === 0) problems.push("lists no values");
|
|
17831
|
+
const seen = /* @__PURE__ */ new Map();
|
|
17832
|
+
for (const value of values) {
|
|
17833
|
+
const key = nameKey(value.name);
|
|
17834
|
+
const earlier = seen.get(key);
|
|
17835
|
+
if (earlier !== void 0) problems.push(`lists "${earlier}" and "${value.name}", which every language derives one identifier from`);
|
|
17836
|
+
else seen.set(key, value.name);
|
|
17837
|
+
}
|
|
17838
|
+
const members = [
|
|
17839
|
+
...t.fields.length > 0 ? ["fields"] : [],
|
|
17840
|
+
...t.params !== void 0 ? ["params"] : [],
|
|
17841
|
+
...t.returns !== void 0 ? ["returns"] : [],
|
|
17842
|
+
...(t.invariants?.length ?? 0) > 0 ? ["invariants"] : [],
|
|
17843
|
+
...t.componentClass !== void 0 ? ["componentClass"] : [],
|
|
17844
|
+
...t.database !== void 0 ? ["database"] : [],
|
|
17845
|
+
...t.table !== void 0 ? ["table"] : [],
|
|
17846
|
+
...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
|
|
17847
|
+
];
|
|
17848
|
+
if (members.length > 0) problems.push(`carries ${members.join(", ")}`);
|
|
17849
|
+
if (problems.length === 0) continue;
|
|
17850
|
+
ctx.addIssue(
|
|
17851
|
+
"error",
|
|
17852
|
+
"ENUM_MEMBERS",
|
|
17853
|
+
`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.`,
|
|
17854
|
+
t.id,
|
|
17855
|
+
isDraft
|
|
17856
|
+
);
|
|
17857
|
+
continue;
|
|
17858
|
+
}
|
|
17859
|
+
if (t.values === void 0) continue;
|
|
17860
|
+
ctx.addIssue(
|
|
17861
|
+
"error",
|
|
17862
|
+
"ENUM_MEMBERS",
|
|
17863
|
+
`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.`,
|
|
17864
|
+
t.id,
|
|
17865
|
+
isDraft
|
|
17866
|
+
);
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
};
|
|
17870
|
+
|
|
17871
|
+
// src/core/rules/integrity/named-scalar-types.ts
|
|
17872
|
+
var namedScalarTypesRule = {
|
|
17873
|
+
name: "named-scalar-types",
|
|
17874
|
+
judges: "design",
|
|
17875
|
+
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.",
|
|
17876
|
+
codes: [
|
|
17877
|
+
{ 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" }
|
|
17878
|
+
],
|
|
17879
|
+
check(ctx) {
|
|
17880
|
+
for (const t of ctx.types) {
|
|
17881
|
+
if (!ctx.isSpecInScope(t.id)) continue;
|
|
17882
|
+
if (t.holds === void 0) continue;
|
|
17883
|
+
const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
|
|
17884
|
+
const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
|
|
17885
|
+
if (t.kind !== "value-object") {
|
|
17886
|
+
ctx.addIssue(
|
|
17887
|
+
"error",
|
|
17888
|
+
"NAMED_SCALAR_MEMBERS",
|
|
17889
|
+
`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.`,
|
|
17890
|
+
t.id,
|
|
17891
|
+
isDraft
|
|
17892
|
+
);
|
|
17893
|
+
continue;
|
|
17894
|
+
}
|
|
17895
|
+
const members = [
|
|
17896
|
+
...t.fields.length > 0 ? ["fields"] : [],
|
|
17897
|
+
...t.componentClass !== void 0 ? ["componentClass"] : [],
|
|
17898
|
+
...t.database !== void 0 ? ["database"] : [],
|
|
17899
|
+
...t.table !== void 0 ? ["table"] : [],
|
|
17900
|
+
...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
|
|
17901
|
+
];
|
|
17902
|
+
if (members.length === 0) continue;
|
|
17903
|
+
ctx.addIssue(
|
|
17904
|
+
"error",
|
|
17905
|
+
"NAMED_SCALAR_MEMBERS",
|
|
17906
|
+
`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.`,
|
|
17907
|
+
t.id,
|
|
17908
|
+
isDraft
|
|
17909
|
+
);
|
|
17910
|
+
}
|
|
17911
|
+
}
|
|
17912
|
+
};
|
|
17913
|
+
|
|
16825
17914
|
// src/core/rules/integrity/public-surface-binding.ts
|
|
16826
17915
|
var publicSurfaceBindingRule = {
|
|
16827
17916
|
name: "public-surface-binding",
|
|
@@ -18250,11 +19339,11 @@ var detailSufficiencyRule = {
|
|
|
18250
19339
|
const contract = ctx.interfaceMap.get(impl.contract);
|
|
18251
19340
|
if (!contract) continue;
|
|
18252
19341
|
const component = ctx.componentMap.get(contract.component);
|
|
18253
|
-
const
|
|
19342
|
+
const draftContext4 = ctx.isImplementationDraft(impl);
|
|
18254
19343
|
for (const method of impl.methods) {
|
|
18255
19344
|
const detail = effectiveDetail(method, impl, component);
|
|
18256
19345
|
if (contract.methods.some((m) => m.name === method.name) && method.narrative.length === 0 && detail.level !== "full") {
|
|
18257
|
-
dialedDown.push({ implementation: impl, method, component, detail, draftContext:
|
|
19346
|
+
dialedDown.push({ implementation: impl, method, component, detail, draftContext: draftContext4 });
|
|
18258
19347
|
}
|
|
18259
19348
|
}
|
|
18260
19349
|
}
|
|
@@ -19679,6 +20768,25 @@ var packRequirementsRule = {
|
|
|
19679
20768
|
}
|
|
19680
20769
|
};
|
|
19681
20770
|
|
|
20771
|
+
// src/core/rules/extension/pack-deprecations.ts
|
|
20772
|
+
var packDeprecationsRule = {
|
|
20773
|
+
name: "pack-deprecations",
|
|
20774
|
+
judges: "design",
|
|
20775
|
+
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.",
|
|
20776
|
+
codes: [
|
|
20777
|
+
{ code: "PACK_FIELD_DEPRECATED", defaultSeverity: "notice", summary: "A loaded pack declares a deprecated field, accepted and ignored for one release" }
|
|
20778
|
+
],
|
|
20779
|
+
check(ctx) {
|
|
20780
|
+
for (const deprecation of ctx.ext.deprecations) {
|
|
20781
|
+
ctx.addIssue(
|
|
20782
|
+
"notice",
|
|
20783
|
+
"PACK_FIELD_DEPRECATED",
|
|
20784
|
+
`Deprecated pack field \u2014 ${deprecation}. It is accepted and ignored in this release and removed in the next; take it out of the pack.`
|
|
20785
|
+
);
|
|
20786
|
+
}
|
|
20787
|
+
}
|
|
20788
|
+
};
|
|
20789
|
+
|
|
19682
20790
|
// src/core/rules/wiring/dependency-cycles.ts
|
|
19683
20791
|
var cyclesRule = {
|
|
19684
20792
|
name: "dependency-cycles",
|
|
@@ -20340,14 +21448,22 @@ var durabilityRule = {
|
|
|
20340
21448
|
};
|
|
20341
21449
|
|
|
20342
21450
|
// src/core/rules/wiring/untyped-seams.ts
|
|
20343
|
-
var
|
|
20344
|
-
function
|
|
20345
|
-
return
|
|
21451
|
+
var UNTYPED_SPELLINGS = /* @__PURE__ */ new Set(["any", "json", "unknown", "object"]);
|
|
21452
|
+
function holdsAny(expr) {
|
|
21453
|
+
return expr.form === "primitive" && expr.name === "any" || expr.args.some(holdsAny);
|
|
21454
|
+
}
|
|
21455
|
+
function tokensUntyped(text3) {
|
|
21456
|
+
return extractTypeIdentifiers(text3).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()));
|
|
21457
|
+
}
|
|
21458
|
+
function positionUntyped(text3, position) {
|
|
21459
|
+
const parse = parseTypePosition(text3, position);
|
|
21460
|
+
if (parse.expression && !parse.problem) return holdsAny(parse.expression);
|
|
21461
|
+
return tokensUntyped(text3);
|
|
20346
21462
|
}
|
|
20347
21463
|
var untypedSeamRule = {
|
|
20348
21464
|
name: "untyped-seams",
|
|
20349
21465
|
judges: "design",
|
|
20350
|
-
description: "Methods on a subsystem's published components (its public surface) should not take or return
|
|
21466
|
+
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.",
|
|
20351
21467
|
codes: [
|
|
20352
21468
|
{ code: "UNTYPED_SEAM", defaultSeverity: "warning", summary: "Bare Json/any/unknown/object parameter or return crossing a subsystem public surface" }
|
|
20353
21469
|
],
|
|
@@ -20365,14 +21481,14 @@ var untypedSeamRule = {
|
|
|
20365
21481
|
const offenders = [];
|
|
20366
21482
|
if (m.params && m.params.length > 0) {
|
|
20367
21483
|
for (const p of m.params) {
|
|
20368
|
-
if (
|
|
21484
|
+
if (positionUntyped(p.type, "param")) {
|
|
20369
21485
|
offenders.push(`param "${p.name}: ${p.type}"`);
|
|
20370
21486
|
}
|
|
20371
21487
|
}
|
|
20372
|
-
if (
|
|
21488
|
+
if (m.returns && positionUntyped(m.returns, "returns")) {
|
|
20373
21489
|
offenders.push(`return "${m.returns}"`);
|
|
20374
21490
|
}
|
|
20375
|
-
} else if (
|
|
21491
|
+
} else if (methodTypeRefs(m).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()))) {
|
|
20376
21492
|
offenders.push(`signature "${m.signature}"`);
|
|
20377
21493
|
}
|
|
20378
21494
|
if (offenders.length) {
|
|
@@ -21616,10 +22732,37 @@ function originOf(shape) {
|
|
|
21616
22732
|
function absence(optional) {
|
|
21617
22733
|
return optional ? "may be absent" : "is always there";
|
|
21618
22734
|
}
|
|
22735
|
+
function judgeNamedScalar(ctx, type, file, facts) {
|
|
22736
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") return;
|
|
22737
|
+
const dialect = dialectOf(facts);
|
|
22738
|
+
const holds = parseTypePosition(type.holds, "holds").expression;
|
|
22739
|
+
if (!dialect || !holds) return;
|
|
22740
|
+
const symbol = type.symbol ?? type.name;
|
|
22741
|
+
const own = (record) => !!record && Object.prototype.hasOwnProperty.call(record, symbol);
|
|
22742
|
+
let declared;
|
|
22743
|
+
if (own(facts.aliasTypes)) {
|
|
22744
|
+
const annotation = facts.aliasTypes[symbol];
|
|
22745
|
+
if (dialect.agrees(annotation, holds, /* @__PURE__ */ new Map())) return;
|
|
22746
|
+
declared = `an alias of \`${annotation}\``;
|
|
22747
|
+
} else if (own(facts.typeShapes)) {
|
|
22748
|
+
declared = "a record (an object shape)";
|
|
22749
|
+
} else {
|
|
22750
|
+
return;
|
|
22751
|
+
}
|
|
22752
|
+
ctx.addIssue(
|
|
22753
|
+
"warning",
|
|
22754
|
+
"TYPE_HOLDS_MISMATCH",
|
|
22755
|
+
`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.`,
|
|
22756
|
+
type.id,
|
|
22757
|
+
void 0,
|
|
22758
|
+
void 0,
|
|
22759
|
+
{ at: symbol }
|
|
22760
|
+
);
|
|
22761
|
+
}
|
|
21619
22762
|
var typeShapeRule = {
|
|
21620
22763
|
name: "type-shape",
|
|
21621
22764
|
judges: "code",
|
|
21622
|
-
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.",
|
|
22765
|
+
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.",
|
|
21623
22766
|
codes: [
|
|
21624
22767
|
{
|
|
21625
22768
|
code: "UNREALIZED_TYPE_FIELD",
|
|
@@ -21635,6 +22778,12 @@ var typeShapeRule = {
|
|
|
21635
22778
|
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",
|
|
21636
22779
|
carryable: true
|
|
21637
22780
|
},
|
|
22781
|
+
{
|
|
22782
|
+
code: "TYPE_HOLDS_MISMATCH",
|
|
22783
|
+
defaultSeverity: "warning",
|
|
22784
|
+
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",
|
|
22785
|
+
carryable: true
|
|
22786
|
+
},
|
|
21638
22787
|
{
|
|
21639
22788
|
code: "TYPE_FIELD_OPTIONALITY",
|
|
21640
22789
|
defaultSeverity: "warning",
|
|
@@ -21649,6 +22798,10 @@ var typeShapeRule = {
|
|
|
21649
22798
|
if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
|
|
21650
22799
|
const file = pathKey(type.sourcePath);
|
|
21651
22800
|
const facts = code.factsAt(file);
|
|
22801
|
+
if (type.holds !== void 0) {
|
|
22802
|
+
judgeNamedScalar(ctx, type, file, facts);
|
|
22803
|
+
continue;
|
|
22804
|
+
}
|
|
21652
22805
|
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
21653
22806
|
const symbol = type.symbol ?? type.name;
|
|
21654
22807
|
const shapes = facts.typeShapes;
|
|
@@ -21703,6 +22856,67 @@ var typeShapeRule = {
|
|
|
21703
22856
|
}
|
|
21704
22857
|
};
|
|
21705
22858
|
|
|
22859
|
+
// src/core/rules/conformance/enum-values.ts
|
|
22860
|
+
var enumValuesRule = {
|
|
22861
|
+
name: "enum-values",
|
|
22862
|
+
judges: "code",
|
|
22863
|
+
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.",
|
|
22864
|
+
codes: [
|
|
22865
|
+
{
|
|
22866
|
+
code: "UNREALIZED_ENUM_VALUE",
|
|
22867
|
+
defaultSeverity: "warning",
|
|
22868
|
+
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",
|
|
22869
|
+
carryable: true
|
|
22870
|
+
},
|
|
22871
|
+
{
|
|
22872
|
+
code: "UNDECLARED_ENUM_VALUE",
|
|
22873
|
+
defaultSeverity: "warning",
|
|
22874
|
+
summary: "The declaration at an enum type's sourcePath holds a value the enum does not list \u2014 a value the design never described",
|
|
22875
|
+
carryable: true
|
|
22876
|
+
}
|
|
22877
|
+
],
|
|
22878
|
+
check(ctx) {
|
|
22879
|
+
const code = ctx.codeIndex();
|
|
22880
|
+
for (const type of ctx.types) {
|
|
22881
|
+
if (type.kind !== "enum" || !type.sourcePath) continue;
|
|
22882
|
+
if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
|
|
22883
|
+
const file = pathKey(type.sourcePath);
|
|
22884
|
+
const facts = code.factsAt(file);
|
|
22885
|
+
const symbol = type.symbol ?? type.name;
|
|
22886
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
22887
|
+
const declared = facts.enumValues;
|
|
22888
|
+
if (!declared || !Object.prototype.hasOwnProperty.call(declared, symbol)) continue;
|
|
22889
|
+
const held = new Set(declared[symbol]);
|
|
22890
|
+
const listed = (type.values ?? []).map((value) => value.name);
|
|
22891
|
+
const listedSet = new Set(listed);
|
|
22892
|
+
const unrealized = listed.filter((value) => !held.has(value));
|
|
22893
|
+
if (unrealized.length > 0) {
|
|
22894
|
+
ctx.addIssue(
|
|
22895
|
+
"warning",
|
|
22896
|
+
"UNREALIZED_ENUM_VALUE",
|
|
22897
|
+
`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).`,
|
|
22898
|
+
type.id,
|
|
22899
|
+
void 0,
|
|
22900
|
+
void 0,
|
|
22901
|
+
{ at: symbol, covers: unrealized }
|
|
22902
|
+
);
|
|
22903
|
+
}
|
|
22904
|
+
const undeclared = declared[symbol].filter((value) => !listedSet.has(value));
|
|
22905
|
+
if (undeclared.length > 0) {
|
|
22906
|
+
ctx.addIssue(
|
|
22907
|
+
"warning",
|
|
22908
|
+
"UNDECLARED_ENUM_VALUE",
|
|
22909
|
+
`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.`,
|
|
22910
|
+
type.id,
|
|
22911
|
+
void 0,
|
|
22912
|
+
void 0,
|
|
22913
|
+
{ at: symbol, covers: undeclared }
|
|
22914
|
+
);
|
|
22915
|
+
}
|
|
22916
|
+
}
|
|
22917
|
+
}
|
|
22918
|
+
};
|
|
22919
|
+
|
|
21706
22920
|
// src/core/rules/conformance/param-conformance.ts
|
|
21707
22921
|
function omittable(optional) {
|
|
21708
22922
|
return optional ? "may be left out" : "is required";
|
|
@@ -21753,7 +22967,7 @@ function agreed(judgements, reading) {
|
|
|
21753
22967
|
var paramConformanceRule = {
|
|
21754
22968
|
name: "param-conformance",
|
|
21755
22969
|
judges: "code",
|
|
21756
|
-
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.",
|
|
22970
|
+
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.",
|
|
21757
22971
|
codes: [
|
|
21758
22972
|
{
|
|
21759
22973
|
code: "UNREALIZED_PARAM",
|
|
@@ -21790,13 +23004,13 @@ var paramConformanceRule = {
|
|
|
21790
23004
|
codeNameOf.set(type.id, named2);
|
|
21791
23005
|
if (type.subsystem) codeNameOf.set(`${type.subsystem}.${type.id}`, named2);
|
|
21792
23006
|
}
|
|
21793
|
-
const
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
|
|
21797
|
-
return
|
|
23007
|
+
const typeAgreesIn = (dialect) => (declared, realized) => {
|
|
23008
|
+
if (!realized.type || !dialect) return false;
|
|
23009
|
+
const stated = parseTypePosition(declared.type, "param", !!declared.optional);
|
|
23010
|
+
if (!stated.expression) return false;
|
|
23011
|
+
return dialect.agrees(realized.type, stated.expression, codeNameOf);
|
|
21798
23012
|
};
|
|
21799
|
-
for (const { implementation, method, sourceFile, draftContext:
|
|
23013
|
+
for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
21800
23014
|
const contract = ctx.interfaceMap.get(implementation.contract);
|
|
21801
23015
|
const declared = contract?.methods.find((m) => m.name === method.name)?.params ?? [];
|
|
21802
23016
|
if (declared.length === 0 || !sourceFile) continue;
|
|
@@ -21809,6 +23023,7 @@ var paramConformanceRule = {
|
|
|
21809
23023
|
const candidates = signatures[symbol];
|
|
21810
23024
|
if (candidates.length === 0) continue;
|
|
21811
23025
|
const injected = new Set(implementation.injectedParams ?? []);
|
|
23026
|
+
const typeAgrees = typeAgreesIn(dialectOf(facts));
|
|
21812
23027
|
const judgements = candidates.map((realized) => judge(declared, realized, injected, typeAgrees));
|
|
21813
23028
|
const subject = candidates.length > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
|
|
21814
23029
|
const opening = subject.charAt(0).toUpperCase() + subject.slice(1);
|
|
@@ -21819,7 +23034,7 @@ var paramConformanceRule = {
|
|
|
21819
23034
|
"UNREALIZED_PARAM",
|
|
21820
23035
|
`Method "${method.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.`,
|
|
21821
23036
|
implementation.id,
|
|
21822
|
-
|
|
23037
|
+
draftContext4,
|
|
21823
23038
|
void 0,
|
|
21824
23039
|
{ at: method.name, covers: unrealized.map((found) => found.unit) }
|
|
21825
23040
|
);
|
|
@@ -21831,7 +23046,7 @@ var paramConformanceRule = {
|
|
|
21831
23046
|
"UNDECLARED_PARAM",
|
|
21832
23047
|
`${opening} realizing method "${method.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.`,
|
|
21833
23048
|
implementation.id,
|
|
21834
|
-
|
|
23049
|
+
draftContext4,
|
|
21835
23050
|
void 0,
|
|
21836
23051
|
{ at: method.name, covers: undeclared.map((found) => found.unit) }
|
|
21837
23052
|
);
|
|
@@ -21843,7 +23058,7 @@ var paramConformanceRule = {
|
|
|
21843
23058
|
"PARAM_NAME_MISMATCH",
|
|
21844
23059
|
`Method "${method.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.`,
|
|
21845
23060
|
implementation.id,
|
|
21846
|
-
|
|
23061
|
+
draftContext4,
|
|
21847
23062
|
void 0,
|
|
21848
23063
|
{ at: method.name, covers: renamed.map((found) => found.unit) }
|
|
21849
23064
|
);
|
|
@@ -21855,7 +23070,7 @@ var paramConformanceRule = {
|
|
|
21855
23070
|
"PARAM_OPTIONALITY",
|
|
21856
23071
|
`Method "${method.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.`,
|
|
21857
23072
|
implementation.id,
|
|
21858
|
-
|
|
23073
|
+
draftContext4,
|
|
21859
23074
|
void 0,
|
|
21860
23075
|
{ at: method.name, covers: disagreed.map((found) => found.unit) }
|
|
21861
23076
|
);
|
|
@@ -21864,6 +23079,62 @@ var paramConformanceRule = {
|
|
|
21864
23079
|
}
|
|
21865
23080
|
};
|
|
21866
23081
|
|
|
23082
|
+
// src/core/rules/conformance/async-conformance.ts
|
|
23083
|
+
var asyncConformanceRule = {
|
|
23084
|
+
name: "async-conformance",
|
|
23085
|
+
judges: "code",
|
|
23086
|
+
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.",
|
|
23087
|
+
codes: [
|
|
23088
|
+
{
|
|
23089
|
+
code: "ASYNC_MISMATCH",
|
|
23090
|
+
defaultSeverity: "warning",
|
|
23091
|
+
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",
|
|
23092
|
+
carryable: true
|
|
23093
|
+
}
|
|
23094
|
+
],
|
|
23095
|
+
check(ctx) {
|
|
23096
|
+
const code = ctx.codeIndex();
|
|
23097
|
+
for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
23098
|
+
const contractMethod = ctx.interfaceMap.get(implementation.contract)?.methods.find((m) => m.name === method.name);
|
|
23099
|
+
if (!contractMethod || typeof contractMethod.returns !== "string" || !sourceFile) continue;
|
|
23100
|
+
const file = pathKey(sourceFile);
|
|
23101
|
+
const facts = code.factsAt(file);
|
|
23102
|
+
if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
|
|
23103
|
+
const symbol = method.symbol ?? method.name;
|
|
23104
|
+
const signatures = facts.functionParams;
|
|
23105
|
+
if (!signatures || !Object.prototype.hasOwnProperty.call(signatures, symbol)) continue;
|
|
23106
|
+
const bodies = signatures[symbol].length;
|
|
23107
|
+
if (bodies === 0) continue;
|
|
23108
|
+
const returns = parseTypeExpression(contractMethod.returns, "returns");
|
|
23109
|
+
if (!returns.expression) continue;
|
|
23110
|
+
const contractAsync = returns.expression.form === "async";
|
|
23111
|
+
const asyncBodies = (facts.asyncFunctions ?? []).filter((name) => name === symbol).length;
|
|
23112
|
+
const subject = bodies > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
|
|
23113
|
+
if (contractAsync && asyncBodies === 0) {
|
|
23114
|
+
ctx.addIssue(
|
|
23115
|
+
"warning",
|
|
23116
|
+
"ASYNC_MISMATCH",
|
|
23117
|
+
`Method "${method.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.`,
|
|
23118
|
+
implementation.id,
|
|
23119
|
+
draftContext4,
|
|
23120
|
+
void 0,
|
|
23121
|
+
{ at: method.name }
|
|
23122
|
+
);
|
|
23123
|
+
} else if (!contractAsync && asyncBodies === bodies) {
|
|
23124
|
+
ctx.addIssue(
|
|
23125
|
+
"warning",
|
|
23126
|
+
"ASYNC_MISMATCH",
|
|
23127
|
+
`Method "${method.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.`,
|
|
23128
|
+
implementation.id,
|
|
23129
|
+
draftContext4,
|
|
23130
|
+
void 0,
|
|
23131
|
+
{ at: method.name }
|
|
23132
|
+
);
|
|
23133
|
+
}
|
|
23134
|
+
}
|
|
23135
|
+
}
|
|
23136
|
+
};
|
|
23137
|
+
|
|
21867
23138
|
// src/core/rules/conformance/route-coverage.ts
|
|
21868
23139
|
function liesUnder2(path49, prefix) {
|
|
21869
23140
|
return path49 === prefix || path49.startsWith(prefix + "/");
|
|
@@ -21932,7 +23203,7 @@ var routeCoverageRule = {
|
|
|
21932
23203
|
const routes = code.factsAt(file).functionRoutes;
|
|
21933
23204
|
return routes && Object.prototype.hasOwnProperty.call(routes, via) ? routes[via] : [];
|
|
21934
23205
|
});
|
|
21935
|
-
const
|
|
23206
|
+
const draftContext4 = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
|
|
21936
23207
|
const where = holders.map((file) => `"${file}"`).join(", ");
|
|
21937
23208
|
if (read2.length === 0) {
|
|
21938
23209
|
ctx.addIssue(
|
|
@@ -21940,7 +23211,7 @@ var routeCoverageRule = {
|
|
|
21940
23211
|
"UNREADABLE_ROUTER",
|
|
21941
23212
|
`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.`,
|
|
21942
23213
|
anchor,
|
|
21943
|
-
|
|
23214
|
+
draftContext4,
|
|
21944
23215
|
void 0,
|
|
21945
23216
|
{ at: via }
|
|
21946
23217
|
);
|
|
@@ -21965,7 +23236,7 @@ var routeCoverageRule = {
|
|
|
21965
23236
|
"UNDECLARED_ROUTE",
|
|
21966
23237
|
`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.`,
|
|
21967
23238
|
anchor,
|
|
21968
|
-
|
|
23239
|
+
draftContext4,
|
|
21969
23240
|
void 0,
|
|
21970
23241
|
{ at: via, covers: undeclared }
|
|
21971
23242
|
);
|
|
@@ -21977,7 +23248,7 @@ var routeCoverageRule = {
|
|
|
21977
23248
|
"UNROUTED_ENDPOINT",
|
|
21978
23249
|
`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.`,
|
|
21979
23250
|
anchor,
|
|
21980
|
-
|
|
23251
|
+
draftContext4,
|
|
21981
23252
|
void 0,
|
|
21982
23253
|
{ at: via, covers: unrouted }
|
|
21983
23254
|
);
|
|
@@ -22080,7 +23351,7 @@ var exportConformanceRule = {
|
|
|
22080
23351
|
}
|
|
22081
23352
|
}
|
|
22082
23353
|
}
|
|
22083
|
-
for (const { implementation, method, sourceFile, draftContext:
|
|
23354
|
+
for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
|
|
22084
23355
|
const handle = method.exportedVia;
|
|
22085
23356
|
if (!handle || !sourceFile) continue;
|
|
22086
23357
|
const file = pathKey(sourceFile);
|
|
@@ -22095,7 +23366,7 @@ var exportConformanceRule = {
|
|
|
22095
23366
|
"UNREALIZED_EXPORT_HANDLE",
|
|
22096
23367
|
`Method "${method.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.`,
|
|
22097
23368
|
implementation.id,
|
|
22098
|
-
|
|
23369
|
+
draftContext4
|
|
22099
23370
|
);
|
|
22100
23371
|
}
|
|
22101
23372
|
for (const listener of ctx.components) {
|
|
@@ -22468,82 +23739,6 @@ var couplingRule = {
|
|
|
22468
23739
|
}
|
|
22469
23740
|
};
|
|
22470
23741
|
|
|
22471
|
-
// src/core/rules/heuristic/signature-language-builtins.ts
|
|
22472
|
-
var LANGUAGE_MARKERS = {
|
|
22473
|
-
rust: /* @__PURE__ */ new Set([
|
|
22474
|
-
"u8",
|
|
22475
|
-
"u16",
|
|
22476
|
-
"u32",
|
|
22477
|
-
"u64",
|
|
22478
|
-
"u128",
|
|
22479
|
-
"usize",
|
|
22480
|
-
"i8",
|
|
22481
|
-
"i16",
|
|
22482
|
-
"i32",
|
|
22483
|
-
"i64",
|
|
22484
|
-
"i128",
|
|
22485
|
-
"isize",
|
|
22486
|
-
"f32",
|
|
22487
|
-
"f64",
|
|
22488
|
-
"vec",
|
|
22489
|
-
"box",
|
|
22490
|
-
"arc",
|
|
22491
|
-
"rc",
|
|
22492
|
-
"refcell",
|
|
22493
|
-
"cell",
|
|
22494
|
-
"mutex",
|
|
22495
|
-
"rwlock",
|
|
22496
|
-
"str"
|
|
22497
|
-
]),
|
|
22498
|
-
typescript: /* @__PURE__ */ new Set(["any", "unknown", "never", "undefined", "promise", "record"]),
|
|
22499
|
-
javascript: /* @__PURE__ */ new Set(["promise", "undefined"]),
|
|
22500
|
-
python: /* @__PURE__ */ new Set(["dict", "tuple"]),
|
|
22501
|
-
csharp: /* @__PURE__ */ new Set(["task"]),
|
|
22502
|
-
go: /* @__PURE__ */ new Set(["chan", "rune"])
|
|
22503
|
-
};
|
|
22504
|
-
var signatureLanguageBuiltinsRule = {
|
|
22505
|
-
name: "signature-language-builtins",
|
|
22506
|
-
judges: "design",
|
|
22507
|
-
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).",
|
|
22508
|
-
codes: [
|
|
22509
|
-
{ code: "LANGUAGE_FOREIGN_BUILTIN", defaultSeverity: "warning", summary: "Signature uses a builtin from a different language family" }
|
|
22510
|
-
],
|
|
22511
|
-
check(ctx) {
|
|
22512
|
-
const markersFor = (family) => {
|
|
22513
|
-
const base = LANGUAGE_MARKERS[family];
|
|
22514
|
-
const extra = ctx.ext.languages[family]?.foreignBuiltins;
|
|
22515
|
-
if (!extra?.length) return base;
|
|
22516
|
-
return /* @__PURE__ */ new Set([...base ?? [], ...extra.map((s) => s.toLowerCase())]);
|
|
22517
|
-
};
|
|
22518
|
-
const families = [.../* @__PURE__ */ new Set([...Object.keys(LANGUAGE_MARKERS), ...Object.keys(ctx.ext.languages)])];
|
|
22519
|
-
const scans = [];
|
|
22520
|
-
for (const intf of ctx.interfaces) {
|
|
22521
|
-
const comp = ctx.componentMap.get(intf.component);
|
|
22522
|
-
const lang = ctx.targetLanguageFor(comp?.subsystem);
|
|
22523
|
-
if (!lang) continue;
|
|
22524
|
-
const ownMarkers = markersFor(lang);
|
|
22525
|
-
if (!ownMarkers || ownMarkers.size === 0) continue;
|
|
22526
|
-
const draft = ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design";
|
|
22527
|
-
for (const method of intf.methods) {
|
|
22528
|
-
for (const ref of methodTypeRefs(method)) scans.push({ intf, method, ref, lang, ownMarkers, draft });
|
|
22529
|
-
}
|
|
22530
|
-
}
|
|
22531
|
-
for (const scan of scans) {
|
|
22532
|
-
const refLower = scan.ref.toLowerCase();
|
|
22533
|
-
if (scan.ownMarkers.has(refLower)) continue;
|
|
22534
|
-
const foreign = families.find((family) => family !== scan.lang && markersFor(family)?.has(refLower));
|
|
22535
|
-
if (!foreign) continue;
|
|
22536
|
-
ctx.addIssue(
|
|
22537
|
-
"warning",
|
|
22538
|
-
"LANGUAGE_FOREIGN_BUILTIN",
|
|
22539
|
-
`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.`,
|
|
22540
|
-
scan.intf.id,
|
|
22541
|
-
scan.draft
|
|
22542
|
-
);
|
|
22543
|
-
}
|
|
22544
|
-
}
|
|
22545
|
-
};
|
|
22546
|
-
|
|
22547
23742
|
// src/core/rules/heuristic/narrative-language-constructs.ts
|
|
22548
23743
|
var UNSUPPORTED_FLOW = {
|
|
22549
23744
|
rust: {
|
|
@@ -23469,6 +24664,11 @@ var SDD_RULES = [
|
|
|
23469
24664
|
signatureSourcesRule,
|
|
23470
24665
|
signatureTypesRule,
|
|
23471
24666
|
signatureTextRule,
|
|
24667
|
+
// The type grammar beside the signatures: how each stored type position is
|
|
24668
|
+
// spelled, then what an enum and a named scalar may hold.
|
|
24669
|
+
typeExpressionsRule,
|
|
24670
|
+
enumTypesRule,
|
|
24671
|
+
namedScalarTypesRule,
|
|
23472
24672
|
// Contracts and the targets narratives name, in four questions with one
|
|
23473
24673
|
// owner each: does the implementation mirror its contract, does a target
|
|
23474
24674
|
// inside this tree resolve, does a target that leaves it pin to exactly one
|
|
@@ -23633,14 +24833,17 @@ var SDD_RULES = [
|
|
|
23633
24833
|
// others named.
|
|
23634
24834
|
typeRealizationRule,
|
|
23635
24835
|
typeShapeRule,
|
|
24836
|
+
// An enum's values beside the data shape, and whether the call completes
|
|
24837
|
+
// later beside the signature: the same readings, of their own facts.
|
|
24838
|
+
enumValuesRule,
|
|
23636
24839
|
paramConformanceRule,
|
|
24840
|
+
asyncConformanceRule,
|
|
23637
24841
|
routeCoverageRule,
|
|
23638
24842
|
unclaimedSourceRule,
|
|
23639
24843
|
exportConformanceRule,
|
|
23640
24844
|
couplingRule,
|
|
23641
|
-
// Target-language fit
|
|
23642
|
-
//
|
|
23643
|
-
signatureLanguageBuiltinsRule,
|
|
24845
|
+
// Target-language fit: what a NARRATIVE may describe. What a contract may
|
|
24846
|
+
// name is the neutral type grammar's (type-expressions), not a language's.
|
|
23644
24847
|
narrativeLanguageConstructsRule,
|
|
23645
24848
|
// The declaration before the consequences: which stereotype may bind a
|
|
23646
24849
|
// technology at all, then where its name may appear.
|
|
@@ -23664,6 +24867,9 @@ var SDD_RULES = [
|
|
|
23664
24867
|
// stage): configuration too, and the family run cannot judge a member against
|
|
23665
24868
|
// a requirement that does not parse.
|
|
23666
24869
|
packRequirementsRule,
|
|
24870
|
+
// The fields a loaded pack still declares that wairon has deprecated: about
|
|
24871
|
+
// the packs' configuration too, and only ever a notice.
|
|
24872
|
+
packDeprecationsRule,
|
|
23667
24873
|
// MUST run last, in this order: each audits what the earlier rules did
|
|
23668
24874
|
// with a declared exception. The debt register first (which carried
|
|
23669
24875
|
// findings the conformance family actually matched), then the allows
|
|
@@ -23706,30 +24912,6 @@ var import_module2 = require("module");
|
|
|
23706
24912
|
function emptyCodeModel() {
|
|
23707
24913
|
return { files: [], projectRoot: "", rootFiles: [] };
|
|
23708
24914
|
}
|
|
23709
|
-
var EXTENSION_LANGUAGE = {
|
|
23710
|
-
".ts": "typescript",
|
|
23711
|
-
".tsx": "typescript",
|
|
23712
|
-
".mts": "typescript",
|
|
23713
|
-
".cts": "typescript",
|
|
23714
|
-
".js": "javascript",
|
|
23715
|
-
".jsx": "javascript",
|
|
23716
|
-
".mjs": "javascript",
|
|
23717
|
-
".cjs": "javascript",
|
|
23718
|
-
".py": "python",
|
|
23719
|
-
".rs": "rust",
|
|
23720
|
-
".go": "go",
|
|
23721
|
-
".cs": "csharp",
|
|
23722
|
-
".java": "java",
|
|
23723
|
-
".c": "c",
|
|
23724
|
-
".h": "c",
|
|
23725
|
-
".cpp": "cpp",
|
|
23726
|
-
".cc": "cpp",
|
|
23727
|
-
".hpp": "cpp",
|
|
23728
|
-
".rb": "ruby",
|
|
23729
|
-
".php": "php",
|
|
23730
|
-
".kt": "kotlin",
|
|
23731
|
-
".swift": "swift"
|
|
23732
|
-
};
|
|
23733
24915
|
var C_FAMILY_COMMENTS = { lineComments: ["//"], blockComments: [["/*", "*/"]] };
|
|
23734
24916
|
var NAMED_IMPORT_BINDINGS_RE = /\bimport\s*\{([^}]*)\}/g;
|
|
23735
24917
|
var JS_PATTERNS = {
|
|
@@ -23962,6 +25144,9 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
23962
25144
|
const typeShapes = /* @__PURE__ */ new Map();
|
|
23963
25145
|
const functionParams = /* @__PURE__ */ new Map();
|
|
23964
25146
|
const functionRoutes = /* @__PURE__ */ new Map();
|
|
25147
|
+
const asyncFunctions = [];
|
|
25148
|
+
const enumValues = /* @__PURE__ */ new Map();
|
|
25149
|
+
const aliasTypes = /* @__PURE__ */ new Map();
|
|
23965
25150
|
const mutableBindings = /* @__PURE__ */ new Set();
|
|
23966
25151
|
const schemaConstants = /* @__PURE__ */ new Map();
|
|
23967
25152
|
const derivedAliases = [];
|
|
@@ -24176,6 +25361,48 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
24176
25361
|
if (fn.body) walk2(fn.body, []);
|
|
24177
25362
|
return routes;
|
|
24178
25363
|
};
|
|
25364
|
+
const completesLater = (fn) => {
|
|
25365
|
+
const mods = fn.modifiers;
|
|
25366
|
+
if (mods?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) return true;
|
|
25367
|
+
const returned = fn.type;
|
|
25368
|
+
return !!returned && ts.isTypeReferenceNode(returned) && ts.isIdentifier(returned.typeName) && returned.typeName.text === "Promise";
|
|
25369
|
+
};
|
|
25370
|
+
const stringLiteralUnion = (type) => {
|
|
25371
|
+
const members = ts.isUnionTypeNode(type) ? [...type.types] : [type];
|
|
25372
|
+
const values = [];
|
|
25373
|
+
for (const member of members) {
|
|
25374
|
+
if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return void 0;
|
|
25375
|
+
values.push(member.literal.text);
|
|
25376
|
+
}
|
|
25377
|
+
return values;
|
|
25378
|
+
};
|
|
25379
|
+
const zodEnumValues = (expression) => {
|
|
25380
|
+
const strings = (array, hops) => {
|
|
25381
|
+
let node2 = array;
|
|
25382
|
+
while (node2 && (ts.isAsExpression(node2) || ts.isParenthesizedExpression(node2) || ts.isSatisfiesExpression(node2))) node2 = node2.expression;
|
|
25383
|
+
if (node2 && ts.isIdentifier(node2) && hops > 0) return strings(schemaConstants.get(node2.text), hops - 1);
|
|
25384
|
+
if (!node2 || !ts.isArrayLiteralExpression(node2) || node2.elements.length === 0) return void 0;
|
|
25385
|
+
const values = [];
|
|
25386
|
+
for (const element of node2.elements) {
|
|
25387
|
+
if (!ts.isStringLiteral(element) && !ts.isNoSubstitutionTemplateLiteral(element)) return void 0;
|
|
25388
|
+
values.push(element.text);
|
|
25389
|
+
}
|
|
25390
|
+
return values;
|
|
25391
|
+
};
|
|
25392
|
+
let node = expression;
|
|
25393
|
+
const walked = /* @__PURE__ */ new Set();
|
|
25394
|
+
while (node && !walked.has(node)) {
|
|
25395
|
+
walked.add(node);
|
|
25396
|
+
if (ts.isCallExpression(node)) {
|
|
25397
|
+
const callee = node.expression;
|
|
25398
|
+
if (ts.isPropertyAccessExpression(callee) && callee.name.text === "enum") return strings(node.arguments[0], 1);
|
|
25399
|
+
node = callee;
|
|
25400
|
+
} else if (ts.isPropertyAccessExpression(node)) {
|
|
25401
|
+
node = node.expression;
|
|
25402
|
+
} else break;
|
|
25403
|
+
}
|
|
25404
|
+
return void 0;
|
|
25405
|
+
};
|
|
24179
25406
|
const visit = (node) => {
|
|
24180
25407
|
const fnName = namedFunctionName(node);
|
|
24181
25408
|
if (fnName && node.body) {
|
|
@@ -24187,6 +25414,7 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
24187
25414
|
const signatures = functionParams.get(fnName) ?? [];
|
|
24188
25415
|
signatures.push(declaredParameters(node));
|
|
24189
25416
|
functionParams.set(fnName, signatures);
|
|
25417
|
+
if (completesLater(node)) asyncFunctions.push(fnName);
|
|
24190
25418
|
const routes = collectRoutes(node);
|
|
24191
25419
|
if (routes.size > 0) {
|
|
24192
25420
|
const known = functionRoutes.get(fnName) ?? /* @__PURE__ */ new Map();
|
|
@@ -24209,10 +25437,17 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
24209
25437
|
} else if (ts.isTypeAliasDeclaration(node)) {
|
|
24210
25438
|
if (ts.isTypeLiteralNode(node.type)) recordDeclaredShape(node.name.text, node.type.members, false);
|
|
24211
25439
|
else {
|
|
25440
|
+
if (!aliasTypes.has(node.name.text)) aliasTypes.set(node.name.text, node.type.getText(sf));
|
|
24212
25441
|
const constant = inferredSchemaConstant(node.type);
|
|
24213
25442
|
if (constant) derivedAliases.push({ name: node.name.text, constant });
|
|
25443
|
+
const literals = stringLiteralUnion(node.type);
|
|
25444
|
+
if (literals) enumValues.set(node.name.text, literals);
|
|
24214
25445
|
}
|
|
24215
25446
|
}
|
|
25447
|
+
if (ts.isEnumDeclaration(node)) {
|
|
25448
|
+
const values = node.members.map((member) => member.initializer && (ts.isStringLiteral(member.initializer) || ts.isNoSubstitutionTemplateLiteral(member.initializer)) ? member.initializer.text : void 0);
|
|
25449
|
+
if (values.length > 0 && values.every((v) => v !== void 0)) enumValues.set(node.name.text, values);
|
|
25450
|
+
}
|
|
24216
25451
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && !schemaConstants.has(node.name.text)) {
|
|
24217
25452
|
schemaConstants.set(node.name.text, node.initializer);
|
|
24218
25453
|
}
|
|
@@ -24334,8 +25569,17 @@ function walkExact(ts, sourceText, fileName) {
|
|
|
24334
25569
|
if (!fields) continue;
|
|
24335
25570
|
typeShapes.set(alias.name, { origin: "derived", fields, methods: [] });
|
|
24336
25571
|
}
|
|
25572
|
+
for (const [name, initializer] of schemaConstants) {
|
|
25573
|
+
const values = zodEnumValues(initializer);
|
|
25574
|
+
if (values) enumValues.set(name, values);
|
|
25575
|
+
}
|
|
25576
|
+
for (const alias of derivedAliases) {
|
|
25577
|
+
if (enumValues.has(alias.name)) continue;
|
|
25578
|
+
const values = enumValues.get(alias.constant);
|
|
25579
|
+
if (values && schemaConstants.has(alias.constant)) enumValues.set(alias.name, values);
|
|
25580
|
+
}
|
|
24337
25581
|
const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
|
|
24338
|
-
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, mutableBindings, reexportOnly };
|
|
25582
|
+
return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, asyncFunctions, enumValues, aliasTypes, mutableBindings, reexportOnly };
|
|
24339
25583
|
}
|
|
24340
25584
|
function resolveRelativeModule(fromFile, specifier) {
|
|
24341
25585
|
if (!specifier.startsWith(".")) return null;
|
|
@@ -24414,7 +25658,7 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
|
|
|
24414
25658
|
const record = (absolute) => {
|
|
24415
25659
|
const key = pathKey(path18.relative(projectRoot, absolute));
|
|
24416
25660
|
if (seen.has(key) || isExcluded(key)) return;
|
|
24417
|
-
if (!
|
|
25661
|
+
if (!languageOfSourcePath(key)) return;
|
|
24418
25662
|
seen.add(key);
|
|
24419
25663
|
found.push(key);
|
|
24420
25664
|
};
|
|
@@ -24496,7 +25740,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
24496
25740
|
continue;
|
|
24497
25741
|
}
|
|
24498
25742
|
const text3 = buffer.toString("utf8");
|
|
24499
|
-
const language =
|
|
25743
|
+
const language = languageOfSourcePath(sourcePath);
|
|
24500
25744
|
let analyzed;
|
|
24501
25745
|
if (language === "typescript" || language === "javascript") {
|
|
24502
25746
|
const ts = resolveTypeScript(projectRoot);
|
|
@@ -24524,6 +25768,9 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
|
|
|
24524
25768
|
typeShapes: Object.fromEntries(facts.typeShapes),
|
|
24525
25769
|
functionParams: Object.fromEntries(facts.functionParams),
|
|
24526
25770
|
functionRoutes: Object.fromEntries([...facts.functionRoutes].map(([k, v]) => [k, [...v.values()]])),
|
|
25771
|
+
asyncFunctions: [...facts.asyncFunctions],
|
|
25772
|
+
enumValues: Object.fromEntries(facts.enumValues),
|
|
25773
|
+
aliasTypes: Object.fromEntries(facts.aliasTypes),
|
|
24527
25774
|
topLevelMutableBindings: [...facts.mutableBindings],
|
|
24528
25775
|
reexportOnly: facts.reexportOnly
|
|
24529
25776
|
};
|
|
@@ -24953,7 +26200,7 @@ function buildRuleContext(opts) {
|
|
|
24953
26200
|
const authoredTypeRefs = new Set((family?.authoredReferences ?? []).filter((r) => r.position === "type" && r.binding !== "local" && memberOf(r.specId) === void 0).map((r) => r.authored));
|
|
24954
26201
|
const isTypeResolved = (ref, generics) => {
|
|
24955
26202
|
const refLower = ref.toLowerCase();
|
|
24956
|
-
if (
|
|
26203
|
+
if (isTypeVocabulary(refLower)) return true;
|
|
24957
26204
|
if (generics.has(refLower)) return true;
|
|
24958
26205
|
if (ownTypes.some((spec) => typeMatchesRef(spec, ref))) return true;
|
|
24959
26206
|
const [first, ...rest] = ref.split(/::|\./);
|
|
@@ -25167,7 +26414,7 @@ function buildRuleContext(opts) {
|
|
|
25167
26414
|
}
|
|
25168
26415
|
return projectNaming;
|
|
25169
26416
|
};
|
|
25170
|
-
const isBuiltinType = (ref) =>
|
|
26417
|
+
const isBuiltinType = (ref) => isTypeVocabulary(ref);
|
|
25171
26418
|
const getRuleSeverity = (ruleCode, defaultSeverity, isDraftContext, subsystemId) => {
|
|
25172
26419
|
if (rules?.sddRuleSeverity?.[ruleCode]) {
|
|
25173
26420
|
return rules.sddRuleSeverity[ruleCode];
|
|
@@ -25345,7 +26592,7 @@ function buildRuleContext(opts) {
|
|
|
25345
26592
|
documentationConfigFor,
|
|
25346
26593
|
namingConfigFor,
|
|
25347
26594
|
isBuiltinType,
|
|
25348
|
-
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 ?? [] },
|
|
26595
|
+
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 ?? [] },
|
|
25349
26596
|
variants: opts.variants ?? [],
|
|
25350
26597
|
surfaceSnapshots,
|
|
25351
26598
|
...opts.projectIdentity ? { projectIdentity: opts.projectIdentity } : {},
|
|
@@ -25354,6 +26601,7 @@ function buildRuleContext(opts) {
|
|
|
25354
26601
|
...opts.projectFamily ? { projectFamily: opts.projectFamily } : {},
|
|
25355
26602
|
...opts.exportUsages ? { exportUsages: opts.exportUsages } : {},
|
|
25356
26603
|
...opts.signatureFacts ? { signatureFacts: opts.signatureFacts } : {},
|
|
26604
|
+
...opts.typeSpellingFacts ? { typeSpellingFacts: opts.typeSpellingFacts } : {},
|
|
25357
26605
|
pinnedExternals,
|
|
25358
26606
|
codeModel: opts.codeModel ?? emptyCodeModel(),
|
|
25359
26607
|
roundTripIssues: opts.roundTripIssues,
|
|
@@ -25708,7 +26956,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
25708
26956
|
let extensions;
|
|
25709
26957
|
let treatAllAsComplete = false;
|
|
25710
26958
|
let packSelections;
|
|
25711
|
-
if (rulesOrOptions && ("scopeSubsystem" in rulesOrOptions || "
|
|
26959
|
+
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)) {
|
|
25712
26960
|
const opts = rulesOrOptions;
|
|
25713
26961
|
rules = opts.rules;
|
|
25714
26962
|
projectType = opts.projectType ?? "backend";
|
|
@@ -25718,7 +26966,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
25718
26966
|
packSelections = opts.packSelections;
|
|
25719
26967
|
}
|
|
25720
26968
|
extensions ??= loadProjectExtensions();
|
|
25721
|
-
scanAllSpecs(
|
|
26969
|
+
scanAllSpecs();
|
|
25722
26970
|
const issues = [];
|
|
25723
26971
|
clearLoaderIssues();
|
|
25724
26972
|
const boundConfig = boundConfiguration();
|
|
@@ -25796,6 +27044,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
25796
27044
|
const producers = new Set(family.references.filter((r) => r.consumer === "").map((r) => r.producer));
|
|
25797
27045
|
const exportUsages = [...producers].map((producer) => exportUsage("", producer));
|
|
25798
27046
|
const signatures = signatureFacts();
|
|
27047
|
+
const typeSpellings = typeSpellingFacts();
|
|
25799
27048
|
const ctx = buildRuleContext({
|
|
25800
27049
|
system,
|
|
25801
27050
|
subsystems,
|
|
@@ -25818,6 +27067,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
|
|
|
25818
27067
|
projectFamily: family,
|
|
25819
27068
|
exportUsages,
|
|
25820
27069
|
signatureFacts: signatures,
|
|
27070
|
+
typeSpellingFacts: typeSpellings,
|
|
25821
27071
|
pinnedExternals,
|
|
25822
27072
|
// By-name selections only: a legacy path ref pins nothing to check. A dry
|
|
25823
27073
|
// run supplies its candidate's; otherwise the stored ones.
|
|
@@ -25938,7 +27188,12 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
25938
27188
|
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));
|
|
25939
27189
|
}
|
|
25940
27190
|
const ownSignatures = signatureFacts();
|
|
25941
|
-
const
|
|
27191
|
+
const ownTypeSpellings = typeSpellingFacts();
|
|
27192
|
+
const partTypeSpellings = {
|
|
27193
|
+
respellings: ownTypeSpellings.respellings.filter((r) => isOwn(r.specId)),
|
|
27194
|
+
problems: ownTypeSpellings.problems.filter((p) => p.specId === void 0 || isOwn(p.specId))
|
|
27195
|
+
};
|
|
27196
|
+
const resolved = resolveSignatures(
|
|
25942
27197
|
[...own.interfaces, ...context.interfaces],
|
|
25943
27198
|
[...own.components, ...context.components],
|
|
25944
27199
|
[...own.types, ...context.types]
|
|
@@ -25977,6 +27232,7 @@ function judgePartAlone(config, scopeSubsystem) {
|
|
|
25977
27232
|
projectFamily: graph(),
|
|
25978
27233
|
exportUsages: [],
|
|
25979
27234
|
signatureFacts: partSignatures,
|
|
27235
|
+
typeSpellingFacts: partTypeSpellings,
|
|
25980
27236
|
pinnedExternals: [],
|
|
25981
27237
|
packSelections: packs.filter((p) => typeof p !== "string"),
|
|
25982
27238
|
packRequirements: [],
|
|
@@ -26032,7 +27288,7 @@ function builtinProjectKinds() {
|
|
|
26032
27288
|
return [...PROJECT_KINDS];
|
|
26033
27289
|
}
|
|
26034
27290
|
function computeGateStateId() {
|
|
26035
|
-
scanAllSpecs(
|
|
27291
|
+
scanAllSpecs();
|
|
26036
27292
|
const content = computeOwnStateId();
|
|
26037
27293
|
const extensions = loadProjectExtensions();
|
|
26038
27294
|
let gate = {};
|
|
@@ -26684,16 +27940,16 @@ function bindReferencedMembers(node, root) {
|
|
|
26684
27940
|
out.push({ ...base, sourceKind: "hosted", hosted: member.source.hosted });
|
|
26685
27941
|
continue;
|
|
26686
27942
|
}
|
|
26687
|
-
const
|
|
27943
|
+
const located2 = root.referenced.find((r) => r.alias === member.alias);
|
|
26688
27944
|
const sourceKind = member.storage === "git" ? "git" : "path";
|
|
26689
|
-
const directory =
|
|
26690
|
-
const commit2 =
|
|
27945
|
+
const directory = located2?.directory ?? (member.storage === "path" ? path20.resolve(node.directory, member.source.path ?? "") : void 0);
|
|
27946
|
+
const commit2 = located2?.commit ?? member.source.commit;
|
|
26691
27947
|
out.push({
|
|
26692
27948
|
...base,
|
|
26693
27949
|
sourceKind,
|
|
26694
27950
|
...directory !== void 0 ? { directory } : {},
|
|
26695
27951
|
...commit2 !== void 0 ? { commit: commit2 } : {},
|
|
26696
|
-
...
|
|
27952
|
+
...located2?.availability === "unavailable" ? { problem: located2.reason } : {}
|
|
26697
27953
|
});
|
|
26698
27954
|
}
|
|
26699
27955
|
return out;
|
|
@@ -27517,7 +28773,8 @@ function emptyIndex() {
|
|
|
27517
28773
|
type: {},
|
|
27518
28774
|
group: {}
|
|
27519
28775
|
},
|
|
27520
|
-
signatures: { sources: [], staleTexts: [] }
|
|
28776
|
+
signatures: { sources: [], staleTexts: [] },
|
|
28777
|
+
typeSpellings: emptyTypeSpellingFacts()
|
|
27521
28778
|
};
|
|
27522
28779
|
}
|
|
27523
28780
|
function isWithin(dir, file) {
|
|
@@ -27874,7 +29131,7 @@ function bareRawReferences(kind, spec) {
|
|
|
27874
29131
|
const out = [];
|
|
27875
29132
|
const seen = /* @__PURE__ */ new Set();
|
|
27876
29133
|
const add2 = (position, value, generics = /* @__PURE__ */ new Set()) => {
|
|
27877
|
-
if (!value || value.includes("::") ||
|
|
29134
|
+
if (!value || value.includes("::") || isTypeVocabulary(value) || generics.has(value.toLowerCase())) return;
|
|
27878
29135
|
const k = `${position}|${value}`;
|
|
27879
29136
|
if (seen.has(k)) return;
|
|
27880
29137
|
seen.add(k);
|
|
@@ -28294,6 +29551,49 @@ function bindImport(raw, suppliers, p) {
|
|
|
28294
29551
|
}
|
|
28295
29552
|
};
|
|
28296
29553
|
}
|
|
29554
|
+
function typePositionText(spec, at) {
|
|
29555
|
+
const [head2, name, member, param] = at.split(".");
|
|
29556
|
+
const named2 = (list, key) => Array.isArray(list) ? list.find((x) => x?.name === key) : void 0;
|
|
29557
|
+
if (head2 === "returns") return spec.returns;
|
|
29558
|
+
if (head2 === "params") return named2(spec.params, name)?.type;
|
|
29559
|
+
if (head2 === "fields") return named2(spec.fields, name)?.type;
|
|
29560
|
+
if (head2 !== "methods") return void 0;
|
|
29561
|
+
const method = named2(spec.methods, name);
|
|
29562
|
+
return member === "returns" ? method?.returns : named2(method?.params, param)?.type;
|
|
29563
|
+
}
|
|
29564
|
+
function writtenSignatureTexts(raws) {
|
|
29565
|
+
const texts = /* @__PURE__ */ new Map();
|
|
29566
|
+
const record = (kind, specId, methods) => {
|
|
29567
|
+
for (const m of methods) {
|
|
29568
|
+
if (m.signatureFrom !== void 0) continue;
|
|
29569
|
+
const derived = deriveMethodSignature(m);
|
|
29570
|
+
if (derived !== void 0) texts.set(`${kind}|${specId}|${m.name}`, derived);
|
|
29571
|
+
}
|
|
29572
|
+
};
|
|
29573
|
+
for (const raw of raws) {
|
|
29574
|
+
for (const intf of raw.index.interfaces) record("interface", intf.id, intf.methods ?? []);
|
|
29575
|
+
for (const type of raw.index.types) record("type", type.id, type.methods ?? []);
|
|
29576
|
+
}
|
|
29577
|
+
return texts;
|
|
29578
|
+
}
|
|
29579
|
+
function canonicalizeRootTypes(raws) {
|
|
29580
|
+
const facts = emptyTypeSpellingFacts();
|
|
29581
|
+
for (const raw of raws) {
|
|
29582
|
+
raw.index.interfaces = raw.index.interfaces.map((intf) => {
|
|
29583
|
+
const read2 = interfaceCanonicalTypes(intf);
|
|
29584
|
+
facts.respellings.push(...read2.respellings);
|
|
29585
|
+
facts.problems.push(...read2.problems);
|
|
29586
|
+
return read2.spec;
|
|
29587
|
+
});
|
|
29588
|
+
raw.index.types = raw.index.types.map((type) => {
|
|
29589
|
+
const read2 = typeCanonicalTypes(type);
|
|
29590
|
+
facts.respellings.push(...read2.respellings);
|
|
29591
|
+
facts.problems.push(...read2.problems);
|
|
29592
|
+
return read2.spec;
|
|
29593
|
+
});
|
|
29594
|
+
}
|
|
29595
|
+
return facts;
|
|
29596
|
+
}
|
|
28297
29597
|
function bindRootReferences(raw, raws, readables) {
|
|
28298
29598
|
const bound2 = /* @__PURE__ */ new Map();
|
|
28299
29599
|
for (const p of raw.pending) {
|
|
@@ -28388,7 +29688,8 @@ function specKind(raw) {
|
|
|
28388
29688
|
if ("component" in raw && Array.isArray(raw.methods)) return "interface";
|
|
28389
29689
|
if ("contract" in raw && Array.isArray(raw.methods)) return "implementation";
|
|
28390
29690
|
if ("kind" in raw && Array.isArray(raw.fields)) return "type";
|
|
28391
|
-
if (raw.kind === "signature") return "type";
|
|
29691
|
+
if (raw.kind === "signature" || raw.kind === "enum") return "type";
|
|
29692
|
+
if ("kind" in raw && typeof raw.holds === "string") return "type";
|
|
28392
29693
|
return void 0;
|
|
28393
29694
|
}
|
|
28394
29695
|
function rewriteSpecRefs(raw, remap) {
|
|
@@ -28686,12 +29987,12 @@ function pairSteps(before, after) {
|
|
|
28686
29987
|
const gapBefore = before.slice(oi + 1, oj).map((step, k) => ({ step, at: oi + 1 + k }));
|
|
28687
29988
|
const gapAfter = after.slice(ni + 1, nj).map((step, k) => ({ step, at: ni + 1 + k }));
|
|
28688
29989
|
const similar = commonRun(gapBefore, gapAfter, (x, y) => recognisablySame(x.step, y.step)).map(([x, y]) => [gapBefore[x].at, gapAfter[y].at]);
|
|
28689
|
-
const
|
|
28690
|
-
for (let k = 0; k <
|
|
28691
|
-
const [a0, b0] =
|
|
28692
|
-
const [a1, b1] =
|
|
29990
|
+
const inner2 = [[oi, ni], ...similar, [oj, nj]];
|
|
29991
|
+
for (let k = 0; k < inner2.length - 1; k++) {
|
|
29992
|
+
const [a0, b0] = inner2[k];
|
|
29993
|
+
const [a1, b1] = inner2[k + 1];
|
|
28693
29994
|
if (a1 - a0 === b1 - b0) for (let d = 1; d < a1 - a0; d++) pairs.push([a0 + d, b0 + d]);
|
|
28694
|
-
if (k <
|
|
29995
|
+
if (k < inner2.length - 2) pairs.push(inner2[k + 1]);
|
|
28695
29996
|
}
|
|
28696
29997
|
if (g < bounds.length - 2) pairs.push(bounds[g + 1]);
|
|
28697
29998
|
}
|
|
@@ -28898,7 +30199,7 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
|
|
|
28898
30199
|
var SpecWorkspace = class {
|
|
28899
30200
|
constructor(rootDir) {
|
|
28900
30201
|
this.cachedIndex = null;
|
|
28901
|
-
this.
|
|
30202
|
+
this.cachedDepth = null;
|
|
28902
30203
|
this.cachedSpecDirs = [];
|
|
28903
30204
|
this.cachedSignature = null;
|
|
28904
30205
|
this.lastSignatureCheckMs = 0;
|
|
@@ -28927,7 +30228,7 @@ var SpecWorkspace = class {
|
|
|
28927
30228
|
}
|
|
28928
30229
|
invalidate() {
|
|
28929
30230
|
this.cachedIndex = null;
|
|
28930
|
-
this.
|
|
30231
|
+
this.cachedDepth = null;
|
|
28931
30232
|
this.cachedSpecDirs = [];
|
|
28932
30233
|
this.cachedConfigFiles = [];
|
|
28933
30234
|
this.cachedRoots = [];
|
|
@@ -28942,8 +30243,8 @@ var SpecWorkspace = class {
|
|
|
28942
30243
|
// Scanning
|
|
28943
30244
|
// -------------------------------------------------------------------------
|
|
28944
30245
|
scanAll(options) {
|
|
28945
|
-
const
|
|
28946
|
-
if (this.cachedIndex && this.
|
|
30246
|
+
const maxDepth = options?.memberDepth ?? Infinity;
|
|
30247
|
+
if (this.cachedIndex && this.cachedDepth === maxDepth) {
|
|
28947
30248
|
const now = Date.now();
|
|
28948
30249
|
if (now - this.lastSignatureCheckMs <= SIGNATURE_TTL_MS) return this.cachedIndex;
|
|
28949
30250
|
this.lastSignatureCheckMs = now;
|
|
@@ -28951,10 +30252,9 @@ var SpecWorkspace = class {
|
|
|
28951
30252
|
this.invalidate();
|
|
28952
30253
|
}
|
|
28953
30254
|
this.loaderIssues = [];
|
|
28954
|
-
this.
|
|
30255
|
+
this.cachedDepth = maxDepth;
|
|
28955
30256
|
this.scanVisitedSpecDirs = [];
|
|
28956
30257
|
this.scanVisitedConfigFiles = [];
|
|
28957
|
-
const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
|
|
28958
30258
|
const scan = this.scanFamily(maxDepth);
|
|
28959
30259
|
this.cachedIndex = scan.index;
|
|
28960
30260
|
this.cachedRoots = scan.raws.map((raw) => raw.record);
|
|
@@ -28995,6 +30295,8 @@ var SpecWorkspace = class {
|
|
|
28995
30295
|
raws.forEach((raw) => this.bindAliases(raw, raws));
|
|
28996
30296
|
const readables = raws.map((raw) => readableOf(raw));
|
|
28997
30297
|
resolveFamilyTables(raws);
|
|
30298
|
+
const writtenTexts = writtenSignatureTexts(raws);
|
|
30299
|
+
const typeSpellings = canonicalizeRootTypes(raws);
|
|
28998
30300
|
raws.forEach((raw) => bindRootReferences(raw, raws, readables));
|
|
28999
30301
|
const index = emptyIndex();
|
|
29000
30302
|
for (const raw of raws) {
|
|
@@ -29009,7 +30311,11 @@ var SpecWorkspace = class {
|
|
|
29009
30311
|
const signatures = resolveTree(index.interfaces, index.components, index.types, raws.flatMap((r) => r.record.authoredReferences));
|
|
29010
30312
|
index.interfaces = signatures.interfaces;
|
|
29011
30313
|
index.types = signatures.types;
|
|
29012
|
-
index.signatures =
|
|
30314
|
+
index.signatures = {
|
|
30315
|
+
...signatures.facts,
|
|
30316
|
+
staleTexts: signatures.facts.staleTexts.filter((stale) => writtenTexts.get(`${stale.kind}|${stale.specId}|${stale.method}`) !== stale.stored)
|
|
30317
|
+
};
|
|
30318
|
+
index.typeSpellings = typeSpellings;
|
|
29013
30319
|
return { index, raws, readables };
|
|
29014
30320
|
}
|
|
29015
30321
|
/**
|
|
@@ -29155,26 +30461,26 @@ var SpecWorkspace = class {
|
|
|
29155
30461
|
decl.kind = "project";
|
|
29156
30462
|
return;
|
|
29157
30463
|
}
|
|
29158
|
-
const
|
|
29159
|
-
if (
|
|
29160
|
-
if ("unavailable" in
|
|
30464
|
+
const located2 = this.memberRoot(raw, decl);
|
|
30465
|
+
if (located2 === null) return;
|
|
30466
|
+
if ("unavailable" in located2) {
|
|
29161
30467
|
if (asserted === "project" || pinnedAsMember(raw.dir, decl.alias)) {
|
|
29162
30468
|
decl.kind = "project";
|
|
29163
|
-
raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason:
|
|
30469
|
+
raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
|
|
29164
30470
|
return;
|
|
29165
30471
|
}
|
|
29166
30472
|
decl.kind = "part";
|
|
29167
|
-
this.memberProblem(raw, "part-unavailable", decl.alias,
|
|
29168
|
-
raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason:
|
|
30473
|
+
this.memberProblem(raw, "part-unavailable", decl.alias, located2.unavailable);
|
|
30474
|
+
raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
|
|
29169
30475
|
return;
|
|
29170
30476
|
}
|
|
29171
|
-
const kind = projectContentAt(
|
|
30477
|
+
const kind = projectContentAt(located2.dir) ? "project" : "part";
|
|
29172
30478
|
decl.kind = kind;
|
|
29173
30479
|
if (asserted !== void 0 && asserted !== kind) {
|
|
29174
30480
|
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`"}`);
|
|
29175
30481
|
}
|
|
29176
|
-
if (kind === "part") this.readPart(raw, decl,
|
|
29177
|
-
else if (decl.storage !== "contained") this.recordReferenced(raw, decl,
|
|
30482
|
+
if (kind === "part") this.readPart(raw, decl, located2.dir, located2.commit);
|
|
30483
|
+
else if (decl.storage !== "contained") this.recordReferenced(raw, decl, located2.dir, located2.commit);
|
|
29178
30484
|
}
|
|
29179
30485
|
/**
|
|
29180
30486
|
* A referenced project member (stage 8): where its root is — the sibling
|
|
@@ -30073,7 +31379,8 @@ var SpecWorkspace = class {
|
|
|
30073
31379
|
* the owning project.
|
|
30074
31380
|
*/
|
|
30075
31381
|
prepareInterfaceForWrite(spec) {
|
|
30076
|
-
const
|
|
31382
|
+
const canonical3 = interfaceCanonicalTypes(spec).spec;
|
|
31383
|
+
const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedMethodSignature(m)) };
|
|
30077
31384
|
return this.relativizeSpec("interface", stored);
|
|
30078
31385
|
}
|
|
30079
31386
|
prepareImplementationForWrite(spec, carry = true) {
|
|
@@ -30084,9 +31391,14 @@ var SpecWorkspace = class {
|
|
|
30084
31391
|
const partDir = this.partHolding(this.getImplementationPath(spec.id, spec.contract))?.part.directory;
|
|
30085
31392
|
return partDir ? partRelativeFilePaths(relative19, this.rootDir, partDir) : relative19;
|
|
30086
31393
|
}
|
|
30087
|
-
/**
|
|
31394
|
+
/**
|
|
31395
|
+
* A type written in its stored form — every type position canonical (one
|
|
31396
|
+
* that is not canonical written as it stands), every params-bearing method's
|
|
31397
|
+
* text derived from them — relative to the owning project.
|
|
31398
|
+
*/
|
|
30088
31399
|
prepareTypeForWrite(spec) {
|
|
30089
|
-
const
|
|
31400
|
+
const canonical3 = typeCanonicalTypes(spec).spec;
|
|
31401
|
+
const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedTypeMethod(m)) };
|
|
30090
31402
|
return this.relativizeSpec("type", stored);
|
|
30091
31403
|
}
|
|
30092
31404
|
prepareGroupForWrite(spec) {
|
|
@@ -30297,7 +31609,7 @@ var SpecWorkspace = class {
|
|
|
30297
31609
|
if (!pathExists(p)) return null;
|
|
30298
31610
|
try {
|
|
30299
31611
|
const raw = readSpecFile(p);
|
|
30300
|
-
return resolveTree([InterfaceSpecSchema.parse(raw)], index.components, index.types).interfaces[0];
|
|
31612
|
+
return resolveTree([interfaceCanonicalTypes(InterfaceSpecSchema.parse(raw)).spec], index.components, index.types).interfaces[0];
|
|
30301
31613
|
} catch (e) {
|
|
30302
31614
|
this.loaderIssues.push({
|
|
30303
31615
|
severity: "error",
|
|
@@ -30873,6 +32185,33 @@ var SpecWorkspace = class {
|
|
|
30873
32185
|
index.listProjectRoots();
|
|
30874
32186
|
return this.cachedIndex.signatures;
|
|
30875
32187
|
}
|
|
32188
|
+
/**
|
|
32189
|
+
* A delta's merged spec with every type position canonical, IN PLACE (an
|
|
32190
|
+
* interface or a type; nothing else holds type positions). Answers the
|
|
32191
|
+
* respellings the write applies: each alias the merge holds — written by the
|
|
32192
|
+
* delta — and each alias the stored file still holds at a position the merge
|
|
32193
|
+
* kept, which the scan recorded and the save rewrites with it. A position
|
|
32194
|
+
* that is not canonical stays as written.
|
|
32195
|
+
*/
|
|
32196
|
+
canonicalizeMerged(kind, merged) {
|
|
32197
|
+
if (kind !== "interface" && kind !== "type") return [];
|
|
32198
|
+
const read2 = kind === "interface" ? interfaceCanonicalTypes(merged) : typeCanonicalTypes(merged);
|
|
32199
|
+
Object.assign(merged, read2.spec);
|
|
32200
|
+
const respelled = new Set(read2.respellings.map((r) => r.path));
|
|
32201
|
+
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);
|
|
32202
|
+
return [...read2.respellings, ...fromFile];
|
|
32203
|
+
}
|
|
32204
|
+
/**
|
|
32205
|
+
* ispec_index.typeSpellingFacts — what the current scan's type
|
|
32206
|
+
* canonicalisation recorded: every stored type position that is an alias of
|
|
32207
|
+
* its canonical spelling, and every one that is not canonical at all. Read
|
|
32208
|
+
* from the cached scan, rescanning first when the tree changed.
|
|
32209
|
+
*/
|
|
32210
|
+
typeSpellingFacts() {
|
|
32211
|
+
const index = this;
|
|
32212
|
+
index.listProjectRoots();
|
|
32213
|
+
return this.cachedIndex.typeSpellings;
|
|
32214
|
+
}
|
|
30876
32215
|
snapshotSpecFiles() {
|
|
30877
32216
|
const index = this.scanAll();
|
|
30878
32217
|
const snapshot = /* @__PURE__ */ new Map();
|
|
@@ -31483,6 +32822,7 @@ var SpecWorkspace = class {
|
|
|
31483
32822
|
const qualifiedDelta = qualifyDeltaRefs(mergeableDelta);
|
|
31484
32823
|
const mergedResult = mergeDelta(result, qualifiedDelta);
|
|
31485
32824
|
for (const field of unsetFields) delete mergedResult[field];
|
|
32825
|
+
const respellings = this.canonicalizeMerged(kind, mergedResult);
|
|
31486
32826
|
deriveMergedTexts(kind, mergedResult);
|
|
31487
32827
|
const withDefaults = deltaSchema.safeParse(mergedResult);
|
|
31488
32828
|
if (withDefaults.success) {
|
|
@@ -31523,6 +32863,7 @@ var SpecWorkspace = class {
|
|
|
31523
32863
|
changes,
|
|
31524
32864
|
ineffective,
|
|
31525
32865
|
notices,
|
|
32866
|
+
respellings: [],
|
|
31526
32867
|
testsToRevisit: [],
|
|
31527
32868
|
summary: `No change to ${kind} "${id}" \u2014 the delta matches what is stored, so nothing ${dryRun ? "would be" : "was"} written.`
|
|
31528
32869
|
};
|
|
@@ -31539,6 +32880,7 @@ var SpecWorkspace = class {
|
|
|
31539
32880
|
changes,
|
|
31540
32881
|
ineffective,
|
|
31541
32882
|
notices,
|
|
32883
|
+
respellings,
|
|
31542
32884
|
testsToRevisit: [],
|
|
31543
32885
|
...stripped.length ? { strippedKeys: stripped } : {},
|
|
31544
32886
|
summary: `Dry run on ${kind} "${id}": ${changes.length} change${changes.length === 1 ? "" : "s"} would be made. Nothing was written.`
|
|
@@ -31557,6 +32899,7 @@ var SpecWorkspace = class {
|
|
|
31557
32899
|
changes,
|
|
31558
32900
|
ineffective,
|
|
31559
32901
|
notices,
|
|
32902
|
+
respellings,
|
|
31560
32903
|
// The store never searches for tests: it holds the tree and knows
|
|
31561
32904
|
// nothing about the rule engine that reads code. The GATED write above
|
|
31562
32905
|
// it fills this in, which is also the only write path a human drives.
|
|
@@ -32111,6 +33454,7 @@ function moveChangeReports(edits, dryRun) {
|
|
|
32111
33454
|
changes,
|
|
32112
33455
|
ineffective: [],
|
|
32113
33456
|
notices: [],
|
|
33457
|
+
respellings: [],
|
|
32114
33458
|
testsToRevisit: [],
|
|
32115
33459
|
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"}.`
|
|
32116
33460
|
}));
|
|
@@ -32409,6 +33753,9 @@ function snapshotSpecFiles() {
|
|
|
32409
33753
|
function signatureFacts() {
|
|
32410
33754
|
return current().signatureFacts();
|
|
32411
33755
|
}
|
|
33756
|
+
function typeSpellingFacts() {
|
|
33757
|
+
return current().typeSpellingFacts();
|
|
33758
|
+
}
|
|
32412
33759
|
function findLegacySpecFiles() {
|
|
32413
33760
|
return current().findLegacySpecFiles();
|
|
32414
33761
|
}
|
|
@@ -35230,6 +36577,19 @@ function composeAgentBrief(agentId) {
|
|
|
35230
36577
|
## Project guidance
|
|
35231
36578
|
|
|
35232
36579
|
${guidance.trim()}
|
|
36580
|
+
`;
|
|
36581
|
+
}
|
|
36582
|
+
const language = implementationLanguage(record);
|
|
36583
|
+
const dialect = language ? typeDialectFor(language) : null;
|
|
36584
|
+
const typeMapping = dialect ? dialect.mappingLines() : void 0;
|
|
36585
|
+
if (typeMapping) {
|
|
36586
|
+
instructions = `${instructions.trimEnd()}
|
|
36587
|
+
|
|
36588
|
+
## Types in ${language}
|
|
36589
|
+
|
|
36590
|
+
Contracts speak wairon's neutral type grammar; write each type in ${language} as:
|
|
36591
|
+
|
|
36592
|
+
${typeMapping.map((line) => `- ${line}`).join("\n")}
|
|
35233
36593
|
`;
|
|
35234
36594
|
}
|
|
35235
36595
|
const profile = deriveExecutionProfile(record);
|
|
@@ -35243,10 +36603,28 @@ ${guidance.trim()}
|
|
|
35243
36603
|
readPaths: record.readPaths,
|
|
35244
36604
|
instructions,
|
|
35245
36605
|
variantGuidance: record.variantGuidance || void 0,
|
|
36606
|
+
...typeMapping ? { typeMapping } : {},
|
|
35246
36607
|
profile: budget ? profile : void 0,
|
|
35247
36608
|
budget
|
|
35248
36609
|
};
|
|
35249
36610
|
}
|
|
36611
|
+
function implementationLanguage(record) {
|
|
36612
|
+
const owned = new Set(record.ownedPaths);
|
|
36613
|
+
const implementations = loadImplementationSpecs().filter((impl) => implementationSourceFiles(impl).some((file) => owned.has(file)));
|
|
36614
|
+
for (const impl of implementations) {
|
|
36615
|
+
for (const technology of impl.technologies ?? []) {
|
|
36616
|
+
const name = typeof technology === "string" ? technology : technology.name;
|
|
36617
|
+
if (typeDialectFor(name)) return name.toLowerCase();
|
|
36618
|
+
}
|
|
36619
|
+
}
|
|
36620
|
+
for (const impl of implementations) {
|
|
36621
|
+
for (const file of implementationSourceFiles(impl)) {
|
|
36622
|
+
const language = languageOfSourcePath(file);
|
|
36623
|
+
if (language) return language;
|
|
36624
|
+
}
|
|
36625
|
+
}
|
|
36626
|
+
return void 0;
|
|
36627
|
+
}
|
|
35250
36628
|
function memberHop(agentId) {
|
|
35251
36629
|
const at = agentId.indexOf("::");
|
|
35252
36630
|
if (at < 0) return null;
|
|
@@ -35824,6 +37202,52 @@ function repairSignatures(apply3) {
|
|
|
35824
37202
|
return planned;
|
|
35825
37203
|
}
|
|
35826
37204
|
|
|
37205
|
+
// src/core/type-spelling-repair.ts
|
|
37206
|
+
function repairTypeSpellings(apply3) {
|
|
37207
|
+
const facts = typeSpellingFacts();
|
|
37208
|
+
const held = new Set(signatureFacts().sources.filter((f) => f.outcome === "restated" && f.differs).map((f) => f.interfaceId));
|
|
37209
|
+
const repairs = /* @__PURE__ */ new Map();
|
|
37210
|
+
const repairOf = (specId, kind) => {
|
|
37211
|
+
const key = `${kind}:${specId}`;
|
|
37212
|
+
let repair = repairs.get(key);
|
|
37213
|
+
if (!repair) {
|
|
37214
|
+
repair = { specId, kind, rewritten: [], proposals: [], authorNeeded: [] };
|
|
37215
|
+
repairs.set(key, repair);
|
|
37216
|
+
}
|
|
37217
|
+
return repair;
|
|
37218
|
+
};
|
|
37219
|
+
const own = (specId) => !specId.includes("::");
|
|
37220
|
+
for (const respelling of facts.respellings) {
|
|
37221
|
+
if (!own(respelling.specId)) continue;
|
|
37222
|
+
if (respelling.kind === "interface" && held.has(respelling.specId)) continue;
|
|
37223
|
+
repairOf(respelling.specId, respelling.kind).rewritten.push(respelling);
|
|
37224
|
+
}
|
|
37225
|
+
for (const problem of facts.problems) {
|
|
37226
|
+
if (problem.specId === void 0 || problem.kind === void 0 || !own(problem.specId)) continue;
|
|
37227
|
+
const repair = repairOf(problem.specId, problem.kind);
|
|
37228
|
+
const proposal = typeProblemIntProposal(problem);
|
|
37229
|
+
if (proposal) repair.proposals.push(proposal);
|
|
37230
|
+
else repair.authorNeeded.push(problem);
|
|
37231
|
+
}
|
|
37232
|
+
const planned = [...repairs.values()];
|
|
37233
|
+
const rewriting = planned.filter((repair) => repair.rewritten.length > 0);
|
|
37234
|
+
if (apply3 && rewriting.length > 0) {
|
|
37235
|
+
const interfaces = new Map(loadInterfaceSpecs().map((i) => [i.id, i]));
|
|
37236
|
+
const types = new Map(loadTypeSpecs().map((t) => [t.id, t]));
|
|
37237
|
+
for (const repair of rewriting) {
|
|
37238
|
+
if (repair.kind === "interface") {
|
|
37239
|
+
const intf = interfaces.get(repair.specId);
|
|
37240
|
+
if (intf) saveInterfaceSpec(intf);
|
|
37241
|
+
continue;
|
|
37242
|
+
}
|
|
37243
|
+
const type = types.get(repair.specId);
|
|
37244
|
+
if (type) saveSpec("type", type);
|
|
37245
|
+
}
|
|
37246
|
+
invalidateSpecCache();
|
|
37247
|
+
}
|
|
37248
|
+
return planned;
|
|
37249
|
+
}
|
|
37250
|
+
|
|
35827
37251
|
// src/core/approval.ts
|
|
35828
37252
|
var crypto7 = __toESM(require("crypto"));
|
|
35829
37253
|
var path35 = __toESM(require("path"));
|
|
@@ -36342,7 +37766,7 @@ function parentPinState(parent) {
|
|
|
36342
37766
|
}
|
|
36343
37767
|
function getStatusReport(options = {}, decor) {
|
|
36344
37768
|
const mark = fillDecor(decor);
|
|
36345
|
-
scanAllSpecs({
|
|
37769
|
+
scanAllSpecs({ memberDepth: options.memberDepth });
|
|
36346
37770
|
const system = loadSystemSpec();
|
|
36347
37771
|
const loaderErrors = getLoaderIssues();
|
|
36348
37772
|
if (loaderErrors.length > 0) {
|
|
@@ -36532,6 +37956,11 @@ function getStatusReport(options = {}, decor) {
|
|
|
36532
37956
|
}
|
|
36533
37957
|
|
|
36534
37958
|
// src/core/index.ts
|
|
37959
|
+
function resolveSignatures(interfaces, components, types) {
|
|
37960
|
+
const canonicalInterfaces = interfaces.map((intf) => interfaceCanonicalTypes(intf).spec);
|
|
37961
|
+
const canonicalTypes = types.map((type) => typeCanonicalTypes(type).spec);
|
|
37962
|
+
return resolveTree(canonicalInterfaces, components, canonicalTypes);
|
|
37963
|
+
}
|
|
36535
37964
|
function resolveDomains2() {
|
|
36536
37965
|
return resolveDomains();
|
|
36537
37966
|
}
|
|
@@ -36847,12 +38276,14 @@ function noticesFrom(verdict) {
|
|
|
36847
38276
|
...verdict.notices.map((n) => `${n.code} (notice): ${n.message}`)
|
|
36848
38277
|
];
|
|
36849
38278
|
}
|
|
36850
|
-
function componentCandidateGate(options = candidateOptions(), storedOwner) {
|
|
38279
|
+
function componentCandidateGate(options = candidateOptions(), storedOwner, stored) {
|
|
36851
38280
|
return {
|
|
36852
38281
|
gate: (kind, merged) => {
|
|
36853
38282
|
refuseUnknownOwner(kind, merged, storedOwner);
|
|
36854
38283
|
const restated = kind === "interface" ? restatedSources(merged.methods) : [];
|
|
36855
38284
|
if (restated.length) throw new Error(`${restatedSourceRefusal(String(merged.id), restated)} Nothing was written.`);
|
|
38285
|
+
const written = deltaWrittenTypeProblems(kind, merged, stored ?? null);
|
|
38286
|
+
if (written.length) throw new Error(`${typeProblemRefusal(kind, String(merged.id), written)} Nothing was written.`);
|
|
36856
38287
|
if (kind !== "component") return;
|
|
36857
38288
|
const verdict = validateComponentCandidate(merged, options);
|
|
36858
38289
|
if (verdict.errors.length) throw new Error(formatCandidateRefusal(verdict));
|
|
@@ -36860,6 +38291,22 @@ function componentCandidateGate(options = candidateOptions(), storedOwner) {
|
|
|
36860
38291
|
}
|
|
36861
38292
|
};
|
|
36862
38293
|
}
|
|
38294
|
+
function canonicalTypesOf(kind, spec) {
|
|
38295
|
+
if (!spec || typeof spec !== "object") return null;
|
|
38296
|
+
if (kind === "interface") return interfaceCanonicalTypes(spec);
|
|
38297
|
+
if (kind === "type") return typeCanonicalTypes(spec);
|
|
38298
|
+
return null;
|
|
38299
|
+
}
|
|
38300
|
+
function deltaWrittenTypeProblems(kind, merged, stored) {
|
|
38301
|
+
const now = canonicalTypesOf(kind, merged)?.problems ?? [];
|
|
38302
|
+
if (now.length === 0) return [];
|
|
38303
|
+
const before = new Set((canonicalTypesOf(kind, stored)?.problems ?? []).map((p) => `${p.path}|${p.written}`));
|
|
38304
|
+
return now.filter((p) => !before.has(`${p.path}|${p.written}`));
|
|
38305
|
+
}
|
|
38306
|
+
function typeProblemRefusal(kind, id, problems) {
|
|
38307
|
+
const lines = problems.map((p) => `${p.code} at ${p.path}: ${p.detail}${p.replacement ? ` \u2014 write ${p.replacement} instead` : ""}.`);
|
|
38308
|
+
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.`;
|
|
38309
|
+
}
|
|
36863
38310
|
function restatedSources(methods) {
|
|
36864
38311
|
if (!Array.isArray(methods)) return [];
|
|
36865
38312
|
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));
|
|
@@ -36965,6 +38412,11 @@ function applyRestatement(restatement, loaded, parent) {
|
|
|
36965
38412
|
`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.`
|
|
36966
38413
|
);
|
|
36967
38414
|
}
|
|
38415
|
+
const types = canonicalTypesOf(restatement.kind, candidate);
|
|
38416
|
+
if (types && types.problems.length) {
|
|
38417
|
+
return refused(restatement, replacedExisting, `${typeProblemRefusal(restatement.kind, String(candidate.id), types.problems)} Nothing was written.`);
|
|
38418
|
+
}
|
|
38419
|
+
if (types) Object.assign(candidate, types.spec);
|
|
36968
38420
|
const derivedNotices = deriveStatedTexts(restatement.kind, candidate);
|
|
36969
38421
|
const labelErrors = resolveLabelsOf(restatement.kind, candidate);
|
|
36970
38422
|
if (labelErrors.length) {
|
|
@@ -36978,7 +38430,8 @@ function applyRestatement(restatement, loaded, parent) {
|
|
|
36978
38430
|
...status.status ? { status: status.status } : {},
|
|
36979
38431
|
replacedExisting,
|
|
36980
38432
|
notices: [...existing ? rewriteNotices(restatement.kind, existing, candidate, carried, cleared) : [], ...derivedNotices],
|
|
36981
|
-
changedMethods: changedMethodsOf(restatement.kind, existing, candidate)
|
|
38433
|
+
changedMethods: changedMethodsOf(restatement.kind, existing, candidate),
|
|
38434
|
+
respellings: types?.respellings ?? []
|
|
36982
38435
|
};
|
|
36983
38436
|
}
|
|
36984
38437
|
var SPEC_SCHEMA = {
|
|
@@ -37017,7 +38470,7 @@ function parseCandidate(kind, candidate) {
|
|
|
37017
38470
|
};
|
|
37018
38471
|
}
|
|
37019
38472
|
function refused(restatement, replacedExisting, refusal2) {
|
|
37020
|
-
return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [] };
|
|
38473
|
+
return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [], respellings: [] };
|
|
37021
38474
|
}
|
|
37022
38475
|
function statusForCreate(restatement, existing) {
|
|
37023
38476
|
if (!STATUSED_KINDS.has(restatement.kind)) return {};
|
|
@@ -37162,6 +38615,7 @@ function writeSpec(restatement) {
|
|
|
37162
38615
|
replacedExisting: application.replacedExisting,
|
|
37163
38616
|
...application.status ? { status: application.status } : {},
|
|
37164
38617
|
notices: [...gateNotices, ...persisted.notices, ...application.notices],
|
|
38618
|
+
respellings: application.respellings,
|
|
37165
38619
|
testsToRevisit
|
|
37166
38620
|
};
|
|
37167
38621
|
}
|
|
@@ -37217,7 +38671,7 @@ function updateSpecGated(kind, id, delta, dryRun) {
|
|
|
37217
38671
|
const bound2 = candidateOptions();
|
|
37218
38672
|
const testRoots = bound2.rules?.conformance?.testRoots ?? [];
|
|
37219
38673
|
const stored = loadSpec(kind, id);
|
|
37220
|
-
const gate = componentCandidateGate(bound2, stored?.subsystem);
|
|
38674
|
+
const gate = componentCandidateGate(bound2, stored?.subsystem, stored);
|
|
37221
38675
|
const report2 = updateSpec(kind, id, delta, gate, dryRun);
|
|
37222
38676
|
const changed = changedMethods(report2);
|
|
37223
38677
|
if (changed.length > 0 && testRoots.length > 0) {
|
|
@@ -40641,7 +42095,7 @@ function errText(message) {
|
|
|
40641
42095
|
function errMessage(e) {
|
|
40642
42096
|
return errText(e instanceof Error ? e.message : String(e));
|
|
40643
42097
|
}
|
|
40644
|
-
var TYPE_REF_GRAMMAR = (what) => `${what}: a primitive
|
|
42098
|
+
var 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.`;
|
|
40645
42099
|
function structured(content, data) {
|
|
40646
42100
|
return { content: [{ type: "text", text: content }], structuredContent: data };
|
|
40647
42101
|
}
|
|
@@ -40736,6 +42190,7 @@ function renderChangeReport(report2) {
|
|
|
40736
42190
|
if (report2.strippedKeys?.length) {
|
|
40737
42191
|
lines.push("", `DROPPED FROM THE STORED FILE (${report2.dryRun ? "would be " : ""}removed \u2014 the schema does not know them):`, ...report2.strippedKeys.map((k) => `- ${k}`));
|
|
40738
42192
|
}
|
|
42193
|
+
lines.push(...renderRespellings(report2.respellings));
|
|
40739
42194
|
lines.push(...renderTestsToRevisit(report2.testsToRevisit));
|
|
40740
42195
|
return lines.join("\n");
|
|
40741
42196
|
}
|
|
@@ -40763,6 +42218,17 @@ function renderTestsToRevisit(entries) {
|
|
|
40763
42218
|
}
|
|
40764
42219
|
return lines;
|
|
40765
42220
|
}
|
|
42221
|
+
var typeRespellingOutput = import_zod11.z.object({
|
|
42222
|
+
specId: import_zod11.z.string().describe("The interface or type holding the position."),
|
|
42223
|
+
kind: import_zod11.z.enum(["interface", "type"]).describe("interface | type."),
|
|
42224
|
+
path: import_zod11.z.string().describe("Where in the spec: methods.save.params.key, methods.save.returns, fields.createdAt, params.listener."),
|
|
42225
|
+
written: import_zod11.z.string().describe("The text the input (or the stored file) held."),
|
|
42226
|
+
stored: import_zod11.z.string().describe("The canonical spelling, which is what is stored and shown.")
|
|
42227
|
+
});
|
|
42228
|
+
function renderRespellings(entries) {
|
|
42229
|
+
if (!entries.length) return [];
|
|
42230
|
+
return ["", "RESPELLED (stored canonical):", ...entries.map((r) => `- ${r.path}: "${r.written}" \u2192 "${r.stored}"`)];
|
|
42231
|
+
}
|
|
40766
42232
|
var specWriteReceiptOutput = {
|
|
40767
42233
|
kind: import_zod11.z.enum(SPEC_KINDS).describe("The spec kind written."),
|
|
40768
42234
|
id: import_zod11.z.string().describe('The id the spec is stored under; "system" for the L0 singleton.'),
|
|
@@ -40776,6 +42242,9 @@ var specWriteReceiptOutput = {
|
|
|
40776
42242
|
notices: import_zod11.z.array(import_zod11.z.string()).describe(
|
|
40777
42243
|
"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."
|
|
40778
42244
|
),
|
|
42245
|
+
respellings: import_zod11.z.array(typeRespellingOutput).describe(
|
|
42246
|
+
"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."
|
|
42247
|
+
),
|
|
40779
42248
|
testsToRevisit: testsToRevisitOutput,
|
|
40780
42249
|
...staleServerOutput
|
|
40781
42250
|
};
|
|
@@ -40784,8 +42253,10 @@ function writeReceipt(sentence, receipt) {
|
|
|
40784
42253
|
|
|
40785
42254
|
NOTICE:
|
|
40786
42255
|
- ${receipt.notices.join("\n- ")}` : "";
|
|
42256
|
+
const respelledBlock = renderRespellings(receipt.respellings).join("\n");
|
|
40787
42257
|
const testsBlock = renderTestsToRevisit(receipt.testsToRevisit).join("\n");
|
|
40788
|
-
return structured(`${sentence}${noticeBlock}${
|
|
42258
|
+
return structured(`${sentence}${noticeBlock}${respelledBlock ? `
|
|
42259
|
+
${respelledBlock}` : ""}${testsBlock ? `
|
|
40789
42260
|
${testsBlock}` : ""}`, receipt);
|
|
40790
42261
|
}
|
|
40791
42262
|
var specDeletionOutput = {
|
|
@@ -40817,6 +42288,9 @@ var specChangeReportOutput = {
|
|
|
40817
42288
|
"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."
|
|
40818
42289
|
),
|
|
40819
42290
|
notices: import_zod11.z.array(import_zod11.z.string()).describe("Store placement notices, gate warnings and delta notices."),
|
|
42291
|
+
respellings: import_zod11.z.array(typeRespellingOutput).describe(
|
|
42292
|
+
"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."
|
|
42293
|
+
),
|
|
40820
42294
|
summary: import_zod11.z.string().describe("One line for people."),
|
|
40821
42295
|
testsToRevisit: testsToRevisitOutput,
|
|
40822
42296
|
strippedKeys: import_zod11.z.array(import_zod11.z.string()).optional().describe(
|
|
@@ -41016,46 +42490,46 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
|
|
|
41016
42490
|
const known = seen.get(schema);
|
|
41017
42491
|
if (known !== void 0) return { ref: known };
|
|
41018
42492
|
seen.set(schema, seen.size);
|
|
41019
|
-
const
|
|
42493
|
+
const inner2 = (s) => schemaShape(s, seen);
|
|
41020
42494
|
const kind = String(def.typeName);
|
|
41021
42495
|
switch (kind) {
|
|
41022
42496
|
case "ZodObject": {
|
|
41023
42497
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
41024
42498
|
return {
|
|
41025
42499
|
kind,
|
|
41026
|
-
keys: Object.keys(shape).sort().map((key) => [key,
|
|
42500
|
+
keys: Object.keys(shape).sort().map((key) => [key, inner2(shape[key])]),
|
|
41027
42501
|
unknownKeys: def.unknownKeys,
|
|
41028
|
-
catchall:
|
|
42502
|
+
catchall: inner2(def.catchall)
|
|
41029
42503
|
};
|
|
41030
42504
|
}
|
|
41031
42505
|
case "ZodArray":
|
|
41032
|
-
return { kind, of:
|
|
42506
|
+
return { kind, of: inner2(def.type), min: def.minLength?.value, max: def.maxLength?.value };
|
|
41033
42507
|
case "ZodOptional":
|
|
41034
42508
|
case "ZodNullable":
|
|
41035
42509
|
case "ZodReadonly":
|
|
41036
42510
|
case "ZodBranded":
|
|
41037
42511
|
case "ZodCatch":
|
|
41038
|
-
return { kind, of:
|
|
42512
|
+
return { kind, of: inner2(def.innerType ?? def.type) };
|
|
41039
42513
|
case "ZodDefault":
|
|
41040
|
-
return { kind, of:
|
|
42514
|
+
return { kind, of: inner2(def.innerType), default: JSON.stringify(def.defaultValue?.()) };
|
|
41041
42515
|
case "ZodEffects":
|
|
41042
|
-
return { kind, effect: def.effect?.type, of:
|
|
42516
|
+
return { kind, effect: def.effect?.type, of: inner2(def.schema) };
|
|
41043
42517
|
case "ZodLazy":
|
|
41044
|
-
return { kind, of:
|
|
42518
|
+
return { kind, of: inner2(def.getter()) };
|
|
41045
42519
|
case "ZodUnion":
|
|
41046
42520
|
case "ZodDiscriminatedUnion": {
|
|
41047
42521
|
const options = def.options instanceof Map ? [...def.options.values()] : def.options;
|
|
41048
|
-
return { kind, discriminator: def.discriminator, of: options.map(
|
|
42522
|
+
return { kind, discriminator: def.discriminator, of: options.map(inner2) };
|
|
41049
42523
|
}
|
|
41050
42524
|
case "ZodIntersection":
|
|
41051
|
-
return { kind, left:
|
|
42525
|
+
return { kind, left: inner2(def.left), right: inner2(def.right) };
|
|
41052
42526
|
case "ZodTuple":
|
|
41053
|
-
return { kind, of: def.items.map(
|
|
42527
|
+
return { kind, of: def.items.map(inner2), rest: inner2(def.rest) };
|
|
41054
42528
|
case "ZodRecord":
|
|
41055
42529
|
case "ZodMap":
|
|
41056
|
-
return { kind, key:
|
|
42530
|
+
return { kind, key: inner2(def.keyType), value: inner2(def.valueType) };
|
|
41057
42531
|
case "ZodSet":
|
|
41058
|
-
return { kind, of:
|
|
42532
|
+
return { kind, of: inner2(def.valueType) };
|
|
41059
42533
|
case "ZodEnum":
|
|
41060
42534
|
return { kind, values: def.values };
|
|
41061
42535
|
case "ZodNativeEnum":
|
|
@@ -41063,7 +42537,7 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
|
|
|
41063
42537
|
case "ZodLiteral":
|
|
41064
42538
|
return { kind, value: def.value };
|
|
41065
42539
|
case "ZodPipeline":
|
|
41066
|
-
return { kind, in:
|
|
42540
|
+
return { kind, in: inner2(def.in), out: inner2(def.out) };
|
|
41067
42541
|
default:
|
|
41068
42542
|
return { kind, checks: def.checks?.map((c) => [c.kind, c.value ?? null]) ?? [] };
|
|
41069
42543
|
}
|
|
@@ -41791,7 +43265,7 @@ ${renderChangeReport(report2)}`,
|
|
|
41791
43265
|
type: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
|
|
41792
43266
|
description: import_zod11.z.string().optional(),
|
|
41793
43267
|
optional: import_zod11.z.boolean().optional().describe(
|
|
41794
|
-
'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
|
|
43268
|
+
'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).'
|
|
41795
43269
|
)
|
|
41796
43270
|
}).strict();
|
|
41797
43271
|
const interfaceMethodShape = {
|
|
@@ -42040,7 +43514,7 @@ ${renderChangeReport(report2)}`,
|
|
|
42040
43514
|
}
|
|
42041
43515
|
);
|
|
42042
43516
|
const typeInput = {
|
|
42043
|
-
kind: import_zod11.z.enum(["entity", "value-object", "signature"]).describe("entity (owned by a subsystem), value-object (often system-level shared),
|
|
43517
|
+
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"),
|
|
42044
43518
|
id: import_zod11.z.string().describe("Lowercase identifier"),
|
|
42045
43519
|
name: import_zod11.z.string().describe("Human-readable name"),
|
|
42046
43520
|
description: import_zod11.z.string().optional(),
|
|
@@ -42074,18 +43548,23 @@ ${renderChangeReport(report2)}`,
|
|
|
42074
43548
|
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)"),
|
|
42075
43549
|
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'),
|
|
42076
43550
|
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)"),
|
|
42077
|
-
returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output"))
|
|
43551
|
+
returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output")),
|
|
43552
|
+
values: import_zod11.z.array(import_zod11.z.object({
|
|
43553
|
+
name: import_zod11.z.string().min(1).describe(`The value's name, exactly as data carries it ("stable", "local_only")`),
|
|
43554
|
+
description: import_zod11.z.string().optional().describe("What the value means")
|
|
43555
|
+
}).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"),
|
|
43556
|
+
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?")')
|
|
42078
43557
|
};
|
|
42079
43558
|
const typeInputFields = Object.keys(typeInput);
|
|
42080
43559
|
reg(
|
|
42081
43560
|
server,
|
|
42082
43561
|
"sdd_add_type",
|
|
42083
43562
|
{
|
|
42084
|
-
description: "Define a type: an entity or value-object (the data components operate on),
|
|
43563
|
+
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.",
|
|
42085
43564
|
inputSchema: typeInput,
|
|
42086
43565
|
outputSchema: specWriteReceiptOutput
|
|
42087
43566
|
},
|
|
42088
|
-
({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns }) => {
|
|
43567
|
+
({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns, values, holds }) => {
|
|
42089
43568
|
try {
|
|
42090
43569
|
const spec = {
|
|
42091
43570
|
kind,
|
|
@@ -42111,7 +43590,9 @@ ${renderChangeReport(report2)}`,
|
|
|
42111
43590
|
...sourcePath ? { sourcePath } : {},
|
|
42112
43591
|
...symbol ? { symbol } : {},
|
|
42113
43592
|
...params ? { params } : {},
|
|
42114
|
-
...returns ? { returns } : {}
|
|
43593
|
+
...returns ? { returns } : {},
|
|
43594
|
+
...values ? { values } : {},
|
|
43595
|
+
...holds ? { holds } : {}
|
|
42115
43596
|
};
|
|
42116
43597
|
const receipt = writeSpec({ kind: "type", spec, fields: typeInputFields });
|
|
42117
43598
|
return writeReceipt(
|
|
@@ -42144,7 +43625,8 @@ ${renderChangeReport(report2)}`,
|
|
|
42144
43625
|
rules: config.rules,
|
|
42145
43626
|
projectType: config.projectType,
|
|
42146
43627
|
scopeSubsystem: subsystem,
|
|
42147
|
-
|
|
43628
|
+
// The tool's flag at the edge: recursive false is a member depth of 0.
|
|
43629
|
+
...recursive === false ? { memberDepth: 0 } : {},
|
|
42148
43630
|
family
|
|
42149
43631
|
};
|
|
42150
43632
|
const result = selectsFamily(options2, declaredMembers(config).length > 0) ? validateFamily(options2) : validateProject(options2);
|
|
@@ -42279,7 +43761,7 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
42279
43761
|
server,
|
|
42280
43762
|
"sdd_update_spec",
|
|
42281
43763
|
{
|
|
42282
|
-
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.",
|
|
43764
|
+
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.",
|
|
42283
43765
|
inputSchema: {
|
|
42284
43766
|
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})"),
|
|
42285
43767
|
id: import_zod11.z.string().describe("The ID of the spec to update (namespaced if needed)"),
|
|
@@ -42308,18 +43790,19 @@ ${testsBlock}` : ""}`, deletion);
|
|
|
42308
43790
|
}
|
|
42309
43791
|
},
|
|
42310
43792
|
({ subsystem, recursive }) => {
|
|
43793
|
+
const memberDepth = recursive === false ? 0 : void 0;
|
|
42311
43794
|
const banner = pendingBanner().map((line) => `\u26A0 TRANSACTION PENDING: ${line}
|
|
42312
43795
|
`).join("");
|
|
42313
43796
|
try {
|
|
42314
43797
|
let approvals;
|
|
42315
43798
|
try {
|
|
42316
|
-
approvals = familyApprovals(
|
|
43799
|
+
approvals = familyApprovals(memberDepth);
|
|
42317
43800
|
} catch {
|
|
42318
43801
|
approvals = void 0;
|
|
42319
43802
|
}
|
|
42320
43803
|
const report2 = getStatusReport({
|
|
42321
43804
|
subsystem,
|
|
42322
|
-
|
|
43805
|
+
memberDepth,
|
|
42323
43806
|
approvals
|
|
42324
43807
|
});
|
|
42325
43808
|
const family = statusFamilyContext();
|
|
@@ -42414,7 +43897,6 @@ function loadProjectConfig3() {
|
|
|
42414
43897
|
AgentTemplateSchema,
|
|
42415
43898
|
BACKEND_COMMANDS,
|
|
42416
43899
|
BUILTIN_PROFILES,
|
|
42417
|
-
BUILTIN_TYPES,
|
|
42418
43900
|
BoundaryItemSchema,
|
|
42419
43901
|
BuiltinTargetConfigSchema,
|
|
42420
43902
|
BuiltinTargetSchema,
|
|
@@ -42448,6 +43930,7 @@ function loadProjectConfig3() {
|
|
|
42448
43930
|
DurabilitySchema,
|
|
42449
43931
|
EXTERNAL_ALIAS_RE,
|
|
42450
43932
|
EndpointSchema,
|
|
43933
|
+
EnumValueSchema,
|
|
42451
43934
|
EventBindingSchema,
|
|
42452
43935
|
ExtDataSchema,
|
|
42453
43936
|
ExternalDeclarationSchema,
|
|
@@ -42462,6 +43945,7 @@ function loadProjectConfig3() {
|
|
|
42462
43945
|
GeminiExporter,
|
|
42463
43946
|
GroupSpecSchema,
|
|
42464
43947
|
GuaranteeSchema,
|
|
43948
|
+
HOLDABLE_PRIMITIVES,
|
|
42465
43949
|
HttpMethodSchema,
|
|
42466
43950
|
ImplementationSpecSchema,
|
|
42467
43951
|
InterfaceSpecSchema,
|
|
@@ -42481,6 +43965,7 @@ function loadProjectConfig3() {
|
|
|
42481
43965
|
NarrativeStepTypeSchema,
|
|
42482
43966
|
OutputTargetSchema,
|
|
42483
43967
|
PATTERN_TYPES,
|
|
43968
|
+
PRIMITIVE_TYPES,
|
|
42484
43969
|
PROJECT_ID_RE,
|
|
42485
43970
|
PROJECT_KINDS,
|
|
42486
43971
|
PUBLIC_NAME_RE,
|
|
@@ -42568,6 +44053,7 @@ function loadProjectConfig3() {
|
|
|
42568
44053
|
buildRuleContext,
|
|
42569
44054
|
callSitesOf,
|
|
42570
44055
|
canonicalTypeRef,
|
|
44056
|
+
canonicalTypeText,
|
|
42571
44057
|
captureApprovedSpecs,
|
|
42572
44058
|
checkDeclarativePack,
|
|
42573
44059
|
clearLoaderIssues,
|
|
@@ -42612,6 +44098,7 @@ function loadProjectConfig3() {
|
|
|
42612
44098
|
detectDomainCandidates,
|
|
42613
44099
|
diagnoseProjectPacks,
|
|
42614
44100
|
diagramSetIndex,
|
|
44101
|
+
dialectOf,
|
|
42615
44102
|
diffAgainstApproval,
|
|
42616
44103
|
diffSize,
|
|
42617
44104
|
discoverPacks,
|
|
@@ -42619,6 +44106,7 @@ function loadProjectConfig3() {
|
|
|
42619
44106
|
effectiveDetail,
|
|
42620
44107
|
effectiveProjectId,
|
|
42621
44108
|
emptyExtensions,
|
|
44109
|
+
emptyTypeSpellingFacts,
|
|
42622
44110
|
ensureDir,
|
|
42623
44111
|
ensureProjectInitialized,
|
|
42624
44112
|
excerptParent,
|
|
@@ -42665,6 +44153,7 @@ function loadProjectConfig3() {
|
|
|
42665
44153
|
importSpecTree,
|
|
42666
44154
|
injectGuide,
|
|
42667
44155
|
installPackFromDirectory,
|
|
44156
|
+
interfaceCanonicalTypes,
|
|
42668
44157
|
interfaceGenericParameters,
|
|
42669
44158
|
internalizeMember,
|
|
42670
44159
|
isDraftSubsystem,
|
|
@@ -42676,9 +44165,11 @@ function loadProjectConfig3() {
|
|
|
42676
44165
|
isProjectInitialized,
|
|
42677
44166
|
isProvidedBy,
|
|
42678
44167
|
isRetired,
|
|
44168
|
+
isTypeVocabulary,
|
|
42679
44169
|
judgesCode,
|
|
42680
44170
|
keyIn,
|
|
42681
44171
|
landReference,
|
|
44172
|
+
languageOfSourcePath,
|
|
42682
44173
|
listDirectChainedSubprojects,
|
|
42683
44174
|
listFiles,
|
|
42684
44175
|
listFilesRecursive,
|
|
@@ -42721,6 +44212,7 @@ function loadProjectConfig3() {
|
|
|
42721
44212
|
moveMethods,
|
|
42722
44213
|
moveMountToMembers,
|
|
42723
44214
|
nameKey,
|
|
44215
|
+
namesAnInteger,
|
|
42724
44216
|
narrativeStepForeignFields,
|
|
42725
44217
|
normalizeReferences,
|
|
42726
44218
|
ownerOf,
|
|
@@ -42732,6 +44224,8 @@ function loadProjectConfig3() {
|
|
|
42732
44224
|
parseDeclarativePack,
|
|
42733
44225
|
parseDeclaredCall,
|
|
42734
44226
|
parseMemberSource,
|
|
44227
|
+
parseTypeExpression,
|
|
44228
|
+
parseTypePosition,
|
|
42735
44229
|
parseYaml,
|
|
42736
44230
|
passesIntentFloor,
|
|
42737
44231
|
pathExists,
|
|
@@ -42745,6 +44239,7 @@ function loadProjectConfig3() {
|
|
|
42745
44239
|
provisionProject,
|
|
42746
44240
|
qualifiedTypeId,
|
|
42747
44241
|
rangeProblem,
|
|
44242
|
+
readCodeAnnotation,
|
|
42748
44243
|
readFileOrNull,
|
|
42749
44244
|
readJsonFile,
|
|
42750
44245
|
readLockRecord,
|
|
@@ -42767,6 +44262,7 @@ function loadProjectConfig3() {
|
|
|
42767
44262
|
renderDiagram,
|
|
42768
44263
|
repairForeignStepFields,
|
|
42769
44264
|
repairSignatures,
|
|
44265
|
+
repairTypeSpellings,
|
|
42770
44266
|
repointExternal,
|
|
42771
44267
|
requiredPolicies,
|
|
42772
44268
|
resolveAgentTopology,
|
|
@@ -42814,9 +44310,15 @@ function loadProjectConfig3() {
|
|
|
42814
44310
|
technologyTokens,
|
|
42815
44311
|
toMarkdown,
|
|
42816
44312
|
typeBindingOf,
|
|
44313
|
+
typeCanonicalTypes,
|
|
44314
|
+
typeDialectFor,
|
|
42817
44315
|
typeGenericParameters,
|
|
44316
|
+
typeIsMany,
|
|
42818
44317
|
typeMatchesRef,
|
|
44318
|
+
typeNamedRefs,
|
|
44319
|
+
typeProblemIntProposal,
|
|
42819
44320
|
typeSourceFiles,
|
|
44321
|
+
typeSpellingFacts,
|
|
42820
44322
|
uninstallPack,
|
|
42821
44323
|
updateMember,
|
|
42822
44324
|
updateSpec,
|
|
@@ -42831,6 +44333,7 @@ function loadProjectConfig3() {
|
|
|
42831
44333
|
writeReachDenials,
|
|
42832
44334
|
writeReachPermits,
|
|
42833
44335
|
writeRootGuideDelegator,
|
|
42834
|
-
writeYamlFile
|
|
44336
|
+
writeYamlFile,
|
|
44337
|
+
writtenTypeRefs
|
|
42835
44338
|
});
|
|
42836
44339
|
//# sourceMappingURL=index.js.map
|