1- // Builds the resource object class model for src/Objects from the blueprint.
1+ // Builds the resource class model for src/Resources from the blueprint.
22//
3- // Each blueprint resource becomes a PHP class. Nested object properties and
4- // lists of objects are split into their own classes named after the base
5- // resource and the property, e.g. the device battery property becomes
6- // DeviceBattery. Discriminated unions (events, action attempts, and
3+ // Each blueprint resource becomes a PHP class in its own file. Nested object
4+ // properties and lists of objects are split into their own classes, named
5+ // after the base resource and the property, e.g. the device battery property
6+ // becomes DeviceBattery. Those classes only exist to type a resource
7+ // property, so they are emitted as local classes in the file of the resource
8+ // that introduced them. Discriminated unions (events, action attempts, and
79// discriminated object lists) are flattened into a single class with the
810// union of the variant properties.
911
@@ -12,24 +14,28 @@ import { pascalCase } from 'change-case'
1214
1315import { getPhpType } from './map-php-type.js'
1416
15- export type ResourceObjectProperty =
17+ export type ResourceClassProperty =
1618 | { name : string ; kind : 'value' ; phpType : string }
1719 | { name : string ; kind : 'objectReference' ; referenceName : string }
1820 | { name : string ; kind : 'listReference' ; referenceName : string }
1921
20- export interface ResourceObjectSchema {
22+ export interface ResourceClassSchema {
2123 name : string
22- properties : ResourceObjectProperty [ ]
24+ properties : ResourceClassProperty [ ]
2325}
2426
25- export interface ResourceObjectModel {
26- baseResourceNames : string [ ]
27- schemas : ResourceObjectSchema [ ]
27+ export interface ResourceSchema {
28+ name : string
29+ resourceClass : ResourceClassSchema
30+ localClasses : ResourceClassSchema [ ]
31+ }
32+
33+ export interface ResourceModel {
34+ resourceNames : string [ ]
35+ resources : ResourceSchema [ ]
2836}
2937
30- export const createResourceObjectModel = (
31- blueprint : Blueprint ,
32- ) : ResourceObjectModel => {
38+ export const createResourceModel = ( blueprint : Blueprint ) : ResourceModel => {
3339 const baseResources = new Map < string , Property [ ] > ( )
3440
3541 for ( const resource of blueprint . resources ) {
@@ -57,50 +63,74 @@ export const createResourceObjectModel = (
5763 )
5864 }
5965
60- const schemas = new Map < string , ResourceObjectSchema > ( )
66+ const classes = new Map < string , ResourceClassSchema > ( )
67+ const localClassNames = new Map < string , string [ ] > ( )
6168
62- const addSchema = (
69+ let currentResourceName = ''
70+
71+ const addClass = (
6372 name : string ,
6473 properties : Property [ ] ,
6574 baseName : string ,
6675 ) : void => {
67- if ( schemas . has ( name ) ) return
68- const schema : ResourceObjectSchema = { name, properties : [ ] }
69- schemas . set ( name , schema )
76+ if ( classes . has ( name ) ) return
77+ const schema : ResourceClassSchema = { name, properties : [ ] }
78+ classes . set ( name , schema )
79+ if ( name !== currentResourceName ) {
80+ localClassNames . get ( currentResourceName ) ?. push ( name )
81+ }
7082 schema . properties = properties . map ( ( property ) =>
71- createResourceObjectProperty ( property , baseName , addSchema ) ,
83+ createResourceClassProperty ( property , baseName , addClass ) ,
7284 )
7385 }
7486
7587 const baseResourceTypes = [ ...baseResources . keys ( ) ] . sort ( )
76- for ( const resourceType of baseResourceTypes ) {
77- addSchema (
78- pascalCase ( resourceType ) ,
79- baseResources . get ( resourceType ) ?? [ ] ,
80- resourceType ,
81- )
82- }
88+ const resources = baseResourceTypes . map ( ( resourceType ) => {
89+ const name = pascalCase ( resourceType )
90+ currentResourceName = name
91+ localClassNames . set ( name , [ ] )
92+ addClass ( name , baseResources . get ( resourceType ) ?? [ ] , resourceType )
93+
94+ const resourceClass = classes . get ( name )
95+ if ( resourceClass == null ) {
96+ throw new Error (
97+ `Missing class for resource ${ resourceType } : ${ name } is already used by a property class of another resource` ,
98+ )
99+ }
100+
101+ return {
102+ name,
103+ resourceClass,
104+ localClasses : ( localClassNames . get ( name ) ?? [ ] )
105+ . map ( ( localClassName ) => {
106+ const localClass = classes . get ( localClassName )
107+ if ( localClass == null ) {
108+ throw new Error ( `Missing local class ${ localClassName } ` )
109+ }
110+ return localClass
111+ } )
112+ . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ,
113+ }
114+ } )
83115
84116 return {
85- baseResourceNames : baseResourceTypes . map ( ( resourceType ) =>
86- pascalCase ( resourceType ) ,
87- ) ,
88- schemas : [ ...schemas . values ( ) ] ,
117+ resourceNames : resources . map ( ( resource ) => resource . name ) ,
118+ resources,
89119 }
90120}
91121
92- const createResourceObjectProperty = (
122+ const createResourceClassProperty = (
93123 property : Property ,
94124 baseName : string ,
95- addSchema : ( name : string , properties : Property [ ] , baseName : string ) => void ,
96- ) : ResourceObjectProperty => {
125+ addClass : ( name : string , properties : Property [ ] , baseName : string ) => void ,
126+ ) : ResourceClassProperty => {
97127 const referenceName = pascalCase ( `${ baseName } _${ property . name } ` )
98128
99129 if ( property . format === 'object' ) {
100130 const { properties } = property
101131
102132 if ( properties . length > 0 ) {
103- addSchema ( referenceName , properties , baseName )
133+ addClass ( referenceName , properties , baseName )
104134 return { name : property . name , kind : 'objectReference' , referenceName }
105135 }
106136 }
@@ -116,7 +146,7 @@ const createResourceObjectProperty = (
116146 : [ ]
117147
118148 if ( itemProperties . length > 0 ) {
119- addSchema ( referenceName , itemProperties , baseName )
149+ addClass ( referenceName , itemProperties , baseName )
120150 return { name : property . name , kind : 'listReference' , referenceName }
121151 }
122152 }
0 commit comments