@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.cjs
CHANGED
|
@@ -288,7 +288,9 @@ function resolveTypeNodeMetadata(type, options) {
|
|
|
288
288
|
case "object":
|
|
289
289
|
return {
|
|
290
290
|
...type,
|
|
291
|
-
properties: type.properties.map(
|
|
291
|
+
properties: type.properties.map(
|
|
292
|
+
(property) => resolveObjectPropertyMetadata(property, options)
|
|
293
|
+
)
|
|
292
294
|
};
|
|
293
295
|
case "record":
|
|
294
296
|
return {
|
|
@@ -1594,7 +1596,7 @@ function generateCustomType(type, ctx) {
|
|
|
1594
1596
|
}
|
|
1595
1597
|
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
1596
1598
|
}
|
|
1597
|
-
var
|
|
1599
|
+
var VOCABULARY_MODE_BLOCKED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1598
1600
|
"$schema",
|
|
1599
1601
|
"$ref",
|
|
1600
1602
|
"$defs",
|
|
@@ -1665,7 +1667,7 @@ function applyCustomConstraint(schema, constraint, ctx) {
|
|
|
1665
1667
|
if (registration.emitsVocabularyKeywords) {
|
|
1666
1668
|
const target = schema;
|
|
1667
1669
|
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
1668
|
-
if (
|
|
1670
|
+
if (VOCABULARY_MODE_BLOCKED_KEYWORDS.has(key)) {
|
|
1669
1671
|
throw new Error(
|
|
1670
1672
|
`Custom constraint "${constraint.constraintId}" with emitsVocabularyKeywords must not overwrite standard JSON Schema keyword "${key}"`
|
|
1671
1673
|
);
|
|
@@ -1714,10 +1716,7 @@ function generateJsonSchema(form, options) {
|
|
|
1714
1716
|
const metadata = options?.metadata;
|
|
1715
1717
|
const vendorPrefix = options?.vendorPrefix;
|
|
1716
1718
|
const enumSerialization = options?.enumSerialization;
|
|
1717
|
-
const ir = canonicalizeChainDSL(
|
|
1718
|
-
form,
|
|
1719
|
-
metadata !== void 0 ? { metadata } : void 0
|
|
1720
|
-
);
|
|
1719
|
+
const ir = canonicalizeChainDSL(form, metadata !== void 0 ? { metadata } : void 0);
|
|
1721
1720
|
const internalOptions = vendorPrefix === void 0 && enumSerialization === void 0 ? void 0 : {
|
|
1722
1721
|
...vendorPrefix !== void 0 && { vendorPrefix },
|
|
1723
1722
|
...enumSerialization !== void 0 && { enumSerialization }
|
|
@@ -1933,7 +1932,10 @@ function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
|
|
|
1933
1932
|
break;
|
|
1934
1933
|
}
|
|
1935
1934
|
case "conditional": {
|
|
1936
|
-
const newRule = createShowRule(
|
|
1935
|
+
const newRule = createShowRule(
|
|
1936
|
+
fieldNameMap.get(element.fieldName) ?? element.fieldName,
|
|
1937
|
+
element.value
|
|
1938
|
+
);
|
|
1937
1939
|
const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
|
|
1938
1940
|
const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
|
|
1939
1941
|
result.push(...childElements);
|
|
@@ -1990,7 +1992,7 @@ function generateUiSchema(form, options) {
|
|
|
1990
1992
|
|
|
1991
1993
|
// src/index.ts
|
|
1992
1994
|
var fs = __toESM(require("fs"), 1);
|
|
1993
|
-
var
|
|
1995
|
+
var path3 = __toESM(require("path"), 1);
|
|
1994
1996
|
|
|
1995
1997
|
// src/extensions/registry.ts
|
|
1996
1998
|
var import_internals3 = require("@formspec/core/internals");
|
|
@@ -2008,8 +2010,10 @@ function buildConstraintTagSources(extensions) {
|
|
|
2008
2010
|
}
|
|
2009
2011
|
function createExtensionRegistry(extensions) {
|
|
2010
2012
|
const reservedTagSources = buildConstraintTagSources(extensions);
|
|
2013
|
+
let symbolMap = /* @__PURE__ */ new Map();
|
|
2011
2014
|
const typeMap = /* @__PURE__ */ new Map();
|
|
2012
2015
|
const typeNameMap = /* @__PURE__ */ new Map();
|
|
2016
|
+
const brandMap = /* @__PURE__ */ new Map();
|
|
2013
2017
|
const constraintMap = /* @__PURE__ */ new Map();
|
|
2014
2018
|
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
2015
2019
|
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
@@ -2033,6 +2037,20 @@ function createExtensionRegistry(extensions) {
|
|
|
2033
2037
|
registration: type
|
|
2034
2038
|
});
|
|
2035
2039
|
}
|
|
2040
|
+
if (type.brand !== void 0) {
|
|
2041
|
+
if (type.brand === "__integerBrand") {
|
|
2042
|
+
throw new Error(
|
|
2043
|
+
`Brand "__integerBrand" is reserved for the builtin Integer type and cannot be registered by extensions`
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
if (brandMap.has(type.brand)) {
|
|
2047
|
+
throw new Error(`Duplicate custom type brand: "${type.brand}"`);
|
|
2048
|
+
}
|
|
2049
|
+
brandMap.set(type.brand, {
|
|
2050
|
+
extensionId: ext.extensionId,
|
|
2051
|
+
registration: type
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2036
2054
|
if (type.builtinConstraintBroadenings !== void 0) {
|
|
2037
2055
|
for (const broadening of type.builtinConstraintBroadenings) {
|
|
2038
2056
|
const key = `${qualifiedId}:${broadening.tagName}`;
|
|
@@ -2102,7 +2120,10 @@ function createExtensionRegistry(extensions) {
|
|
|
2102
2120
|
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
|
|
2103
2121
|
);
|
|
2104
2122
|
}
|
|
2105
|
-
if (Object.hasOwn(
|
|
2123
|
+
if (Object.hasOwn(
|
|
2124
|
+
import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS,
|
|
2125
|
+
(0, import_internals3.normalizeConstraintTagName)(canonicalTagName)
|
|
2126
|
+
)) {
|
|
2106
2127
|
throw new Error(
|
|
2107
2128
|
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals3.normalizeConstraintTagName)(canonicalTagName)}".`
|
|
2108
2129
|
);
|
|
@@ -2123,6 +2144,11 @@ function createExtensionRegistry(extensions) {
|
|
|
2123
2144
|
extensions,
|
|
2124
2145
|
findType: (typeId) => typeMap.get(typeId),
|
|
2125
2146
|
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
2147
|
+
findTypeByBrand: (brand) => brandMap.get(brand),
|
|
2148
|
+
findTypeBySymbol: (symbol) => symbolMap.get(symbol),
|
|
2149
|
+
setSymbolMap: (map) => {
|
|
2150
|
+
symbolMap = map;
|
|
2151
|
+
},
|
|
2126
2152
|
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
2127
2153
|
findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal.normalizeFormSpecTagName)(tagName)),
|
|
2128
2154
|
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
@@ -2193,7 +2219,7 @@ var jsonSchema7Schema = import_zod3.z.lazy(
|
|
|
2193
2219
|
);
|
|
2194
2220
|
|
|
2195
2221
|
// src/generators/class-schema.ts
|
|
2196
|
-
var
|
|
2222
|
+
var ts6 = __toESM(require("typescript"), 1);
|
|
2197
2223
|
|
|
2198
2224
|
// src/analyzer/program.ts
|
|
2199
2225
|
var ts4 = __toESM(require("typescript"), 1);
|
|
@@ -2984,6 +3010,71 @@ function isObjectType(type) {
|
|
|
2984
3010
|
function isIntersectionType(type) {
|
|
2985
3011
|
return !!(type.flags & ts3.TypeFlags.Intersection);
|
|
2986
3012
|
}
|
|
3013
|
+
function collectBrandIdentifiers(type) {
|
|
3014
|
+
if (!type.isIntersection()) {
|
|
3015
|
+
return [];
|
|
3016
|
+
}
|
|
3017
|
+
const brands = [];
|
|
3018
|
+
for (const prop of type.getProperties()) {
|
|
3019
|
+
const decl = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
3020
|
+
if (decl === void 0) continue;
|
|
3021
|
+
if (!ts3.isPropertySignature(decl) && !ts3.isPropertyDeclaration(decl)) continue;
|
|
3022
|
+
if (!ts3.isComputedPropertyName(decl.name)) continue;
|
|
3023
|
+
if (!ts3.isIdentifier(decl.name.expression)) continue;
|
|
3024
|
+
brands.push(decl.name.expression.text);
|
|
3025
|
+
}
|
|
3026
|
+
return brands;
|
|
3027
|
+
}
|
|
3028
|
+
function resolveCanonicalSymbol(type, checker) {
|
|
3029
|
+
const raw = type.aliasSymbol ?? type.getSymbol();
|
|
3030
|
+
if (raw === void 0) return void 0;
|
|
3031
|
+
return raw.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(raw) : raw;
|
|
3032
|
+
}
|
|
3033
|
+
function resolveSymbolBasedCustomType(type, extensionRegistry, checker) {
|
|
3034
|
+
if (extensionRegistry === void 0) {
|
|
3035
|
+
return null;
|
|
3036
|
+
}
|
|
3037
|
+
const canonical = resolveCanonicalSymbol(type, checker);
|
|
3038
|
+
if (canonical === void 0) {
|
|
3039
|
+
return null;
|
|
3040
|
+
}
|
|
3041
|
+
const registration = extensionRegistry.findTypeBySymbol(canonical);
|
|
3042
|
+
if (registration === void 0) {
|
|
3043
|
+
return null;
|
|
3044
|
+
}
|
|
3045
|
+
return {
|
|
3046
|
+
kind: "custom",
|
|
3047
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
3048
|
+
payload: null
|
|
3049
|
+
};
|
|
3050
|
+
}
|
|
3051
|
+
function isIntegerBrandedType(type) {
|
|
3052
|
+
if (!type.isIntersection()) {
|
|
3053
|
+
return false;
|
|
3054
|
+
}
|
|
3055
|
+
const hasNumberBase = type.types.some((member) => !!(member.flags & ts3.TypeFlags.Number));
|
|
3056
|
+
if (!hasNumberBase) {
|
|
3057
|
+
return false;
|
|
3058
|
+
}
|
|
3059
|
+
return collectBrandIdentifiers(type).includes("__integerBrand");
|
|
3060
|
+
}
|
|
3061
|
+
function resolveBrandedCustomType(type, extensionRegistry) {
|
|
3062
|
+
if (extensionRegistry === void 0) {
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
for (const brand of collectBrandIdentifiers(type)) {
|
|
3066
|
+
const registration = extensionRegistry.findTypeByBrand(brand);
|
|
3067
|
+
if (registration === void 0) {
|
|
3068
|
+
continue;
|
|
3069
|
+
}
|
|
3070
|
+
return {
|
|
3071
|
+
kind: "custom",
|
|
3072
|
+
typeId: `${registration.extensionId}/${registration.registration.typeName}`,
|
|
3073
|
+
payload: null
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
3076
|
+
return null;
|
|
3077
|
+
}
|
|
2987
3078
|
function isResolvableObjectLikeAliasTypeNode(typeNode) {
|
|
2988
3079
|
if (ts3.isParenthesizedTypeNode(typeNode)) {
|
|
2989
3080
|
return isResolvableObjectLikeAliasTypeNode(typeNode.type);
|
|
@@ -4095,6 +4186,14 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4095
4186
|
if (customType) {
|
|
4096
4187
|
return customType;
|
|
4097
4188
|
}
|
|
4189
|
+
const symbolCustomType = resolveSymbolBasedCustomType(type, extensionRegistry, checker);
|
|
4190
|
+
if (symbolCustomType) {
|
|
4191
|
+
return symbolCustomType;
|
|
4192
|
+
}
|
|
4193
|
+
const brandedCustomType = resolveBrandedCustomType(type, extensionRegistry);
|
|
4194
|
+
if (brandedCustomType) {
|
|
4195
|
+
return brandedCustomType;
|
|
4196
|
+
}
|
|
4098
4197
|
const primitiveAlias = tryResolveNamedPrimitiveAlias(
|
|
4099
4198
|
type,
|
|
4100
4199
|
checker,
|
|
@@ -4109,6 +4208,9 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4109
4208
|
if (primitiveAlias) {
|
|
4110
4209
|
return primitiveAlias;
|
|
4111
4210
|
}
|
|
4211
|
+
if (isIntegerBrandedType(type)) {
|
|
4212
|
+
return { kind: "primitive", primitiveKind: "integer" };
|
|
4213
|
+
}
|
|
4112
4214
|
if (type.flags & ts3.TypeFlags.String) {
|
|
4113
4215
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4114
4216
|
}
|
|
@@ -4211,7 +4313,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
4211
4313
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4212
4314
|
}
|
|
4213
4315
|
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
4214
|
-
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
|
|
4316
|
+
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null)) && !isIntegerBrandedType(type)) {
|
|
4215
4317
|
return null;
|
|
4216
4318
|
}
|
|
4217
4319
|
const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
|
|
@@ -4297,6 +4399,9 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
4297
4399
|
visitedAliases
|
|
4298
4400
|
);
|
|
4299
4401
|
}
|
|
4402
|
+
if (isIntegerBrandedType(type)) {
|
|
4403
|
+
return { kind: "primitive", primitiveKind: "integer" };
|
|
4404
|
+
}
|
|
4300
4405
|
if (type.flags & ts3.TypeFlags.String) {
|
|
4301
4406
|
return { kind: "primitive", primitiveKind: "string" };
|
|
4302
4407
|
}
|
|
@@ -5033,7 +5138,7 @@ function createProgramContextFromProgram(program, filePath) {
|
|
|
5033
5138
|
sourceFile
|
|
5034
5139
|
};
|
|
5035
5140
|
}
|
|
5036
|
-
function createProgramContext(filePath) {
|
|
5141
|
+
function createProgramContext(filePath, additionalFiles) {
|
|
5037
5142
|
const absolutePath = path.resolve(filePath);
|
|
5038
5143
|
const fileDir = path.dirname(absolutePath);
|
|
5039
5144
|
const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
|
|
@@ -5056,7 +5161,8 @@ function createProgramContext(filePath) {
|
|
|
5056
5161
|
throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
|
|
5057
5162
|
}
|
|
5058
5163
|
compilerOptions = parsed.options;
|
|
5059
|
-
|
|
5164
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5165
|
+
fileNames = [.../* @__PURE__ */ new Set([...parsed.fileNames, absolutePath, ...normalizedAdditional])];
|
|
5060
5166
|
} else {
|
|
5061
5167
|
compilerOptions = {
|
|
5062
5168
|
target: ts4.ScriptTarget.ES2022,
|
|
@@ -5066,7 +5172,8 @@ function createProgramContext(filePath) {
|
|
|
5066
5172
|
skipLibCheck: true,
|
|
5067
5173
|
declaration: true
|
|
5068
5174
|
};
|
|
5069
|
-
|
|
5175
|
+
const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
|
|
5176
|
+
fileNames = [.../* @__PURE__ */ new Set([absolutePath, ...normalizedAdditional])];
|
|
5070
5177
|
}
|
|
5071
5178
|
const program = ts4.createProgram(fileNames, compilerOptions);
|
|
5072
5179
|
const sourceFile = program.getSourceFile(absolutePath);
|
|
@@ -5370,6 +5477,132 @@ function makeFileProvenance(filePath) {
|
|
|
5370
5477
|
};
|
|
5371
5478
|
}
|
|
5372
5479
|
|
|
5480
|
+
// src/extensions/symbol-registry.ts
|
|
5481
|
+
var ts5 = __toESM(require("typescript"), 1);
|
|
5482
|
+
var path2 = __toESM(require("path"), 1);
|
|
5483
|
+
function buildSymbolMapFromConfig(configPath, program, checker, extensionRegistry) {
|
|
5484
|
+
const symbolMap = /* @__PURE__ */ new Map();
|
|
5485
|
+
const normalizedPath = path2.resolve(configPath);
|
|
5486
|
+
const configFile = program.getSourceFile(normalizedPath);
|
|
5487
|
+
if (configFile === void 0) {
|
|
5488
|
+
return symbolMap;
|
|
5489
|
+
}
|
|
5490
|
+
function visit(node) {
|
|
5491
|
+
if (ts5.isCallExpression(node) && isDefineCustomTypeCall(node, checker)) {
|
|
5492
|
+
processDefineCustomTypeCall(node);
|
|
5493
|
+
}
|
|
5494
|
+
ts5.forEachChild(node, visit);
|
|
5495
|
+
}
|
|
5496
|
+
function processDefineCustomTypeCall(call) {
|
|
5497
|
+
const typeArgNode = call.typeArguments?.[0];
|
|
5498
|
+
if (typeArgNode === void 0) {
|
|
5499
|
+
return;
|
|
5500
|
+
}
|
|
5501
|
+
const resolvedType = checker.getTypeFromTypeNode(typeArgNode);
|
|
5502
|
+
const canonical = resolveCanonicalSymbol2(resolvedType, checker);
|
|
5503
|
+
if (canonical === void 0) {
|
|
5504
|
+
return;
|
|
5505
|
+
}
|
|
5506
|
+
const typeName = extractTypeNameFromCallArg(call);
|
|
5507
|
+
if (typeName === null) {
|
|
5508
|
+
return;
|
|
5509
|
+
}
|
|
5510
|
+
let entry;
|
|
5511
|
+
const extensionId = extractEnclosingExtensionId(call, checker);
|
|
5512
|
+
if (extensionId !== null) {
|
|
5513
|
+
const reg = extensionRegistry.findType(`${extensionId}/${typeName}`);
|
|
5514
|
+
if (reg !== void 0) {
|
|
5515
|
+
entry = { extensionId, registration: reg };
|
|
5516
|
+
}
|
|
5517
|
+
}
|
|
5518
|
+
entry ??= findRegistrationByTypeName(extensionRegistry, typeName);
|
|
5519
|
+
if (entry === void 0) {
|
|
5520
|
+
return;
|
|
5521
|
+
}
|
|
5522
|
+
symbolMap.set(canonical, entry);
|
|
5523
|
+
}
|
|
5524
|
+
visit(configFile);
|
|
5525
|
+
return symbolMap;
|
|
5526
|
+
}
|
|
5527
|
+
function isDefineCustomTypeCall(node, checker) {
|
|
5528
|
+
if (node.typeArguments === void 0 || node.typeArguments.length === 0) return false;
|
|
5529
|
+
const callSymbol = checker.getSymbolAtLocation(node.expression);
|
|
5530
|
+
if (callSymbol !== void 0) {
|
|
5531
|
+
const resolved = callSymbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(callSymbol) : callSymbol;
|
|
5532
|
+
const decl = resolved.declarations?.[0];
|
|
5533
|
+
if (decl !== void 0) {
|
|
5534
|
+
const sourceFile = decl.getSourceFile().fileName.replace(/\\/g, "/");
|
|
5535
|
+
return resolved.name === "defineCustomType" && // Match whether in node_modules/@formspec/core or monorepo packages/core.
|
|
5536
|
+
(sourceFile.includes("@formspec/core") || sourceFile.includes("/packages/core/"));
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
return ts5.isIdentifier(node.expression) && node.expression.text === "defineCustomType";
|
|
5540
|
+
}
|
|
5541
|
+
function resolveCanonicalSymbol2(type, checker) {
|
|
5542
|
+
const raw = type.aliasSymbol ?? type.getSymbol();
|
|
5543
|
+
if (raw === void 0) return void 0;
|
|
5544
|
+
return raw.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(raw) : raw;
|
|
5545
|
+
}
|
|
5546
|
+
function extractTypeNameFromCallArg(call) {
|
|
5547
|
+
const arg = call.arguments[0];
|
|
5548
|
+
if (arg === void 0 || !ts5.isObjectLiteralExpression(arg)) {
|
|
5549
|
+
return null;
|
|
5550
|
+
}
|
|
5551
|
+
const typeNameProp = arg.properties.find(
|
|
5552
|
+
(p) => ts5.isPropertyAssignment(p) && ts5.isIdentifier(p.name) && p.name.text === "typeName"
|
|
5553
|
+
);
|
|
5554
|
+
if (typeNameProp === void 0 || !ts5.isStringLiteral(typeNameProp.initializer)) {
|
|
5555
|
+
return null;
|
|
5556
|
+
}
|
|
5557
|
+
return typeNameProp.initializer.text;
|
|
5558
|
+
}
|
|
5559
|
+
function extractEnclosingExtensionId(call, checker) {
|
|
5560
|
+
for (let node = call.parent; !ts5.isSourceFile(node); node = node.parent) {
|
|
5561
|
+
if (ts5.isCallExpression(node) && isDefineExtensionCall(node, checker)) {
|
|
5562
|
+
return extractExtensionIdFromCallArg(node);
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
return null;
|
|
5566
|
+
}
|
|
5567
|
+
function isDefineExtensionCall(node, checker) {
|
|
5568
|
+
const callSymbol = checker.getSymbolAtLocation(node.expression);
|
|
5569
|
+
if (callSymbol !== void 0) {
|
|
5570
|
+
const resolved = callSymbol.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(callSymbol) : callSymbol;
|
|
5571
|
+
const decl = resolved.declarations?.[0];
|
|
5572
|
+
if (decl !== void 0) {
|
|
5573
|
+
const sourceFile = decl.getSourceFile().fileName.replace(/\\/g, "/");
|
|
5574
|
+
return resolved.name === "defineExtension" && (sourceFile.includes("@formspec/core") || sourceFile.includes("/packages/core/"));
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
return ts5.isIdentifier(node.expression) && node.expression.text === "defineExtension";
|
|
5578
|
+
}
|
|
5579
|
+
function extractExtensionIdFromCallArg(call) {
|
|
5580
|
+
const arg = call.arguments[0];
|
|
5581
|
+
if (arg === void 0 || !ts5.isObjectLiteralExpression(arg)) {
|
|
5582
|
+
return null;
|
|
5583
|
+
}
|
|
5584
|
+
const prop = arg.properties.find(
|
|
5585
|
+
(p) => ts5.isPropertyAssignment(p) && ts5.isIdentifier(p.name) && p.name.text === "extensionId"
|
|
5586
|
+
);
|
|
5587
|
+
if (prop === void 0 || !ts5.isStringLiteral(prop.initializer)) {
|
|
5588
|
+
return null;
|
|
5589
|
+
}
|
|
5590
|
+
return prop.initializer.text;
|
|
5591
|
+
}
|
|
5592
|
+
function findRegistrationByTypeName(registry, typeName) {
|
|
5593
|
+
for (const ext of registry.extensions) {
|
|
5594
|
+
if (ext.types === void 0) {
|
|
5595
|
+
continue;
|
|
5596
|
+
}
|
|
5597
|
+
for (const type of ext.types) {
|
|
5598
|
+
if (type.typeName === typeName) {
|
|
5599
|
+
return { extensionId: ext.extensionId, registration: type };
|
|
5600
|
+
}
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
return void 0;
|
|
5604
|
+
}
|
|
5605
|
+
|
|
5373
5606
|
// src/validate/constraint-validator.ts
|
|
5374
5607
|
var import_internal4 = require("@formspec/analysis/internal");
|
|
5375
5608
|
function validateFieldNode(ctx, field) {
|
|
@@ -5502,7 +5735,8 @@ function formatLocation(location) {
|
|
|
5502
5735
|
return `${location.file}:${String(location.line)}:${String(location.column)}`;
|
|
5503
5736
|
}
|
|
5504
5737
|
function generateSchemasFromClass(options) {
|
|
5505
|
-
const
|
|
5738
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5739
|
+
const ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5506
5740
|
const classDecl = findClassByName(ctx.sourceFile, options.className);
|
|
5507
5741
|
if (!classDecl) {
|
|
5508
5742
|
throw new Error(`Class "${options.className}" not found in ${options.filePath}`);
|
|
@@ -5567,7 +5801,8 @@ function generateSchemasDetailed(options) {
|
|
|
5567
5801
|
function generateSchemasDetailedInternal(options) {
|
|
5568
5802
|
let ctx;
|
|
5569
5803
|
try {
|
|
5570
|
-
|
|
5804
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5805
|
+
ctx = createProgramContext(options.filePath, additionalFiles);
|
|
5571
5806
|
} catch (error) {
|
|
5572
5807
|
return {
|
|
5573
5808
|
ok: false,
|
|
@@ -5606,13 +5841,16 @@ function generateSchemasFromProgramDetailedInternal(options) {
|
|
|
5606
5841
|
}
|
|
5607
5842
|
function generateSchemasBatch(options) {
|
|
5608
5843
|
const contextCache = /* @__PURE__ */ new Map();
|
|
5844
|
+
const resolved = resolveOptions(options);
|
|
5845
|
+
let symbolMapProgram;
|
|
5609
5846
|
return options.targets.map((target) => {
|
|
5610
5847
|
let ctx;
|
|
5611
5848
|
try {
|
|
5612
|
-
const cacheKey =
|
|
5849
|
+
const cacheKey = ts6.sys.useCaseSensitiveFileNames ? target.filePath : target.filePath.toLowerCase();
|
|
5613
5850
|
const cachedContext = contextCache.get(cacheKey);
|
|
5614
5851
|
if (cachedContext === void 0) {
|
|
5615
|
-
|
|
5852
|
+
const additionalFiles = options.configPath !== void 0 ? [options.configPath] : void 0;
|
|
5853
|
+
ctx = createProgramContext(target.filePath, additionalFiles);
|
|
5616
5854
|
contextCache.set(cacheKey, ctx);
|
|
5617
5855
|
} else {
|
|
5618
5856
|
ctx = cachedContext;
|
|
@@ -5623,9 +5861,25 @@ function generateSchemasBatch(options) {
|
|
|
5623
5861
|
diagnostics: [createProgramContextFailureDiagnostic(target.filePath, error)]
|
|
5624
5862
|
});
|
|
5625
5863
|
}
|
|
5864
|
+
if (options.configPath !== void 0 && resolved.extensionRegistry !== void 0 && isMutableRegistry(resolved.extensionRegistry) && ctx.program !== symbolMapProgram) {
|
|
5865
|
+
const symbolMap = buildSymbolMapFromConfig(
|
|
5866
|
+
options.configPath,
|
|
5867
|
+
ctx.program,
|
|
5868
|
+
ctx.checker,
|
|
5869
|
+
resolved.extensionRegistry
|
|
5870
|
+
);
|
|
5871
|
+
resolved.extensionRegistry.setSymbolMap(symbolMap);
|
|
5872
|
+
symbolMapProgram = ctx.program;
|
|
5873
|
+
}
|
|
5626
5874
|
return withTarget(
|
|
5627
5875
|
target,
|
|
5628
|
-
|
|
5876
|
+
generateSchemasFromResolvedOptions(
|
|
5877
|
+
ctx,
|
|
5878
|
+
target.filePath,
|
|
5879
|
+
target.typeName,
|
|
5880
|
+
resolved,
|
|
5881
|
+
options.discriminator
|
|
5882
|
+
)
|
|
5629
5883
|
);
|
|
5630
5884
|
});
|
|
5631
5885
|
}
|
|
@@ -5646,11 +5900,19 @@ function generateSchemasBatchFromProgram(options) {
|
|
|
5646
5900
|
);
|
|
5647
5901
|
});
|
|
5648
5902
|
}
|
|
5903
|
+
function isMutableRegistry(reg) {
|
|
5904
|
+
return "setSymbolMap" in reg && typeof reg.setSymbolMap === "function";
|
|
5905
|
+
}
|
|
5649
5906
|
function resolveOptions(options) {
|
|
5650
5907
|
const configRegistry = options.config?.extensions !== void 0 ? createExtensionRegistry(options.config.extensions) : void 0;
|
|
5908
|
+
const legacyRegistry = options.extensionRegistry;
|
|
5651
5909
|
return {
|
|
5652
|
-
//
|
|
5653
|
-
|
|
5910
|
+
// When the caller provides the deprecated extensionRegistry field directly,
|
|
5911
|
+
// it is typed as the read-only ExtensionRegistry interface. We cast here
|
|
5912
|
+
// because the legacy path was introduced before MutableExtensionRegistry was
|
|
5913
|
+
// split out; callers using createExtensionRegistry() always get a mutable
|
|
5914
|
+
// registry, and this cast is safe for all registries produced by this module.
|
|
5915
|
+
extensionRegistry: legacyRegistry ?? configRegistry,
|
|
5654
5916
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
5655
5917
|
vendorPrefix: options.vendorPrefix ?? options.config?.vendorPrefix,
|
|
5656
5918
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
@@ -5661,13 +5923,31 @@ function resolveOptions(options) {
|
|
|
5661
5923
|
}
|
|
5662
5924
|
function generateSchemasFromDetailedProgramContext(ctx, filePath, typeName, options) {
|
|
5663
5925
|
const resolved = resolveOptions(options);
|
|
5926
|
+
if (options.configPath !== void 0 && resolved.extensionRegistry !== void 0 && isMutableRegistry(resolved.extensionRegistry)) {
|
|
5927
|
+
const symbolMap = buildSymbolMapFromConfig(
|
|
5928
|
+
options.configPath,
|
|
5929
|
+
ctx.program,
|
|
5930
|
+
ctx.checker,
|
|
5931
|
+
resolved.extensionRegistry
|
|
5932
|
+
);
|
|
5933
|
+
resolved.extensionRegistry.setSymbolMap(symbolMap);
|
|
5934
|
+
}
|
|
5935
|
+
return generateSchemasFromResolvedOptions(
|
|
5936
|
+
ctx,
|
|
5937
|
+
filePath,
|
|
5938
|
+
typeName,
|
|
5939
|
+
resolved,
|
|
5940
|
+
options.discriminator
|
|
5941
|
+
);
|
|
5942
|
+
}
|
|
5943
|
+
function generateSchemasFromResolvedOptions(ctx, filePath, typeName, resolved, discriminator) {
|
|
5664
5944
|
const analysisResult = analyzeNamedTypeToIRFromProgramContextDetailed(
|
|
5665
5945
|
ctx,
|
|
5666
5946
|
filePath,
|
|
5667
5947
|
typeName,
|
|
5668
5948
|
resolved.extensionRegistry,
|
|
5669
5949
|
resolved.metadata,
|
|
5670
|
-
|
|
5950
|
+
discriminator
|
|
5671
5951
|
);
|
|
5672
5952
|
if (!analysisResult.ok) {
|
|
5673
5953
|
return {
|
|
@@ -5709,7 +5989,7 @@ function createProgramContextFailureDiagnostic(filePath, error) {
|
|
|
5709
5989
|
}
|
|
5710
5990
|
|
|
5711
5991
|
// src/static-build.ts
|
|
5712
|
-
var
|
|
5992
|
+
var ts7 = __toESM(require("typescript"), 1);
|
|
5713
5993
|
function toStaticBuildContext(context) {
|
|
5714
5994
|
return context;
|
|
5715
5995
|
}
|
|
@@ -5724,7 +6004,7 @@ function getModuleSymbol(context) {
|
|
|
5724
6004
|
return context.checker.getSymbolAtLocation(context.sourceFile) ?? sourceFileWithSymbol.symbol;
|
|
5725
6005
|
}
|
|
5726
6006
|
function isSchemaSourceDeclaration(declaration) {
|
|
5727
|
-
return
|
|
6007
|
+
return ts7.isClassDeclaration(declaration) || ts7.isInterfaceDeclaration(declaration) || ts7.isTypeAliasDeclaration(declaration);
|
|
5728
6008
|
}
|
|
5729
6009
|
function resolveModuleExport(context, exportName = "default") {
|
|
5730
6010
|
const moduleSymbol = getModuleSymbol(context);
|
|
@@ -5735,14 +6015,14 @@ function resolveModuleExport(context, exportName = "default") {
|
|
|
5735
6015
|
if (exportSymbol === null) {
|
|
5736
6016
|
return null;
|
|
5737
6017
|
}
|
|
5738
|
-
return exportSymbol.flags &
|
|
6018
|
+
return exportSymbol.flags & ts7.SymbolFlags.Alias ? context.checker.getAliasedSymbol(exportSymbol) : exportSymbol;
|
|
5739
6019
|
}
|
|
5740
6020
|
function resolveModuleExportDeclaration(context, exportName = "default") {
|
|
5741
6021
|
return resolveModuleExport(context, exportName)?.declarations?.find(isSchemaSourceDeclaration) ?? null;
|
|
5742
6022
|
}
|
|
5743
6023
|
|
|
5744
6024
|
// src/generators/discovered-schema.ts
|
|
5745
|
-
var
|
|
6025
|
+
var ts8 = __toESM(require("typescript"), 1);
|
|
5746
6026
|
var import_internal5 = require("@formspec/analysis/internal");
|
|
5747
6027
|
var import_internals6 = require("@formspec/core/internals");
|
|
5748
6028
|
function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
@@ -5752,17 +6032,17 @@ function toDiscoveredTypeSchemas(result, resolvedMetadata) {
|
|
|
5752
6032
|
};
|
|
5753
6033
|
}
|
|
5754
6034
|
function isNamedTypeDeclaration(declaration) {
|
|
5755
|
-
return
|
|
6035
|
+
return ts8.isClassDeclaration(declaration) || ts8.isInterfaceDeclaration(declaration) || ts8.isTypeAliasDeclaration(declaration);
|
|
5756
6036
|
}
|
|
5757
6037
|
function hasConcreteTypeArguments(type, checker) {
|
|
5758
6038
|
if ("aliasTypeArguments" in type && Array.isArray(type.aliasTypeArguments) && type.aliasTypeArguments.length > 0) {
|
|
5759
6039
|
return true;
|
|
5760
6040
|
}
|
|
5761
|
-
if ((type.flags &
|
|
6041
|
+
if ((type.flags & ts8.TypeFlags.Object) === 0) {
|
|
5762
6042
|
return false;
|
|
5763
6043
|
}
|
|
5764
6044
|
const objectType = type;
|
|
5765
|
-
if ((objectType.objectFlags &
|
|
6045
|
+
if ((objectType.objectFlags & ts8.ObjectFlags.Reference) === 0) {
|
|
5766
6046
|
return false;
|
|
5767
6047
|
}
|
|
5768
6048
|
return checker.getTypeArguments(objectType).length > 0;
|
|
@@ -5775,13 +6055,13 @@ function getNamedTypeDeclaration2(type) {
|
|
|
5775
6055
|
return declaration;
|
|
5776
6056
|
}
|
|
5777
6057
|
}
|
|
5778
|
-
const aliasDeclaration = type.aliasSymbol?.declarations?.find(
|
|
6058
|
+
const aliasDeclaration = type.aliasSymbol?.declarations?.find(ts8.isTypeAliasDeclaration);
|
|
5779
6059
|
return aliasDeclaration;
|
|
5780
6060
|
}
|
|
5781
6061
|
function getFallbackName(sourceNode, fallback = "AnonymousType") {
|
|
5782
6062
|
if (sourceNode !== void 0 && "name" in sourceNode) {
|
|
5783
6063
|
const namedNode = sourceNode;
|
|
5784
|
-
if (namedNode.name !== void 0 &&
|
|
6064
|
+
if (namedNode.name !== void 0 && ts8.isIdentifier(namedNode.name)) {
|
|
5785
6065
|
return namedNode.name.text;
|
|
5786
6066
|
}
|
|
5787
6067
|
}
|
|
@@ -5900,17 +6180,14 @@ function toStandaloneJsonSchema(root, typeRegistry, options) {
|
|
|
5900
6180
|
rootLogicalName: root.name
|
|
5901
6181
|
}
|
|
5902
6182
|
);
|
|
5903
|
-
const schema = generateJsonSchemaFromIR(
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
vendorPrefix: options?.vendorPrefix
|
|
5912
|
-
}
|
|
5913
|
-
);
|
|
6183
|
+
const schema = generateJsonSchemaFromIR(ir, {
|
|
6184
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6185
|
+
extensionRegistry: options?.extensionRegistry,
|
|
6186
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6187
|
+
enumSerialization: options?.enumSerialization,
|
|
6188
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- migration bridge reads deprecated fields
|
|
6189
|
+
vendorPrefix: options?.vendorPrefix
|
|
6190
|
+
});
|
|
5914
6191
|
const result = schema.properties?.["__result"];
|
|
5915
6192
|
if (result === void 0) {
|
|
5916
6193
|
throw new Error("FormSpec failed to extract the standalone schema root from the synthetic IR.");
|
|
@@ -6009,7 +6286,7 @@ function generateSchemasFromResolvedType(options, skipNamedDeclaration = false,
|
|
|
6009
6286
|
}
|
|
6010
6287
|
function generateSchemasFromDeclaration(options) {
|
|
6011
6288
|
const filePath = options.declaration.getSourceFile().fileName;
|
|
6012
|
-
if (
|
|
6289
|
+
if (ts8.isClassDeclaration(options.declaration)) {
|
|
6013
6290
|
return generateSchemasFromAnalysis(
|
|
6014
6291
|
analyzeClassToIR(
|
|
6015
6292
|
options.declaration,
|
|
@@ -6025,7 +6302,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
6025
6302
|
options
|
|
6026
6303
|
);
|
|
6027
6304
|
}
|
|
6028
|
-
if (
|
|
6305
|
+
if (ts8.isInterfaceDeclaration(options.declaration)) {
|
|
6029
6306
|
return generateSchemasFromAnalysis(
|
|
6030
6307
|
analyzeInterfaceToIR(
|
|
6031
6308
|
options.declaration,
|
|
@@ -6041,7 +6318,7 @@ function generateSchemasFromDeclaration(options) {
|
|
|
6041
6318
|
options
|
|
6042
6319
|
);
|
|
6043
6320
|
}
|
|
6044
|
-
if (
|
|
6321
|
+
if (ts8.isTypeAliasDeclaration(options.declaration)) {
|
|
6045
6322
|
const analyzedAlias = analyzeTypeAliasToIR(
|
|
6046
6323
|
options.declaration,
|
|
6047
6324
|
options.context.checker,
|
|
@@ -6104,7 +6381,7 @@ function generateSchemasFromReturnType(options) {
|
|
|
6104
6381
|
const returnType = signature !== void 0 ? options.context.checker.getReturnTypeOfSignature(signature) : options.context.checker.getTypeAtLocation(options.declaration);
|
|
6105
6382
|
const type = unwrapPromiseType(options.context.checker, returnType);
|
|
6106
6383
|
const sourceNode = type !== returnType ? unwrapPromiseTypeNode(options.declaration.type) ?? options.declaration.type ?? options.declaration : options.declaration.type ?? options.declaration;
|
|
6107
|
-
const fallbackName = options.declaration.name !== void 0 &&
|
|
6384
|
+
const fallbackName = options.declaration.name !== void 0 && ts8.isIdentifier(options.declaration.name) ? `${options.declaration.name.text}ReturnType` : "ReturnType";
|
|
6108
6385
|
return generateSchemasFromResolvedType({
|
|
6109
6386
|
...options,
|
|
6110
6387
|
type,
|
|
@@ -6139,14 +6416,14 @@ function unwrapPromiseTypeNode(typeNode) {
|
|
|
6139
6416
|
if (typeNode === void 0) {
|
|
6140
6417
|
return void 0;
|
|
6141
6418
|
}
|
|
6142
|
-
if (
|
|
6419
|
+
if (ts8.isParenthesizedTypeNode(typeNode)) {
|
|
6143
6420
|
const unwrapped = unwrapPromiseTypeNode(typeNode.type);
|
|
6144
6421
|
return unwrapped ?? typeNode;
|
|
6145
6422
|
}
|
|
6146
6423
|
return isPromiseTypeReferenceNode(typeNode) ? typeNode.typeArguments[0] : typeNode;
|
|
6147
6424
|
}
|
|
6148
6425
|
function isPromiseTypeReferenceNode(typeNode) {
|
|
6149
|
-
return
|
|
6426
|
+
return ts8.isTypeReferenceNode(typeNode) && ts8.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments !== void 0 && typeNode.typeArguments.length > 0;
|
|
6150
6427
|
}
|
|
6151
6428
|
|
|
6152
6429
|
// src/generators/mixed-authoring.ts
|
|
@@ -6368,8 +6645,8 @@ function writeSchemas(form, options) {
|
|
|
6368
6645
|
if (!fs.existsSync(outDir)) {
|
|
6369
6646
|
fs.mkdirSync(outDir, { recursive: true });
|
|
6370
6647
|
}
|
|
6371
|
-
const jsonSchemaPath =
|
|
6372
|
-
const uiSchemaPath =
|
|
6648
|
+
const jsonSchemaPath = path3.join(outDir, `${name}-schema.json`);
|
|
6649
|
+
const uiSchemaPath = path3.join(outDir, `${name}-uischema.json`);
|
|
6373
6650
|
fs.writeFileSync(jsonSchemaPath, JSON.stringify(jsonSchema, null, indent));
|
|
6374
6651
|
fs.writeFileSync(uiSchemaPath, JSON.stringify(uiSchema2, null, indent));
|
|
6375
6652
|
return { jsonSchemaPath, uiSchemaPath };
|