@vertz/compiler 0.2.18 → 0.2.20
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/index.d.ts +27 -2
- package/dist/index.js +82 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type DiagnosticSeverity = "error" | "warning" | "info";
|
|
2
|
-
type DiagnosticCode = "VERTZ_SCHEMA_NAMING" | "VERTZ_SCHEMA_PLACEMENT" | "VERTZ_SCHEMA_EXECUTION" | "VERTZ_SCHEMA_MISSING_ID" | "VERTZ_SCHEMA_DYNAMIC_NAME" | "VERTZ_MODULE_CIRCULAR" | "VERTZ_MODULE_EXPORT_INVALID" | "VERTZ_MODULE_IMPORT_MISSING" | "VERTZ_MODULE_DUPLICATE_NAME" | "VERTZ_MODULE_DYNAMIC_NAME" | "VERTZ_MODULE_OPTIONS_INVALID" | "VERTZ_MODULE_WRONG_OWNERSHIP" | "VERTZ_SERVICE_INJECT_MISSING" | "VERTZ_SERVICE_UNUSED" | "VERTZ_SERVICE_DYNAMIC_NAME" | "VERTZ_ENV_MISSING_DEFAULT" | "VERTZ_ENV_DUPLICATE" | "VERTZ_ENV_DYNAMIC_CONFIG" | "VERTZ_MW_MISSING_NAME" | "VERTZ_MW_MISSING_HANDLER" | "VERTZ_MW_DYNAMIC_NAME" | "VERTZ_MW_NON_OBJECT_CONFIG" | "VERTZ_MW_REQUIRES_UNSATISFIED" | "VERTZ_MW_PROVIDES_COLLISION" | "VERTZ_MW_ORDER_INVALID" | "VERTZ_RT_UNKNOWN_MODULE_DEF" | "VERTZ_RT_DYNAMIC_PATH" | "VERTZ_RT_MISSING_HANDLER" | "VERTZ_RT_MISSING_PREFIX" | "VERTZ_RT_DYNAMIC_CONFIG" | "VERTZ_RT_INVALID_PATH" | "VERTZ_ROUTE_DUPLICATE" | "VERTZ_ROUTE_PARAM_MISMATCH" | "VERTZ_ROUTE_MISSING_RESPONSE" | "VERTZ_APP_MISSING" | "VERTZ_APP_NOT_FOUND" | "VERTZ_APP_DUPLICATE" | "VERTZ_APP_BASEPATH_FORMAT" | "VERTZ_APP_INLINE_MODULE" | "VERTZ_DEP_CYCLE" | "VERTZ_DEP_CIRCULAR" | "VERTZ_DEP_UNRESOLVED_INJECT" | "VERTZ_DEP_INIT_ORDER" | "VERTZ_CTX_COLLISION" | "VERTZ_DEAD_CODE" | "ENTITY_MISSING_ARGS" | "ENTITY_NON_LITERAL_NAME" | "ENTITY_INVALID_NAME" | "ENTITY_DUPLICATE_NAME" | "ENTITY_CONFIG_NOT_OBJECT" | "ENTITY_MISSING_MODEL" | "ENTITY_MODEL_UNRESOLVABLE" | "ENTITY_ACTION_NAME_COLLISION" | "ENTITY_ACTION_MISSING_SCHEMA" | "ENTITY_ACTION_INVALID_METHOD" | "ENTITY_UNKNOWN_ACCESS_OP" | "ENTITY_UNRESOLVED_IMPORT" | "ENTITY_ROUTE_COLLISION" | "ENTITY_NO_ROUTES" | "ENTITY_MODEL_NOT_REGISTERED" | "ACCESS_MULTIPLE_DEFINITIONS" | "ACCESS_NON_LITERAL_KEY" | "ACCESS_NON_LITERAL_ROLE" | "ACCESS_DUPLICATE_ENTITLEMENT" | "ACCESS_WHERE_NOT_TRANSLATABLE";
|
|
2
|
+
type DiagnosticCode = "VERTZ_SCHEMA_NAMING" | "VERTZ_SCHEMA_PLACEMENT" | "VERTZ_SCHEMA_EXECUTION" | "VERTZ_SCHEMA_MISSING_ID" | "VERTZ_SCHEMA_DYNAMIC_NAME" | "VERTZ_MODULE_CIRCULAR" | "VERTZ_MODULE_EXPORT_INVALID" | "VERTZ_MODULE_IMPORT_MISSING" | "VERTZ_MODULE_DUPLICATE_NAME" | "VERTZ_MODULE_DYNAMIC_NAME" | "VERTZ_MODULE_OPTIONS_INVALID" | "VERTZ_MODULE_WRONG_OWNERSHIP" | "VERTZ_SERVICE_INJECT_MISSING" | "VERTZ_SERVICE_UNUSED" | "VERTZ_SERVICE_DYNAMIC_NAME" | "VERTZ_ENV_MISSING_DEFAULT" | "VERTZ_ENV_DUPLICATE" | "VERTZ_ENV_DYNAMIC_CONFIG" | "VERTZ_MW_MISSING_NAME" | "VERTZ_MW_MISSING_HANDLER" | "VERTZ_MW_DYNAMIC_NAME" | "VERTZ_MW_NON_OBJECT_CONFIG" | "VERTZ_MW_REQUIRES_UNSATISFIED" | "VERTZ_MW_PROVIDES_COLLISION" | "VERTZ_MW_ORDER_INVALID" | "VERTZ_RT_UNKNOWN_MODULE_DEF" | "VERTZ_RT_DYNAMIC_PATH" | "VERTZ_RT_MISSING_HANDLER" | "VERTZ_RT_MISSING_PREFIX" | "VERTZ_RT_DYNAMIC_CONFIG" | "VERTZ_RT_INVALID_PATH" | "VERTZ_ROUTE_DUPLICATE" | "VERTZ_ROUTE_PARAM_MISMATCH" | "VERTZ_ROUTE_MISSING_RESPONSE" | "VERTZ_APP_MISSING" | "VERTZ_APP_NOT_FOUND" | "VERTZ_APP_DUPLICATE" | "VERTZ_APP_BASEPATH_FORMAT" | "VERTZ_APP_INLINE_MODULE" | "VERTZ_DEP_CYCLE" | "VERTZ_DEP_CIRCULAR" | "VERTZ_DEP_UNRESOLVED_INJECT" | "VERTZ_DEP_INIT_ORDER" | "VERTZ_CTX_COLLISION" | "VERTZ_DEAD_CODE" | "ENTITY_MISSING_ARGS" | "ENTITY_NON_LITERAL_NAME" | "ENTITY_INVALID_NAME" | "ENTITY_DUPLICATE_NAME" | "ENTITY_CONFIG_NOT_OBJECT" | "ENTITY_MISSING_MODEL" | "ENTITY_MODEL_UNRESOLVABLE" | "ENTITY_ACTION_NAME_COLLISION" | "ENTITY_ACTION_MISSING_SCHEMA" | "ENTITY_ACTION_INVALID_METHOD" | "ENTITY_UNKNOWN_ACCESS_OP" | "ENTITY_UNRESOLVED_IMPORT" | "ENTITY_ROUTE_COLLISION" | "ENTITY_NO_ROUTES" | "ENTITY_MODEL_NOT_REGISTERED" | "ENTITY_EXPOSE_EMPTY_SELECT" | "ENTITY_EXPOSE_NON_LITERAL" | "ENTITY_EXPOSE_RELATION_UNRESOLVED" | "ACCESS_MULTIPLE_DEFINITIONS" | "ACCESS_NON_LITERAL_KEY" | "ACCESS_NON_LITERAL_ROLE" | "ACCESS_DUPLICATE_ENTITLEMENT" | "ACCESS_WHERE_NOT_TRANSLATABLE";
|
|
3
3
|
interface SourceContext {
|
|
4
4
|
lines: {
|
|
5
5
|
number: number;
|
|
@@ -197,9 +197,24 @@ interface EntityIR extends SourceLocation {
|
|
|
197
197
|
hooks: EntityHooksIR;
|
|
198
198
|
actions: EntityActionIR[];
|
|
199
199
|
relations: EntityRelationIR[];
|
|
200
|
+
expose?: EntityExposeIR;
|
|
200
201
|
tenantScoped?: boolean;
|
|
201
202
|
table?: string;
|
|
202
203
|
}
|
|
204
|
+
interface EntityExposeIR {
|
|
205
|
+
select: EntityExposeFieldIR[];
|
|
206
|
+
include?: EntityExposeRelationIR[];
|
|
207
|
+
}
|
|
208
|
+
interface EntityExposeFieldIR {
|
|
209
|
+
name: string;
|
|
210
|
+
conditional: boolean;
|
|
211
|
+
}
|
|
212
|
+
interface EntityExposeRelationIR {
|
|
213
|
+
name: string;
|
|
214
|
+
entity?: string;
|
|
215
|
+
type?: "one" | "many";
|
|
216
|
+
select?: EntityExposeFieldIR[];
|
|
217
|
+
}
|
|
203
218
|
interface EntityModelRef {
|
|
204
219
|
variableName: string;
|
|
205
220
|
importSource?: string;
|
|
@@ -423,6 +438,9 @@ declare class EntityAnalyzer extends BaseAnalyzer<EntityAnalyzerResult> {
|
|
|
423
438
|
private extractActions;
|
|
424
439
|
private resolveSchemaFromExpression;
|
|
425
440
|
private extractRelations;
|
|
441
|
+
private extractExpose;
|
|
442
|
+
private extractExposeFields;
|
|
443
|
+
private checkExposeNonLiteral;
|
|
426
444
|
/**
|
|
427
445
|
* Extract primaryKey and hiddenFields from the model's table type.
|
|
428
446
|
* Navigates ModelDef.table._columns to inspect column metadata.
|
|
@@ -434,6 +452,13 @@ declare class EntityAnalyzer extends BaseAnalyzer<EntityAnalyzerResult> {
|
|
|
434
452
|
*/
|
|
435
453
|
private resolveModelRelationTypes;
|
|
436
454
|
/**
|
|
455
|
+
* Post-processing: validate expose.include relations after entity resolution.
|
|
456
|
+
* Emits ENTITY_EXPOSE_RELATION_UNRESOLVED for relations whose target entity
|
|
457
|
+
* could not be resolved. The IR preserves the entries; the ir-adapter handles
|
|
458
|
+
* omission from codegen output.
|
|
459
|
+
*/
|
|
460
|
+
private validateExposeRelations;
|
|
461
|
+
/**
|
|
437
462
|
* Post-processing: resolve relation `entity` fields by matching
|
|
438
463
|
* each relation's _target return type to the table type of known entities.
|
|
439
464
|
*/
|
|
@@ -911,4 +936,4 @@ declare class PlacementValidator implements Validator {
|
|
|
911
936
|
private checkFileLocation;
|
|
912
937
|
private checkMixedExports;
|
|
913
938
|
}
|
|
914
|
-
export { typecheckWatch, typecheck, resolveImportPath, resolveIdentifier, resolveExport, resolveConfig, renderSchemaRegistryFile, renderRouteTableFile, renderBootFile, parseWatchBlock, parseTscOutput, parseSchemaName2 as parseSchemaName, parseInjectRefs, parseImports, mergeIR, mergeDiagnostics, isSchemaFile, isSchemaExpression, isFromImport, injectEntityRoutes, hasErrors, getVariableNameForCall, getStringValue, getSourceLocation, getPropertyValue, getProperties, getNumberValue, getBooleanValue, getArrayElements, findMethodCallsOnVariable, findCallExpressions, findAffectedModules, filterBySeverity, extractSchemaId, extractObjectLiteral, extractMethodSignatures, extractIdentifierNames, detectRouteCollisions, defineConfig, createSchemaExecutor, createNamedSchemaRef, createInlineSchemaRef, createEmptyDependencyGraph, createEmptyAppIR, createDiagnosticFromLocation, createDiagnostic, createCompiler, categorizeChanges, buildSchemaRegistry, buildRouteTable, buildManifest, buildBootManifest, addDiagnosticsToIR, VertzConfig, Validator, ValidationConfig, ValidPart, ValidOperation, TypecheckWatchOptions, TypecheckResult, TypecheckOptions, TypecheckDiagnostic, SourceLocation, SourceContext, ServiceMethodParam, ServiceMethodIR, ServiceIR, ServiceAnalyzerResult, ServiceAnalyzer, SchemaRegistryManifest, SchemaRegistryGenerator, SchemaRegistryEntry, SchemaRef, SchemaNameParts, SchemaIR, SchemaExecutor, SchemaExecutionResult, SchemaConfig, SchemaAnalyzerResult, SchemaAnalyzer, RouterIR, RouteTableSchemas, RouteTableManifest, RouteTableGenerator, RouteTableEntry, RouteIR, RouteAnalyzerResult, RouteAnalyzer, ResolvedImport, ResolvedConfig, PlacementValidator, ParsedSchemaName, OpenAPITag, OpenAPIServer, OpenAPIResponse, OpenAPIRequestBody, OpenAPIPathItem, OpenAPIParameter, OpenAPIOperation, OpenAPIInfo, OpenAPIGenerator, OpenAPIDocument, OpenAPIConfig, NamingValidator, NamedSchemaRef, ModuleValidator, ModuleRegistration, ModuleIR, ModuleDefContext, ModuleAnalyzerResult, ModuleAnalyzer, MiddlewareRef, MiddlewareIR, MiddlewareAnalyzerResult, MiddlewareAnalyzer, ManifestRoute, ManifestModule, ManifestMiddleware, ManifestGenerator, ManifestDiagnostic, ManifestDependencyEdge, JSONSchemaObject, InlineSchemaRef, InjectRef, IncrementalResult, IncrementalCompiler, ImportRef, HttpMethod, Generator, FileChange, FileCategory, EnvVariableIR, EnvIR, EnvAnalyzerResult, EnvAnalyzer, EntityRelationIR, EntityModelSchemaRefs, EntityModelRef, EntityIR, EntityHooksIR, EntityAnalyzerResult, EntityAnalyzer, EntityActionIR, EntityAccessRuleKind, EntityAccessIR, DiagnosticSeverity, DiagnosticCode, Diagnostic, DependencyNodeKind, DependencyNode, DependencyGraphResult, DependencyGraphInput, DependencyGraphIR, DependencyGraphAnalyzer, DependencyEdgeKind, DependencyEdge, DatabaseIR, DatabaseAnalyzerResult, DatabaseAnalyzer, CreateDiagnosticOptions, CompletenessValidator, CompilerDependencies, CompilerConfig, Compiler, CompileResult, CategorizedChanges, CategorizeOptions, BootModuleEntry, BootMiddlewareEntry, BootManifest, BootGenerator, BaseGenerator, BaseAnalyzer, AppManifest, AppIR, AppDefinition, AppAnalyzerResult, AppAnalyzer, Analyzer, AccessWhereCondition, AccessWhereClauseIR, AccessIR, AccessEntityIR, AccessAnalyzerResult, AccessAnalyzer };
|
|
939
|
+
export { typecheckWatch, typecheck, resolveImportPath, resolveIdentifier, resolveExport, resolveConfig, renderSchemaRegistryFile, renderRouteTableFile, renderBootFile, parseWatchBlock, parseTscOutput, parseSchemaName2 as parseSchemaName, parseInjectRefs, parseImports, mergeIR, mergeDiagnostics, isSchemaFile, isSchemaExpression, isFromImport, injectEntityRoutes, hasErrors, getVariableNameForCall, getStringValue, getSourceLocation, getPropertyValue, getProperties, getNumberValue, getBooleanValue, getArrayElements, findMethodCallsOnVariable, findCallExpressions, findAffectedModules, filterBySeverity, extractSchemaId, extractObjectLiteral, extractMethodSignatures, extractIdentifierNames, detectRouteCollisions, defineConfig, createSchemaExecutor, createNamedSchemaRef, createInlineSchemaRef, createEmptyDependencyGraph, createEmptyAppIR, createDiagnosticFromLocation, createDiagnostic, createCompiler, categorizeChanges, buildSchemaRegistry, buildRouteTable, buildManifest, buildBootManifest, addDiagnosticsToIR, VertzConfig, Validator, ValidationConfig, ValidPart, ValidOperation, TypecheckWatchOptions, TypecheckResult, TypecheckOptions, TypecheckDiagnostic, SourceLocation, SourceContext, ServiceMethodParam, ServiceMethodIR, ServiceIR, ServiceAnalyzerResult, ServiceAnalyzer, SchemaRegistryManifest, SchemaRegistryGenerator, SchemaRegistryEntry, SchemaRef, SchemaNameParts, SchemaIR, SchemaExecutor, SchemaExecutionResult, SchemaConfig, SchemaAnalyzerResult, SchemaAnalyzer, RouterIR, RouteTableSchemas, RouteTableManifest, RouteTableGenerator, RouteTableEntry, RouteIR, RouteAnalyzerResult, RouteAnalyzer, ResolvedImport, ResolvedConfig, PlacementValidator, ParsedSchemaName, OpenAPITag, OpenAPIServer, OpenAPIResponse, OpenAPIRequestBody, OpenAPIPathItem, OpenAPIParameter, OpenAPIOperation, OpenAPIInfo, OpenAPIGenerator, OpenAPIDocument, OpenAPIConfig, NamingValidator, NamedSchemaRef, ModuleValidator, ModuleRegistration, ModuleIR, ModuleDefContext, ModuleAnalyzerResult, ModuleAnalyzer, MiddlewareRef, MiddlewareIR, MiddlewareAnalyzerResult, MiddlewareAnalyzer, ManifestRoute, ManifestModule, ManifestMiddleware, ManifestGenerator, ManifestDiagnostic, ManifestDependencyEdge, JSONSchemaObject, InlineSchemaRef, InjectRef, IncrementalResult, IncrementalCompiler, ImportRef, HttpMethod, Generator, FileChange, FileCategory, EnvVariableIR, EnvIR, EnvAnalyzerResult, EnvAnalyzer, EntityRelationIR, EntityModelSchemaRefs, EntityModelRef, EntityIR, EntityHooksIR, EntityExposeRelationIR, EntityExposeIR, EntityExposeFieldIR, EntityAnalyzerResult, EntityAnalyzer, EntityActionIR, EntityAccessRuleKind, EntityAccessIR, DiagnosticSeverity, DiagnosticCode, Diagnostic, DependencyNodeKind, DependencyNode, DependencyGraphResult, DependencyGraphInput, DependencyGraphIR, DependencyGraphAnalyzer, DependencyEdgeKind, DependencyEdge, DatabaseIR, DatabaseAnalyzerResult, DatabaseAnalyzer, CreateDiagnosticOptions, CompletenessValidator, CompilerDependencies, CompilerConfig, Compiler, CompileResult, CategorizedChanges, CategorizeOptions, BootModuleEntry, BootMiddlewareEntry, BootManifest, BootGenerator, BaseGenerator, BaseAnalyzer, AppManifest, AppIR, AppDefinition, AppAnalyzerResult, AppAnalyzer, Analyzer, AccessWhereCondition, AccessWhereClauseIR, AccessIR, AccessEntityIR, AccessAnalyzerResult, AccessAnalyzer };
|
package/dist/index.js
CHANGED
|
@@ -985,6 +985,7 @@ class EntityAnalyzer extends BaseAnalyzer {
|
|
|
985
985
|
}
|
|
986
986
|
}
|
|
987
987
|
this.resolveRelationEntities(entities, modelExprs);
|
|
988
|
+
this.validateExposeRelations(entities);
|
|
988
989
|
return { entities };
|
|
989
990
|
}
|
|
990
991
|
findEntityCalls(file) {
|
|
@@ -1079,6 +1080,7 @@ class EntityAnalyzer extends BaseAnalyzer {
|
|
|
1079
1080
|
if (modelExpr) {
|
|
1080
1081
|
this.extractModelTableMetadata(modelExpr, modelRef);
|
|
1081
1082
|
}
|
|
1083
|
+
const expose = this.extractExpose(configObj, loc);
|
|
1082
1084
|
for (const action of actions) {
|
|
1083
1085
|
if (CRUD_OPS.includes(action.name)) {
|
|
1084
1086
|
this.addDiagnostic({
|
|
@@ -1107,6 +1109,7 @@ class EntityAnalyzer extends BaseAnalyzer {
|
|
|
1107
1109
|
hooks,
|
|
1108
1110
|
actions,
|
|
1109
1111
|
relations,
|
|
1112
|
+
...expose ? { expose } : {},
|
|
1110
1113
|
...tenantScoped !== undefined && tenantScoped !== null ? { tenantScoped } : {},
|
|
1111
1114
|
...table !== undefined && table !== null ? { table } : {},
|
|
1112
1115
|
...loc
|
|
@@ -1445,6 +1448,65 @@ class EntityAnalyzer extends BaseAnalyzer {
|
|
|
1445
1448
|
};
|
|
1446
1449
|
});
|
|
1447
1450
|
}
|
|
1451
|
+
extractExpose(configObj, loc) {
|
|
1452
|
+
const exposeExpr = getPropertyValue(configObj, "expose");
|
|
1453
|
+
if (!exposeExpr || !exposeExpr.isKind(SyntaxKind5.ObjectLiteralExpression))
|
|
1454
|
+
return;
|
|
1455
|
+
const selectExpr = getPropertyValue(exposeExpr, "select");
|
|
1456
|
+
if (!selectExpr || !selectExpr.isKind(SyntaxKind5.ObjectLiteralExpression))
|
|
1457
|
+
return;
|
|
1458
|
+
this.checkExposeNonLiteral(selectExpr, "expose.select", loc);
|
|
1459
|
+
const select = this.extractExposeFields(selectExpr);
|
|
1460
|
+
if (select.length === 0) {
|
|
1461
|
+
this.addDiagnostic({
|
|
1462
|
+
code: "ENTITY_EXPOSE_EMPTY_SELECT",
|
|
1463
|
+
severity: "warning",
|
|
1464
|
+
message: "expose.select is empty — no fields will be visible in the API",
|
|
1465
|
+
...loc
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
const includeExpr = getPropertyValue(exposeExpr, "include");
|
|
1469
|
+
let include;
|
|
1470
|
+
if (includeExpr?.isKind(SyntaxKind5.ObjectLiteralExpression)) {
|
|
1471
|
+
this.checkExposeNonLiteral(includeExpr, "expose.include", loc);
|
|
1472
|
+
include = getProperties(includeExpr).filter(({ value }) => getBooleanValue(value) !== false).map(({ name, value }) => {
|
|
1473
|
+
const boolVal = getBooleanValue(value);
|
|
1474
|
+
if (boolVal === true || !value.isKind(SyntaxKind5.ObjectLiteralExpression)) {
|
|
1475
|
+
return { name };
|
|
1476
|
+
}
|
|
1477
|
+
const relSelectExpr = getPropertyValue(value, "select");
|
|
1478
|
+
if (relSelectExpr?.isKind(SyntaxKind5.ObjectLiteralExpression)) {
|
|
1479
|
+
return {
|
|
1480
|
+
name,
|
|
1481
|
+
select: this.extractExposeFields(relSelectExpr)
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
return { name };
|
|
1485
|
+
});
|
|
1486
|
+
if (include.length === 0)
|
|
1487
|
+
include = undefined;
|
|
1488
|
+
}
|
|
1489
|
+
return { select, ...include ? { include } : {} };
|
|
1490
|
+
}
|
|
1491
|
+
extractExposeFields(obj) {
|
|
1492
|
+
return getProperties(obj).map(({ name, value }) => ({
|
|
1493
|
+
name,
|
|
1494
|
+
conditional: getBooleanValue(value) !== true
|
|
1495
|
+
}));
|
|
1496
|
+
}
|
|
1497
|
+
checkExposeNonLiteral(obj, context, loc) {
|
|
1498
|
+
for (const prop of obj.getProperties()) {
|
|
1499
|
+
if (prop.isKind(SyntaxKind5.SpreadAssignment) || prop.isKind(SyntaxKind5.PropertyAssignment) && prop.getNameNode().isKind(SyntaxKind5.ComputedPropertyName)) {
|
|
1500
|
+
this.addDiagnostic({
|
|
1501
|
+
code: "ENTITY_EXPOSE_NON_LITERAL",
|
|
1502
|
+
severity: "warning",
|
|
1503
|
+
message: `${context} contains non-literal properties (spread or computed) that can't be statically analyzed`,
|
|
1504
|
+
...loc
|
|
1505
|
+
});
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1448
1510
|
extractModelTableMetadata(modelExpr, modelRef) {
|
|
1449
1511
|
try {
|
|
1450
1512
|
const modelType = modelExpr.getType();
|
|
@@ -1515,6 +1577,26 @@ class EntityAnalyzer extends BaseAnalyzer {
|
|
|
1515
1577
|
} catch {}
|
|
1516
1578
|
return result;
|
|
1517
1579
|
}
|
|
1580
|
+
validateExposeRelations(entities) {
|
|
1581
|
+
for (const entity of entities) {
|
|
1582
|
+
if (!entity.expose?.include)
|
|
1583
|
+
continue;
|
|
1584
|
+
const relationMap = new Map(entity.relations.map((r) => [r.name, r]));
|
|
1585
|
+
for (const rel of entity.expose.include) {
|
|
1586
|
+
const matchedRelation = relationMap.get(rel.name);
|
|
1587
|
+
if (!matchedRelation || !matchedRelation.entity) {
|
|
1588
|
+
this.addDiagnostic({
|
|
1589
|
+
code: "ENTITY_EXPOSE_RELATION_UNRESOLVED",
|
|
1590
|
+
severity: "warning",
|
|
1591
|
+
message: `expose.include references relation "${rel.name}" whose target entity could not be resolved`,
|
|
1592
|
+
file: entity.sourceFile,
|
|
1593
|
+
line: entity.sourceLine,
|
|
1594
|
+
column: entity.sourceColumn
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1518
1600
|
resolveRelationEntities(entities, modelExprs) {
|
|
1519
1601
|
try {
|
|
1520
1602
|
const tableToEntity = new Map;
|