@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 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertz/compiler",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Vertz compiler — internal, no stability guarantee",