@formspec/build 0.1.0-alpha.44 → 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 +33 -7
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +34 -10
- 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 +324 -71
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +320 -70
- 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 +310 -64
- 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 +311 -67
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +106 -23
- 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 +107 -26
- 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 {
|
|
@@ -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,30 +2978,70 @@ 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
|
+
}
|
|
2955
3019
|
function isIntegerBrandedType(type) {
|
|
2956
3020
|
if (!type.isIntersection()) {
|
|
2957
3021
|
return false;
|
|
2958
3022
|
}
|
|
2959
|
-
const hasNumberBase = type.types.some(
|
|
2960
|
-
(member) => !!(member.flags & ts3.TypeFlags.Number)
|
|
2961
|
-
);
|
|
3023
|
+
const hasNumberBase = type.types.some((member) => !!(member.flags & ts3.TypeFlags.Number));
|
|
2962
3024
|
if (!hasNumberBase) {
|
|
2963
3025
|
return false;
|
|
2964
3026
|
}
|
|
2965
|
-
return type
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
return false;
|
|
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;
|
|
2976
3037
|
}
|
|
2977
|
-
return
|
|
2978
|
-
|
|
3038
|
+
return {
|
|
3039
|
+
kind: "custom",
|
|
3040
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
3041
|
+
payload: null
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
return null;
|
|
2979
3045
|
}
|
|
2980
3046
|
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
2981
3047
|
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
@@ -4088,6 +4154,14 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4088
4154
|
if (customType) {
|
|
4089
4155
|
return customType;
|
|
4090
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
|
+
}
|
|
4091
4165
|
const primitiveAlias = tryResolveNamedPrimitiveAlias(
|
|
4092
4166
|
type,
|
|
4093
4167
|
checker,
|
|
@@ -5032,7 +5106,7 @@ function createProgramContextFromProgram(program, filePath) {
|
|
|
5032
5106
|
sourceFile
|
|
5033
5107
|
};
|
|
5034
5108
|
}
|
|
5035
|
-
function createProgramContext(filePath) {
|
|
5109
|
+
function createProgramContext(filePath, additionalFiles) {
|
|
5036
5110
|
const absolutePath = path.resolve(filePath);
|
|
5037
5111
|
const fileDir = path.dirname(absolutePath);
|
|
5038
5112
|
const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
|
|
@@ -5055,7 +5129,8 @@ function createProgramContext(filePath) {
|
|
|
5055
5129
|
throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
|
|
5056
5130
|
}
|
|
5057
5131
|
compilerOptions = parsed.options;
|
|
5058
|
-
|
|
5132
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5133
|
+
fileNames = [.../* @__PURE__ */ new Set([...parsed.fileNames, absolutePath, ...normalizedAdditional])];
|
|
5059
5134
|
} else {
|
|
5060
5135
|
compilerOptions = {
|
|
5061
5136
|
target: ts4.ScriptTarget.ES2022,
|
|
@@ -5065,7 +5140,8 @@ function createProgramContext(filePath) {
|
|
|
5065
5140
|
skipLibCheck: true,
|
|
5066
5141
|
declaration: true
|
|
5067
5142
|
};
|
|
5068
|
-
|
|
5143
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5144
|
+
fileNames = [.../* @__PURE__ */ new Set([absolutePath, ...normalizedAdditional])];
|
|
5069
5145
|
}
|
|
5070
5146
|
const program = ts4.createProgram(fileNames, compilerOptions);
|
|
5071
5147
|
const sourceFile = program.getSourceFile(absolutePath);
|
|
@@ -5369,10 +5445,134 @@ function makeFileProvenance(filePath) {
|
|
|
5369
5445
|
};
|
|
5370
5446
|
}
|
|
5371
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
|
+
|
|
5372
5574
|
// src/validate/constraint-validator.ts
|
|
5373
|
-
import {
|
|
5374
|
-
analyzeConstraintTargets
|
|
5375
|
-
} from "@formspec/analysis/internal";
|
|
5575
|
+
import { analyzeConstraintTargets } from "@formspec/analysis/internal";
|
|
5376
5576
|
function validateFieldNode(ctx, field) {
|
|
5377
5577
|
const analysis = analyzeConstraintTargets(
|
|
5378
5578
|
field.name,
|
|
@@ -5503,7 +5703,8 @@ function formatLocation(location) {
|
|
|
5503
5703
|
return `${location.file}:${String(location.line)}:${String(location.column)}`;
|
|
5504
5704
|
}
|
|
5505
5705
|
function generateSchemasFromClass(options) {
|
|
5506
|
-
const
|
|
5706
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5707
|
+
const ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5507
5708
|
const classDecl = findClassByName(ctx.sourceFile, options.className);
|
|
5508
5709
|
if (!classDecl) {
|
|
5509
5710
|
throw new Error(`Class "${options.className}" not found in ${options.filePath}`);
|
|
@@ -5568,7 +5769,8 @@ function generateSchemasDetailed(options) {
|
|
|
5568
5769
|
function generateSchemasDetailedInternal(options) {
|
|
5569
5770
|
let ctx;
|
|
5570
5771
|
try {
|
|
5571
|
-
|
|
5772
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5773
|
+
ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5572
5774
|
} catch (error) {
|
|
5573
5775
|
return {
|
|
5574
5776
|
ok: false,
|
|
@@ -5607,13 +5809,16 @@ function generateSchemasFromProgramDetailedInternal(options) {
|
|
|
5607
5809
|
}
|
|
5608
5810
|
function generateSchemasBatch(options) {
|
|
5609
5811
|
const contextCache = /* @__PURE__ */ new Map();
|
|
5812
|
+
const resolved = resolveOptions(options);
|
|
5813
|
+
let symbolMapProgram;
|
|
5610
5814
|
return options.targets.map((target) => {
|
|
5611
5815
|
let ctx;
|
|
5612
5816
|
try {
|
|
5613
|
-
const cacheKey =
|
|
5817
|
+
const cacheKey = ts6.sys.useCaseSensitiveFileNames ? target.filePath : target.filePath.toLowerCase();
|
|
5614
5818
|
const cachedContext = contextCache.get(cacheKey);
|
|
5615
5819
|
if (cachedContext === void 0) {
|
|
5616
|
-
|
|
5820
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5821
|
+
ctx = createProgramContext(target.filePath, additionalFiles);
|
|
5617
5822
|
contextCache.set(cacheKey, ctx);
|
|
5618
5823
|
} else {
|
|
5619
5824
|
ctx = cachedContext;
|
|
@@ -5624,9 +5829,25 @@ function generateSchemasBatch(options) {
|
|
|
5624
5829
|
diagnostics: [createProgramContextFailureDiagnostic(target.filePath, error)]
|
|
5625
5830
|
});
|
|
5626
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
|
+
}
|
|
5627
5842
|
return withTarget(
|
|
5628
5843
|
target,
|
|
5629
|
-
|
|
5844
|
+
generateSchemasFromResolvedOptions(
|
|
5845
|
+
ctx,
|
|
5846
|
+
target.filePath,
|
|
5847
|
+
target.typeName,
|
|
5848
|
+
resolved,
|
|
5849
|
+
options.discriminator
|
|
5850
|
+
)
|
|
5630
5851
|
);
|
|
5631
5852
|
});
|
|
5632
5853
|
}
|
|
@@ -5647,11 +5868,19 @@ function generateSchemasBatchFromProgram(options) {
|
|
|
5647
5868
|
);
|
|
5648
5869
|
});
|
|
5649
5870
|
}
|
|
5871
|
+
function isMutableRegistry(reg) {
|
|
5872
|
+
return "setSymbolMap" in reg && typeof reg.setSymbolMap === "function";
|
|
5873
|
+
}
|
|
5650
5874
|
function resolveOptions(options) {
|
|
5651
5875
|
const configRegistry = options.config?.extensions !== void 0 ? createExtensionRegistry(options.config.extensions) : void 0;
|
|
5876
|
+
const legacyRegistry = options.extensionRegistry;
|
|
5652
5877
|
return {
|
|
5653
|
-
//
|
|
5654
|
-
|
|
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,
|
|
5655
5884
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
5656
5885
|
vendorPrefix: options.vendorPrefix ?? options.config?.vendorPrefix,
|
|
5657
5886
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
@@ -5662,13 +5891,31 @@ function resolveOptions(options) {
|
|
|
5662
5891
|
}
|
|
5663
5892
|
function generateSchemasFromDetailedProgramContext(ctx, filePath, typeName, options) {
|
|
5664
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) {
|
|
5665
5912
|
const analysisResult = analyzeNamedTypeToIRFromProgramContextDetailed(
|
|
5666
5913
|
ctx,
|
|
5667
5914
|
filePath,
|
|
5668
5915
|
typeName,
|
|
5669
5916
|
resolved.extensionRegistry,
|
|
5670
5917
|
resolved.metadata,
|
|
5671
|
-
|
|
5918
|
+
discriminator
|
|
5672
5919
|
);
|
|
5673
5920
|
if (!analysisResult.ok) {
|
|
5674
5921
|
return {
|
|
@@ -5710,7 +5957,7 @@ function createProgramContextFailureDiagnostic(filePath, error) {
|
|
|
5710
5957
|
}
|
|
5711
5958
|
|
|
5712
5959
|
// src/static-build.ts
|
|
5713
|
-
import * as
|
|
5960
|
+
import * as ts7 from "typescript";
|
|
5714
5961
|
function toStaticBuildContext(context) {
|
|
5715
5962
|
return context;
|
|
5716
5963
|
}
|
|
@@ -5725,7 +5972,7 @@ function getModuleSymbol(context) {
|
|
|
5725
5972
|
return context.checker.getSymbolAtLocation(context.sourceFile) ?? sourceFileWithSymbol.symbol;
|
|
5726
5973
|
}
|
|
5727
5974
|
function isSchemaSourceDeclaration(declaration) {
|
|
5728
|
-
return
|
|
5975
|
+
return ts7.isClassDeclaration(declaration) || ts7.isInterfaceDeclaration(declaration) || ts7.isTypeAliasDeclaration(declaration);
|
|
5729
5976
|
}
|
|
5730
5977
|
function resolveModuleExport(context, exportName = "default") {
|
|
5731
5978
|
const moduleSymbol = getModuleSymbol(context);
|
|
@@ -5736,14 +5983,14 @@ function resolveModuleExport(context, exportName = "default") {
|
|
|
5736
5983
|
if (exportSymbol === null) {
|
|
5737
5984
|
return null;
|
|
5738
5985
|
}
|
|
5739
|
-
return exportSymbol.flags &
|
|
5986
|
+
return exportSymbol.flags & ts7.SymbolFlags.Alias ? context.checker.getAliasedSymbol(exportSymbol) : exportSymbol;
|
|
5740
5987
|
}
|
|
5741
5988
|
function resolveModuleExportDeclaration(context, exportName = "default") {
|
|
5742
5989
|
return resolveModuleExport(context, exportName)?.declarations?.find(isSchemaSourceDeclaration) ?? null;
|
|
5743
5990
|
}
|
|
5744
5991
|
|
|
5745
5992
|
// src/generators/discovered-schema.ts
|
|
5746
|
-
import * as
|
|
5993
|
+
import * as ts8 from "typescript";
|
|
5747
5994
|
import { analyzeMetadataForNodeWithChecker as analyzeMetadataForNodeWithChecker2 } from "@formspec/analysis/internal";
|
|
5748
5995
|
import { IR_VERSION as IR_VERSION3 } from "@formspec/core/internals";
|
|
5749
5996
|
function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
@@ -5753,17 +6000,17 @@ function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
|
5753
6000
|
};
|
|
5754
6001
|
}
|
|
5755
6002
|
function isNamedTypeDeclaration(declaration) {
|
|
5756
|
-
return
|
|
6003
|
+
return ts8.isClassDeclaration(declaration) || ts8.isInterfaceDeclaration(declaration) || ts8.isTypeAliasDeclaration(declaration);
|
|
5757
6004
|
}
|
|
5758
6005
|
function hasConcreteTypeArguments(type, checker) {
|
|
5759
6006
|
if ("aliasTypeArguments" in type && Array.isArray(type.aliasTypeArguments) && type.aliasTypeArguments.length > 0) {
|
|
5760
6007
|
return true;
|
|
5761
6008
|
}
|
|
5762
|
-
if ((type.flags &
|
|
6009
|
+
if ((type.flags & ts8.TypeFlags.Object) === 0) {
|
|
5763
6010
|
return false;
|
|
5764
6011
|
}
|
|
5765
6012
|
const objectType = type;
|
|
5766
|
-
if ((objectType.objectFlags &
|
|
6013
|
+
if ((objectType.objectFlags & ts8.ObjectFlags.Reference) === 0) {
|
|
5767
6014
|
return false;
|
|
5768
6015
|
}
|
|
5769
6016
|
return checker.getTypeArguments(objectType).length > 0;
|
|
@@ -5776,13 +6023,13 @@ function getNamedTypeDeclaration2(type) {
|
|
|
5776
6023
|
return declaration;
|
|
5777
6024
|
}
|
|
5778
6025
|
}
|
|
5779
|
-
const aliasDeclaration = type.aliasSymbol?.declarations?.find(
|
|
6026
|
+
const aliasDeclaration = type.aliasSymbol?.declarations?.find(ts8.isTypeAliasDeclaration);
|
|
5780
6027
|
return aliasDeclaration;
|
|
5781
6028
|
}
|
|
5782
6029
|
function getFallbackName(sourceNode, fallback = "AnonymousType") {
|
|
5783
6030
|
if (sourceNode !== void 0 && "name" in sourceNode) {
|
|
5784
6031
|
const namedNode = sourceNode;
|
|
5785
|
-
if (namedNode.name !== void 0 &&
|
|
6032
|
+
if (namedNode.name !== void 0 && ts8.isIdentifier(namedNode.name)) {
|
|
5786
6033
|
return namedNode.name.text;
|
|
5787
6034
|
}
|
|
5788
6035
|
}
|
|
@@ -5901,17 +6148,14 @@ function toStandaloneJsonSchema(root, typeRegistry, options) {
|
|
|
5901
6148
|
rootLogicalName: root.name
|
|
5902
6149
|
}
|
|
5903
6150
|
);
|
|
5904
|
-
const schema = generateJsonSchemaFromIR(
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
vendorPrefix: options?.vendorPrefix
|
|
5913
|
-
}
|
|
5914
|
-
);
|
|
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
|
+
});
|
|
5915
6159
|
const result = schema.properties?.["__result"];
|
|
5916
6160
|
if (result === void 0) {
|
|
5917
6161
|
throw new Error("FormSpec failed to extract the standalone schema root from the synthetic IR.");
|
|
@@ -6010,7 +6254,7 @@ function generateSchemasFromResolvedType(options, skipNamedDeclaration = false,
|
|
|
6010
6254
|
}
|
|
6011
6255
|
function generateSchemasFromDeclaration(options) {
|
|
6012
6256
|
const filePath = options.declaration.getSourceFile().fileName;
|
|
6013
|
-
if (
|
|
6257
|
+
if (ts8.isClassDeclaration(options.declaration)) {
|
|
6014
6258
|
return generateSchemasFromAnalysis(
|
|
6015
6259
|
analyzeClassToIR(
|
|
6016
6260
|
options.declaration,
|
|
@@ -6026,7 +6270,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
6026
6270
|
options
|
|
6027
6271
|
);
|
|
6028
6272
|
}
|
|
6029
|
-
if (
|
|
6273
|
+
if (ts8.isInterfaceDeclaration(options.declaration)) {
|
|
6030
6274
|
return generateSchemasFromAnalysis(
|
|
6031
6275
|
analyzeInterfaceToIR(
|
|
6032
6276
|
options.declaration,
|
|
@@ -6042,7 +6286,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
6042
6286
|
options
|
|
6043
6287
|
);
|
|
6044
6288
|
}
|
|
6045
|
-
if (
|
|
6289
|
+
if (ts8.isTypeAliasDeclaration(options.declaration)) {
|
|
6046
6290
|
const analyzedAlias = analyzeTypeAliasToIR(
|
|
6047
6291
|
options.declaration,
|
|
6048
6292
|
options.context.checker,
|
|
@@ -6105,7 +6349,7 @@ function generateSchemasFromReturnType(options) {
|
|
|
6105
6349
|
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
6106
6350
|
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
6107
6351
|
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
6108
|
-
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";
|
|
6109
6353
|
return generateSchemasFromResolvedType({
|
|
6110
6354
|
...options,
|
|
6111
6355
|
type,
|
|
@@ -6140,14 +6384,14 @@ function unwrapPromiseTypeNode(typeNode) {
|
|
|
6140
6384
|
if (typeNode === void 0) {
|
|
6141
6385
|
return void 0;
|
|
6142
6386
|
}
|
|
6143
|
-
if (
|
|
6387
|
+
if (ts8.isParenthesizedTypeNode(typeNode)) {
|
|
6144
6388
|
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
6145
6389
|
return unwrapped ?? typeNode;
|
|
6146
6390
|
}
|
|
6147
6391
|
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
6148
6392
|
}
|
|
6149
6393
|
function isPromiseTypeReferenceNode(typeNode) {
|
|
6150
|
-
return
|
|
6394
|
+
return ts8.isTypeReferenceNode(typeNode) && ts8.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
6151
6395
|
}
|
|
6152
6396
|
|
|
6153
6397
|
// src/generators/mixed-authoring.ts
|
|
@@ -6369,8 +6613,8 @@ function writeSchemas(form, options) {
|
|
|
6369
6613
|
if (!fs.existsSync(outDir)) {
|
|
6370
6614
|
fs.mkdirSync(outDir, { recursive: true });
|
|
6371
6615
|
}
|
|
6372
|
-
const jsonSchemaPath =
|
|
6373
|
-
const uiSchemaPath =
|
|
6616
|
+
const jsonSchemaPath = path3.join(outDir, `${name}-schema.json`);
|
|
6617
|
+
const uiSchemaPath = path3.join(outDir, `${name}-uischema.json`);
|
|
6374
6618
|
fs.writeFileSync(jsonSchemaPath, JSON.stringify(jsonSchema, null, indent));
|
|
6375
6619
|
fs.writeFileSync(uiSchemaPath, JSON.stringify(uiSchema2, null, indent));
|
|
6376
6620
|
return { jsonSchemaPath, uiSchemaPath };
|