import { type Node, createWrappedNode, IndentationText, Project, QuoteKind, ScriptTarget, SourceFile, TextChange, } from 'ts-morph'; import ts, { type Declaration, factory, idText, Statement } from 'typescript'; import type { Driver } from '../Definitions/Global/Drivers.js'; import { UnitOfMeasure } from '../Definitions/Global/UOM.js'; import { types } from 'util'; import { Family } from '../Definitions/index.js'; import { CommandDefinition, DataTypeDefinition, DriverDefinition, NodeClassDefinition, ParameterDefinition, } from '../Model/ClassDefinition.js'; import { EnumDefinitionMap } from '../Model/EnumDefinition.js'; import { CodeFactory } from './CodeFactory.js'; import { createMemberName } from './EnumFactory.js'; // #region Type aliases (1) type GeneratedNodeClass = { family: T; name: string; id: string; path: string; statements: any; sourceFile: SourceFile; }; // #endregion Type aliases (1) // #region Classes (1) export class NodeClassFactory extends CodeFactory { // #region Properties (2) public static _basePath: string; public static project = new Project({ //@ts-ignore compilerOptions: { target: ScriptTarget.ESNext, module: ts.ModuleKind.Node18 }, manipulationSettings: { usePrefixAndSuffixTextForRename: true, quoteKind: QuoteKind.Single, useTrailingCommas: false, indentationText: IndentationText.Tab, newLineKind: ts.NewLineKind.CarriageReturnLineFeed, insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, }, }); static instance: NodeClassFactory = new NodeClassFactory(ts.factory); // #endregion Properties (2) // #region Public Static Getters And Setters (2) public static get basePath() { return (this._basePath ??= './'); } public static set basePath(value: string) { this._basePath = value; } // #endregion Public Static Getters And Setters (2) // #region Public Static Methods (4) public static buildNodeClasses(map: { [x: string]: NodeClassDefinition; }): GeneratedNodeClass[] { return Object.values(map) .filter(p => !p.equivalentTo) .map(p => { try { return NodeClassFactory.instance.createNodeClass(p); } catch (e) { console.error(e); } }); } public createNodeClass(nodeClassDef: NodeClassDefinition) { let path = `${NodeClassFactory.basePath}/${Family[nodeClassDef.family]}/Generated/${nodeClassDef.name}.ts`; let sf = ts.createSourceFile(path, '', ts.ScriptTarget.ES2024, true, ts.ScriptKind.TS); //@ts-expect-error sf.statements = [ this.createImportDeclaration('../../../Definitions/Global/index.js', ['Family', ' UnitOfMeasure']), this.createImportDeclaration('../../../Model/NodeInfo.js', ['NodeInfo'], true), this.createImportDeclaration('../../../ISY.js', ['ISY']), this.createImportDeclaration('../../../ISYNode.js', ['ISYNode']), this.createImportDeclaration('../../ISYDeviceNode.js', ['ISYDeviceNode']), this.createImportDeclaration('../index.js', ['Base']), this.createImportDeclaration('../../../Definitions/Global/Drivers.js', ['Driver']), this.createImportDeclaration('type-fest', ['IntRange'], true), this.createImportDeclaration('../../../Model/DriverState,js', ['DriverState'], true), factory.createImportDeclaration( undefined, factory.createImportClause( false, undefined, factory.createNamedImports([ factory.createImportSpecifier(false, undefined, factory.createIdentifier(Family[nodeClassDef.family])), ]) ), factory.createStringLiteral('../../../Definitions/index.js'), undefined ), this.createImportDeclaration('../../NodeFactory.js', ['NodeFactory']), factory.createVariableStatement( undefined, factory.createVariableDeclarationList( [ factory.createVariableDeclaration( factory.createIdentifier('nodeDefId'), undefined, undefined, factory.createStringLiteral(nodeClassDef.id) ), ], ts.NodeFlags.Const ) ), factory.createTypeAliasDeclaration( undefined, factory.createIdentifier('Commands'), undefined, factory.createTypeReferenceNode(this.createQualifiedName(nodeClassDef.name, 'Commands', 'Type')) ), factory.createTypeAliasDeclaration( undefined, factory.createIdentifier('Drivers'), undefined, factory.createTypeReferenceNode(this.createQualifiedName(nodeClassDef.name, 'Drivers', 'Type'), undefined) ), factory.createClassDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(`${nodeClassDef.name}`), undefined, [ factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ factory.createExpressionWithTypeArguments(factory.createIdentifier('Base'), [ factory.createTypeReferenceNode(factory.createIdentifier('Drivers'), undefined), factory.createTypeReferenceNode(factory.createIdentifier('Commands'), undefined), ]), ]), factory.createHeritageClause(ts.SyntaxKind.ImplementsKeyword, [ factory.createExpressionWithTypeArguments( factory.createPropertyAccessExpression( factory.createIdentifier(nodeClassDef.name), factory.createIdentifier('Interface') ), undefined ), ]), ], [ factory.createPropertyDeclaration( [ factory.createToken(ts.SyntaxKind.PublicKeyword), factory.createToken(ts.SyntaxKind.OverrideKeyword), factory.createToken(ts.SyntaxKind.ReadonlyKeyword), ], factory.createIdentifier('commands'), undefined, undefined, factory.createObjectLiteralExpression( [ ...Object.values(nodeClassDef.commands).map(c => factory.createPropertyAssignment( factory.createIdentifier(c.id), factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(c.name)) ) ), ], true ) ), // factory.createPropertyDeclaration( // [factory.createToken(ts.SyntaxKind.PublicKeyword)], // factory.createIdentifier("drivers"), // undefined, // factory.createTypeReferenceNode(factory.createIdentifier("Drivers"), undefined), // factory.createObjectLiteralExpression([], false) // ), factory.createPropertyDeclaration( [factory.createToken(ts.SyntaxKind.StaticKeyword), factory.createToken(ts.SyntaxKind.OverrideKeyword)], factory.createIdentifier('nodeDefId'), undefined, undefined, factory.createStringLiteral(nodeClassDef.id) ), NodeClassFactory.instance.createPropertyDeclaration( 'implements', factory.createArrayLiteralExpression( nodeClassDef.implementedBy ? [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)].concat( !nodeClassDef.implements || nodeClassDef.implements.length == 0 ? [] : nodeClassDef.implements?.map(p => factory.createStringLiteral(p)) ) : [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)] ), NodeClassFactory.instance.createModifiers(ts.ModifierFlags.Static | ts.ModifierFlags.Override) ), factory.createPropertyDeclaration( [factory.createToken(ts.SyntaxKind.DeclareKeyword), factory.createToken(ts.SyntaxKind.ReadonlyKeyword)], factory.createIdentifier('nodeDefId'), undefined, nodeClassDef.equivalents ? NodeClassFactory.instance.createUnionTypeNode( ...[NodeClassFactory.instance.createLiteralTypeNode(nodeClassDef.id)].concat( !nodeClassDef.equivalents || nodeClassDef.equivalents.length == 0 ? [] : nodeClassDef.equivalents?.map(p => factory.createLiteralTypeNode(factory.createStringLiteral(p)) ) ) ) : NodeClassFactory.instance.createLiteralTypeNode(nodeClassDef.id), undefined ), factory.createConstructorDeclaration( undefined, [ factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('isy'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('ISY'), undefined), undefined ), factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('nodeInfo'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('NodeInfo'), [ this.createTypeReferenceNode(Family[nodeClassDef.family], 'Family'), ]), undefined ), ], factory.createBlock( [ factory.createExpressionStatement( factory.createCallExpression(factory.createSuper(), undefined, [ factory.createIdentifier('isy'), factory.createIdentifier('nodeInfo'), ]) ), ...Object.values(nodeClassDef.drivers).map(p => NodeClassFactory.instance.createDriverInitializationStatement(p) ), ], true ) ), ...Object.values(nodeClassDef.commands).map(p => NodeClassFactory.instance.createCommandMethodDeclaration(p)), ...Object.values(nodeClassDef.drivers).map(p => NodeClassFactory.instance.createDriverGetDeclaration(p)), ] ), factory.createExpressionStatement( factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier('NodeFactory'), factory.createIdentifier('register') ), undefined, [factory.createIdentifier(`${nodeClassDef.name}`)] ) ), ...(nodeClassDef.equivalents ? nodeClassDef.equivalents?.map(p => factory.createExpressionStatement( factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier('NodeFactory'), factory.createIdentifier('register') ), undefined, [factory.createIdentifier(`${nodeClassDef.name}`), factory.createStringLiteral(p)] ) ) ) : []), factory.createModuleDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(nodeClassDef.name), factory.createModuleBlock([ factory.createInterfaceDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier('Interface'), undefined, [ factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ factory.createExpressionWithTypeArguments(factory.createIdentifier('Omit'), [ NodeClassFactory.instance.createTypeReferenceNode( 'InstanceType', NodeClassFactory.instance.factory.createTypeQueryNode( factory.createIdentifier(`${nodeClassDef.name}`) ) ), factory.createTypeOperatorNode( ts.SyntaxKind.KeyOfKeyword, factory.createTypeReferenceNode(factory.createIdentifier('ISYDeviceNode'), [ factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), ]) ), ]), ]), ], [ /*factory.createPropertySignature( undefined, factory.createIdentifier('nodeDefId'), undefined, nodeClassDef.equivalents ? NodeClassFactory.instance.createUnionTypeNode( ...[NodeClassFactory.instance.createLiteralTypeNode(nodeClassDef.id)].concat( !nodeClassDef.equivalents || nodeClassDef.equivalents.length == 0 ? [] : nodeClassDef.equivalents?.map((p) => factory.createLiteralTypeNode(factory.createStringLiteral(p))) ) ) : NodeClassFactory.instance.createLiteralTypeNode(nodeClassDef.id) )*/ ] ), factory.createFunctionDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], undefined, factory.createIdentifier('is'), undefined, [ factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('node'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('ISYNode'), [ factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), ]), undefined ), ], factory.createTypePredicateNode( undefined, factory.createIdentifier('node'), factory.createTypeReferenceNode(factory.createIdentifier(`${nodeClassDef.name}`), undefined) ), NodeClassFactory.instance.createBlock( true, NodeClassFactory.instance.createReturnStatement( factory.createCallExpression( factory.createPropertyAccessExpression( factory.createArrayLiteralExpression( nodeClassDef.equivalents ? [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)].concat( !nodeClassDef.equivalents || nodeClassDef.equivalents.length == 0 ? [] : nodeClassDef.equivalents?.map(p => factory.createStringLiteral(p)) ) : [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)] ), 'includes' ), undefined, [ factory.createPropertyAccessExpression( factory.createIdentifier('node'), factory.createIdentifier('nodeDefId') ), ] ) ) ) ), factory.createFunctionDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], undefined, factory.createIdentifier('isImplementedBy'), undefined, [ factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('node'), undefined, NodeClassFactory.instance.createTypeReferenceNode( 'ISYNode', NodeClassFactory.instance.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), NodeClassFactory.instance.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), NodeClassFactory.instance.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), NodeClassFactory.instance.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ), undefined ), ], factory.createTypePredicateNode( undefined, factory.createIdentifier('node'), factory.createTypeReferenceNode(factory.createIdentifier(`${nodeClassDef.name}`), undefined) ), NodeClassFactory.instance.createBlock( true, factory.createReturnStatement( factory.createCallExpression( factory.createPropertyAccessExpression( factory.createArrayLiteralExpression( nodeClassDef.implementedBy ? [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)].concat( !nodeClassDef.implementedBy || nodeClassDef.implementedBy.length == 0 ? [] : nodeClassDef.implementedBy?.map(p => factory.createStringLiteral(p)) ) : [NodeClassFactory.instance.createStringLiteral(nodeClassDef.id)] ), 'includes' ), undefined, [ factory.createPropertyAccessExpression( factory.createIdentifier('node'), factory.createIdentifier('nodeDefId') ), ] ) ) ) ), factory.createFunctionDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], undefined, factory.createIdentifier('create'), undefined, [ factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('isy'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('ISY'), undefined), undefined ), factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier('nodeInfo'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('NodeInfo'), [ this.createTypeReferenceNode(Family[nodeClassDef.family], 'Family'), ]), undefined ), ], undefined, factory.createBlock( [ factory.createReturnStatement( factory.createNewExpression(factory.createIdentifier(`${nodeClassDef.name}`), undefined, [ factory.createIdentifier('isy'), factory.createIdentifier('nodeInfo'), ]) ), ], true ) ), factory.createVariableStatement( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList( [ factory.createVariableDeclaration( factory.createIdentifier('Node'), undefined, undefined, factory.createIdentifier(`${nodeClassDef.name}`) ), ], ts.NodeFlags.Const ) ), this.createVariableStatement( 'Class', factory.createIdentifier(`${nodeClassDef.name}`), true ), this.createModuleDeclaration( 'Commands', this.createModuleBlock( factory.createTypeAliasDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier('Type'), undefined, factory.createTypeLiteralNode([ ...Object.values(nodeClassDef.commands).map(NodeClassFactory.instance.createCommandSignature), ]) ) ), ts.ModifierFlags.Export ), this.factory.createEnumDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier('Commands'), [ ...Object.values(nodeClassDef.commands).map(p => factory.createEnumMember(p.name, this.createLiteral(p.id)) ), ] ), this.createModuleDeclaration( 'Drivers', this.createModuleBlock( factory.createTypeAliasDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier('Type'), undefined, factory.createTypeLiteralNode([ ...Object.values(nodeClassDef.drivers).map(NodeClassFactory.instance.createDriverSignature), ]) ) ), ts.ModifierFlags.Export ), this.factory.createEnumDeclaration( [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier('Drivers'), [ ...Object.values(nodeClassDef.drivers).map(p => factory.createEnumMember(p.name, this.createLiteral(p.id)) ), ] ), ]), ts.NodeFlags.Namespace ), ]; //let f = createWrappedNode(sf); let p = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); // p.printFile() let f = NodeClassFactory.project.createSourceFile(path, p.printFile(sf), { overwrite: true }); f.formatText({ indentSize: 1, insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, insertSpaceAfterCommaDelimiter: true, insertSpaceAfterSemicolonInForStatements: true, insertSpaceBeforeAndAfterBinaryOperators: true, insertSpaceAfterConstructor: true, newLineCharacter: '\n', trimTrailingWhitespace: true, ensureNewLineAtEndOfFile: true, indentStyle: ts.IndentStyle.Smart, }); f.fixUnusedIdentifiers(); let currentKind = ts.SyntaxKind.Unknown; for (const s of f.getStatements()) { if (currentKind.valueOf() != s.getKind().valueOf()) { if (currentKind != ts.SyntaxKind.Unknown) { s.prependWhitespace('\n'); } currentKind = s.getKind().valueOf(); } } f.insertText(0, '/* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT DIRECTLY. */\n\n'); return { family: nodeClassDef.family, name: nodeClassDef.name, id: nodeClassDef.id, path, statements: sf.statements, sourceFile: f, }; } public static generateAll(): { family: Family; path: string; statements: ts.Statement[] }[] { let modules = []; for (const family of NodeClassDefinition.Map.keys()) { var t = this.generateClassesForFamily(family); modules.push(NodeClassFactory.buildClassIndex(family, t)); } return modules; } public static generateClassesForFamily(family: T): GeneratedNodeClass[] { return NodeClassFactory.buildNodeClasses( NodeClassDefinition.Map.get(family) as { [x: string]: NodeClassDefinition } ); } // #region Functions (12) static buildClassIndex(family: T, classes: GeneratedNodeClass[]) { return { family, path: `/${Family[family]}/Generated/index.ts`, statements: [ ...classes.map(p => factory.createExportDeclaration( undefined, false, undefined, factory.createStringLiteral(`./${p.name}.js`), undefined ) ), ], }; } createCommandArguments(def: CommandDefinition) { let c = [factory.createStringLiteral(def.id)]; let n = []; let r: ParameterDefinition[] = []; if (def.parameters) { for (let p of def.parameters) { let p2 = p; if (!p2?.id || p2.id == 'value') { n.push(this.createUOMParameterArgument(p2)); //.push(factory.createIdentifier(p2.name ?? 'value')); } else { r.push(p2); } } } let fnl = [ ...c, ...n, ...(r.length > 0 ? [ factory.createObjectLiteralExpression( r.map(q => factory.createPropertyAssignment( factory.createIdentifier(q.id ?? 'value'), this.createUOMParameterArgument(q) ) ), false ), ] : []), ]; return fnl.length > 0 ? fnl : undefined; } createUOMParameterArgument(parent: ParameterDefinition) { if (parent.dataType.length == 1) { let dt = parent.dataType[0]; return factory.createArrayLiteralExpression([ factory.createIdentifier(parent.name), factory.createPropertyAccessChain( factory.createIdentifier('UnitOfMeasure'), undefined, factory.createIdentifier(UnitOfMeasure[dt.uom] ?? 'Unknown') ), ]); } return factory.createIdentifier(parent.name ?? 'value'); } createCommandMethodArguments(def: CommandDefinition): ts.ParameterDeclaration[] { let p1: ts.ParameterDeclaration[] = []; let p2: ts.ParameterDeclaration[] = []; for (let p of def.parameters) { if (p.optional) { p2.push(this.createParameterDeclarationSignature(p)); } else { p1.push(this.createParameterDeclarationSignature(p)); } } return [...p1, ...p2]; } createCommandSignatureArguments(def: CommandDefinition): ts.ParameterDeclaration[] { let p1: ts.ParameterDeclaration[] = []; let p2: ts.ParameterDeclaration[] = []; for (let p of def.parameters) { if (p.optional) { p2.push(this.createParameterSignature(p)); } else { p1.push(this.createParameterSignature(p)); } } return [...p1, ...p2]; } createCommandMethodDeclaration(def: CommandDefinition) { return factory.createMethodDeclaration( [factory.createToken(ts.SyntaxKind.AsyncKeyword)], undefined, factory.createIdentifier(def.name), undefined, undefined, def.parameters ? this.createCommandMethodArguments(def) : [], undefined, factory.createBlock([ factory.createReturnStatement( factory.createCallExpression( factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier('sendCommand')), undefined, NodeClassFactory.instance.createCommandArguments(def) ) ), ]) ); } addUOMType(def: DataTypeDefinition, typeNode: ts.TypeNode) { return factory.createTupleTypeNode([ typeNode, factory.createTypeReferenceNode( factory.createQualifiedName( factory.createIdentifier('UnitOfMeasure'), factory.createIdentifier(UnitOfMeasure[def.uom]) ), undefined ), ]); } /*addMaybeUOMType(def: DataTypeDefinition, typeNode: ts.TypeNode) { return factory.createTypeParameterDeclaration(typeNode, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier('UnitOfMeasure'), factory.createIdentifier(UnitOfMeasure[def.uom])), undefined)); }*/ createCommandParameterType(def: DataTypeDefinition, parent: ParameterDefinition): ts.TypeNode { if (def.enum) { { if (EnumDefinitionMap.has(parent.classDef.family)) { var enumDef = EnumDefinitionMap.get(parent.classDef.family)[def.indexId]; // ?? EnumDefinitionMap[Family.Global]?[def.indexId] if (enumDef) { return factory.createTypeReferenceNode( factory.createQualifiedName( factory.createIdentifier(Family[parent.classDef.family]), factory.createIdentifier(enumDef.name) ), undefined ); } } if (def.values) { return NodeClassFactory.instance.createUnionTypeNode( ...Object.keys(def.values).map(p => factory.createLiteralTypeNode(factory.createNumericLiteral(p))) ); } // return NodeClassFactory.instance.createUnionTypeNode(... // Object.values(def.values).map((p) => factory.createTypeReferenceNode( // factory.createQualifiedName( // factory.createIdentifier("UnitOfMeasure"), // factory.createIdentifier(UnitOfMeasure) // ), // undefined // ))) } } return factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); } createCommandSignature(def: CommandDefinition) { const that = this; return factory.createPropertySignature( undefined, factory.createIdentifier(def.id), undefined, factory.createIntersectionTypeNode([ factory.createParenthesizedType( factory.createFunctionTypeNode( undefined, def.parameters ? NodeClassFactory.instance.createCommandSignatureArguments(def) : [], factory.createTypeReferenceNode(factory.createIdentifier('Promise'), [ factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), ]) ) ), factory.createTypeLiteralNode([ factory.createPropertySignature( undefined, factory.createIdentifier('label'), undefined, factory.createLiteralTypeNode(factory.createStringLiteral(def.label)) ), factory.createPropertySignature( undefined, factory.createIdentifier('name'), undefined, factory.createLiteralTypeNode(factory.createStringLiteral(def.name)) ), ]), ]) ); } createDriverGetDeclaration(def: DriverDefinition) { return factory.createGetAccessorDeclaration( [factory.createToken(ts.SyntaxKind.PublicKeyword)], factory.createIdentifier(def.name), [], NodeClassFactory.instance.createUnionTypeNode( ...def.dataType?.map(p => NodeClassFactory.instance.createDriverReturnType(p, def)) ), factory.createBlock( [ factory.createReturnStatement( factory.createPropertyAccessChain( factory.createPropertyAccessExpression( factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier('drivers')), factory.createIdentifier(def.id) ), factory.createToken(ts.SyntaxKind.QuestionDotToken), factory.createIdentifier('value') ) ), ], true ) ); } createDriverInitializationStatement(def: DriverDefinition): ts.Statement { return factory.createExpressionStatement( factory.createBinaryExpression( factory.createPropertyAccessExpression( factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier('drivers')), factory.createIdentifier(def.id) ), factory.createToken(ts.SyntaxKind.EqualsToken), factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier('Driver'), factory.createIdentifier('create') ), undefined, [ factory.createStringLiteral(def.id), factory.createThis(), factory.createElementAccessExpression( factory.createPropertyAccessExpression( factory.createIdentifier('nodeInfo'), factory.createIdentifier('state') ), this.createStringLiteral(def.id) ), factory.createObjectLiteralExpression( [ factory.createPropertyAssignment( factory.createIdentifier('uom'), factory.createPropertyAccessExpression( factory.createIdentifier('UnitOfMeasure'), factory.createIdentifier(UnitOfMeasure[def.dataType[0]?.uom] ?? 'Unknown') ) ), factory.createPropertyAssignment( factory.createIdentifier('label'), factory.createStringLiteral(def.label) ), factory.createPropertyAssignment( factory.createIdentifier('name'), factory.createStringLiteral(def.name) ), ], false ), ] ) ) ); } createDriverPropertyReturnType(def: DataTypeDefinition, parent: DriverDefinition): ts.TypeNode { if (def.enum) { { if (EnumDefinitionMap.has(parent.classDef.family)) { var enumDef = EnumDefinitionMap.get(parent.classDef.family)[def.indexId]; // ?? EnumDefinitionMap[Family.Global]?[def.indexId] if (enumDef) { return factory.createTypeReferenceNode( factory.createQualifiedName( factory.createIdentifier(Family[parent.classDef.family]), factory.createIdentifier(enumDef.name) ), undefined ); } } if (def.values) { return NodeClassFactory.instance.createUnionTypeNode( ...Object.keys(def.values).map(p => factory.createLiteralTypeNode(factory.createNumericLiteral(p))) ); } // return NodeClassFactory.instance.createUnionTypeNode(... // Object.values(def.values).map((p) => factory.createTypeReferenceNode( // factory.createQualifiedName( // factory.createIdentifier("UnitOfMeasure"), // factory.createIdentifier(UnitOfMeasure) // ), // undefined // ))) } } if ( 'min' in def && 'max' in def && def.max < 1000 && def.min >= 0 && Number.isInteger(def.min) && Number.isInteger(def.max) ) { return factory.createTypeReferenceNode(factory.createIdentifier('IntRange'), [ factory.createLiteralTypeNode(this.createLiteral(def.min)), factory.createLiteralTypeNode(this.createLiteral(def.max)), ]); } return factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); } createDriverSignature(def: DriverDefinition) { return factory.createPropertySignature( undefined, factory.createIdentifier(def.id), undefined, factory.createTypeLiteralNode([ factory.createPropertySignature( undefined, factory.createIdentifier('uom'), undefined, def.dataType ? NodeClassFactory.instance.createUnionTypeNode( ...def.dataType?.map(p => NodeClassFactory.instance.createTypeNodeForUOM(p.uom)) ) : factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) ), factory.createPropertySignature( undefined, factory.createIdentifier('value'), undefined, def.dataType ? NodeClassFactory.instance.createUnionTypeNode( ...def.dataType.map(p => NodeClassFactory.instance.createDriverReturnType(p, def)) ) : factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) ), factory.createPropertySignature( undefined, factory.createIdentifier('label'), undefined, factory.createLiteralTypeNode(factory.createStringLiteral(def.label)) ), factory.createPropertySignature( undefined, factory.createIdentifier('name'), undefined, factory.createLiteralTypeNode(factory.createStringLiteral(def.name)) ), ]) ); } createDriverReturnType(def: DataTypeDefinition, parent: DriverDefinition): ts.TypeNode { if (def.enum) { { if (EnumDefinitionMap.has(parent.classDef.family)) { var enumDef = EnumDefinitionMap.get(parent.classDef.family)[def.indexId]; // ?? EnumDefinitionMap[Family.Global]?[def.indexId] if (enumDef) { return factory.createTypeReferenceNode( factory.createQualifiedName( factory.createIdentifier(Family[parent.classDef.family]), factory.createIdentifier(enumDef.name) ), undefined ); } } if (def.values) { return NodeClassFactory.instance.createUnionTypeNode( ...Object.keys(def.values).map(p => factory.createLiteralTypeNode(factory.createNumericLiteral(p))) ); } // return NodeClassFactory.instance.createUnionTypeNode(... // Object.values(def.values).map((p) => factory.createTypeReferenceNode( // factory.createQualifiedName( // factory.createIdentifier("UnitOfMeasure"), // factory.createIdentifier(UnitOfMeasure) // ), // undefined // ))) } } if ('min' in def && 'max' in def && def.max < 1000 && def.min >= 0) { return factory.createTypeReferenceNode(factory.createIdentifier('IntRange'), [ factory.createLiteralTypeNode(this.createLiteral(def.min)), factory.createLiteralTypeNode(this.createLiteral(def.max)), ]); } return factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); } createParameterDeclarationSignature(def: ParameterDefinition) { return factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier(def.name ?? 'value'), def.optional ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, def.dataType ? NodeClassFactory.instance.createUnionTypeNode( ...def.dataType?.map(p => NodeClassFactory.instance.createCommandParameterType(p, def)) ) : factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), undefined ); } createParameterSignature(def: ParameterDefinition) { return factory.createParameterDeclaration( undefined, undefined, factory.createIdentifier(def.id ?? 'value'), def.optional ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, def.dataType ? NodeClassFactory.instance.createUnionTypeNode( ...def.dataType?.map(p => NodeClassFactory.instance.createCommandParameterType(p, def)) ) : factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), undefined ); } createTypeNodeForUOM(uom: number): ts.TypeNode { return NodeClassFactory.instance.createTypeReferenceNode(UnitOfMeasure[uom] ?? 'Unknown', 'UnitOfMeasure'); } // #endregion Public Static Methods (4) } // #endregion Classes (1) // #endregion Functions (12)