@formspec/build 0.1.0-alpha.30 → 0.1.0-alpha.32
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/README.md +82 -5
- package/dist/analyzer/class-analyzer.d.ts +6 -0
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/browser.cjs +166 -24
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +166 -24
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +180 -0
- package/dist/build-beta.d.ts +180 -0
- package/dist/build-internal.d.ts +180 -0
- package/dist/build.d.ts +180 -0
- package/dist/cli.cjs +584 -33
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +582 -33
- package/dist/cli.js.map +1 -1
- package/dist/generators/discovered-schema.d.ts +112 -0
- package/dist/generators/discovered-schema.d.ts.map +1 -0
- package/dist/index.cjs +573 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +565 -33
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +197 -33
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +197 -33
- package/dist/internals.js.map +1 -1
- package/dist/static-build.d.ts +61 -0
- package/dist/static-build.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,11 +19,11 @@ Most app code can use `formspec`, but use `@formspec/build` directly when you ne
|
|
|
19
19
|
|
|
20
20
|
## Public Entry Points
|
|
21
21
|
|
|
22
|
-
| Entry point | Purpose
|
|
23
|
-
| --------------------------- |
|
|
24
|
-
| `@formspec/build` | Public build APIs
|
|
25
|
-
| `@formspec/build/browser` | Browser-safe chain-DSL and IR surface
|
|
26
|
-
| `@formspec/build/internals` | Unstable low-level IR/analyzer APIs
|
|
22
|
+
| Entry point | Purpose |
|
|
23
|
+
| --------------------------- | ------------------------------------- |
|
|
24
|
+
| `@formspec/build` | Public build APIs |
|
|
25
|
+
| `@formspec/build/browser` | Browser-safe chain-DSL and IR surface |
|
|
26
|
+
| `@formspec/build/internals` | Unstable low-level IR/analyzer APIs |
|
|
27
27
|
|
|
28
28
|
## Chain DSL Generation
|
|
29
29
|
|
|
@@ -63,6 +63,83 @@ const result = generateSchemasFromClass({
|
|
|
63
63
|
});
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
### Static Build Context
|
|
67
|
+
|
|
68
|
+
Use the static build context APIs when you need to inspect exports, declarations,
|
|
69
|
+
or method signatures before deciding what schemas to generate.
|
|
70
|
+
|
|
71
|
+
Public helpers in this workflow:
|
|
72
|
+
|
|
73
|
+
- `createStaticBuildContext(filePath)` - Create a reusable compiler-backed context from a file.
|
|
74
|
+
- `createStaticBuildContextFromProgram(program, filePath)` - Reuse a host-owned `ts.Program`.
|
|
75
|
+
- `resolveModuleExport(context, exportName?)` - Resolve any exported symbol, including functions and other non-schema declarations.
|
|
76
|
+
- `resolveModuleExportDeclaration(context, exportName?)` - Resolve only schema-source declarations (`class`, `interface`, `type` alias).
|
|
77
|
+
- `generateSchemasFromDeclaration(...)` - Generate from a resolved schema-source declaration.
|
|
78
|
+
- `generateSchemasFromParameter(...)` - Generate from a method or function parameter declaration.
|
|
79
|
+
- `generateSchemasFromReturnType(...)` - Generate from a method or function return type.
|
|
80
|
+
- `generateSchemasFromType(...)` - Generate directly from a resolved `ts.Type`.
|
|
81
|
+
|
|
82
|
+
Use `resolveModuleExportDeclaration(...)` when your tooling wants to hand a resolved
|
|
83
|
+
declaration straight to `generateSchemasFromDeclaration(...)`. Use `resolveModuleExport(...)`
|
|
84
|
+
when you need lower-level TypeScript access first, for example to inspect a function
|
|
85
|
+
export and then generate schemas from one of its signature types.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import * as ts from "typescript";
|
|
89
|
+
import {
|
|
90
|
+
createStaticBuildContext,
|
|
91
|
+
generateSchemasFromDeclaration,
|
|
92
|
+
generateSchemasFromParameter,
|
|
93
|
+
generateSchemasFromReturnType,
|
|
94
|
+
resolveModuleExport,
|
|
95
|
+
resolveModuleExportDeclaration,
|
|
96
|
+
} from "@formspec/build";
|
|
97
|
+
|
|
98
|
+
const context = createStaticBuildContext("./src/service.ts");
|
|
99
|
+
const serviceDeclaration = resolveModuleExportDeclaration(context, "PaymentService");
|
|
100
|
+
|
|
101
|
+
if (serviceDeclaration && ts.isClassDeclaration(serviceDeclaration)) {
|
|
102
|
+
const submitMethod = serviceDeclaration.members.find(
|
|
103
|
+
(member): member is ts.MethodDeclaration =>
|
|
104
|
+
ts.isMethodDeclaration(member) &&
|
|
105
|
+
ts.isIdentifier(member.name) &&
|
|
106
|
+
member.name.text === "submit"
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (submitMethod?.parameters[0]) {
|
|
110
|
+
const inputSchemas = generateSchemasFromParameter({
|
|
111
|
+
context,
|
|
112
|
+
parameter: submitMethod.parameters[0],
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const inputDeclaration = resolveModuleExportDeclaration(context, "SubmitInput");
|
|
118
|
+
if (inputDeclaration) {
|
|
119
|
+
const inputSchemas = generateSchemasFromDeclaration({
|
|
120
|
+
context,
|
|
121
|
+
declaration: inputDeclaration,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const paymentSymbol = resolveModuleExport(context, "submitPayment");
|
|
126
|
+
const paymentDeclaration = paymentSymbol?.declarations?.find(ts.isFunctionDeclaration);
|
|
127
|
+
if (paymentDeclaration) {
|
|
128
|
+
const outputSchemas = generateSchemasFromReturnType({
|
|
129
|
+
context,
|
|
130
|
+
declaration: paymentDeclaration,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If you already own a `ts.Program`, use `createStaticBuildContextFromProgram(program, filePath)`
|
|
136
|
+
instead of letting FormSpec create one. If your tool has already resolved a raw
|
|
137
|
+
`ts.Type` or signature declaration, use `generateSchemasFromType(...)` or
|
|
138
|
+
`generateSchemasFromReturnType(...)` directly.
|
|
139
|
+
|
|
140
|
+
This is the supported public path for build-time analysis workflows that used to
|
|
141
|
+
require `@formspec/build/internals`.
|
|
142
|
+
|
|
66
143
|
### Supported TSDoc Examples
|
|
67
144
|
|
|
68
145
|
```ts
|
|
@@ -57,7 +57,13 @@ export type AnalyzeTypeAliasToIRResult = {
|
|
|
57
57
|
readonly ok: false;
|
|
58
58
|
readonly error: string;
|
|
59
59
|
};
|
|
60
|
+
export interface DeclarationRootInfo {
|
|
61
|
+
readonly metadata?: ResolvedMetadata;
|
|
62
|
+
readonly annotations: readonly AnnotationNode[];
|
|
63
|
+
readonly diagnostics: readonly ConstraintSemanticDiagnostic[];
|
|
64
|
+
}
|
|
60
65
|
type AnalyzerMetadataPolicy = ReturnType<typeof normalizeMetadataPolicy>;
|
|
66
|
+
export declare function analyzeDeclarationRootInfo(declaration: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeAliasDeclaration, checker: ts.TypeChecker, file?: string, extensionRegistry?: ExtensionRegistry, metadataPolicy?: MetadataPolicyInput): DeclarationRootInfo;
|
|
61
67
|
/**
|
|
62
68
|
* Analyzes a class declaration and produces canonical IR FieldNodes.
|
|
63
69
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/class-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAEL,KAAK,4BAA4B,EAElC,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EAIR,cAAc,EAId,cAAc,EACd,SAAS,EACT,gBAAgB,EAEjB,MAAM,0BAA0B,CAAC;AAQlC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAGL,uBAAuB,EAExB,MAAM,sBAAsB,CAAC;AAoE9B;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;CAC3E;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,gBAAgB;IAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtD,kDAAkD;IAClD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACtD,wDAAwD;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,4BAA4B,EAAE,CAAC;IAC/D,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,SAAS,UAAU,EAAE,CAAC;IAChD,qBAAqB;IACrB,QAAQ,CAAC,aAAa,EAAE,SAAS,UAAU,EAAE,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAClC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"class-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/class-analyzer.ts"],"names":[],"mappings":"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"}
|
package/dist/browser.cjs
CHANGED
|
@@ -757,9 +757,9 @@ function collectFields(elements, properties, required, ctx) {
|
|
|
757
757
|
for (const element of elements) {
|
|
758
758
|
switch (element.kind) {
|
|
759
759
|
case "field":
|
|
760
|
-
properties[
|
|
760
|
+
properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
|
|
761
761
|
if (element.required) {
|
|
762
|
-
required.push(
|
|
762
|
+
required.push(getSerializedFieldName(element));
|
|
763
763
|
}
|
|
764
764
|
break;
|
|
765
765
|
case "group":
|
|
@@ -830,19 +830,21 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
|
|
|
830
830
|
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
|
|
831
831
|
return schema;
|
|
832
832
|
}
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
833
|
+
const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
|
|
834
|
+
const nullableValueBranch = getNullableUnionValueSchema(schema);
|
|
835
|
+
if (nullableValueBranch !== void 0) {
|
|
836
|
+
const updatedNullableValueBranch = applyPathTargetedConstraints(
|
|
837
|
+
nullableValueBranch,
|
|
838
|
+
pathConstraints,
|
|
839
|
+
ctx,
|
|
840
|
+
resolveTraversableTypeNode(typeNode, ctx)
|
|
841
|
+
);
|
|
842
|
+
if (schema.oneOf !== void 0) {
|
|
843
|
+
schema.oneOf = schema.oneOf.map(
|
|
844
|
+
(branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
return schema;
|
|
846
848
|
}
|
|
847
849
|
if (schema.$ref) {
|
|
848
850
|
const { $ref, ...rest } = schema;
|
|
@@ -857,7 +859,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
|
|
|
857
859
|
const missingOverrides = {};
|
|
858
860
|
for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
|
|
859
861
|
if (schema.properties[target]) {
|
|
860
|
-
|
|
862
|
+
mergeSchemaOverride(schema.properties[target], overrideSchema);
|
|
861
863
|
} else {
|
|
862
864
|
missingOverrides[target] = overrideSchema;
|
|
863
865
|
}
|
|
@@ -931,7 +933,7 @@ function generateObjectType(type, ctx) {
|
|
|
931
933
|
const properties = {};
|
|
932
934
|
const required = [];
|
|
933
935
|
for (const prop of type.properties) {
|
|
934
|
-
const propertyName =
|
|
936
|
+
const propertyName = getSerializedObjectPropertyName(prop);
|
|
935
937
|
properties[propertyName] = generatePropertySchema(prop, ctx);
|
|
936
938
|
if (!prop.optional) {
|
|
937
939
|
required.push(propertyName);
|
|
@@ -985,7 +987,16 @@ function isNullableUnion(type) {
|
|
|
985
987
|
return nullCount === 1;
|
|
986
988
|
}
|
|
987
989
|
function generateReferenceType(type, ctx) {
|
|
988
|
-
return { $ref: `#/$defs/${
|
|
990
|
+
return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
|
|
991
|
+
}
|
|
992
|
+
function getSerializedFieldName(field) {
|
|
993
|
+
return getSerializedName(field.name, field.metadata);
|
|
994
|
+
}
|
|
995
|
+
function getSerializedObjectPropertyName(property) {
|
|
996
|
+
return getSerializedName(property.name, property.metadata);
|
|
997
|
+
}
|
|
998
|
+
function getSerializedTypeName(logicalName, ctx) {
|
|
999
|
+
return ctx.typeNameMap[logicalName] ?? logicalName;
|
|
989
1000
|
}
|
|
990
1001
|
function applyResolvedMetadata(schema, metadata) {
|
|
991
1002
|
const displayName = getDisplayName(metadata);
|
|
@@ -996,17 +1007,148 @@ function applyResolvedMetadata(schema, metadata) {
|
|
|
996
1007
|
function resolveReferencedType(type, ctx) {
|
|
997
1008
|
return ctx.typeRegistry[type.name]?.type;
|
|
998
1009
|
}
|
|
1010
|
+
function dereferenceTypeNode(typeNode, ctx) {
|
|
1011
|
+
if (typeNode?.kind !== "reference") {
|
|
1012
|
+
return typeNode;
|
|
1013
|
+
}
|
|
1014
|
+
return resolveReferencedType(typeNode, ctx);
|
|
1015
|
+
}
|
|
1016
|
+
function unwrapNullableTypeNode(typeNode) {
|
|
1017
|
+
if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
|
|
1018
|
+
return typeNode;
|
|
1019
|
+
}
|
|
1020
|
+
return typeNode.members.find(
|
|
1021
|
+
(member) => !(member.kind === "primitive" && member.primitiveKind === "null")
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
function resolveTraversableTypeNode(typeNode, ctx) {
|
|
1025
|
+
const dereferenced = dereferenceTypeNode(typeNode, ctx);
|
|
1026
|
+
const unwrapped = unwrapNullableTypeNode(dereferenced);
|
|
1027
|
+
if (unwrapped !== dereferenced) {
|
|
1028
|
+
return resolveTraversableTypeNode(unwrapped, ctx);
|
|
1029
|
+
}
|
|
1030
|
+
return dereferenced;
|
|
1031
|
+
}
|
|
999
1032
|
function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
return
|
|
1033
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1034
|
+
if (effectiveType?.kind === "array") {
|
|
1035
|
+
return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
|
|
1003
1036
|
}
|
|
1004
|
-
if (
|
|
1005
|
-
const
|
|
1006
|
-
return
|
|
1037
|
+
if (effectiveType?.kind === "object") {
|
|
1038
|
+
const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
|
|
1039
|
+
return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
|
|
1007
1040
|
}
|
|
1008
1041
|
return logicalName;
|
|
1009
1042
|
}
|
|
1043
|
+
function resolveTargetTypeNode(logicalName, typeNode, ctx) {
|
|
1044
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1045
|
+
if (effectiveType?.kind === "array") {
|
|
1046
|
+
return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
|
|
1047
|
+
}
|
|
1048
|
+
if (effectiveType?.kind !== "object") {
|
|
1049
|
+
return void 0;
|
|
1050
|
+
}
|
|
1051
|
+
return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
|
|
1052
|
+
}
|
|
1053
|
+
function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
|
|
1054
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
1055
|
+
for (const constraint of pathConstraints) {
|
|
1056
|
+
const target = constraint.path?.segments[0];
|
|
1057
|
+
if (!target) {
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
const grouped = byTarget.get(target) ?? [];
|
|
1061
|
+
grouped.push(constraint);
|
|
1062
|
+
byTarget.set(target, grouped);
|
|
1063
|
+
}
|
|
1064
|
+
const overrides = {};
|
|
1065
|
+
for (const [target, constraints] of byTarget) {
|
|
1066
|
+
overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
|
|
1067
|
+
constraints.map(stripLeadingPathSegment),
|
|
1068
|
+
resolveTargetTypeNode(target, typeNode, ctx),
|
|
1069
|
+
ctx
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
return overrides;
|
|
1073
|
+
}
|
|
1074
|
+
function buildPathOverrideSchema(constraints, typeNode, ctx) {
|
|
1075
|
+
const schema = {};
|
|
1076
|
+
const directConstraints = [];
|
|
1077
|
+
const nestedConstraints = [];
|
|
1078
|
+
for (const constraint of constraints) {
|
|
1079
|
+
if (constraint.path === void 0 || constraint.path.segments.length === 0) {
|
|
1080
|
+
directConstraints.push(constraint);
|
|
1081
|
+
} else {
|
|
1082
|
+
nestedConstraints.push(constraint);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
1086
|
+
if (nestedConstraints.length === 0) {
|
|
1087
|
+
return schema;
|
|
1088
|
+
}
|
|
1089
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1090
|
+
if (effectiveType?.kind === "array") {
|
|
1091
|
+
schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
|
|
1092
|
+
return schema;
|
|
1093
|
+
}
|
|
1094
|
+
schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
|
|
1095
|
+
return schema;
|
|
1096
|
+
}
|
|
1097
|
+
function mergeSchemaOverride(target, override) {
|
|
1098
|
+
const nullableValueBranch = getNullableUnionValueSchema(target);
|
|
1099
|
+
if (nullableValueBranch !== void 0) {
|
|
1100
|
+
mergeSchemaOverride(nullableValueBranch, override);
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
if (override.properties !== void 0) {
|
|
1104
|
+
const mergedProperties = target.properties ?? {};
|
|
1105
|
+
for (const [name, propertyOverride] of Object.entries(override.properties)) {
|
|
1106
|
+
const existing = mergedProperties[name];
|
|
1107
|
+
if (existing === void 0) {
|
|
1108
|
+
mergedProperties[name] = propertyOverride;
|
|
1109
|
+
} else {
|
|
1110
|
+
mergeSchemaOverride(existing, propertyOverride);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
target.properties = mergedProperties;
|
|
1114
|
+
}
|
|
1115
|
+
if (override.items !== void 0) {
|
|
1116
|
+
if (target.items === void 0) {
|
|
1117
|
+
target.items = override.items;
|
|
1118
|
+
} else {
|
|
1119
|
+
mergeSchemaOverride(target.items, override.items);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
for (const [key, value] of Object.entries(override)) {
|
|
1123
|
+
if (key === "properties" || key === "items") {
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
target[key] = value;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function stripLeadingPathSegment(constraint) {
|
|
1130
|
+
const segments = constraint.path?.segments;
|
|
1131
|
+
if (segments === void 0 || segments.length === 0) {
|
|
1132
|
+
return constraint;
|
|
1133
|
+
}
|
|
1134
|
+
const [, ...rest] = segments;
|
|
1135
|
+
if (rest.length === 0) {
|
|
1136
|
+
const { path: _path, ...stripped } = constraint;
|
|
1137
|
+
return stripped;
|
|
1138
|
+
}
|
|
1139
|
+
return {
|
|
1140
|
+
...constraint,
|
|
1141
|
+
path: { segments: rest }
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
function getNullableUnionValueSchema(schema) {
|
|
1145
|
+
if (schema.oneOf?.length !== 2) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
|
|
1149
|
+
const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
|
|
1150
|
+
return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
|
|
1151
|
+
}
|
|
1010
1152
|
function generateDynamicType(type) {
|
|
1011
1153
|
if (type.dynamicKind === "enum") {
|
|
1012
1154
|
const schema = {
|