@@ -100,6 +100,9 @@ export interface TypeParser {
100100 isNodeReferenceToEffectSqlModelModuleApi : (
101101 memberName : string
102102 ) => ( node : ts . Node ) => Nano . Nano < ts . SourceFile , TypeParserIssue , never >
103+ isNodeReferenceToEffectSchemaModelModuleApi : (
104+ memberName : string
105+ ) => ( node : ts . Node ) => Nano . Nano < ts . SourceFile , TypeParserIssue , never >
103106 isNodeReferenceToEffectLayerModuleApi : (
104107 memberName : string
105108 ) => ( node : ts . Node ) => Nano . Nano < ts . SourceFile , TypeParserIssue , never >
@@ -334,6 +337,14 @@ export interface TypeParser {
334337 TypeParserIssue ,
335338 never
336339 >
340+ extendsEffectSchemaModelClass : ( atLocation : ts . ClassDeclaration ) => Nano . Nano <
341+ {
342+ className : ts . Identifier
343+ selfTypeNode : ts . TypeNode
344+ } ,
345+ TypeParserIssue ,
346+ never
347+ >
337348 lazyExpression : ( node : ts . Node ) => Nano . Nano <
338349 ParsedLazyExpression ,
339350 TypeParserIssue ,
@@ -2451,6 +2462,87 @@ export function make(
24512462 ( atLocation ) => atLocation
24522463 )
24532464
2465+ const isEffectSchemaModelTypeSourceFile = Nano . cachedBy (
2466+ Nano . fn ( "TypeParser.isEffectSchemaModelTypeSourceFile" ) ( function * (
2467+ sourceFile : ts . SourceFile
2468+ ) {
2469+ const moduleSymbol = typeChecker . getSymbolAtLocation ( sourceFile )
2470+ if ( ! moduleSymbol ) return yield * typeParserIssue ( "Node has no symbol" , undefined , sourceFile )
2471+ // check for Class
2472+ const classSymbol = typeChecker . tryGetMemberInModuleExports ( "Class" , moduleSymbol )
2473+ if ( ! classSymbol ) return yield * typeParserIssue ( "Model's Class type not found" , undefined , sourceFile )
2474+ // check for Generated (unique to Model, not present in Schema)
2475+ const generatedSymbol = typeChecker . tryGetMemberInModuleExports ( "Generated" , moduleSymbol )
2476+ if ( ! generatedSymbol ) {
2477+ return yield * typeParserIssue ( "Model's Generated type not found" , undefined , sourceFile )
2478+ }
2479+ // check for FieldOption (unique to v4 Model)
2480+ const fieldOptionSymbol = typeChecker . tryGetMemberInModuleExports ( "FieldOption" , moduleSymbol )
2481+ if ( ! fieldOptionSymbol ) {
2482+ return yield * typeParserIssue ( "Model's FieldOption type not found" , undefined , sourceFile )
2483+ }
2484+ return sourceFile
2485+ } ) ,
2486+ "TypeParser.isEffectSchemaModelTypeSourceFile" ,
2487+ ( sourceFile ) => sourceFile
2488+ )
2489+
2490+ const isNodeReferenceToEffectSchemaModelModuleApi = ( memberName : string ) =>
2491+ Nano . cachedBy (
2492+ Nano . fn ( "TypeParser.isNodeReferenceToEffectSchemaModelModuleApi" ) ( function * (
2493+ node : ts . Node
2494+ ) {
2495+ return yield * isNodeReferenceToExportOfPackageModule (
2496+ node ,
2497+ "effect" ,
2498+ isEffectSchemaModelTypeSourceFile ,
2499+ memberName
2500+ )
2501+ } ) ,
2502+ `TypeParser.isNodeReferenceToEffectSchemaModelModuleApi(${ memberName } )` ,
2503+ ( node ) => node
2504+ )
2505+
2506+ const extendsEffectSchemaModelClass = Nano . cachedBy (
2507+ Nano . fn ( "TypeParser.extendsEffectSchemaModelClass" ) ( function * (
2508+ atLocation : ts . ClassDeclaration
2509+ ) {
2510+ if ( ! atLocation . name ) {
2511+ return yield * typeParserIssue ( "Class has no name" , undefined , atLocation )
2512+ }
2513+ const heritageClauses = atLocation . heritageClauses
2514+ if ( ! heritageClauses ) {
2515+ return yield * typeParserIssue ( "Class has no heritage clauses" , undefined , atLocation )
2516+ }
2517+ for ( const heritageClause of heritageClauses ) {
2518+ for ( const typeX of heritageClause . types ) {
2519+ if ( ts . isExpressionWithTypeArguments ( typeX ) ) {
2520+ const expression = typeX . expression
2521+ if ( ts . isCallExpression ( expression ) ) {
2522+ // Model.Class<T>("name")({})
2523+ const schemaCall = expression . expression
2524+ if ( ts . isCallExpression ( schemaCall ) && schemaCall . typeArguments && schemaCall . typeArguments . length > 0 ) {
2525+ const isEffectSchemaModelModuleApi = yield * pipe (
2526+ isNodeReferenceToEffectSchemaModelModuleApi ( "Class" ) ( schemaCall . expression ) ,
2527+ Nano . orUndefined
2528+ )
2529+ if ( isEffectSchemaModelModuleApi ) {
2530+ return {
2531+ className : atLocation . name ,
2532+ selfTypeNode : schemaCall . typeArguments [ 0 ] !
2533+ }
2534+ }
2535+ }
2536+ }
2537+ }
2538+ }
2539+ }
2540+ return yield * typeParserIssue ( "Class does not extend effect's Model.Class" , undefined , atLocation )
2541+ } ) ,
2542+ "TypeParser.extendsEffectSchemaModelClass" ,
2543+ ( atLocation ) => atLocation
2544+ )
2545+
24542546 const isEffectLayerTypeSourceFile = Nano . cachedBy (
24552547 Nano . fn ( "TypeParser.isEffectLayerTypeSourceFile" ) ( function * (
24562548 sourceFile : ts . SourceFile
@@ -2967,6 +3059,7 @@ export function make(
29673059 isNodeReferenceToEffectDataModuleApi,
29683060 isNodeReferenceToEffectContextModuleApi,
29693061 isNodeReferenceToEffectSqlModelModuleApi,
3062+ isNodeReferenceToEffectSchemaModelModuleApi,
29703063 isNodeReferenceToEffectLayerModuleApi,
29713064 isNodeReferenceToEffectSchemaParserModuleApi,
29723065 isServiceMapTypeSourceFile,
@@ -3004,6 +3097,7 @@ export function make(
30043097 extendsSchemaTaggedRequest,
30053098 extendsSchemaRequestClass,
30063099 extendsEffectSqlModelClass,
3100+ extendsEffectSchemaModelClass,
30073101 lazyExpression,
30083102 emptyFunction,
30093103 pipingFlows,
0 commit comments