@formspec/build 0.1.0-alpha.43 → 0.1.0-alpha.45
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/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +4 -1
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +35 -9
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +36 -12
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +106 -5
- package/dist/build-beta.d.ts +106 -5
- package/dist/build-internal.d.ts +106 -5
- package/dist/build.d.ts +106 -5
- package/dist/cli.cjs +343 -59
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +339 -58
- package/dist/cli.js.map +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/registry.d.ts +64 -5
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/extensions/symbol-registry.d.ts +33 -0
- package/dist/extensions/symbol-registry.d.ts.map +1 -0
- package/dist/generators/class-schema.d.ts +16 -0
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/discovered-schema.d.ts.map +1 -1
- package/dist/index.cjs +328 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +329 -54
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +124 -10
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.d.ts +1 -1
- package/dist/internals.d.ts.map +1 -1
- package/dist/internals.js +125 -13
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/metadata/collision-guards.d.ts.map +1 -1
- package/dist/metadata/policy.d.ts.map +1 -1
- package/dist/metadata/resolve.d.ts.map +1 -1
- package/dist/ui-schema/ir-generator.d.ts.map +1 -1
- package/dist/validate/constraint-validator.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -229,7 +229,9 @@ function resolveTypeNodeMetadata(type, options) {
|
|
|
229
229
|
case "object":
|
|
230
230
|
return {
|
|
231
231
|
...type,
|
|
232
|
-
properties: type.properties.map(
|
|
232
|
+
properties: type.properties.map(
|
|
233
|
+
(property) => resolveObjectPropertyMetadata(property, options)
|
|
234
|
+
)
|
|
233
235
|
};
|
|
234
236
|
case "record":
|
|
235
237
|
return {
|
|
@@ -1535,7 +1537,7 @@ function generateCustomType(type, ctx) {
|
|
|
1535
1537
|
}
|
|
1536
1538
|
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
1537
1539
|
}
|
|
1538
|
-
var
|
|
1540
|
+
var VOCABULARY_MODE_BLOCKED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1539
1541
|
"$schema",
|
|
1540
1542
|
"$ref",
|
|
1541
1543
|
"$defs",
|
|
@@ -1606,7 +1608,7 @@ function applyCustomConstraint(schema, constraint, ctx) {
|
|
|
1606
1608
|
if (registration.emitsVocabularyKeywords) {
|
|
1607
1609
|
const target = schema;
|
|
1608
1610
|
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
1609
|
-
if (
|
|
1611
|
+
if (VOCABULARY_MODE_BLOCKED_KEYWORDS.has(key)) {
|
|
1610
1612
|
throw new Error(
|
|
1611
1613
|
`Custom constraint "${constraint.constraintId}" with emitsVocabularyKeywords must not overwrite standard JSON Schema keyword "${key}"`
|
|
1612
1614
|
);
|
|
@@ -1655,10 +1657,7 @@ function generateJsonSchema(form, options) {
|
|
|
1655
1657
|
const metadata = options?.metadata;
|
|
1656
1658
|
const vendorPrefix = options?.vendorPrefix;
|
|
1657
1659
|
const enumSerialization = options?.enumSerialization;
|
|
1658
|
-
const ir = canonicalizeChainDSL(
|
|
1659
|
-
form,
|
|
1660
|
-
metadata !== void 0 ? { metadata } : void 0
|
|
1661
|
-
);
|
|
1660
|
+
const ir = canonicalizeChainDSL(form, metadata !== void 0 ? { metadata } : void 0);
|
|
1662
1661
|
const internalOptions = vendorPrefix === void 0 && enumSerialization === void 0 ? void 0 : {
|
|
1663
1662
|
...vendorPrefix !== void 0 && { vendorPrefix },
|
|
1664
1663
|
...enumSerialization !== void 0 && { enumSerialization }
|
|
@@ -1874,7 +1873,10 @@ function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
|
|
|
1874
1873
|
break;
|
|
1875
1874
|
}
|
|
1876
1875
|
case "conditional": {
|
|
1877
|
-
const newRule = createShowRule(
|
|
1876
|
+
const newRule = createShowRule(
|
|
1877
|
+
fieldNameMap.get(element.fieldName) ?? element.fieldName,
|
|
1878
|
+
element.value
|
|
1879
|
+
);
|
|
1878
1880
|
const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
|
|
1879
1881
|
const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
|
|
1880
1882
|
result.push(...childElements);
|
|
@@ -1931,7 +1933,7 @@ function generateUiSchema(form, options) {
|
|
|
1931
1933
|
|
|
1932
1934
|
// src/index.ts
|
|
1933
1935
|
import * as fs from "fs";
|
|
1934
|
-
import * as
|
|
1936
|
+
import * as path3 from "path";
|
|
1935
1937
|
|
|
1936
1938
|
// src/extensions/registry.ts
|
|
1937
1939
|
import {
|
|
@@ -1955,8 +1957,10 @@ function buildConstraintTagSources(extensions) {
|
|
|
1955
1957
|
}
|
|
1956
1958
|
function createExtensionRegistry(extensions) {
|
|
1957
1959
|
const reservedTagSources = buildConstraintTagSources(extensions);
|
|
1960
|
+
let symbolMap = /* @__PURE__ */ new Map();
|
|
1958
1961
|
const typeMap = /* @__PURE__ */ new Map();
|
|
1959
1962
|
const typeNameMap = /* @__PURE__ */ new Map();
|
|
1963
|
+
const brandMap = /* @__PURE__ */ new Map();
|
|
1960
1964
|
const constraintMap = /* @__PURE__ */ new Map();
|
|
1961
1965
|
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
1962
1966
|
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
@@ -1980,6 +1984,20 @@ function createExtensionRegistry(extensions) {
|
|
|
1980
1984
|
registration: type
|
|
1981
1985
|
});
|
|
1982
1986
|
}
|
|
1987
|
+
if (type.brand !== void 0) {
|
|
1988
|
+
if (type.brand === "__integerBrand") {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
`Brand "__integerBrand" is reserved for the builtin Integer type and cannot be registered by extensions`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
if (brandMap.has(type.brand)) {
|
|
1994
|
+
throw new Error(`Duplicate custom type brand: "${type.brand}"`);
|
|
1995
|
+
}
|
|
1996
|
+
brandMap.set(type.brand, {
|
|
1997
|
+
extensionId: ext.extensionId,
|
|
1998
|
+
registration: type
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
1983
2001
|
if (type.builtinConstraintBroadenings !== void 0) {
|
|
1984
2002
|
for (const broadening of type.builtinConstraintBroadenings) {
|
|
1985
2003
|
const key = `${qualifiedId}:${broadening.tagName}`;
|
|
@@ -2049,7 +2067,10 @@ function createExtensionRegistry(extensions) {
|
|
|
2049
2067
|
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
|
|
2050
2068
|
);
|
|
2051
2069
|
}
|
|
2052
|
-
if (Object.hasOwn(
|
|
2070
|
+
if (Object.hasOwn(
|
|
2071
|
+
BUILTIN_CONSTRAINT_DEFINITIONS,
|
|
2072
|
+
normalizeConstraintTagName(canonicalTagName)
|
|
2073
|
+
)) {
|
|
2053
2074
|
throw new Error(
|
|
2054
2075
|
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${normalizeConstraintTagName(canonicalTagName)}".`
|
|
2055
2076
|
);
|
|
@@ -2070,6 +2091,11 @@ function createExtensionRegistry(extensions) {
|
|
|
2070
2091
|
extensions,
|
|
2071
2092
|
findType: (typeId) => typeMap.get(typeId),
|
|
2072
2093
|
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
2094
|
+
findTypeByBrand: (brand) => brandMap.get(brand),
|
|
2095
|
+
findTypeBySymbol: (symbol) => symbolMap.get(symbol),
|
|
2096
|
+
setSymbolMap: (map) => {
|
|
2097
|
+
symbolMap = map;
|
|
2098
|
+
},
|
|
2073
2099
|
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
2074
2100
|
findConstraintTag: (tagName) => constraintTagMap.get(normalizeFormSpecTagName(tagName)),
|
|
2075
2101
|
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
@@ -2140,7 +2166,7 @@ var jsonSchema7Schema = z3.lazy(
|
|
|
2140
2166
|
);
|
|
2141
2167
|
|
|
2142
2168
|
// src/generators/class-schema.ts
|
|
2143
|
-
import * as
|
|
2169
|
+
import * as ts6 from "typescript";
|
|
2144
2170
|
|
|
2145
2171
|
// src/analyzer/program.ts
|
|
2146
2172
|
import * as ts4 from "typescript";
|
|
@@ -2952,6 +2978,71 @@ function isObjectType(type) {
|
|
|
2952
2978
|
function isIntersectionType(type) {
|
|
2953
2979
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
2954
2980
|
}
|
|
2981
|
+
function collectBrandIdentifiers(type) {
|
|
2982
|
+
if (!type.isIntersection()) {
|
|
2983
|
+
return [];
|
|
2984
|
+
}
|
|
2985
|
+
const brands = [];
|
|
2986
|
+
for (const prop of type.getProperties()) {
|
|
2987
|
+
const decl = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
2988
|
+
if (decl === void 0) continue;
|
|
2989
|
+
if (!ts3.isPropertySignature(decl) && !ts3.isPropertyDeclaration(decl)) continue;
|
|
2990
|
+
if (!ts3.isComputedPropertyName(decl.name)) continue;
|
|
2991
|
+
if (!ts3.isIdentifier(decl.name.expression)) continue;
|
|
2992
|
+
brands.push(decl.name.expression.text);
|
|
2993
|
+
}
|
|
2994
|
+
return brands;
|
|
2995
|
+
}
|
|
2996
|
+
function resolveCanonicalSymbol(type, checker) {
|
|
2997
|
+
const raw = type.aliasSymbol ?? type.getSymbol();
|
|
2998
|
+
if (raw === void 0) return void 0;
|
|
2999
|
+
return raw.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(raw) : raw;
|
|
3000
|
+
}
|
|
3001
|
+
function resolveSymbolBasedCustomType(type, extensionRegistry, checker) {
|
|
3002
|
+
if (extensionRegistry === void 0) {
|
|
3003
|
+
return null;
|
|
3004
|
+
}
|
|
3005
|
+
const canonical = resolveCanonicalSymbol(type, checker);
|
|
3006
|
+
if (canonical === void 0) {
|
|
3007
|
+
return null;
|
|
3008
|
+
}
|
|
3009
|
+
const registration = extensionRegistry.findTypeBySymbol(canonical);
|
|
3010
|
+
if (registration === void 0) {
|
|
3011
|
+
return null;
|
|
3012
|
+
}
|
|
3013
|
+
return {
|
|
3014
|
+
kind: "custom",
|
|
3015
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
3016
|
+
payload: null
|
|
3017
|
+
};
|
|
3018
|
+
}
|
|
3019
|
+
function isIntegerBrandedType(type) {
|
|
3020
|
+
if (!type.isIntersection()) {
|
|
3021
|
+
return false;
|
|
3022
|
+
}
|
|
3023
|
+
const hasNumberBase = type.types.some((member) => !!(member.flags & ts3.TypeFlags.Number));
|
|
3024
|
+
if (!hasNumberBase) {
|
|
3025
|
+
return false;
|
|
3026
|
+
}
|
|
3027
|
+
return collectBrandIdentifiers(type).includes("__integerBrand");
|
|
3028
|
+
}
|
|
3029
|
+
function resolveBrandedCustomType(type, extensionRegistry) {
|
|
3030
|
+
if (extensionRegistry === void 0) {
|
|
3031
|
+
return null;
|
|
3032
|
+
}
|
|
3033
|
+
for (const brand of collectBrandIdentifiers(type)) {
|
|
3034
|
+
const registration = extensionRegistry.findTypeByBrand(brand);
|
|
3035
|
+
if (registration === void 0) {
|
|
3036
|
+
continue;
|
|
3037
|
+
}
|
|
3038
|
+
return {
|
|
3039
|
+
kind: "custom",
|
|
3040
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
3041
|
+
payload: null
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
return null;
|
|
3045
|
+
}
|
|
2955
3046
|
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
2956
3047
|
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
2957
3048
|
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
@@ -4063,6 +4154,14 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4063
4154
|
if (customType) {
|
|
4064
4155
|
return customType;
|
|
4065
4156
|
}
|
|
4157
|
+
const symbolCustomType = resolveSymbolBasedCustomType(type, extensionRegistry, checker);
|
|
4158
|
+
if (symbolCustomType) {
|
|
4159
|
+
return symbolCustomType;
|
|
4160
|
+
}
|
|
4161
|
+
const brandedCustomType = resolveBrandedCustomType(type, extensionRegistry);
|
|
4162
|
+
if (brandedCustomType) {
|
|
4163
|
+
return brandedCustomType;
|
|
4164
|
+
}
|
|
4066
4165
|
const primitiveAlias = tryResolveNamedPrimitiveAlias(
|
|
4067
4166
|
type,
|
|
4068
4167
|
checker,
|
|
@@ -4077,6 +4176,9 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4077
4176
|
if (primitiveAlias) {
|
|
4078
4177
|
return primitiveAlias;
|
|
4079
4178
|
}
|
|
4179
|
+
if (isIntegerBrandedType(type)) {
|
|
4180
|
+
return { kind: "primitive", primitiveKind: "integer" };
|
|
4181
|
+
}
|
|
4080
4182
|
if (type.flags & ts3.TypeFlags.String) {
|
|
4081
4183
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4082
4184
|
}
|
|
@@ -4179,7 +4281,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4179
4281
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4180
4282
|
}
|
|
4181
4283
|
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
4182
|
-
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
|
|
4284
|
+
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null)) && !isIntegerBrandedType(type)) {
|
|
4183
4285
|
return null;
|
|
4184
4286
|
}
|
|
4185
4287
|
const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
|
|
@@ -4265,6 +4367,9 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
4265
4367
|
visitedAliases
|
|
4266
4368
|
);
|
|
4267
4369
|
}
|
|
4370
|
+
if (isIntegerBrandedType(type)) {
|
|
4371
|
+
return { kind: "primitive", primitiveKind: "integer" };
|
|
4372
|
+
}
|
|
4268
4373
|
if (type.flags & ts3.TypeFlags.String) {
|
|
4269
4374
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4270
4375
|
}
|
|
@@ -5001,7 +5106,7 @@ function createProgramContextFromProgram(program, filePath) {
|
|
|
5001
5106
|
sourceFile
|
|
5002
5107
|
};
|
|
5003
5108
|
}
|
|
5004
|
-
function createProgramContext(filePath) {
|
|
5109
|
+
function createProgramContext(filePath, additionalFiles) {
|
|
5005
5110
|
const absolutePath = path.resolve(filePath);
|
|
5006
5111
|
const fileDir = path.dirname(absolutePath);
|
|
5007
5112
|
const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
|
|
@@ -5024,7 +5129,8 @@ function createProgramContext(filePath) {
|
|
|
5024
5129
|
throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
|
|
5025
5130
|
}
|
|
5026
5131
|
compilerOptions = parsed.options;
|
|
5027
|
-
|
|
5132
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5133
|
+
fileNames = [.../* @__PURE__ */ new Set([...parsed.fileNames, absolutePath, ...normalizedAdditional])];
|
|
5028
5134
|
} else {
|
|
5029
5135
|
compilerOptions = {
|
|
5030
5136
|
target: ts4.ScriptTarget.ES2022,
|
|
@@ -5034,7 +5140,8 @@ function createProgramContext(filePath) {
|
|
|
5034
5140
|
skipLibCheck: true,
|
|
5035
5141
|
declaration: true
|
|
5036
5142
|
};
|
|
5037
|
-
|
|
5143
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5144
|
+
fileNames = [.../* @__PURE__ */ new Set([absolutePath, ...normalizedAdditional])];
|
|
5038
5145
|
}
|
|
5039
5146
|
const program = ts4.createProgram(fileNames, compilerOptions);
|
|
5040
5147
|
const sourceFile = program.getSourceFile(absolutePath);
|
|
@@ -5338,10 +5445,134 @@ function makeFileProvenance(filePath) {
|
|
|
5338
5445
|
};
|
|
5339
5446
|
}
|
|
5340
5447
|
|
|
5448
|
+
// src/extensions/symbol-registry.ts
|
|
5449
|
+
import * as ts5 from "typescript";
|
|
5450
|
+
import * as path2 from "path";
|
|
5451
|
+
function buildSymbolMapFromConfig(configPath, program, checker, extensionRegistry) {
|
|
5452
|
+
const symbolMap = /* @__PURE__ */ new Map();
|
|
5453
|
+
const normalizedPath = path2.resolve(configPath);
|
|
5454
|
+
const configFile = program.getSourceFile(normalizedPath);
|
|
5455
|
+
if (configFile === void 0) {
|
|
5456
|
+
return symbolMap;
|
|
5457
|
+
}
|
|
5458
|
+
function visit(node) {
|
|
5459
|
+
if (ts5.isCallExpression(node) && isDefineCustomTypeCall(node, checker)) {
|
|
5460
|
+
processDefineCustomTypeCall(node);
|
|
5461
|
+
}
|
|
5462
|
+
ts5.forEachChild(node, visit);
|
|
5463
|
+
}
|
|
5464
|
+
function processDefineCustomTypeCall(call) {
|
|
5465
|
+
const typeArgNode = call.typeArguments?.[0];
|
|
5466
|
+
if (typeArgNode === void 0) {
|
|
5467
|
+
return;
|
|
5468
|
+
}
|
|
5469
|
+
const resolvedType = checker.getTypeFromTypeNode(typeArgNode);
|
|
5470
|
+
const canonical = resolveCanonicalSymbol2(resolvedType, checker);
|
|
5471
|
+
if (canonical === void 0) {
|
|
5472
|
+
return;
|
|
5473
|
+
}
|
|
5474
|
+
const typeName = extractTypeNameFromCallArg(call);
|
|
5475
|
+
if (typeName === null) {
|
|
5476
|
+
return;
|
|
5477
|
+
}
|
|
5478
|
+
let entry;
|
|
5479
|
+
const extensionId = extractEnclosingExtensionId(call, checker);
|
|
5480
|
+
if (extensionId !== null) {
|
|
5481
|
+
const reg = extensionRegistry.findType(`${extensionId}/${typeName}`);
|
|
5482
|
+
if (reg !== void 0) {
|
|
5483
|
+
entry = { extensionId, registration: reg };
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
entry ??= findRegistrationByTypeName(extensionRegistry, typeName);
|
|
5487
|
+
if (entry === void 0) {
|
|
5488
|
+
return;
|
|
5489
|
+
}
|
|
5490
|
+
symbolMap.set(canonical, entry);
|
|
5491
|
+
}
|
|
5492
|
+
visit(configFile);
|
|
5493
|
+
return symbolMap;
|
|
5494
|
+
}
|
|
5495
|
+
function isDefineCustomTypeCall(node, checker) {
|
|
5496
|
+
if (node.typeArguments === void 0 || node.typeArguments.length === 0) return false;
|
|
5497
|
+
const callSymbol = checker.getSymbolAtLocation(node.expression);
|
|
5498
|
+
if (callSymbol !== void 0) {
|
|
5499
|
+
const resolved = callSymbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(callSymbol) : callSymbol;
|
|
5500
|
+
const decl = resolved.declarations?.[0];
|
|
5501
|
+
if (decl !== void 0) {
|
|
5502
|
+
const sourceFile = decl.getSourceFile().fileName.replace(/\\/g, "/");
|
|
5503
|
+
return resolved.name === "defineCustomType" && // Match whether in node_modules/@formspec/core or monorepo packages/core.
|
|
5504
|
+
(sourceFile.includes("@formspec/core") || sourceFile.includes("/packages/core/"));
|
|
5505
|
+
}
|
|
5506
|
+
}
|
|
5507
|
+
return ts5.isIdentifier(node.expression) && node.expression.text === "defineCustomType";
|
|
5508
|
+
}
|
|
5509
|
+
function resolveCanonicalSymbol2(type, checker) {
|
|
5510
|
+
const raw = type.aliasSymbol ?? type.getSymbol();
|
|
5511
|
+
if (raw === void 0) return void 0;
|
|
5512
|
+
return raw.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(raw) : raw;
|
|
5513
|
+
}
|
|
5514
|
+
function extractTypeNameFromCallArg(call) {
|
|
5515
|
+
const arg = call.arguments[0];
|
|
5516
|
+
if (arg === void 0 || !ts5.isObjectLiteralExpression(arg)) {
|
|
5517
|
+
return null;
|
|
5518
|
+
}
|
|
5519
|
+
const typeNameProp = arg.properties.find(
|
|
5520
|
+
(p) => ts5.isPropertyAssignment(p) && ts5.isIdentifier(p.name) && p.name.text === "typeName"
|
|
5521
|
+
);
|
|
5522
|
+
if (typeNameProp === void 0 || !ts5.isStringLiteral(typeNameProp.initializer)) {
|
|
5523
|
+
return null;
|
|
5524
|
+
}
|
|
5525
|
+
return typeNameProp.initializer.text;
|
|
5526
|
+
}
|
|
5527
|
+
function extractEnclosingExtensionId(call, checker) {
|
|
5528
|
+
for (let node = call.parent; !ts5.isSourceFile(node); node = node.parent) {
|
|
5529
|
+
if (ts5.isCallExpression(node) && isDefineExtensionCall(node, checker)) {
|
|
5530
|
+
return extractExtensionIdFromCallArg(node);
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
return null;
|
|
5534
|
+
}
|
|
5535
|
+
function isDefineExtensionCall(node, checker) {
|
|
5536
|
+
const callSymbol = checker.getSymbolAtLocation(node.expression);
|
|
5537
|
+
if (callSymbol !== void 0) {
|
|
5538
|
+
const resolved = callSymbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(callSymbol) : callSymbol;
|
|
5539
|
+
const decl = resolved.declarations?.[0];
|
|
5540
|
+
if (decl !== void 0) {
|
|
5541
|
+
const sourceFile = decl.getSourceFile().fileName.replace(/\\/g, "/");
|
|
5542
|
+
return resolved.name === "defineExtension" && (sourceFile.includes("@formspec/core") || sourceFile.includes("/packages/core/"));
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
return ts5.isIdentifier(node.expression) && node.expression.text === "defineExtension";
|
|
5546
|
+
}
|
|
5547
|
+
function extractExtensionIdFromCallArg(call) {
|
|
5548
|
+
const arg = call.arguments[0];
|
|
5549
|
+
if (arg === void 0 || !ts5.isObjectLiteralExpression(arg)) {
|
|
5550
|
+
return null;
|
|
5551
|
+
}
|
|
5552
|
+
const prop = arg.properties.find(
|
|
5553
|
+
(p) => ts5.isPropertyAssignment(p) && ts5.isIdentifier(p.name) && p.name.text === "extensionId"
|
|
5554
|
+
);
|
|
5555
|
+
if (prop === void 0 || !ts5.isStringLiteral(prop.initializer)) {
|
|
5556
|
+
return null;
|
|
5557
|
+
}
|
|
5558
|
+
return prop.initializer.text;
|
|
5559
|
+
}
|
|
5560
|
+
function findRegistrationByTypeName(registry, typeName) {
|
|
5561
|
+
for (const ext of registry.extensions) {
|
|
5562
|
+
if (ext.types === void 0) {
|
|
5563
|
+
continue;
|
|
5564
|
+
}
|
|
5565
|
+
for (const type of ext.types) {
|
|
5566
|
+
if (type.typeName === typeName) {
|
|
5567
|
+
return { extensionId: ext.extensionId, registration: type };
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
return void 0;
|
|
5572
|
+
}
|
|
5573
|
+
|
|
5341
5574
|
// src/validate/constraint-validator.ts
|
|
5342
|
-
import {
|
|
5343
|
-
analyzeConstraintTargets
|
|
5344
|
-
} from "@formspec/analysis/internal";
|
|
5575
|
+
import { analyzeConstraintTargets } from "@formspec/analysis/internal";
|
|
5345
5576
|
function validateFieldNode(ctx, field) {
|
|
5346
5577
|
const analysis = analyzeConstraintTargets(
|
|
5347
5578
|
field.name,
|
|
@@ -5472,7 +5703,8 @@ function formatLocation(location) {
|
|
|
5472
5703
|
return `${location.file}:${String(location.line)}:${String(location.column)}`;
|
|
5473
5704
|
}
|
|
5474
5705
|
function generateSchemasFromClass(options) {
|
|
5475
|
-
const
|
|
5706
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5707
|
+
const ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5476
5708
|
const classDecl = findClassByName(ctx.sourceFile, options.className);
|
|
5477
5709
|
if (!classDecl) {
|
|
5478
5710
|
throw new Error(`Class "${options.className}" not found in ${options.filePath}`);
|
|
@@ -5537,7 +5769,8 @@ function generateSchemasDetailed(options) {
|
|
|
5537
5769
|
function generateSchemasDetailedInternal(options) {
|
|
5538
5770
|
let ctx;
|
|
5539
5771
|
try {
|
|
5540
|
-
|
|
5772
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5773
|
+
ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5541
5774
|
} catch (error) {
|
|
5542
5775
|
return {
|
|
5543
5776
|
ok: false,
|
|
@@ -5576,13 +5809,16 @@ function generateSchemasFromProgramDetailedInternal(options) {
|
|
|
5576
5809
|
}
|
|
5577
5810
|
function generateSchemasBatch(options) {
|
|
5578
5811
|
const contextCache = /* @__PURE__ */ new Map();
|
|
5812
|
+
const resolved = resolveOptions(options);
|
|
5813
|
+
let symbolMapProgram;
|
|
5579
5814
|
return options.targets.map((target) => {
|
|
5580
5815
|
let ctx;
|
|
5581
5816
|
try {
|
|
5582
|
-
const cacheKey =
|
|
5817
|
+
const cacheKey = ts6.sys.useCaseSensitiveFileNames ? target.filePath : target.filePath.toLowerCase();
|
|
5583
5818
|
const cachedContext = contextCache.get(cacheKey);
|
|
5584
5819
|
if (cachedContext === void 0) {
|
|
5585
|
-
|
|
5820
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5821
|
+
ctx = createProgramContext(target.filePath, additionalFiles);
|
|
5586
5822
|
contextCache.set(cacheKey, ctx);
|
|
5587
5823
|
} else {
|
|
5588
5824
|
ctx = cachedContext;
|
|
@@ -5593,9 +5829,25 @@ function generateSchemasBatch(options) {
|
|
|
5593
5829
|
diagnostics: [createProgramContextFailureDiagnostic(target.filePath, error)]
|
|
5594
5830
|
});
|
|
5595
5831
|
}
|
|
5832
|
+
if (options.configPath !== void 0 && resolved.extensionRegistry !== void 0 && isMutableRegistry(resolved.extensionRegistry) && ctx.program !== symbolMapProgram) {
|
|
5833
|
+
const symbolMap = buildSymbolMapFromConfig(
|
|
5834
|
+
options.configPath,
|
|
5835
|
+
ctx.program,
|
|
5836
|
+
ctx.checker,
|
|
5837
|
+
resolved.extensionRegistry
|
|
5838
|
+
);
|
|
5839
|
+
resolved.extensionRegistry.setSymbolMap(symbolMap);
|
|
5840
|
+
symbolMapProgram = ctx.program;
|
|
5841
|
+
}
|
|
5596
5842
|
return withTarget(
|
|
5597
5843
|
target,
|
|
5598
|
-
|
|
5844
|
+
generateSchemasFromResolvedOptions(
|
|
5845
|
+
ctx,
|
|
5846
|
+
target.filePath,
|
|
5847
|
+
target.typeName,
|
|
5848
|
+
resolved,
|
|
5849
|
+
options.discriminator
|
|
5850
|
+
)
|
|
5599
5851
|
);
|
|
5600
5852
|
});
|
|
5601
5853
|
}
|
|
@@ -5616,11 +5868,19 @@ function generateSchemasBatchFromProgram(options) {
|
|
|
5616
5868
|
);
|
|
5617
5869
|
});
|
|
5618
5870
|
}
|
|
5871
|
+
function isMutableRegistry(reg) {
|
|
5872
|
+
return "setSymbolMap" in reg && typeof reg.setSymbolMap === "function";
|
|
5873
|
+
}
|
|
5619
5874
|
function resolveOptions(options) {
|
|
5620
5875
|
const configRegistry = options.config?.extensions !== void 0 ? createExtensionRegistry(options.config.extensions) : void 0;
|
|
5876
|
+
const legacyRegistry = options.extensionRegistry;
|
|
5621
5877
|
return {
|
|
5622
|
-
//
|
|
5623
|
-
|
|
5878
|
+
// When the caller provides the deprecated extensionRegistry field directly,
|
|
5879
|
+
// it is typed as the read-only ExtensionRegistry interface. We cast here
|
|
5880
|
+
// because the legacy path was introduced before MutableExtensionRegistry was
|
|
5881
|
+
// split out; callers using createExtensionRegistry() always get a mutable
|
|
5882
|
+
// registry, and this cast is safe for all registries produced by this module.
|
|
5883
|
+
extensionRegistry: legacyRegistry ?? configRegistry,
|
|
5624
5884
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
5625
5885
|
vendorPrefix: options.vendorPrefix ?? options.config?.vendorPrefix,
|
|
5626
5886
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
@@ -5631,13 +5891,31 @@ function resolveOptions(options) {
|
|
|
5631
5891
|
}
|
|
5632
5892
|
function generateSchemasFromDetailedProgramContext(ctx, filePath, typeName, options) {
|
|
5633
5893
|
const resolved = resolveOptions(options);
|
|
5894
|
+
if (options.configPath !== void 0 && resolved.extensionRegistry !== void 0 && isMutableRegistry(resolved.extensionRegistry)) {
|
|
5895
|
+
const symbolMap = buildSymbolMapFromConfig(
|
|
5896
|
+
options.configPath,
|
|
5897
|
+
ctx.program,
|
|
5898
|
+
ctx.checker,
|
|
5899
|
+
resolved.extensionRegistry
|
|
5900
|
+
);
|
|
5901
|
+
resolved.extensionRegistry.setSymbolMap(symbolMap);
|
|
5902
|
+
}
|
|
5903
|
+
return generateSchemasFromResolvedOptions(
|
|
5904
|
+
ctx,
|
|
5905
|
+
filePath,
|
|
5906
|
+
typeName,
|
|
5907
|
+
resolved,
|
|
5908
|
+
options.discriminator
|
|
5909
|
+
);
|
|
5910
|
+
}
|
|
5911
|
+
function generateSchemasFromResolvedOptions(ctx, filePath, typeName, resolved, discriminator) {
|
|
5634
5912
|
const analysisResult = analyzeNamedTypeToIRFromProgramContextDetailed(
|
|
5635
5913
|
ctx,
|
|
5636
5914
|
filePath,
|
|
5637
5915
|
typeName,
|
|
5638
5916
|
resolved.extensionRegistry,
|
|
5639
5917
|
resolved.metadata,
|
|
5640
|
-
|
|
5918
|
+
discriminator
|
|
5641
5919
|
);
|
|
5642
5920
|
if (!analysisResult.ok) {
|
|
5643
5921
|
return {
|
|
@@ -5679,7 +5957,7 @@ function createProgramContextFailureDiagnostic(filePath, error) {
|
|
|
5679
5957
|
}
|
|
5680
5958
|
|
|
5681
5959
|
// src/static-build.ts
|
|
5682
|
-
import * as
|
|
5960
|
+
import * as ts7 from "typescript";
|
|
5683
5961
|
function toStaticBuildContext(context) {
|
|
5684
5962
|
return context;
|
|
5685
5963
|
}
|
|
@@ -5694,7 +5972,7 @@ function getModuleSymbol(context) {
|
|
|
5694
5972
|
return context.checker.getSymbolAtLocation(context.sourceFile) ?? sourceFileWithSymbol.symbol;
|
|
5695
5973
|
}
|
|
5696
5974
|
function isSchemaSourceDeclaration(declaration) {
|
|
5697
|
-
return
|
|
5975
|
+
return ts7.isClassDeclaration(declaration) || ts7.isInterfaceDeclaration(declaration) || ts7.isTypeAliasDeclaration(declaration);
|
|
5698
5976
|
}
|
|
5699
5977
|
function resolveModuleExport(context, exportName = "default") {
|
|
5700
5978
|
const moduleSymbol = getModuleSymbol(context);
|
|
@@ -5705,14 +5983,14 @@ function resolveModuleExport(context, exportName = "default") {
|
|
|
5705
5983
|
if (exportSymbol === null) {
|
|
5706
5984
|
return null;
|
|
5707
5985
|
}
|
|
5708
|
-
return exportSymbol.flags &
|
|
5986
|
+
return exportSymbol.flags & ts7.SymbolFlags.Alias ? context.checker.getAliasedSymbol(exportSymbol) : exportSymbol;
|
|
5709
5987
|
}
|
|
5710
5988
|
function resolveModuleExportDeclaration(context, exportName = "default") {
|
|
5711
5989
|
return resolveModuleExport(context, exportName)?.declarations?.find(isSchemaSourceDeclaration) ?? null;
|
|
5712
5990
|
}
|
|
5713
5991
|
|
|
5714
5992
|
// src/generators/discovered-schema.ts
|
|
5715
|
-
import * as
|
|
5993
|
+
import * as ts8 from "typescript";
|
|
5716
5994
|
import { analyzeMetadataForNodeWithChecker as analyzeMetadataForNodeWithChecker2 } from "@formspec/analysis/internal";
|
|
5717
5995
|
import { IR_VERSION as IR_VERSION3 } from "@formspec/core/internals";
|
|
5718
5996
|
function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
@@ -5722,17 +6000,17 @@ function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
|
5722
6000
|
};
|
|
5723
6001
|
}
|
|
5724
6002
|
function isNamedTypeDeclaration(declaration) {
|
|
5725
|
-
return
|
|
6003
|
+
return ts8.isClassDeclaration(declaration) || ts8.isInterfaceDeclaration(declaration) || ts8.isTypeAliasDeclaration(declaration);
|
|
5726
6004
|
}
|
|
5727
6005
|
function hasConcreteTypeArguments(type, checker) {
|
|
5728
6006
|
if ("aliasTypeArguments" in type && Array.isArray(type.aliasTypeArguments) && type.aliasTypeArguments.length > 0) {
|
|
5729
6007
|
return true;
|
|
5730
6008
|
}
|
|
5731
|
-
if ((type.flags &
|
|
6009
|
+
if ((type.flags & ts8.TypeFlags.Object) === 0) {
|
|
5732
6010
|
return false;
|
|
5733
6011
|
}
|
|
5734
6012
|
const objectType = type;
|
|
5735
|
-
if ((objectType.objectFlags &
|
|
6013
|
+
if ((objectType.objectFlags & ts8.ObjectFlags.Reference) === 0) {
|
|
5736
6014
|
return false;
|
|
5737
6015
|
}
|
|
5738
6016
|
return checker.getTypeArguments(objectType).length > 0;
|
|
@@ -5745,13 +6023,13 @@ function getNamedTypeDeclaration2(type) {
|
|
|
5745
6023
|
return declaration;
|
|
5746
6024
|
}
|
|
5747
6025
|
}
|
|
5748
|
-
const aliasDeclaration = type.aliasSymbol?.declarations?.find(
|
|
6026
|
+
const aliasDeclaration = type.aliasSymbol?.declarations?.find(ts8.isTypeAliasDeclaration);
|
|
5749
6027
|
return aliasDeclaration;
|
|
5750
6028
|
}
|
|
5751
6029
|
function getFallbackName(sourceNode, fallback = "AnonymousType") {
|
|
5752
6030
|
if (sourceNode !== void 0 && "name" in sourceNode) {
|
|
5753
6031
|
const namedNode = sourceNode;
|
|
5754
|
-
if (namedNode.name !== void 0 &&
|
|
6032
|
+
if (namedNode.name !== void 0 && ts8.isIdentifier(namedNode.name)) {
|
|
5755
6033
|
return namedNode.name.text;
|
|
5756
6034
|
}
|
|
5757
6035
|
}
|
|
@@ -5870,17 +6148,14 @@ function toStandaloneJsonSchema(root, typeRegistry, options) {
|
|
|
5870
6148
|
rootLogicalName: root.name
|
|
5871
6149
|
}
|
|
5872
6150
|
);
|
|
5873
|
-
const schema = generateJsonSchemaFromIR(
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
vendorPrefix: options?.vendorPrefix
|
|
5882
|
-
}
|
|
5883
|
-
);
|
|
6151
|
+
const schema = generateJsonSchemaFromIR(ir, {
|
|
6152
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6153
|
+
extensionRegistry: options?.extensionRegistry,
|
|
6154
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6155
|
+
enumSerialization: options?.enumSerialization,
|
|
6156
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6157
|
+
vendorPrefix: options?.vendorPrefix
|
|
6158
|
+
});
|
|
5884
6159
|
const result = schema.properties?.["__result"];
|
|
5885
6160
|
if (result === void 0) {
|
|
5886
6161
|
throw new Error("FormSpec failed to extract the standalone schema root from the synthetic IR.");
|
|
@@ -5979,7 +6254,7 @@ function generateSchemasFromResolvedType(options, skipNamedDeclaration = false,
|
|
|
5979
6254
|
}
|
|
5980
6255
|
function generateSchemasFromDeclaration(options) {
|
|
5981
6256
|
const filePath = options.declaration.getSourceFile().fileName;
|
|
5982
|
-
if (
|
|
6257
|
+
if (ts8.isClassDeclaration(options.declaration)) {
|
|
5983
6258
|
return generateSchemasFromAnalysis(
|
|
5984
6259
|
analyzeClassToIR(
|
|
5985
6260
|
options.declaration,
|
|
@@ -5995,7 +6270,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
5995
6270
|
options
|
|
5996
6271
|
);
|
|
5997
6272
|
}
|
|
5998
|
-
if (
|
|
6273
|
+
if (ts8.isInterfaceDeclaration(options.declaration)) {
|
|
5999
6274
|
return generateSchemasFromAnalysis(
|
|
6000
6275
|
analyzeInterfaceToIR(
|
|
6001
6276
|
options.declaration,
|
|
@@ -6011,7 +6286,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
6011
6286
|
options
|
|
6012
6287
|
);
|
|
6013
6288
|
}
|
|
6014
|
-
if (
|
|
6289
|
+
if (ts8.isTypeAliasDeclaration(options.declaration)) {
|
|
6015
6290
|
const analyzedAlias = analyzeTypeAliasToIR(
|
|
6016
6291
|
options.declaration,
|
|
6017
6292
|
options.context.checker,
|
|
@@ -6074,7 +6349,7 @@ function generateSchemasFromReturnType(options) {
|
|
|
6074
6349
|
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
6075
6350
|
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
6076
6351
|
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
6077
|
-
const fallbackName = options.declaration.name !== void 0 &&
|
|
6352
|
+
const fallbackName = options.declaration.name !== void 0 && ts8.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
|
|
6078
6353
|
return generateSchemasFromResolvedType({
|
|
6079
6354
|
...options,
|
|
6080
6355
|
type,
|
|
@@ -6109,14 +6384,14 @@ function unwrapPromiseTypeNode(typeNode) {
|
|
|
6109
6384
|
if (typeNode === void 0) {
|
|
6110
6385
|
return void 0;
|
|
6111
6386
|
}
|
|
6112
|
-
if (
|
|
6387
|
+
if (ts8.isParenthesizedTypeNode(typeNode)) {
|
|
6113
6388
|
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
6114
6389
|
return unwrapped ?? typeNode;
|
|
6115
6390
|
}
|
|
6116
6391
|
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
6117
6392
|
}
|
|
6118
6393
|
function isPromiseTypeReferenceNode(typeNode) {
|
|
6119
|
-
return
|
|
6394
|
+
return ts8.isTypeReferenceNode(typeNode) && ts8.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
6120
6395
|
}
|
|
6121
6396
|
|
|
6122
6397
|
// src/generators/mixed-authoring.ts
|
|
@@ -6338,8 +6613,8 @@ function writeSchemas(form, options) {
|
|
|
6338
6613
|
if (!fs.existsSync(outDir)) {
|
|
6339
6614
|
fs.mkdirSync(outDir, { recursive: true });
|
|
6340
6615
|
}
|
|
6341
|
-
const jsonSchemaPath =
|
|
6342
|
-
const uiSchemaPath =
|
|
6616
|
+
const jsonSchemaPath = path3.join(outDir, `${name}-schema.json`);
|
|
6617
|
+
const uiSchemaPath = path3.join(outDir, `${name}-uischema.json`);
|
|
6343
6618
|
fs.writeFileSync(jsonSchemaPath, JSON.stringify(jsonSchema, null, indent));
|
|
6344
6619
|
fs.writeFileSync(uiSchemaPath, JSON.stringify(uiSchema2, null, indent));
|
|
6345
6620
|
return { jsonSchemaPath, uiSchemaPath };
|