From 98cafffd0991de09d70dc8f76cad5e11515e6eaa Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Thu, 30 Nov 2023 16:45:48 +0100 Subject: [PATCH 01/23] feat(type-compiler): inline external types --- packages/type-compiler/src/compiler.ts | 153 ++++++++++++------ packages/type-compiler/src/reflection-ast.ts | 25 ++- .../tests/inline-external-types.spec.ts | 148 +++++++++++++++++ packages/type-compiler/tests/utils.ts | 26 +-- 4 files changed, 290 insertions(+), 62 deletions(-) create mode 100644 packages/type-compiler/tests/inline-external-types.spec.ts diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 028329eec..4c0c8dbb1 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -74,12 +74,12 @@ import ts from 'typescript'; import { ensureImportIsEmitted, - extractJSDocAttribute, + extractJSDocAttribute, getEntityName, getGlobalsOfSourceFile, getIdentifierName, getNameAsString, getPropertyName, - hasModifier, + hasModifier, isBuiltType, isNodeWithLocals, NodeConverter, PackExpression, @@ -188,15 +188,19 @@ const serverEnv = 'undefined' !== typeof process; export const packSize: number = 2 ** packSizeByte; //64 const reflectionModes = ['always', 'default', 'never'] as const; -interface ReflectionOptions { +export interface ReflectionOptions { /** * Allows to exclude type definitions/TS files from being included in the type compilation step. * When a global .d.ts is matched, their types won't be embedded (useful to exclude DOM for example) */ exclude?: string[]; + /** + * External imports to reflect + */ + external?: Record; // '*' or true? } -interface ReflectionConfig { +export interface ReflectionConfig { mode: typeof reflectionModes[number]; options: ReflectionOptions; /** @@ -497,6 +501,33 @@ function getReceiveTypeParameter(type: TypeNode): TypeReferenceNode | undefined return; } +interface DeepkitTypeCompilerOptions extends ReflectionOptions { + reflection?: string | string[]; +} + +export interface ReflectionTransformerConfig { + compilerOptions: ts.CompilerOptions; + extends?: string; + deepkitTypeCompilerOptions?: DeepkitTypeCompilerOptions; +} + +export interface EmbedDeclaration { + name: EntityName, + sourceFile: SourceFile, + assignType?: boolean; +} + +export class EmbedDeclarations extends Map { + getByName(name: string): EmbedDeclaration | null { + for (const [,d] of this) { + if (getEntityName(d.name) === name) { + return d; + } + } + return null; + } +} + /** * Read the TypeScript AST and generate pack struct (instructions + pre-defined stack). * @@ -506,7 +537,7 @@ function getReceiveTypeParameter(type: TypeNode): TypeReferenceNode | undefined */ export class ReflectionTransformer implements CustomTransformer { sourceFile!: SourceFile; - protected f: NodeFactory; + public f: NodeFactory; protected currentReflectionConfig: ReflectionConfig = { mode: 'never', options: {}, baseDir: '' }; public defaultExcluded: string[] = [ @@ -515,7 +546,7 @@ export class ReflectionTransformer implements CustomTransformer { 'lib.es2017.typedarrays.d.ts', ]; - protected embedAssignType: boolean = false; + public embedAssignType: boolean = false; protected reflectionMode?: typeof reflectionModes[number]; protected reflectionOptions?: ReflectionOptions; @@ -533,7 +564,7 @@ export class ReflectionTransformer implements CustomTransformer { * Types added to this map will get a type program at the top root level of the program. * This is for imported types, which need to be inlined into the current file, as we do not emit type imports (TS will omit them). */ - protected embedDeclarations = new Map(); + public embedDeclarations = new EmbedDeclarations(); /** * When a node was embedded or compiled (from the maps above), we store it here to know to not add it again. @@ -557,13 +588,13 @@ export class ReflectionTransformer implements CustomTransformer { protected tempResultIdentifier?: Identifier; protected parseConfigHost?: ParseConfigHost; - protected config: { compilerOptions: ts.CompilerOptions, extends?: string, reflectionOptions?: ReflectionOptions, reflection?: string | string[] } = { compilerOptions: {} }; + protected config: ReflectionTransformerConfig = { compilerOptions: {}}; constructor( protected context: TransformationContext, ) { this.f = context.factory; - this.nodeConverter = new NodeConverter(this.f); + this.nodeConverter = new NodeConverter(this); //it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); @@ -678,17 +709,17 @@ export class ReflectionTransformer implements CustomTransformer { let basePath = this.config.compilerOptions.configFilePath as string; if (basePath) { basePath = dirname(basePath); - if (!this.reflectionMode && currentConfig.reflection !== undefined) this.reflectionMode = this.parseReflectionMode(currentConfig.reflection, basePath); - if (!this.compilerOptions && currentConfig.reflectionOptions !== undefined) { - this.reflectionOptions = this.parseReflectionOptionsDefaults(currentConfig.reflectionOptions, basePath); + if (!this.reflectionMode && currentConfig.deepkitTypeCompilerOptions !== undefined) this.reflectionMode = this.parseReflectionMode(currentConfig.deepkitTypeCompilerOptions.reflection, basePath); + if (!this.compilerOptions && currentConfig.deepkitTypeCompilerOptions !== undefined) { + this.reflectionOptions = this.parseReflectionOptionsDefaults(currentConfig.deepkitTypeCompilerOptions, basePath); } while ((this.reflectionMode === undefined || this.compilerOptions === undefined) && 'string' === typeof basePath && currentConfig.extends) { const path = join(basePath, currentConfig.extends); - const nextConfig = ts.readConfigFile(path, (path: string) => this.host.readFile(path)); + const nextConfig = ts.readConfigFile(path, (path: string) => this.host.readFile(path)) as { config: ReflectionTransformerConfig }; if (!nextConfig) break; - if (!this.reflectionMode && nextConfig.config.reflection !== undefined) this.reflectionMode = this.parseReflectionMode(nextConfig.config.reflection, basePath); - if (!this.reflectionOptions && nextConfig.config.reflectionOptions !== undefined) { - this.reflectionOptions = this.parseReflectionOptionsDefaults(nextConfig.config.reflectionOptions, basePath); + if (!this.reflectionMode && nextConfig.config.deepkitTypeCompilerOptions !== undefined) this.reflectionMode = this.parseReflectionMode(nextConfig.config.deepkitTypeCompilerOptions.reflection, basePath); + if (!this.reflectionOptions && nextConfig.config.deepkitTypeCompilerOptions !== undefined) { + this.reflectionOptions = this.parseReflectionOptionsDefaults(nextConfig.config.deepkitTypeCompilerOptions, basePath); } currentConfig = Object.assign({}, nextConfig.config); basePath = dirname(path); @@ -975,7 +1006,7 @@ export class ReflectionTransformer implements CustomTransformer { const compileDeclarations = (node: Node): any => { node = visitEachChild(node, compileDeclarations, this.context); - if ((isTypeAliasDeclaration(node) || isInterfaceDeclaration(node) || isEnumDeclaration(node))) { + if (isTypeAliasDeclaration(node) || isInterfaceDeclaration(node) || isEnumDeclaration(node)) { const d = this.compileDeclarations.get(node); if (!d) { return node; @@ -1982,7 +2013,7 @@ export class ReflectionTransformer implements CustomTransformer { // return node; // } - protected getDeclarationVariableName(typeName: EntityName): Identifier { + public getDeclarationVariableName(typeName: EntityName): Identifier { if (isIdentifier(typeName)) { return this.f.createIdentifier('__Ω' + getIdentifierName(typeName)); } @@ -1995,6 +2026,16 @@ export class ReflectionTransformer implements CustomTransformer { return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName)); } + // TODO: what to do when the external type depends on another external type? should that be automatically resolved, or should the user specify that explicitly as well? + protected isImportMarkedAsExternal(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return false; + const external = config.options.external?.[importDeclaration.moduleSpecifier.text]; + if (!external) return false; + if (external === '*') return true; + const typeName = getEntityName(entityName); + return external.includes(typeName); + } + protected isExcluded(filePath: string): boolean { if (!this.currentReflectionConfig.options.exclude) return false; @@ -2183,25 +2224,27 @@ export class ReflectionTransformer implements CustomTransformer { return; } - // check if this is a viable option: - // //check if the referenced file has reflection info emitted. if not, any is emitted for that reference - // const typeVar = this.getDeclarationVariableName(typeName); - // //check if typeVar is exported in referenced file - // const builtType = isNodeWithLocals(found) && found.locals && found.locals.has(typeVar.escapedText); - // if (!builtType) { - // program.pushOp(ReflectionOp.any); - // return; - // } - //check if the referenced file has reflection info emitted. if not, any is emitted for that reference - const reflection = this.findReflectionFromPath(found.fileName); - if (reflection.mode === 'never') { - program.pushOp(ReflectionOp.any); - return; - } + const typeVar = this.getDeclarationVariableName(typeName); + //check if typeVar is exported in referenced file + const builtType = isBuiltType(typeVar, found); + + if (!builtType) { + if (!this.isImportMarkedAsExternal(resolved.importDeclaration, typeName, declarationReflection)) return; + this.embedDeclarations.set(declaration, { + name: typeName, + sourceFile: declarationSourceFile + }); + } else { + //check if the referenced file has reflection info emitted. if not, any is emitted for that reference + const reflection = this.findReflectionFromPath(found.fileName); + if (reflection.mode === 'never') { + program.pushOp(ReflectionOp.any); + return; + } - // this.addImports.push({ identifier: typeVar, from: resolved.importDeclaration.moduleSpecifier }); - this.addImports.push({ identifier: this.getDeclarationVariableName(typeName), from: resolved.importDeclaration.moduleSpecifier }); + this.addImports.push({ identifier: this.getDeclarationVariableName(typeName), from: resolved.importDeclaration.moduleSpecifier }); + } } } else { //it's a reference type inside the same file. Make sure its type is reflected @@ -2252,7 +2295,27 @@ export class ReflectionTransformer implements CustomTransformer { return; } - if (resolved.importDeclaration && isIdentifier(typeName)) ensureImportIsEmitted(resolved.importDeclaration, typeName); + if (resolved.importDeclaration && isIdentifier(typeName)) { + ensureImportIsEmitted(resolved.importDeclaration, typeName); + + // check if the referenced declaration has reflection disabled + const declarationReflection = this.findReflectionConfig(declaration, program); + if (declarationReflection.mode !== 'never') { + const declarationSourceFile = resolved.importDeclaration.getSourceFile(); + // //check if the referenced file has reflection info emitted. if not, any is emitted for that reference + const typeVar = this.getDeclarationVariableName(typeName); + // //check if typeVar is exported in referenced file + const builtType = isBuiltType(typeVar, declarationSourceFile); + + if (!builtType && this.isImportMarkedAsExternal(resolved.importDeclaration, typeName, declarationReflection)) { + this.embedDeclarations.set(declaration, { + name: typeName, + sourceFile: declarationSourceFile, + assignType: true, + }); + } + } + } program.pushFrame(); if (type.typeArguments) { for (const typeArgument of type.typeArguments) { @@ -2352,9 +2415,7 @@ export class ReflectionTransformer implements CustomTransformer { protected resolveTypeOnlyImport(entityName: EntityName, program: CompilerProgram) { program.pushOp(ReflectionOp.any); - const typeName = ts.isIdentifier(entityName) - ? getIdentifierName(entityName) - : getIdentifierName(entityName.right); + const typeName = getEntityName(entityName); this.resolveTypeName(typeName, program); } @@ -2634,7 +2695,7 @@ export class ReflectionTransformer implements CustomTransformer { * * where we embed assignType() at the beginning of the type. */ - protected wrapWithAssignType(fn: Expression, type: Expression) { + public wrapWithAssignType(fn: Expression, type: Expression) { this.embedAssignType = true; return this.f.createCallExpression( @@ -2788,19 +2849,19 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (reflection === undefined && packageJson.reflection !== undefined) { + if (reflection === undefined && packageJson.deepkitTypeCompilerOptions !== undefined) { return { - mode: this.parseReflectionMode(packageJson.reflection, currentDir), + mode: this.parseReflectionMode(packageJson.deepkitTypeCompilerOptions.reflection, currentDir), baseDir: currentDir, - options: this.parseReflectionOptionsDefaults(packageJson.reflectionOptions || {}) + options: this.parseReflectionOptionsDefaults(packageJson.deepkitTypeCompilerOptions || {}) }; } - if (reflection === undefined && tsConfig.reflection !== undefined) { + if (reflection === undefined && tsConfig.deepkitTypeCompilerOptions !== undefined) { return { - mode: this.parseReflectionMode(tsConfig.reflection, currentDir), + mode: this.parseReflectionMode(tsConfig.deepkitTypeCompilerOptions.reflection, currentDir), baseDir: currentDir, - options: this.parseReflectionOptionsDefaults(tsConfig.reflectionOptions || {}) + options: this.parseReflectionOptionsDefaults(tsConfig.deepkitTypeCompilerOptions || {}) }; } diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index a0cae46d5..e1a614a18 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -33,6 +33,7 @@ import type { import ts from 'typescript'; import { cloneNode as tsNodeClone, CloneNodeHook } from '@marcj/ts-clone-node'; import { SourceFile } from './ts-types.js'; +import { ReflectionTransformer } from './compiler.js'; const { isArrowFunction, @@ -122,7 +123,10 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - constructor(protected f: NodeFactory) { + protected f: NodeFactory + + constructor(protected transformer: ReflectionTransformer) { + this.f = transformer.f; } toExpression(node?: T): Expression { @@ -139,14 +143,19 @@ export class NodeConverter { if (node.pos === -1 && node.end === -1 && node.parent === undefined) { if (isArrowFunction(node)) { - if (node.body.pos === -1 && node.body.end === -1 && node.body.parent === undefined) return node; + // if (node.body.pos === -1 && node.body.end === -1 && node.body.parent === undefined) return node; return this.f.createArrowFunction(node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, this.toExpression(node.body as Expression)); } return node; } switch (node.kind) { case SyntaxKind.Identifier: - return finish(node, this.f.createIdentifier(getIdentifierName(node as Identifier))); + const typeName = getIdentifierName(node as Identifier); + const embedDeclaration = this.transformer.embedDeclarations.getByName(typeName); + if (embedDeclaration?.assignType) { + return this.transformer.wrapWithAssignType(finish(node, this.f.createIdentifier(typeName)), this.transformer.getDeclarationVariableName(node as Identifier)); + } + return finish(node, this.f.createIdentifier(typeName)); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: @@ -186,10 +195,20 @@ function isExternalOrCommonJsModule(file: SourceFile): boolean { return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined; } +export function isBuiltType(typeVar: Identifier, sourceFile: SourceFile): boolean { + return isNodeWithLocals(sourceFile) && !!sourceFile.locals?.has(typeVar.escapedText); +} + export function isNodeWithLocals(node: Node): node is (Node & { locals: SymbolTable | undefined }) { return 'locals' in node; } +export function getEntityName(typeName: EntityName): string { + return isIdentifier(typeName) + ? getIdentifierName(typeName) + : getIdentifierName(typeName.right); +} + //logic copied from typescript export function getGlobalsOfSourceFile(file: SourceFile): SymbolTable | void { if (file.redirectInfo) return; diff --git a/packages/type-compiler/tests/inline-external-types.spec.ts b/packages/type-compiler/tests/inline-external-types.spec.ts new file mode 100644 index 000000000..634087b77 --- /dev/null +++ b/packages/type-compiler/tests/inline-external-types.spec.ts @@ -0,0 +1,148 @@ +import { test, expect } from '@jest/globals'; +import { isCustomTypeClass } from '@deepkit/type'; + +import { transpile, transpileAndRun } from './utils'; +test('class type', () => { + const res = transpile({ + app: `import { Observable } from 'rxjs'; + + type A = Observable; + ` + }, undefined, { + external: { + 'rxjs': ['Observable'], + }, + }); + + expect(res.app).toContain('const __ΩObservable = ['); + expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ΩObservable)'); +}) +test('class typeOf', () => { + const res = transpileAndRun({ + app: `import { Observable } from 'rxjs'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + external: { + 'rxjs': ['Subject'], + }, + }); + + expect(isCustomTypeClass(res)).toBe(true); +}) + +// Not supported yet +test.todo('function'/*, () => { + const res = transpileAndRun({ + app: `import { preview } from 'vite'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + external: { + 'vite': ['preview'], + }, + }); +}*/) + +test('only a single type is transformed', () => { + const res = transpile({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + + type A = ConfigEnv; + + type B = CorsOrigin; + ` + }, undefined, { + external: { + 'vite': ['ConfigEnv'], + }, + }); + expect(res.app).toContain('const __ΩConfigEnv = ['); + expect(res.app).not.toContain('const __ΩCorsOrigin = ['); +}) + +test('interface typeOf', () => { + const res = transpileAndRun({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + external: { + 'vite': ['ConfigEnv'], + }, + }); + expect(res).toMatchInlineSnapshot(` +{ + "annotations": {}, + "id": 2, + "kind": 30, + "typeArguments": undefined, + "typeName": "ConfigEnv", + "types": [ + { + "kind": 32, + "name": "command", + "parent": [Circular], + "type": { + "kind": 23, + "parent": [Circular], + "types": [ + { + "kind": 13, + "literal": "build", + "parent": [Circular], + }, + { + "kind": 13, + "literal": "serve", + "parent": [Circular], + }, + ], + }, + }, + { + "kind": 32, + "name": "mode", + "parent": [Circular], + "type": { + "kind": 5, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "ssrBuild", + "optional": true, + "parent": [Circular], + "type": { + "kind": 7, + "parent": [Circular], + }, + }, + ], +} +`); +}); + +test('all exports marked as external', () => { + const res = transpile({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + import { typeOf } from '@deepkit/type'; + + type A = ConfigEnv; + type B = CorsOrigin; + ` + }, undefined, { + external: { + 'vite': '*', + }, + }); + expect(res.app).toContain('const __ΩConfigEnv = ['); + expect(res.app).toContain('const __ΩCorsOrigin = ['); +}); diff --git a/packages/type-compiler/tests/utils.ts b/packages/type-compiler/tests/utils.ts index c94ebad84..670b330b8 100644 --- a/packages/type-compiler/tests/utils.ts +++ b/packages/type-compiler/tests/utils.ts @@ -1,9 +1,9 @@ import * as ts from 'typescript'; import { createSourceFile, getPreEmitDiagnostics, ScriptTarget, ScriptKind, TransformationContext } from 'typescript'; import { createFSBackedSystem, createVirtualCompilerHost, knownLibFilesForCompilerOptions } from '@typescript/vfs'; -import { ReflectionTransformer } from '../src/compiler.js'; -import { readFileSync } from 'fs'; -import { dirname, join } from 'path'; +import { ReflectionOptions, ReflectionTransformer } from '../src/compiler.js'; +import { readFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; const defaultLibLocation = dirname(require.resolve('typescript')) + '/'; //node_modules/typescript/lib/ @@ -25,8 +25,8 @@ function readLibs(compilerOptions: ts.CompilerOptions, files: Map, options: ts.CompilerOptions = {}): Record { - const compilerOptions: ts.CompilerOptions = { +export function transform(files: Record, compilerOptions: ts.CompilerOptions = {}, reflectionOptions?: ReflectionOptions): Record { + compilerOptions = { ...defaultCompilerOptions, target: ts.ScriptTarget.ES2016, allowNonTsExtensions: true, @@ -34,7 +34,7 @@ export function transform(files: Record, options: ts.CompilerOpt moduleResolution: ts.ModuleResolutionKind.NodeJs, experimentalDecorators: true, esModuleInterop: true, - ...options + ...compilerOptions }; const fsMap = new Map(); @@ -52,7 +52,7 @@ export function transform(files: Record, options: ts.CompilerOpt for (const fileName of Object.keys(files)) { const sourceFile = host.compilerHost.getSourceFile(fullPath(fileName), ScriptTarget.ES2022); if (!sourceFile) continue; - const transform = ts.transform(sourceFile, [(context) => (node) => new ReflectionTransformer(context).forHost(host.compilerHost).withReflectionMode('always').transformSourceFile(node)]); + const transform = ts.transform(sourceFile, [(context) => (node) => new ReflectionTransformer(context).forHost(host.compilerHost).withReflectionMode('always', reflectionOptions).transformSourceFile(node)]); const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); const code = printer.printNode(ts.EmitHint.SourceFile, transform.transformed[0], transform.transformed[0]); res[fileName] = code; @@ -64,16 +64,16 @@ export function transform(files: Record, options: ts.CompilerOpt /** * The first entry in files is executed as main script */ -export function transpileAndRun(files: Record, options: ts.CompilerOptions = {}): any { - const source = transpile(files); +export function transpileAndRun(files: Record, compilerOptions: ts.CompilerOptions = {}, reflectionOptions?: ReflectionOptions): any { + const source = transpile(files, compilerOptions, reflectionOptions); console.log('transpiled', source); const first = Object.keys(files)[0]; return eval(source[first]); } -export function transpile(files: Record, options: ts.CompilerOptions = {}): Record { - const compilerOptions: ts.CompilerOptions = { +export function transpile(files: Record, compilerOptions: ts.CompilerOptions = {}, reflectionOptions?: ReflectionOptions): Record { + compilerOptions = { ...defaultCompilerOptions, target: ts.ScriptTarget.ES2015, allowNonTsExtensions: true, @@ -82,7 +82,7 @@ export function transpile(files: Record, options: ts.CompilerOpt experimentalDecorators: true, esModuleInterop: true, skipLibCheck: true, - ...options + ...compilerOptions }; const fsMap = new Map(); @@ -108,7 +108,7 @@ export function transpile(files: Record, options: ts.CompilerOpt program.emit(undefined, (fileName, data) => { res[fileName.slice(__dirname.length + 1).replace(/\.js$/, '')] = data; }, undefined, undefined, { - before: [(context: TransformationContext) => new ReflectionTransformer(context).forHost(host.compilerHost).withReflectionMode('always')], + before: [(context: TransformationContext) => new ReflectionTransformer(context).forHost(host.compilerHost).withReflectionMode('always', reflectionOptions)], }); return res; From 1978d3103d967cdbb67f9d493d588caec817b976 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 5 Dec 2023 10:18:13 +0100 Subject: [PATCH 02/23] rename external to inlineExternalImports --- packages/type-compiler/src/compiler.ts | 23 ++++++++++--------- packages/type-compiler/src/reflection-ast.ts | 6 +---- ...pec.ts => inline-external-imports.spec.ts} | 16 ++++++------- 3 files changed, 21 insertions(+), 24 deletions(-) rename packages/type-compiler/tests/{inline-external-types.spec.ts => inline-external-imports.spec.ts} (91%) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 4c0c8dbb1..ddbf47d04 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -197,7 +197,7 @@ export interface ReflectionOptions { /** * External imports to reflect */ - external?: Record; // '*' or true? + inlineExternalImports?: true | Record; } export interface ReflectionConfig { @@ -537,7 +537,7 @@ export class EmbedDeclarations extends Map { */ export class ReflectionTransformer implements CustomTransformer { sourceFile!: SourceFile; - public f: NodeFactory; + protected f: NodeFactory; protected currentReflectionConfig: ReflectionConfig = { mode: 'never', options: {}, baseDir: '' }; public defaultExcluded: string[] = [ @@ -594,7 +594,7 @@ export class ReflectionTransformer implements CustomTransformer { protected context: TransformationContext, ) { this.f = context.factory; - this.nodeConverter = new NodeConverter(this); + this.nodeConverter = new NodeConverter(this.f, this); //it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); @@ -2026,14 +2026,15 @@ export class ReflectionTransformer implements CustomTransformer { return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName)); } - // TODO: what to do when the external type depends on another external type? should that be automatically resolved, or should the user specify that explicitly as well? - protected isImportMarkedAsExternal(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + // TODO: what to do when the inlineExternalImports type depends on another inlineExternalImports type? should that be automatically resolved, or should the user specify that explicitly as well? + protected shouldInlineExternalImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return false; - const external = config.options.external?.[importDeclaration.moduleSpecifier.text]; - if (!external) return false; - if (external === '*') return true; + if (config.options.inlineExternalImports === true) return true; + const externalImport = config.options.inlineExternalImports?.[importDeclaration.moduleSpecifier.text]; + if (!externalImport) return false; + if (externalImport === true) return true; const typeName = getEntityName(entityName); - return external.includes(typeName); + return externalImport.includes(typeName); } protected isExcluded(filePath: string): boolean { @@ -2230,7 +2231,7 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(typeVar, found); if (!builtType) { - if (!this.isImportMarkedAsExternal(resolved.importDeclaration, typeName, declarationReflection)) return; + if (!this.shouldInlineExternalImport(resolved.importDeclaration, typeName, declarationReflection)) return; this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile @@ -2307,7 +2308,7 @@ export class ReflectionTransformer implements CustomTransformer { // //check if typeVar is exported in referenced file const builtType = isBuiltType(typeVar, declarationSourceFile); - if (!builtType && this.isImportMarkedAsExternal(resolved.importDeclaration, typeName, declarationReflection)) { + if (!builtType && this.shouldInlineExternalImport(resolved.importDeclaration, typeName, declarationReflection)) { this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile, diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index e1a614a18..d03e4d9ee 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -123,11 +123,7 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - protected f: NodeFactory - - constructor(protected transformer: ReflectionTransformer) { - this.f = transformer.f; - } + constructor(protected f: NodeFactory, protected transformer: ReflectionTransformer) {} toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); diff --git a/packages/type-compiler/tests/inline-external-types.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts similarity index 91% rename from packages/type-compiler/tests/inline-external-types.spec.ts rename to packages/type-compiler/tests/inline-external-imports.spec.ts index 634087b77..1e6491865 100644 --- a/packages/type-compiler/tests/inline-external-types.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -9,7 +9,7 @@ test('class type', () => { type A = Observable; ` }, undefined, { - external: { + inlineExternalImports: { 'rxjs': ['Observable'], }, }); @@ -25,7 +25,7 @@ test('class typeOf', () => { typeOf(); ` }, undefined, { - external: { + inlineExternalImports: { 'rxjs': ['Subject'], }, }); @@ -42,7 +42,7 @@ test.todo('function'/*, () => { typeOf(); ` }, undefined, { - external: { + inlineExternalImports: { 'vite': ['preview'], }, }); @@ -57,7 +57,7 @@ test('only a single type is transformed', () => { type B = CorsOrigin; ` }, undefined, { - external: { + inlineExternalImports: { 'vite': ['ConfigEnv'], }, }); @@ -73,7 +73,7 @@ test('interface typeOf', () => { typeOf(); ` }, undefined, { - external: { + inlineExternalImports: { 'vite': ['ConfigEnv'], }, }); @@ -130,7 +130,7 @@ test('interface typeOf', () => { `); }); -test('all exports marked as external', () => { +test('inline all external imports for package', () => { const res = transpile({ app: `import { ConfigEnv, CorsOrigin } from 'vite'; import { typeOf } from '@deepkit/type'; @@ -139,8 +139,8 @@ test('all exports marked as external', () => { type B = CorsOrigin; ` }, undefined, { - external: { - 'vite': '*', + inlineExternalImports: { + 'vite': true, }, }); expect(res.app).toContain('const __ΩConfigEnv = ['); From beab43814979e1539692fa24ee652218a5e9042a Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 5 Dec 2023 11:54:49 +0100 Subject: [PATCH 03/23] improve --- packages/type-compiler/src/compiler.ts | 61 ++- packages/type-compiler/src/reflection-ast.ts | 3 +- .../tests/inline-external-imports.spec.ts | 393 +++++++++++++++--- 3 files changed, 363 insertions(+), 94 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 0b9d9ba57..2e51ede15 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -826,7 +826,6 @@ export class ReflectionTransformer implements CustomTransformer { } else if (isArrowFunction(node)) { return this.decorateArrow(node); } else if ((isNewExpression(node) || isCallExpression(node)) && node.typeArguments && node.typeArguments.length > 0) { - if (isCallExpression(node)) { const autoTypeFunctions = ['valuesOf', 'propertiesOf', 'typeOf']; if (isIdentifier(node.expression) && autoTypeFunctions.includes(getIdentifierName(node.expression))) { @@ -1823,7 +1822,7 @@ export class ReflectionTransformer implements CustomTransformer { if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - ensureImportIsEmitted(resolved.importDeclaration, narrowed.exprName); + this.resolveImport(resolved.declaration, resolved.importDeclaration, narrowed.exprName, program); } } @@ -1982,6 +1981,8 @@ export class ReflectionTransformer implements CustomTransformer { importDeclaration = declaration.parent; } + // TODO: check if it's a built type here? + if (importDeclaration) { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); @@ -2030,7 +2031,37 @@ export class ReflectionTransformer implements CustomTransformer { return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName)); } - // TODO: what to do when the inlineExternalImports type depends on another inlineExternalImports type? should that be automatically resolved, or should the user specify that explicitly as well? + protected resolveImport(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, program: CompilerProgram) { + if (isVariableDeclaration(declaration)) { + if (declaration.type) { + declaration = declaration.type; + } else if (declaration.initializer) { + declaration = declaration.initializer; + } + } + + ensureImportIsEmitted(importDeclaration, typeName); + + // check if the referenced declaration has reflection disabled + const declarationReflection = this.findReflectionConfig(declaration, program); + if (declarationReflection.mode !== 'never') { + const declarationSourceFile = importDeclaration.getSourceFile(); + + const runtimeTypeName = this.getDeclarationVariableName(typeName); + + const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); + + if (!builtType && this.shouldInlineExternalImport(importDeclaration, typeName, declarationReflection)) { + this.embedDeclarations.set(declaration, { + name: typeName, + sourceFile: declarationSourceFile, + assignType: true, + }); + } + } + } + + // TODO: what to do when the external type depends on another external type? should that be automatically resolved, or should the user explicitly specify that as well? protected shouldInlineExternalImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return false; if (config.options.inlineExternalImports === true) return true; @@ -2138,7 +2169,9 @@ export class ReflectionTransformer implements CustomTransformer { } if (isModuleDeclaration(declaration) && resolved.importDeclaration) { - if (isIdentifier(typeName)) ensureImportIsEmitted(resolved.importDeclaration, typeName); + if (isIdentifier(typeName)) { + this.resolveImport(declaration, resolved.importDeclaration, typeName, program); + } //we can not infer from module declaration, so do `typeof T` in runtime program.pushOp( @@ -2294,25 +2327,7 @@ export class ReflectionTransformer implements CustomTransformer { } if (resolved.importDeclaration && isIdentifier(typeName)) { - ensureImportIsEmitted(resolved.importDeclaration, typeName); - - // check if the referenced declaration has reflection disabled - const declarationReflection = this.findReflectionConfig(declaration, program); - if (declarationReflection.mode !== 'never') { - const declarationSourceFile = resolved.importDeclaration.getSourceFile(); - // //check if the referenced file has reflection info emitted. if not, any is emitted for that reference - const typeVar = this.getDeclarationVariableName(typeName); - // //check if typeVar is exported in referenced file - const builtType = isBuiltType(typeVar, declarationSourceFile); - - if (!builtType && this.shouldInlineExternalImport(resolved.importDeclaration, typeName, declarationReflection)) { - this.embedDeclarations.set(declaration, { - name: typeName, - sourceFile: declarationSourceFile, - assignType: true, - }); - } - } + this.resolveImport(resolved.declaration, resolved.importDeclaration, typeName, program); } program.pushFrame(); if (type.typeArguments) { diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index d03e4d9ee..6cdf0cebb 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -139,11 +139,10 @@ export class NodeConverter { if (node.pos === -1 && node.end === -1 && node.parent === undefined) { if (isArrowFunction(node)) { - // if (node.body.pos === -1 && node.body.end === -1 && node.body.parent === undefined) return node; return this.f.createArrowFunction(node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, this.toExpression(node.body as Expression)); } - return node; } + switch (node.kind) { case SyntaxKind.Identifier: const typeName = getIdentifierName(node as Identifier); diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index 1e6491865..c2102dfa7 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -1,8 +1,267 @@ import { test, expect } from '@jest/globals'; -import { isCustomTypeClass } from '@deepkit/type'; import { transpile, transpileAndRun } from './utils'; -test('class type', () => { + +test('symbol type var', () => { + const res = transpile({ + app: `import { config } from 'rxjs'; + + type A = typeof config; + ` + }, undefined, { + inlineExternalImports: { + 'rxjs': ['config'], + }, + }); + + expect(res.app).toContain('const __Ωconfig = ['); + expect(res.app).toContain('() => __assignType(rxjs_1.config, __Ωconfig)'); +}); + +test('symbol typeOf', () => { + const res = transpileAndRun({ + app: `import { typeOf } from '@deepkit/type'; + import { config } from 'rxjs'; + + typeOf(); + ` + }, undefined, { + inlineExternalImports: { + 'rxjs': ['config'], + }, + }); + + expect(res).toMatchInlineSnapshot(` + { + "annotations": {}, + "id": 2, + "kind": 30, + "typeName": undefined, + "types": [ + { + "kind": 32, + "name": "onUnhandledError", + "parent": [Circular], + "type": { + "kind": 10, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "onStoppedNotification", + "parent": [Circular], + "type": { + "kind": 10, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "Promise", + "parent": [Circular], + "type": { + "kind": 11, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "useDeprecatedSynchronousErrorHandling", + "parent": [Circular], + "type": { + "jit": {}, + "kind": 7, + "origin": { + "kind": 13, + "literal": false, + }, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "useDeprecatedNextContext", + "parent": [Circular], + "type": { + "jit": {}, + "kind": 7, + "origin": { + "kind": 13, + "literal": false, + }, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "__type", + "parent": [Circular], + "type": { + "kind": 25, + "parent": [Circular], + "type": { + "kind": 23, + "types": [ + { + "function": [Function], + "kind": 17, + "name": "", + "parameters": [], + "return": { + "kind": 1, + }, + }, + { + "jit": {}, + "kind": 5, + "origin": { + "kind": 13, + "literal": "n!", + }, + }, + ], + }, + }, + }, + ], + } + `); +}); + +test('function type var', () => { + const res = transpile({ + app: `import { map } from 'rxjs/operators'; + + type A = typeof map; + ` + }, undefined, { + inlineExternalImports: { + 'rxjs/operators': ['map'], + }, + }); + + expect(res.app).toContain('const __Ωmap = ['); + expect(res.app).toContain('() => __assignType(operators_1.map, __Ωmap)'); +}); + +test('function typeOf', () => { + const res = transpileAndRun({ + app: `import { map } from 'rxjs/operators'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + inlineExternalImports: { + 'rxjs/operators': ['map'], + }, + }); + + expect(res).toMatchInlineSnapshot(` + { + "function": [Function], + "inlined": true, + "kind": 17, + "name": "map", + "parameters": [ + { + "kind": 18, + "name": "project", + "parent": { + "function": [Function], + "kind": 17, + "name": "map", + "parameters": [Circular], + "return": { + "kind": 0, + "parent": [Circular], + }, + "typeName": undefined, + }, + "type": { + "kind": 17, + "name": undefined, + "parameters": [ + { + "kind": 18, + "name": "value", + "parent": [Circular], + "type": { + "kind": 1, + "parent": [Circular], + }, + }, + { + "kind": 18, + "name": "index", + "parent": [Circular], + "type": { + "kind": 6, + "parent": [Circular], + }, + }, + ], + "parent": [Circular], + "return": { + "kind": 1, + "parent": [Circular], + }, + }, + }, + ], + "return": { + "kind": 0, + "parent": { + "function": [Function], + "kind": 17, + "name": "map", + "parameters": [ + { + "kind": 18, + "name": "project", + "parent": [Circular], + "type": { + "kind": 17, + "name": undefined, + "parameters": [ + { + "kind": 18, + "name": "value", + "parent": [Circular], + "type": { + "kind": 1, + "parent": [Circular], + }, + }, + { + "kind": 18, + "name": "index", + "parent": [Circular], + "type": { + "kind": 6, + "parent": [Circular], + }, + }, + ], + "parent": [Circular], + "return": { + "kind": 1, + "parent": [Circular], + }, + }, + }, + ], + "return": [Circular], + "typeName": undefined, + }, + }, + "typeName": undefined, + } + `); +}) + +test('class type var', () => { const res = transpile({ app: `import { Observable } from 'rxjs'; @@ -30,24 +289,17 @@ test('class typeOf', () => { }, }); - expect(isCustomTypeClass(res)).toBe(true); + expect(res).toMatchInlineSnapshot(` + { + "classType": [Function], + "kind": 20, + "typeArguments": [], + "typeName": undefined, + "types": [], + } + `); }) -// Not supported yet -test.todo('function'/*, () => { - const res = transpileAndRun({ - app: `import { preview } from 'vite'; - import { typeOf } from '@deepkit/type'; - - typeOf(); - ` - }, undefined, { - inlineExternalImports: { - 'vite': ['preview'], - }, - }); -}*/) - test('only a single type is transformed', () => { const res = transpile({ app: `import { ConfigEnv, CorsOrigin } from 'vite'; @@ -61,6 +313,7 @@ test('only a single type is transformed', () => { 'vite': ['ConfigEnv'], }, }); + expect(res.app).toContain('const __ΩConfigEnv = ['); expect(res.app).not.toContain('const __ΩCorsOrigin = ['); }) @@ -77,60 +330,61 @@ test('interface typeOf', () => { 'vite': ['ConfigEnv'], }, }); + expect(res).toMatchInlineSnapshot(` -{ - "annotations": {}, - "id": 2, - "kind": 30, - "typeArguments": undefined, - "typeName": "ConfigEnv", - "types": [ - { - "kind": 32, - "name": "command", - "parent": [Circular], - "type": { - "kind": 23, - "parent": [Circular], - "types": [ - { - "kind": 13, - "literal": "build", - "parent": [Circular], - }, - { - "kind": 13, - "literal": "serve", - "parent": [Circular], - }, - ], - }, - }, - { - "kind": 32, - "name": "mode", - "parent": [Circular], - "type": { - "kind": 5, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "ssrBuild", - "optional": true, - "parent": [Circular], - "type": { - "kind": 7, - "parent": [Circular], - }, - }, - ], -} -`); + { + "annotations": {}, + "id": 2, + "kind": 30, + "typeArguments": undefined, + "typeName": "ConfigEnv", + "types": [ + { + "kind": 32, + "name": "command", + "parent": [Circular], + "type": { + "kind": 23, + "parent": [Circular], + "types": [ + { + "kind": 13, + "literal": "build", + "parent": [Circular], + }, + { + "kind": 13, + "literal": "serve", + "parent": [Circular], + }, + ], + }, + }, + { + "kind": 32, + "name": "mode", + "parent": [Circular], + "type": { + "kind": 5, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "ssrBuild", + "optional": true, + "parent": [Circular], + "type": { + "kind": 7, + "parent": [Circular], + }, + }, + ], + } + `); }); -test('inline all external imports for package', () => { +test('inline all external type imports for package', () => { const res = transpile({ app: `import { ConfigEnv, CorsOrigin } from 'vite'; import { typeOf } from '@deepkit/type'; @@ -143,6 +397,7 @@ test('inline all external imports for package', () => { 'vite': true, }, }); + expect(res.app).toContain('const __ΩConfigEnv = ['); expect(res.app).toContain('const __ΩCorsOrigin = ['); }); From 54b14d4a3f551ba0c0f4db1b2895f7a980e02acf Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 5 Dec 2023 17:17:55 +0100 Subject: [PATCH 04/23] improve 2nd iteration --- packages/type-compiler/src/compiler.ts | 87 +++++++------- packages/type-compiler/src/reflection-ast.ts | 14 +-- packages/type-compiler/src/resolver.ts | 17 ++- .../tests/inline-external-imports.spec.ts | 106 +++++++++++------- 4 files changed, 125 insertions(+), 99 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 2e51ede15..3e9222db3 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -13,6 +13,7 @@ import type { ArrayTypeNode, ArrowFunction, Bundle, + CallExpression, CallSignatureDeclaration, ClassDeclaration, ClassElement, @@ -85,6 +86,7 @@ import { isNodeWithLocals, NodeConverter, PackExpression, + SerializedEntityNameAsExpression, serializeEntityNameAsExpression, } from './reflection-ast.js'; import { SourceFile } from './ts-types.js'; @@ -511,23 +513,6 @@ export interface ReflectionTransformerConfig { deepkitTypeCompilerOptions?: DeepkitTypeCompilerOptions; } -export interface EmbedDeclaration { - name: EntityName, - sourceFile: SourceFile, - assignType?: boolean; -} - -export class EmbedDeclarations extends Map { - getByName(name: string): EmbedDeclaration | null { - for (const [,d] of this) { - if (getEntityName(d.name) === name) { - return d; - } - } - return null; - } -} - /** * Read the TypeScript AST and generate pack struct (instructions + pre-defined stack). * @@ -564,7 +549,7 @@ export class ReflectionTransformer implements CustomTransformer { * Types added to this map will get a type program at the top root level of the program. * This is for imported types, which need to be inlined into the current file, as we do not emit type imports (TS will omit them). */ - public embedDeclarations = new EmbedDeclarations(); + protected embedDeclarations = new Map(); /** * When a node was embedded or compiled (from the maps above), we store it here to know to not add it again. @@ -594,7 +579,7 @@ export class ReflectionTransformer implements CustomTransformer { protected context: TransformationContext, ) { this.f = context.factory; - this.nodeConverter = new NodeConverter(this.f, this); + this.nodeConverter = new NodeConverter(this.f); //it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); @@ -1819,14 +1804,13 @@ export class ReflectionTransformer implements CustomTransformer { // this.addImports.push({ identifier: narrowed.exprName, from: originImportStatement.moduleSpecifier }); // } // } + let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, narrowed.exprName); if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - this.resolveImport(resolved.declaration, resolved.importDeclaration, narrowed.exprName, program); + expression = this.resolveImport(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } - - const expression = serializeEntityNameAsExpression(this.f, narrowed.exprName); program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); break; } @@ -1935,11 +1919,12 @@ export class ReflectionTransformer implements CustomTransformer { * This is a custom resolver based on populated `locals` from the binder. It uses a custom resolution algorithm since * we have no access to the binder/TypeChecker directly and instantiating a TypeChecker per file/transformer is incredible slow. */ - protected resolveDeclaration(typeName: EntityName): { declaration: Node, importDeclaration?: ImportDeclaration, typeOnly?: boolean } | void { - let current: Node = typeName.parent; + protected resolveDeclaration(typeName: EntityName): { declaration: Node, importDeclaration?: ImportDeclaration, sourceFile: SourceFile, typeOnly: boolean } | void { + let current: Node = typeName.parent if (typeName.kind === SyntaxKind.QualifiedName) return; //namespace access not supported yet, e.g. type a = Namespace.X; let declaration: Node | undefined = undefined; + let sourceFile: SourceFile = this.sourceFile; while (current) { if (isNodeWithLocals(current) && current.locals) { @@ -1981,11 +1966,13 @@ export class ReflectionTransformer implements CustomTransformer { importDeclaration = declaration.parent; } - // TODO: check if it's a built type here? - if (importDeclaration) { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); + if (!declaration) { + sourceFile = importDeclaration.getSourceFile(); + declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, sourceFile); + } } if (declaration && declaration.kind === SyntaxKind.TypeParameter && declaration.parent.kind === SyntaxKind.TypeAliasDeclaration) { @@ -1995,7 +1982,7 @@ export class ReflectionTransformer implements CustomTransformer { if (!declaration) return; - return { declaration, importDeclaration, typeOnly }; + return { declaration, importDeclaration, typeOnly, sourceFile }; } // protected resolveType(node: TypeNode): Declaration | Node { @@ -2031,17 +2018,11 @@ export class ReflectionTransformer implements CustomTransformer { return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName)); } - protected resolveImport(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, program: CompilerProgram) { - if (isVariableDeclaration(declaration)) { - if (declaration.type) { - declaration = declaration.type; - } else if (declaration.initializer) { - declaration = declaration.initializer; - } - } - + protected resolveImport(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T { ensureImportIsEmitted(importDeclaration, typeName); + if (isTypeAliasDeclaration(declaration)) return expression; + // check if the referenced declaration has reflection disabled const declarationReflection = this.findReflectionConfig(declaration, program); if (declarationReflection.mode !== 'never') { @@ -2055,19 +2036,33 @@ export class ReflectionTransformer implements CustomTransformer { this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile, - assignType: true, }); + // if (!isTypeAliasDeclaration(declaration)) { + return this.wrapWithAssignType(expression, runtimeTypeName); + // } } } + + return expression; } - // TODO: what to do when the external type depends on another external type? should that be automatically resolved, or should the user explicitly specify that as well? protected shouldInlineExternalImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { - if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return false; + if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; if (config.options.inlineExternalImports === true) return true; - const externalImport = config.options.inlineExternalImports?.[importDeclaration.moduleSpecifier.text]; + const resolvedModule = this.resolver.resolveImpl(importDeclaration.moduleSpecifier.text, importDeclaration.getSourceFile().fileName); + if (!resolvedModule) { + throw new Error('Cannot resolve module'); + } + if (!resolvedModule.packageId) { + throw new Error('Missing package id for resolved module'); + } + if (!resolvedModule.isExternalLibraryImport) { + throw new Error('Resolved module is not an external library import'); + } + const externalImport = config.options.inlineExternalImports?.[resolvedModule.packageId.name]; if (!externalImport) return false; if (externalImport === true) return true; + if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; const typeName = getEntityName(entityName); return externalImport.includes(typeName); } @@ -2169,14 +2164,15 @@ export class ReflectionTransformer implements CustomTransformer { } if (isModuleDeclaration(declaration) && resolved.importDeclaration) { + let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - this.resolveImport(declaration, resolved.importDeclaration, typeName, program); + expression = this.resolveImport(declaration, resolved.importDeclaration, typeName, expression, program) } //we can not infer from module declaration, so do `typeof T` in runtime program.pushOp( ReflectionOp.typeof, - program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, serializeEntityNameAsExpression(this.f, typeName))) + program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression)) ); } else if (isTypeAliasDeclaration(declaration) || isInterfaceDeclaration(declaration) || isEnumDeclaration(declaration)) { //Set/Map are interface declarations @@ -2232,7 +2228,6 @@ export class ReflectionTransformer implements CustomTransformer { } if (isGlobal) { - //we don't embed non-global imported declarations anymore, only globals this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile @@ -2252,7 +2247,7 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const found = this.resolver.resolve(this.sourceFile, resolved.importDeclaration); + const found = this.resolver.resolve(resolved.sourceFile, resolved.importDeclaration); if (!found) { debug('module not found'); program.pushOp(ReflectionOp.any); @@ -2326,8 +2321,9 @@ export class ReflectionTransformer implements CustomTransformer { return; } + let body: Identifier | PropertyAccessExpression | CallExpression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); if (resolved.importDeclaration && isIdentifier(typeName)) { - this.resolveImport(resolved.declaration, resolved.importDeclaration, typeName, program); + body = this.resolveImport(resolved.declaration, resolved.importDeclaration, typeName, body, program); } program.pushFrame(); if (type.typeArguments) { @@ -2335,7 +2331,6 @@ export class ReflectionTransformer implements CustomTransformer { this.extractPackStructOfType(typeArgument, program); } } - const body = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); program.popFrameImplicit(); diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index 6cdf0cebb..bf38dd856 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -33,7 +33,6 @@ import type { import ts from 'typescript'; import { cloneNode as tsNodeClone, CloneNodeHook } from '@marcj/ts-clone-node'; import { SourceFile } from './ts-types.js'; -import { ReflectionTransformer } from './compiler.js'; const { isArrowFunction, @@ -123,7 +122,7 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - constructor(protected f: NodeFactory, protected transformer: ReflectionTransformer) {} + constructor(protected f: NodeFactory) {} toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -139,18 +138,15 @@ export class NodeConverter { if (node.pos === -1 && node.end === -1 && node.parent === undefined) { if (isArrowFunction(node)) { + if (node.body.pos === -1 && node.body.end === -1 && node.body.parent === undefined) return node; return this.f.createArrowFunction(node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, this.toExpression(node.body as Expression)); } + return node; } switch (node.kind) { case SyntaxKind.Identifier: - const typeName = getIdentifierName(node as Identifier); - const embedDeclaration = this.transformer.embedDeclarations.getByName(typeName); - if (embedDeclaration?.assignType) { - return this.transformer.wrapWithAssignType(finish(node, this.f.createIdentifier(typeName)), this.transformer.getDeclarationVariableName(node as Identifier)); - } - return finish(node, this.f.createIdentifier(typeName)); + return finish(node, this.f.createIdentifier(getIdentifierName(node as Identifier))); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: @@ -249,7 +245,7 @@ export function serializeEntityNameAsExpression(f: NodeFactory, node: EntityName return node; } -type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression; +export type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression; /** * Serializes an qualified name as an expression for decorator type metadata. diff --git a/packages/type-compiler/src/resolver.ts b/packages/type-compiler/src/resolver.ts index 8ed21000f..ef0831edf 100644 --- a/packages/type-compiler/src/resolver.ts +++ b/packages/type-compiler/src/resolver.ts @@ -1,4 +1,13 @@ -import type { CompilerHost, CompilerOptions, ExportDeclaration, Expression, ImportDeclaration, ResolvedModule, SourceFile, StringLiteral, } from 'typescript'; +import type { + CompilerHost, + CompilerOptions, + ExportDeclaration, + Expression, + ImportDeclaration, + ResolvedModuleFull, + SourceFile, + StringLiteral, +} from 'typescript'; import ts from 'typescript'; import * as micromatch from 'micromatch'; import { isAbsolute } from 'path'; @@ -61,12 +70,12 @@ export class Resolver { return this.resolveSourceFile(from.fileName, (moduleSpecifier as StringLiteral).text); } - resolveImpl(modulePath: string, fromPath: string): ResolvedModule | undefined { + resolveImpl(modulePath: string, fromPath: string): ResolvedModuleFull | undefined { if (this.host.resolveModuleNames !== undefined) { - return this.host.resolveModuleNames([modulePath], fromPath, /*reusedNames*/ undefined, /*redirectedReference*/ undefined, this.compilerOptions)[0]; + return this.host.resolveModuleNames([modulePath], fromPath, /*reusedNames*/ undefined, /*redirectedReference*/ undefined, this.compilerOptions)[0] as ResolvedModuleFull | undefined; } const result = resolveModuleName(modulePath, fromPath, this.compilerOptions, this.host); - return result.resolvedModule; + return result.resolvedModule as ResolvedModuleFull; } /** diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index c2102dfa7..ad32ed2bd 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -1,8 +1,44 @@ import { test, expect } from '@jest/globals'; +import { ReflectionKind, TypeClass, TypeFunction } from '@deepkit/type'; import { transpile, transpileAndRun } from './utils'; -test('symbol type var', () => { +test('string type alias', () => { + const res = transpile({ + app: `import { NIL } from 'uuid'; + + type T = typeof NIL; + ` + }, undefined, { + inlineExternalImports: { + 'uuid': ['NIL'], + }, + }); + + expect(res.app).not.toContain('const __ΩNIL = ['); + expect(res.app).not.toContain('() => __assignType(uuid_1.NIL, __ΩNIL)'); + expect(res.app).toContain('() => uuid_1.NIL'); +}); + +test('typeOf string type alias', () => { + const res = transpileAndRun({ + app: `import { typeOf } from '@deepkit/type'; + import { NIL } from 'uuid'; + + typeOf(); + ` + }); + + expect(res).toMatchInlineSnapshot(` + { + "kind": 13, + "literal": "00000000-0000-0000-0000-000000000000", + "typeName": undefined, + } + `); +}); + +test('object type alias', () => { const res = transpile({ app: `import { config } from 'rxjs'; @@ -14,11 +50,12 @@ test('symbol type var', () => { }, }); - expect(res.app).toContain('const __Ωconfig = ['); - expect(res.app).toContain('() => __assignType(rxjs_1.config, __Ωconfig)'); + expect(res.app).not.toContain('const __Ωconfig = ['); + expect(res.app).not.toContain('() => __assignType(rxjs_1.config, __Ωconfig)'); + expect(res.app).toContain('() => rxjs_1.config'); }); -test('symbol typeOf', () => { +test('typeOf object type alias', () => { const res = transpileAndRun({ app: `import { typeOf } from '@deepkit/type'; import { config } from 'rxjs'; @@ -101,26 +138,12 @@ test('symbol typeOf', () => { "kind": 25, "parent": [Circular], "type": { - "kind": 23, - "types": [ - { - "function": [Function], - "kind": 17, - "name": "", - "parameters": [], - "return": { - "kind": 1, - }, - }, - { - "jit": {}, - "kind": 5, - "origin": { - "kind": 13, - "literal": "n!", - }, - }, - ], + "jit": {}, + "kind": 5, + "origin": { + "kind": 13, + "literal": "!", + }, }, }, }, @@ -129,7 +152,7 @@ test('symbol typeOf', () => { `); }); -test('function type var', () => { +test('function type alias', () => { const res = transpile({ app: `import { map } from 'rxjs/operators'; @@ -145,7 +168,7 @@ test('function type var', () => { expect(res.app).toContain('() => __assignType(operators_1.map, __Ωmap)'); }); -test('function typeOf', () => { +test('typeOf function type alias', () => { const res = transpileAndRun({ app: `import { map } from 'rxjs/operators'; import { typeOf } from '@deepkit/type'; @@ -154,9 +177,13 @@ test('function typeOf', () => { ` }, undefined, { inlineExternalImports: { - 'rxjs/operators': ['map'], + 'rxjs/operators': ['map', 'OperatorFunction'], }, - }); + }) as TypeFunction; + + expect(res.return.kind).not.toBe(ReflectionKind.never); + + console.log(res.return); expect(res).toMatchInlineSnapshot(` { @@ -273,6 +300,8 @@ test('class type var', () => { }, }); + console.log(res.app); + expect(res.app).toContain('const __ΩObservable = ['); expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ΩObservable)'); }) @@ -281,23 +310,20 @@ test('class typeOf', () => { app: `import { Observable } from 'rxjs'; import { typeOf } from '@deepkit/type'; - typeOf(); + typeOf>(); ` }, undefined, { inlineExternalImports: { - 'rxjs': ['Subject'], + 'rxjs': ['Observable'], }, - }); + }) as TypeClass; - expect(res).toMatchInlineSnapshot(` - { - "classType": [Function], - "kind": 20, - "typeArguments": [], - "typeName": undefined, - "types": [], - } - `); + expect(res.implements![0]).toMatchObject({ + kind: 30, + typeName: 'Subscribable', + }); + expect(res.typeArguments).toHaveLength(1); + expect(res.types).toHaveLength(1); }) test('only a single type is transformed', () => { From d0ac2691b02c86bf136281d1e35d776274c226a6 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 5 Dec 2023 17:23:00 +0100 Subject: [PATCH 05/23] rename inlineExternalImports to inlineExternalLibraryImports matches with typescript's definition of it --- packages/type-compiler/src/compiler.ts | 12 ++--- .../tests/inline-external-imports.spec.ts | 49 ++++++++++++++----- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 3e9222db3..9ae72de2c 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -199,7 +199,7 @@ export interface ReflectionOptions { /** * External imports to reflect */ - inlineExternalImports?: true | Record; + inlineExternalLibraryImports?: true | Record; } export interface ReflectionConfig { @@ -2032,7 +2032,7 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); - if (!builtType && this.shouldInlineExternalImport(importDeclaration, typeName, declarationReflection)) { + if (!builtType && this.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection)) { this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile, @@ -2046,9 +2046,9 @@ export class ReflectionTransformer implements CustomTransformer { return expression; } - protected shouldInlineExternalImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + protected shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; - if (config.options.inlineExternalImports === true) return true; + if (config.options.inlineExternalLibraryImports === true) return true; const resolvedModule = this.resolver.resolveImpl(importDeclaration.moduleSpecifier.text, importDeclaration.getSourceFile().fileName); if (!resolvedModule) { throw new Error('Cannot resolve module'); @@ -2059,7 +2059,7 @@ export class ReflectionTransformer implements CustomTransformer { if (!resolvedModule.isExternalLibraryImport) { throw new Error('Resolved module is not an external library import'); } - const externalImport = config.options.inlineExternalImports?.[resolvedModule.packageId.name]; + const externalImport = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; if (!externalImport) return false; if (externalImport === true) return true; if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; @@ -2256,7 +2256,7 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { - if (!this.shouldInlineExternalImport(resolved.importDeclaration, typeName, declarationReflection)) return; + if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index ad32ed2bd..7f3819b22 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -10,7 +10,7 @@ test('string type alias', () => { type T = typeof NIL; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'uuid': ['NIL'], }, }); @@ -45,7 +45,7 @@ test('object type alias', () => { type A = typeof config; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs': ['config'], }, }); @@ -63,7 +63,7 @@ test('typeOf object type alias', () => { typeOf(); ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs': ['config'], }, }); @@ -159,7 +159,7 @@ test('function type alias', () => { type A = typeof map; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs/operators': ['map'], }, }); @@ -176,7 +176,7 @@ test('typeOf function type alias', () => { typeOf(); ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs/operators': ['map', 'OperatorFunction'], }, }) as TypeFunction; @@ -295,12 +295,39 @@ test('class type var', () => { type A = Observable; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs': ['Observable'], }, }); - console.log(res.app); + // TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ΩSubscriber) + // "use strict"; + // Object.defineProperty(exports, "__esModule", { value: true }); + // exports.__ΩUnsubscribable = exports.__ΩSubscribable = exports.__ΩSubscription = exports.__ΩObserver = exports.__ΩTeardownLogic = exports.__ΩSubscriber = exports.__ΩOperator = exports.__ΩObservable = void 0; + // const __ΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y']; + // exports.__ΩObservable = __ΩObservable; + // const __ΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My']; + // exports.__ΩOperator = __ΩOperator; + // const __ΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ΩObserver, 'destination', () => Subscriber, () => __ΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+ Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; + // exports.__ΩTeardownLogic = __ΩTeardownLogic; + // const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; + // const __ΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My']; + // exports.__ΩObserver = __ΩObserver; + // const __ΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y']; + // exports.__ΩSubscription = __ΩSubscription; + // const __ΩSubscribable = ['T', () => __ΩPartial, () => __ΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; + // exports.__ΩSubscribable = __ΩSubscribable; + // const __ΩUnsubscribable = ['unsubscribe', 'PP$1!My']; + // exports.__ΩUnsubscribable = __ΩUnsubscribable; + // const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; + // function __assignType(fn, args) { + // fn.__type = args; + // return fn; + // } + // const rxjs_1 = require("rxjs"); + // const __ΩA = [() => __assignType(rxjs_1.Observable, __ΩObservable), 'P#7!y']; expect(res.app).toContain('const __ΩObservable = ['); expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ΩObservable)'); @@ -313,7 +340,7 @@ test('class typeOf', () => { typeOf>(); ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'rxjs': ['Observable'], }, }) as TypeClass; @@ -335,7 +362,7 @@ test('only a single type is transformed', () => { type B = CorsOrigin; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'vite': ['ConfigEnv'], }, }); @@ -352,7 +379,7 @@ test('interface typeOf', () => { typeOf(); ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'vite': ['ConfigEnv'], }, }); @@ -419,7 +446,7 @@ test('inline all external type imports for package', () => { type B = CorsOrigin; ` }, undefined, { - inlineExternalImports: { + inlineExternalLibraryImports: { 'vite': true, }, }); From 8d869b3829c98c15d6c21aceab07d140fcdfaf2b Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Wed, 6 Dec 2023 10:30:20 +0100 Subject: [PATCH 06/23] =?UTF-8?q?prefix=20external=20runtime=20type=20name?= =?UTF-8?q?s=20with=20`=5F=5F=C9=B5=CE=A9`=20so=20that=20external=20type?= =?UTF-8?q?=20names=20don't=20clash=20with=20user=20defined=20type=20names?= =?UTF-8?q?=20when=20inlined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/type-compiler/src/compiler.ts | 64 ++++++++++++------- .../tests/inline-external-imports.spec.ts | 64 +++++++++++++------ 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index edb174b6f..6525266b1 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -536,6 +536,8 @@ export class ReflectionTransformer implements CustomTransformer { protected reflectionMode?: typeof reflectionModes[number]; protected reflectionOptions?: ReflectionOptions; + protected isMaybeEmbeddingExternalLibraryImport: boolean = false; + /** * Types added to this map will get a type program directly under it. * This is for types used in the very same file. @@ -545,6 +547,8 @@ export class ReflectionTransformer implements CustomTransformer { { name: EntityName, sourceFile: SourceFile, compiled?: Statement[] } >(); + protected externalRuntimeTypeNames = new Set(); + /** * Types added to this map will get a type program at the top root level of the program. * This is for imported types, which need to be inlined into the current file, as we do not emit type imports (TS will omit them). @@ -1808,7 +1812,7 @@ export class ReflectionTransformer implements CustomTransformer { if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - expression = this.resolveImport(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); + expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); @@ -2005,44 +2009,58 @@ export class ReflectionTransformer implements CustomTransformer { // return node; // } - public getDeclarationVariableName(typeName: EntityName): Identifier { - if (isIdentifier(typeName)) { - return this.f.createIdentifier('__Ω' + getIdentifierName(typeName)); + protected getRuntimeTypeName(typeName: string): string { + if (this.externalRuntimeTypeNames.has(typeName)) { + return `__ɵΩ${typeName}`; } + return `__Ω${typeName}`; + } - function joinQualifiedName(name: EntityName): string { - if (isIdentifier(name)) return getIdentifierName(name); - return joinQualifiedName(name.left) + '_' + getIdentifierName(name.right); - } + protected getDeclarationVariableName(typeName: EntityName): Identifier { + return this.f.createIdentifier(this.getRuntimeTypeName(getNameAsString(typeName))); + } + + protected addExternalLibraryImportEmbedDeclaration(declaration: Node, sourceFile: SourceFile, typeName: EntityName): void { + this.isMaybeEmbeddingExternalLibraryImport = true; + + this.externalRuntimeTypeNames.add(getNameAsString(typeName)); - return this.f.createIdentifier('__Ω' + joinQualifiedName(typeName)); + this.embedDeclarations.set(declaration, { + name: typeName, + sourceFile, + }); } - protected resolveImport(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T { + protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T { ensureImportIsEmitted(importDeclaration, typeName); - if (isTypeAliasDeclaration(declaration)) return expression; + if (isTypeAliasDeclaration(declaration)) { + this.isMaybeEmbeddingExternalLibraryImport = false; + return expression; + } // check if the referenced declaration has reflection disabled const declarationReflection = this.findReflectionConfig(declaration, program); if (declarationReflection.mode !== 'never') { const declarationSourceFile = importDeclaration.getSourceFile(); + if (this.isMaybeEmbeddingExternalLibraryImport) { + this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName)); + } + const runtimeTypeName = this.getDeclarationVariableName(typeName); const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); if (!builtType && this.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection)) { - this.embedDeclarations.set(declaration, { - name: typeName, - sourceFile: declarationSourceFile, - }); - // if (!isTypeAliasDeclaration(declaration)) { - return this.wrapWithAssignType(expression, runtimeTypeName); - // } + this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName)); } } + this.isMaybeEmbeddingExternalLibraryImport = false; + return expression; } @@ -2166,7 +2184,7 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - expression = this.resolveImport(declaration, resolved.importDeclaration, typeName, expression, program) + expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } //we can not infer from module declaration, so do `typeof T` in runtime @@ -2257,11 +2275,9 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.embedDeclarations.set(declaration, { - name: typeName, - sourceFile: declarationSourceFile - }); + this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); } else { + this.isMaybeEmbeddingExternalLibraryImport = false; //check if the referenced file has reflection info emitted. if not, any is emitted for that reference const reflection = this.findReflectionFromPath(found.fileName); if (reflection.mode === 'never') { @@ -2323,7 +2339,7 @@ export class ReflectionTransformer implements CustomTransformer { let body: Identifier | PropertyAccessExpression | CallExpression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); if (resolved.importDeclaration && isIdentifier(typeName)) { - body = this.resolveImport(resolved.declaration, resolved.importDeclaration, typeName, body, program); + body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); } program.pushFrame(); if (type.typeArguments) { diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index 7f3819b22..044aec823 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -300,25 +300,26 @@ test('class type var', () => { }, }); - // TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ΩSubscriber) - // "use strict"; - // Object.defineProperty(exports, "__esModule", { value: true }); - // exports.__ΩUnsubscribable = exports.__ΩSubscribable = exports.__ΩSubscription = exports.__ΩObserver = exports.__ΩTeardownLogic = exports.__ΩSubscriber = exports.__ΩOperator = exports.__ΩObservable = void 0; - // const __ΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y']; - // exports.__ΩObservable = __ΩObservable; - // const __ΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My']; - // exports.__ΩOperator = __ΩOperator; - // const __ΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ΩObserver, 'destination', () => Subscriber, () => __ΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+ Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; - // exports.__ΩTeardownLogic = __ΩTeardownLogic; + console.log(res.app); + + // TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber) + // + // exports.__ΩUnsubscribable = exports.__ɵΩSubscribable = exports.__ɵΩSubscription = exports.__ɵΩObserver = exports.__ɵΩTeardownLogic = exports.__ɵΩSubscriber = exports.__ɵΩOperator = exports.__ɵΩObservable = void 0; + // const __ɵΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ɵΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y']; + // exports.__ɵΩObservable = __ɵΩObservable; + // const __ɵΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ɵΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My']; + // exports.__ɵΩOperator = __ɵΩOperator; + // const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ɵΩObserver, 'destination', () => Subscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+ Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; + // exports.__ɵΩTeardownLogic = __ɵΩTeardownLogic; // const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; - // const __ΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My']; - // exports.__ΩObserver = __ΩObserver; - // const __ΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y']; - // exports.__ΩSubscription = __ΩSubscription; - // const __ΩSubscribable = ['T', () => __ΩPartial, () => __ΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; - // exports.__ΩSubscribable = __ΩSubscribable; + // const __ɵΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My']; + // exports.__ɵΩObserver = __ɵΩObserver; + // const __ɵΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y']; + // exports.__ɵΩSubscription = __ɵΩSubscription; + // const __ɵΩSubscribable = ['T', () => __ΩPartial, () => __ɵΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; + // exports.__ɵΩSubscribable = __ɵΩSubscribable; // const __ΩUnsubscribable = ['unsubscribe', 'PP$1!My']; // exports.__ΩUnsubscribable = __ΩUnsubscribable; // const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; @@ -327,11 +328,32 @@ test('class type var', () => { // return fn; // } // const rxjs_1 = require("rxjs"); - // const __ΩA = [() => __assignType(rxjs_1.Observable, __ΩObservable), 'P#7!y']; + // const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩObservable), 'P#7!y']; - expect(res.app).toContain('const __ΩObservable = ['); - expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ΩObservable)'); + expect(res.app).toContain('const __ɵΩObservable = ['); + expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ɵΩObservable)'); + // FIXME: why isn't it being prefixed with `ɵ`? + expect(res.app).toContain('const __ɵΩUnsubscribable = ['); }) + +test('runtime type name clashing', () => { + const res = transpile({ + app: `import { Observable } from 'rxjs'; + + type Subscribable = any; + + type A = Observable; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['Observable'], + }, + }); + + expect(res.app).toContain('const __ɵΩSubscribable = ['); + expect(res.app).toContain('const __ΩSubscribable = ['); +}) + test('class typeOf', () => { const res = transpileAndRun({ app: `import { Observable } from 'rxjs'; From 37322ce78568bb86671695c8109be4816ac36496 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Wed, 6 Dec 2023 11:39:56 +0100 Subject: [PATCH 07/23] =?UTF-8?q?prefix=20external=20runtime=20type=20name?= =?UTF-8?q?s=20with=20`=5F=5F=C9=B5=CE=A9`=20so=20that=20external=20type?= =?UTF-8?q?=20names=20don't=20clash=20with=20user=20defined=20type=20names?= =?UTF-8?q?=20when=20inlined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/type-compiler/src/compiler.ts | 109 ++++++++++-------- packages/type-compiler/src/reflection-ast.ts | 9 +- .../tests/inline-external-imports.spec.ts | 70 ++++++----- 3 files changed, 105 insertions(+), 83 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 6525266b1..a62d6de81 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -547,6 +547,8 @@ export class ReflectionTransformer implements CustomTransformer { { name: EntityName, sourceFile: SourceFile, compiled?: Statement[] } >(); + protected externalSourceFileNames = new Set(); + protected externalRuntimeTypeNames = new Set(); /** @@ -583,7 +585,7 @@ export class ReflectionTransformer implements CustomTransformer { protected context: TransformationContext, ) { this.f = context.factory; - this.nodeConverter = new NodeConverter(this.f); + this.nodeConverter = new NodeConverter(this.f, this.externalRuntimeTypeNames); //it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); @@ -2025,6 +2027,8 @@ export class ReflectionTransformer implements CustomTransformer { this.externalRuntimeTypeNames.add(getNameAsString(typeName)); + this.externalSourceFileNames.add(sourceFile.fileName); + this.embedDeclarations.set(declaration, { name: typeName, sourceFile, @@ -2237,69 +2241,74 @@ export class ReflectionTransformer implements CustomTransformer { //to break recursion, we track which declaration has already been compiled if (!this.compiledDeclarations.has(declaration) && !this.compileDeclarations.has(declaration)) { const declarationSourceFile = findSourceFile(declaration) || this.sourceFile; - const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; - const isFromImport = resolved.importDeclaration !== undefined; if (this.isExcluded(declarationSourceFile.fileName)) { program.pushOp(ReflectionOp.any); return; } - if (isGlobal) { - this.embedDeclarations.set(declaration, { - name: typeName, - sourceFile: declarationSourceFile - }); - } else if (isFromImport) { - if (resolved.importDeclaration) { - //if explicit `import {type T}`, we do not emit an import and instead push any - if (resolved.typeOnly) { - this.resolveTypeOnlyImport(typeName, program); - return; - } - - // check if the referenced declaration has reflection disabled - const declarationReflection = this.findReflectionConfig(declaration, program); - if (declarationReflection.mode === 'never') { - program.pushOp(ReflectionOp.any); - return; - } + if (this.externalSourceFileNames.has(declarationSourceFile.fileName)) { + this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + } else { + const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; + const isFromImport = resolved.importDeclaration !== undefined; + + if (isGlobal) { + this.embedDeclarations.set(declaration, { + name: typeName, + sourceFile: declarationSourceFile + }); + } else if (isFromImport) { + if (resolved.importDeclaration) { + //if explicit `import {type T}`, we do not emit an import and instead push any + if (resolved.typeOnly) { + this.resolveTypeOnlyImport(typeName, program); + return; + } - const found = this.resolver.resolve(resolved.sourceFile, resolved.importDeclaration); - if (!found) { - debug('module not found'); - program.pushOp(ReflectionOp.any); - return; - } + // check if the referenced declaration has reflection disabled + const declarationReflection = this.findReflectionConfig(declaration, program); + if (declarationReflection.mode === 'never') { + program.pushOp(ReflectionOp.any); + return; + } - const builtType = isBuiltType(runtimeTypeName, found); - if (!builtType) { - if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); - } else { - this.isMaybeEmbeddingExternalLibraryImport = false; - //check if the referenced file has reflection info emitted. if not, any is emitted for that reference - const reflection = this.findReflectionFromPath(found.fileName); - if (reflection.mode === 'never') { + const found = this.resolver.resolve(resolved.sourceFile, resolved.importDeclaration); + if (!found) { + debug('module not found'); program.pushOp(ReflectionOp.any); return; } - this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); + const builtType = isBuiltType(runtimeTypeName, found); + if (!builtType) { + if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; + this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + } else { + this.isMaybeEmbeddingExternalLibraryImport = false; + //check if the referenced file has reflection info emitted. if not, any is emitted for that reference + const reflection = this.findReflectionFromPath(found.fileName); + if (reflection.mode === 'never') { + program.pushOp(ReflectionOp.any); + return; + } + + this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); + } + } + } else { + //it's a reference type inside the same file. Make sure its type is reflected + const reflection = this.findReflectionConfig(declaration, program); + if (reflection.mode === 'never') { + program.pushOp(ReflectionOp.any); + return; } - } - } else { - //it's a reference type inside the same file. Make sure its type is reflected - const reflection = this.findReflectionConfig(declaration, program); - if (reflection.mode === 'never') { - program.pushOp(ReflectionOp.any); - return; - } - this.compileDeclarations.set(declaration, { - name: typeName, - sourceFile: declarationSourceFile, - }); + this.compileDeclarations.set(declaration, { + name: typeName, + sourceFile: declarationSourceFile, + }); + } } } diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index bf38dd856..ec75d5281 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -109,6 +109,10 @@ export function hasModifier(node: { modifiers?: NodeArray }, modif return node.modifiers.some(v => v.kind === modifier); } +export function getExternalRuntimeTypeName(typeName: string): string { + return `__ɵΩ${typeName}`; +} + const cloneHook = (node: T, payload: { depth: number }): CloneNodeHook | undefined => { if (isIdentifier(node)) { //ts-clone-node wants to read `node.text` which does not exist. we hook into it and provide the correct value. @@ -122,7 +126,7 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - constructor(protected f: NodeFactory) {} + constructor(protected f: NodeFactory, protected externalRuntimeTypeNames: Set) {} toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -146,7 +150,8 @@ export class NodeConverter { switch (node.kind) { case SyntaxKind.Identifier: - return finish(node, this.f.createIdentifier(getIdentifierName(node as Identifier))); + const typeName = getIdentifierName(node as Identifier); + return finish(node, this.f.createIdentifier(this.externalRuntimeTypeNames.has(typeName) ? getExternalRuntimeTypeName(typeName) : typeName)); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index 044aec823..90f3f7793 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -1,5 +1,6 @@ import { test, expect } from '@jest/globals'; import { ReflectionKind, TypeClass, TypeFunction } from '@deepkit/type'; +import { Unsubscribable } from 'rxjs'; import { transpile, transpileAndRun } from './utils'; @@ -300,40 +301,47 @@ test('class type var', () => { }, }); - console.log(res.app); - - // TODO: how to resolve the typeof imports? -> __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber) - // - // exports.__ΩUnsubscribable = exports.__ɵΩSubscribable = exports.__ɵΩSubscription = exports.__ɵΩObserver = exports.__ɵΩTeardownLogic = exports.__ɵΩSubscriber = exports.__ɵΩOperator = exports.__ɵΩObservable = void 0; - // const __ɵΩObservable = ['T', () => Observable, 'source', () => __ΩOperator, 'operator', () => Observable, 'this', () => __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩOperator, () => Observable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ɵΩSubscription), 'value', 'next', 'forEach', () => Observable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$`09PPe#!7:0;PPe#!-J`0<5e!!o="x"w>y']; - // exports.__ɵΩObservable = __ɵΩObservable; - // const __ɵΩOperator = ['T', 'R', () => Subscriber_2.Subscriber, 'subscriber', 'source', () => __ɵΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\'My']; - // exports.__ɵΩOperator = __ɵΩOperator; - // const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => Subscriber, 'create', 'isStopped', () => Subscriber, () => __ɵΩObserver, 'destination', () => Subscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\'8P$/$2(8Pe#!7)0*s)3+ Subscription_3.Subscription, () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; - // exports.__ɵΩTeardownLogic = __ɵΩTeardownLogic; - // const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; - // const __ɵΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\'My']; - // exports.__ɵΩObserver = __ɵΩObserver; - // const __ɵΩSubscription = [() => Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\'Pn(2)$0*Pn,$o+#2)$0-5x"w.y']; - // exports.__ɵΩSubscription = __ɵΩSubscription; - // const __ɵΩSubscribable = ['T', () => __ΩPartial, () => __ɵΩObserver, 'observer', () => __ΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; - // exports.__ɵΩSubscribable = __ɵΩSubscribable; - // const __ΩUnsubscribable = ['unsubscribe', 'PP$1!My']; - // exports.__ΩUnsubscribable = __ΩUnsubscribable; - // const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; - // function __assignType(fn, args) { - // fn.__type = args; - // return fn; - // } - // const rxjs_1 = require("rxjs"); - // const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩObservable), 'P#7!y']; - expect(res.app).toContain('const __ɵΩObservable = ['); expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ɵΩObservable)'); - // FIXME: why isn't it being prefixed with `ɵ`? + expect(res.app).toContain('const __ɵΩUnsubscribable = ['); + + expect(res.app).toMatchInlineSnapshot(` + ""use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.__ɵΩSubscriptionLike = exports.__ɵΩUnsubscribable = exports.__ɵΩSubscribable = exports.__ɵΩSubscription = exports.__ɵΩObserver = exports.__ɵΩTeardownLogic = exports.__ɵΩSubscriber = exports.__ɵΩOperator = exports.__ɵΩObservable = void 0; + const __ɵΩObservable = ['T', () => __ɵΩObservable, 'source', () => __ΩOperator, 'operator', () => __ɵΩObservable, 'this', () => __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩOperator, () => __ɵΩObservable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ɵΩSubscription), 'value', 'next', 'forEach', () => __ɵΩObservable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; + exports.__ɵΩObservable = __ɵΩObservable; + const __ɵΩOperator = ['T', 'R', () => __assignType(Subscriber_2.Subscriber, __ɵΩSubscriber), 'subscriber', 'source', () => __ɵΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; + exports.__ɵΩOperator = __ɵΩOperator; + const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩSubscriber, 'create', 'isStopped', () => __ɵΩSubscriber, () => __ɵΩObserver, 'destination', () => __ɵΩSubscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __assignType(Subscription_3.Subscription, __ɵΩSubscription), () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; + exports.__ɵΩTeardownLogic = __ɵΩTeardownLogic; + const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; + const __ɵΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; + exports.__ɵΩObserver = __ɵΩObserver; + const __ɵΩSubscription = [() => __ɵΩSubscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', () => __ΩSubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + exports.__ɵΩSubscription = __ɵΩSubscription; + const __ɵΩSubscribable = ['T', () => __ΩPartial, () => __ɵΩObserver, 'observer', () => __ɵΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; + exports.__ɵΩSubscribable = __ɵΩSubscribable; + const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩSubscriber, 'create', 'isStopped', () => __ɵΩSubscriber, () => __ɵΩObserver, 'destination', () => __ɵΩSubscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩSubscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', () => __ɵΩSubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + exports.__ɵΩSubscription = __ɵΩSubscription; + const __ɵΩUnsubscribable = ['unsubscribe', 'PP$1!My']; + exports.__ɵΩUnsubscribable = __ɵΩUnsubscribable; + const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; + const __ɵΩSubscriptionLike = [() => __ɵΩUnsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; + exports.__ɵΩSubscriptionLike = __ɵΩSubscriptionLike; + function __assignType(fn, args) { + fn.__type = args; + return fn; + } + const rxjs_1 = require("rxjs"); + const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩObservable), 'P#7!y']; + " + `); }) test('runtime type name clashing', () => { From 0b19891ad9e1dffc5523924bd441079c12758d2b Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Wed, 6 Dec 2023 16:46:51 +0100 Subject: [PATCH 08/23] external runtime types are now scoped to encapsulate each embedded external library correctly --- packages/type-compiler/src/compiler.ts | 186 +++++++++--------- packages/type-compiler/src/externals.ts | 107 ++++++++++ packages/type-compiler/src/reflection-ast.ts | 13 +- packages/type-compiler/src/resolver.ts | 31 ++- .../tests/inline-external-imports.spec.ts | 85 ++++---- .../type-compiler/tests/transform.spec.ts | 2 +- 6 files changed, 287 insertions(+), 137 deletions(-) create mode 100644 packages/type-compiler/src/externals.ts diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index a62d6de81..9459b2a1a 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -49,7 +49,7 @@ import type { Modifier, ModuleDeclaration, Node, - NodeFactory, + NodeFactory, ObjectLiteralExpression, ParseConfigHost, PropertyAccessExpression, PropertyDeclaration, @@ -69,18 +69,18 @@ import type { TypeParameterDeclaration, TypeQueryNode, TypeReferenceNode, - UnionTypeNode, + UnionTypeNode, VariableDeclaration, } from 'typescript'; import ts from 'typescript'; import { ensureImportIsEmitted, extractJSDocAttribute, - getEntityName, + getEntityName, getExternalRuntimeTypeName, getGlobalsOfSourceFile, getIdentifierName, getNameAsString, - getPropertyName, + getPropertyName, getRuntimeTypeName, hasModifier, isBuiltType, isNodeWithLocals, @@ -96,6 +96,8 @@ import stripJsonComments from 'strip-json-comments'; import { MappedModifier, ReflectionOp, TypeNumberBrand } from '@deepkit/type-spec'; import { patternMatch, ReflectionMode, reflectionModeMatcher, reflectionModes, Resolver } from './resolver.js'; import { knownLibFilesForCompilerOptions } from '@typescript/vfs'; +import { ExternalLibraryImport, Externals } from './externals'; +import { entity } from '@deepkit/type'; // don't use from @deepkit/core since we don't want to have a dependency to @deepkit/core export function isObject(obj: any): obj is { [key: string]: any } { @@ -193,7 +195,7 @@ export const packSize: number = 2 ** packSizeByte; //64 export interface ReflectionOptions { /** * Allows to exclude type definitions/TS files from being included in the type compilation step. - * When a global .d.ts is matched, their types won't be embedded (useful to exclude DOM for example) + * When a global .d.ts is matched, their types won't be embeddedLibraryVariables (useful to exclude DOM for example) */ exclude?: string[]; /** @@ -536,8 +538,6 @@ export class ReflectionTransformer implements CustomTransformer { protected reflectionMode?: typeof reflectionModes[number]; protected reflectionOptions?: ReflectionOptions; - protected isMaybeEmbeddingExternalLibraryImport: boolean = false; - /** * Types added to this map will get a type program directly under it. * This is for types used in the very same file. @@ -547,9 +547,7 @@ export class ReflectionTransformer implements CustomTransformer { { name: EntityName, sourceFile: SourceFile, compiled?: Statement[] } >(); - protected externalSourceFileNames = new Set(); - - protected externalRuntimeTypeNames = new Set(); + protected externals: Externals; /** * Types added to this map will get a type program at the top root level of the program. @@ -558,7 +556,7 @@ export class ReflectionTransformer implements CustomTransformer { protected embedDeclarations = new Map(); /** - * When a node was embedded or compiled (from the maps above), we store it here to know to not add it again. + * When a node was embeddedLibraryVariables or compiled (from the maps above), we store it here to know to not add it again. */ protected compiledDeclarations = new Set(); @@ -585,11 +583,12 @@ export class ReflectionTransformer implements CustomTransformer { protected context: TransformationContext, ) { this.f = context.factory; - this.nodeConverter = new NodeConverter(this.f, this.externalRuntimeTypeNames); //it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); this.resolver = new Resolver(this.compilerOptions, this.host); + this.externals = new Externals(this.resolver); + this.nodeConverter = new NodeConverter(this.f, this.externals); } forHost(host: CompilerHost): this { @@ -990,6 +989,42 @@ export class ReflectionTransformer implements CustomTransformer { newTopStatements.push(...this.createProgramVarFromNode(node, d.name, d.sourceFile)); } } + + if (this.externals.libraryImports.size) { + for (const imports of this.externals.libraryImports.values()) { + for (const { declaration } of imports) { + this.compiledDeclarations.add(declaration); + } + } + const entries = Array.from(this.externals.libraryImports.entries()); + this.externals.libraryImports.clear(); + + for (const [library, imports] of entries) { + if (!this.externals.embeddedLibraryVariables.has(library)) { + const objectLiteral = this.f.createObjectLiteralExpression(); + const variableDeclaration = this.f.createVariableDeclaration( + this.f.createIdentifier(getExternalRuntimeTypeName(library)), + undefined, + undefined, + objectLiteral, + ); + const variableStatement = this.f.createVariableStatement( + [], + this.f.createVariableDeclarationList([ + variableDeclaration + ], NodeFlags.Const), + ); + newTopStatements.unshift(variableStatement); + this.externals.embeddedLibraryVariables.add(library); + } + + for (const value of imports) { + this.externals.setEmbeddingLibraryImport(value); + newTopStatements.push(this.createProgramVarForExternalLibraryImport(value.declaration, value.name, value.sourceFile, value.module.packageId.name)); + this.externals.finishEmbeddingLibraryImport(); + } + } + } } //externalize type aliases @@ -1095,23 +1130,6 @@ export class ReflectionTransformer implements CustomTransformer { newTopStatements.push(assignType); } - if (this.tempResultIdentifier) { - newTopStatements.push( - this.f.createVariableStatement( - undefined, - this.f.createVariableDeclarationList( - [this.f.createVariableDeclaration( - this.tempResultIdentifier, - undefined, - undefined, - undefined - )], - ts.NodeFlags.None - ) - ) - ); - } - if (newTopStatements.length) { // we want to keep "use strict", or "use client", etc at the very top const indexOfFirstLiteralExpression = this.sourceFile.statements.findIndex(v => isExpressionStatement(v) && isStringLiteral(v.expression)); @@ -1177,7 +1195,14 @@ export class ReflectionTransformer implements CustomTransformer { return node; } - protected createProgramVarFromNode(node: Node, name: EntityName, sourceFile: SourceFile): Statement[] { + protected createProgramVarForExternalLibraryImport(node: Node, name: EntityName, sourceFile: SourceFile, libraryName: string): Statement { + const typeProgramExpression = this.createTypeProgramExpression(node, sourceFile); + const left = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(libraryName)), getNameAsString(name)) + const assignment = this.f.createAssignment(left, typeProgramExpression!); + return this.f.createExpressionStatement(assignment); + } + + protected createTypeProgramExpression(node: Node, sourceFile: SourceFile): Expression | undefined { const typeProgram = new CompilerProgram(node, sourceFile); if ((isTypeAliasDeclaration(node) || isInterfaceDeclaration(node)) && node.typeParameters) { @@ -1200,7 +1225,11 @@ export class ReflectionTransformer implements CustomTransformer { typeProgram.pushOp(ReflectionOp.nominal); } - const typeProgramExpression = this.packOpsAndStack(typeProgram); + return this.packOpsAndStack(typeProgram); + } + + protected createProgramVarFromNode(node: Node, name: EntityName, sourceFile: SourceFile): Statement[] { + const typeProgramExpression = this.createTypeProgramExpression(node, sourceFile); const variable = this.f.createVariableStatement( [], @@ -1803,20 +1832,21 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as TypeQueryNode; // if (program.importSpecifier) { - // //if this is set, the current program is embedded into another file. All locally used symbols like a variable in `typeof` need to be imported + // //if this is set, the current program is embeddedLibraryVariables into another file. All locally used symbols like a variable in `typeof` need to be imported // //in the other file as well. // if (isIdentifier(narrowed.exprName)) { // const originImportStatement = program.importSpecifier.parent.parent.parent; // this.addImports.push({ identifier: narrowed.exprName, from: originImportStatement.moduleSpecifier }); // } // } - let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, narrowed.exprName); + let expression: Expression = serializeEntityNameAsExpression(this.f, narrowed.exprName); if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } + console.log(getNameAsString(narrowed.exprName)); program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); break; } @@ -2011,35 +2041,35 @@ export class ReflectionTransformer implements CustomTransformer { // return node; // } - protected getRuntimeTypeName(typeName: string): string { - if (this.externalRuntimeTypeNames.has(typeName)) { - return `__ɵΩ${typeName}`; - } - return `__Ω${typeName}`; - } - protected getDeclarationVariableName(typeName: EntityName): Identifier { - return this.f.createIdentifier(this.getRuntimeTypeName(getNameAsString(typeName))); + const name = getNameAsString(typeName); + return this.externals.isEmbeddingLibraryImport() && !this.externals.globalTypes.has(name) + ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.externals.getEmbeddingLibraryImport().module.packageId.name)}.${name}`) + : this.f.createIdentifier(getRuntimeTypeName(name)); } - protected addExternalLibraryImportEmbedDeclaration(declaration: Node, sourceFile: SourceFile, typeName: EntityName): void { - this.isMaybeEmbeddingExternalLibraryImport = true; + protected embedExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { + let externalLibraryImport: ExternalLibraryImport; + if (importDeclaration) { + const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); + externalLibraryImport = this.externals.addLibraryImport(typeName, declaration, sourceFile, resolvedModule); + } else { + externalLibraryImport = this.externals.addLibraryImport(typeName, declaration, sourceFile); + } - this.externalRuntimeTypeNames.add(getNameAsString(typeName)); + this.externals.addRuntimeTypeName(typeName); - this.externalSourceFileNames.add(sourceFile.fileName); + if (sourceFile.fileName !== this.sourceFile.fileName) { + this.externals.addSourceFile(sourceFile); + } - this.embedDeclarations.set(declaration, { - name: typeName, - sourceFile, - }); + return externalLibraryImport; } - protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: T, program: CompilerProgram): CallExpression | T { + protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: Expression, program: CompilerProgram): Expression { ensureImportIsEmitted(importDeclaration, typeName); if (isTypeAliasDeclaration(declaration)) { - this.isMaybeEmbeddingExternalLibraryImport = false; return expression; } @@ -2048,47 +2078,20 @@ export class ReflectionTransformer implements CustomTransformer { if (declarationReflection.mode !== 'never') { const declarationSourceFile = importDeclaration.getSourceFile(); - if (this.isMaybeEmbeddingExternalLibraryImport) { - this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); - return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName)); - } - const runtimeTypeName = this.getDeclarationVariableName(typeName); const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); - if (!builtType && this.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection)) { - this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); - return this.wrapWithAssignType(expression, this.getDeclarationVariableName(typeName)); + if (this.externals.isEmbeddingLibraryImport() || (!builtType && this.externals.shouldInlineLibraryImport(importDeclaration, typeName, declarationReflection))) { + const { module } = this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); + // return this.wrapWithAssignType(expression, this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(embedLibrary.packageId.name)), typeName)); } } - this.isMaybeEmbeddingExternalLibraryImport = false; - return expression; } - protected shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { - if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; - if (config.options.inlineExternalLibraryImports === true) return true; - const resolvedModule = this.resolver.resolveImpl(importDeclaration.moduleSpecifier.text, importDeclaration.getSourceFile().fileName); - if (!resolvedModule) { - throw new Error('Cannot resolve module'); - } - if (!resolvedModule.packageId) { - throw new Error('Missing package id for resolved module'); - } - if (!resolvedModule.isExternalLibraryImport) { - throw new Error('Resolved module is not an external library import'); - } - const externalImport = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; - if (!externalImport) return false; - if (externalImport === true) return true; - if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; - const typeName = getEntityName(entityName); - return externalImport.includes(typeName); - } - protected isExcluded(filePath: string): boolean { if (!this.currentReflectionConfig.options.exclude) return false; return patternMatch(filePath, this.currentReflectionConfig.options.exclude, this.currentReflectionConfig.baseDir); @@ -2186,7 +2189,7 @@ export class ReflectionTransformer implements CustomTransformer { } if (isModuleDeclaration(declaration) && resolved.importDeclaration) { - let expression: SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression(this.f, typeName); + let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } @@ -2236,7 +2239,8 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const runtimeTypeName = this.getDeclarationVariableName(typeName); + const runtimeTypeName = this.getDeclarationVariableName(typeName) + // const runtimeTypeName = this.f.createIdentifier(getRuntimeTypeName(getNameAsString(typeName))); //to break recursion, we track which declaration has already been compiled if (!this.compiledDeclarations.has(declaration) && !this.compileDeclarations.has(declaration)) { @@ -2247,13 +2251,16 @@ export class ReflectionTransformer implements CustomTransformer { return; } - if (this.externalSourceFileNames.has(declarationSourceFile.fileName)) { - this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + if (this.externals.hasSourceFile(declarationSourceFile)) { + this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile); } else { const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; const isFromImport = resolved.importDeclaration !== undefined; if (isGlobal) { + if (this.externals.isEmbeddingLibraryImport()) { + this.externals.addGlobalType(getNameAsString(typeName)); + } this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile @@ -2282,10 +2289,9 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { - if (!this.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.addExternalLibraryImportEmbedDeclaration(declaration, declarationSourceFile, typeName); + if (!this.externals.shouldInlineLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; + this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); } else { - this.isMaybeEmbeddingExternalLibraryImport = false; //check if the referenced file has reflection info emitted. if not, any is emitted for that reference const reflection = this.findReflectionFromPath(found.fileName); if (reflection.mode === 'never') { @@ -2346,7 +2352,7 @@ export class ReflectionTransformer implements CustomTransformer { return; } - let body: Identifier | PropertyAccessExpression | CallExpression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); + let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); if (resolved.importDeclaration && isIdentifier(typeName)) { body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); } diff --git a/packages/type-compiler/src/externals.ts b/packages/type-compiler/src/externals.ts new file mode 100644 index 000000000..789152a8c --- /dev/null +++ b/packages/type-compiler/src/externals.ts @@ -0,0 +1,107 @@ +import type { + EntityName, + ImportDeclaration, SourceFile, +} from 'typescript'; +import ts, { Node, ResolvedModuleFull } from 'typescript'; + +const { + isStringLiteral, +} = ts; + +import { getEntityName, getNameAsString } from './reflection-ast.js'; +import { ReflectionConfig } from './compiler.js'; +import { Resolver } from './resolver.js'; + +export interface ExternalLibraryImport { declaration: Node; name: EntityName; sourceFile: SourceFile; module: Required; } + +export class Externals { + public sourceFileNames = new Set(); + + public runtimeTypeNames = new Set(); + + public libraryImports = new Map>; + + protected embeddingLibraryImport?: ExternalLibraryImport; + + public embeddedLibraryVariables = new Set(); + + public globalTypes = new Set(); + + constructor(protected resolver: Resolver) {} + + setEmbeddingLibraryImport(value: ExternalLibraryImport): void { + if (this.embeddingLibraryImport) { + throw new Error('Already embedding module'); + } + this.embeddingLibraryImport = value; + } + + getEmbeddingLibraryImport(): ExternalLibraryImport { + if (!this.embeddingLibraryImport) { + throw new Error('Not embedding external library import'); + } + return this.embeddingLibraryImport; + } + + addGlobalType(typeName: string) { + this.globalTypes.add(typeName); + } + + isEmbeddingLibraryImport(): boolean { + return !!this.embeddingLibraryImport; + } + + finishEmbeddingLibraryImport(): void { + delete this.embeddingLibraryImport; + } + + public hasLibraryImport(entityName: EntityName, module?: Required): boolean { + if (!module) { + module = this.getEmbeddingLibraryImport().module; + } + const imports = this.libraryImports.get(module.packageId.name); + if (!imports) return false; + const typeName = getEntityName(entityName); + return [...imports].some(d => getNameAsString(d.name) === typeName) + } + + public addLibraryImport(name: EntityName, declaration: Node, sourceFile: SourceFile, module?: Required): ExternalLibraryImport { + if (!module) { + module = this.getEmbeddingLibraryImport().module; + } + const imports = this.libraryImports.get(module.packageId.name) || new Set(); + const externalLibraryImport: ExternalLibraryImport = { + name, + declaration, + sourceFile, + module, + } + this.libraryImports.set(module.packageId.name, imports.add(externalLibraryImport)); + // this.embeddingModule = module; + return externalLibraryImport; + } + + public addRuntimeTypeName(typeName: EntityName): void { + this.runtimeTypeNames.add(getNameAsString(typeName)); + } + + public addSourceFile(sourceFile: SourceFile): void { + this.sourceFileNames.add(sourceFile.fileName); + } + + public hasSourceFile(sourceFile: SourceFile): boolean { + return this.sourceFileNames.has(sourceFile.fileName); + } + + public shouldInlineLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; + if (config.options.inlineExternalLibraryImports === true) return true; + const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); + const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; + if (!imports) return false; + if (imports === true) return true; + if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; + const typeName = getEntityName(entityName); + return imports.includes(typeName); + } +} diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index ec75d5281..0a33983f8 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -33,6 +33,7 @@ import type { import ts from 'typescript'; import { cloneNode as tsNodeClone, CloneNodeHook } from '@marcj/ts-clone-node'; import { SourceFile } from './ts-types.js'; +import { Externals } from './externals'; const { isArrowFunction, @@ -113,6 +114,10 @@ export function getExternalRuntimeTypeName(typeName: string): string { return `__ɵΩ${typeName}`; } +export function getRuntimeTypeName(typeName: string): string { + return `__Ω${typeName}`; +} + const cloneHook = (node: T, payload: { depth: number }): CloneNodeHook | undefined => { if (isIdentifier(node)) { //ts-clone-node wants to read `node.text` which does not exist. we hook into it and provide the correct value. @@ -126,7 +131,7 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - constructor(protected f: NodeFactory, protected externalRuntimeTypeNames: Set) {} + constructor(protected f: NodeFactory, protected externals: Externals) {} toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -150,8 +155,10 @@ export class NodeConverter { switch (node.kind) { case SyntaxKind.Identifier: - const typeName = getIdentifierName(node as Identifier); - return finish(node, this.f.createIdentifier(this.externalRuntimeTypeNames.has(typeName) ? getExternalRuntimeTypeName(typeName) : typeName)); + const name = getIdentifierName(node as Identifier); + return this.externals.isEmbeddingLibraryImport() && !this.externals.globalTypes.has(name) + ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.externals.getEmbeddingLibraryImport().module.packageId.name)}.${name}`) + : this.f.createIdentifier(getRuntimeTypeName(name)); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: diff --git a/packages/type-compiler/src/resolver.ts b/packages/type-compiler/src/resolver.ts index ef0831edf..ce82febbb 100644 --- a/packages/type-compiler/src/resolver.ts +++ b/packages/type-compiler/src/resolver.ts @@ -15,6 +15,7 @@ import { isAbsolute } from 'path'; const { createSourceFile, resolveModuleName, + isStringLiteral, SyntaxKind, ScriptTarget, } = ts; @@ -70,12 +71,40 @@ export class Resolver { return this.resolveSourceFile(from.fileName, (moduleSpecifier as StringLiteral).text); } + resolveExternalLibraryImport(importDeclaration: ImportDeclaration): Required { + const resolvedModule = this.resolveImport(importDeclaration); + console.log(resolvedModule); + if (!resolvedModule.packageId) { + throw new Error('Missing package id for resolved module'); + /*resolvedModule.packageId = { + name: (importDeclaration.moduleSpecifier as StringLiteral).text.replace(/[^a-zA-Z0-9]+/g, '_'), + subModuleName: '', + version: '', + };*/ + } + if (!resolvedModule.isExternalLibraryImport) { + throw new Error('Resolved module is not an external library import'); + } + return resolvedModule as Required; + } + + resolveImport(importDeclaration: ImportDeclaration): ResolvedModuleFull { + if (!isStringLiteral(importDeclaration.moduleSpecifier)) { + throw new Error('Invalid import declaration module specifier'); + } + const resolvedModule = this.resolveImpl(importDeclaration.moduleSpecifier.text, importDeclaration.getSourceFile().fileName); + if (!resolvedModule) { + throw new Error('Cannot resolve module'); + } + return resolvedModule; + } + resolveImpl(modulePath: string, fromPath: string): ResolvedModuleFull | undefined { if (this.host.resolveModuleNames !== undefined) { return this.host.resolveModuleNames([modulePath], fromPath, /*reusedNames*/ undefined, /*redirectedReference*/ undefined, this.compilerOptions)[0] as ResolvedModuleFull | undefined; } const result = resolveModuleName(modulePath, fromPath, this.compilerOptions, this.host); - return result.resolvedModule as ResolvedModuleFull; + return result.resolvedModule; } /** diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts index 90f3f7793..c538aaeef 100644 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-imports.spec.ts @@ -153,7 +153,11 @@ test('typeOf object type alias', () => { `); }); -test('function type alias', () => { +test('removes import', () => { + +}); + +test('declares scoped variable', () => { const res = transpile({ app: `import { map } from 'rxjs/operators'; @@ -165,8 +169,23 @@ test('function type alias', () => { }, }); - expect(res.app).toContain('const __Ωmap = ['); - expect(res.app).toContain('() => __assignType(operators_1.map, __Ωmap)'); + expect(res.app).toContain('__ɵΩrxjs_operators = {}'); +}) + +test('function type alias', () => { + const res = transpile({ + app: `import { map } from 'rxjs/operators'; + + type A = typeof map; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['map'], + }, + }); + + expect(res.app).toContain('__ɵΩrxjs_operators.Ωmap = ['); + expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); }); test('typeOf function type alias', () => { @@ -301,45 +320,27 @@ test('class type var', () => { }, }); - expect(res.app).toContain('const __ɵΩObservable = ['); - expect(res.app).toContain('() => __assignType(rxjs_1.Observable, __ɵΩObservable)'); - - expect(res.app).toContain('const __ɵΩUnsubscribable = ['); - expect(res.app).toMatchInlineSnapshot(` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); - exports.__ɵΩSubscriptionLike = exports.__ɵΩUnsubscribable = exports.__ɵΩSubscribable = exports.__ɵΩSubscription = exports.__ɵΩObserver = exports.__ɵΩTeardownLogic = exports.__ɵΩSubscriber = exports.__ɵΩOperator = exports.__ɵΩObservable = void 0; - const __ɵΩObservable = ['T', () => __ɵΩObservable, 'source', () => __ΩOperator, 'operator', () => __ɵΩObservable, 'this', () => __assignType(Subscriber_1.Subscriber, __ɵΩSubscriber), 'subscriber', () => __ΩTeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩOperator, () => __ɵΩObservable, 'lift', () => __ΩPartial, () => __ΩObserver, 'observer', () => __assignType(Subscription_1.Subscription, __ɵΩSubscription), 'value', 'next', 'forEach', () => __ɵΩObservable, 'pipe', 'toPromise', () => __ΩSubscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; - exports.__ɵΩObservable = __ɵΩObservable; - const __ɵΩOperator = ['T', 'R', () => __assignType(Subscriber_2.Subscriber, __ɵΩSubscriber), 'subscriber', 'source', () => __ɵΩTeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; - exports.__ɵΩOperator = __ɵΩOperator; - const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩSubscriber, 'create', 'isStopped', () => __ɵΩSubscriber, () => __ɵΩObserver, 'destination', () => __ɵΩSubscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __assignType(Subscription_3.Subscription, __ɵΩSubscription), () => __ΩUnsubscribable, '', 'PP7!n"P$/#$Jy']; - exports.__ɵΩTeardownLogic = __ɵΩTeardownLogic; + const __ɵΩrxjs = {}; + __ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ɵΩrxjs.Partial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; - const __ɵΩObserver = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; - exports.__ɵΩObserver = __ɵΩObserver; - const __ɵΩSubscription = [() => __ɵΩSubscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', () => __ΩSubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - exports.__ɵΩSubscription = __ɵΩSubscription; - const __ɵΩSubscribable = ['T', () => __ΩPartial, () => __ɵΩObserver, 'observer', () => __ɵΩUnsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; - exports.__ɵΩSubscribable = __ɵΩSubscribable; - const __ɵΩSubscriber = ['T', () => Subscription_2.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩSubscriber, 'create', 'isStopped', () => __ɵΩSubscriber, () => __ɵΩObserver, 'destination', () => __ɵΩSubscriber, () => __ɵΩObserver, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩObserver, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩSubscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩTeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩTeardownLogic, 'remove', () => __ɵΩSubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - exports.__ɵΩSubscription = __ɵΩSubscription; - const __ɵΩUnsubscribable = ['unsubscribe', 'PP$1!My']; - exports.__ɵΩUnsubscribable = __ɵΩUnsubscribable; + __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; + __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; + __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; + __ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ɵΩrxjs.Exclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; - const __ɵΩSubscriptionLike = [() => __ɵΩUnsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; - exports.__ɵΩSubscriptionLike = __ɵΩSubscriptionLike; - function __assignType(fn, args) { - fn.__type = args; - return fn; - } - const rxjs_1 = require("rxjs"); - const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩObservable), 'P#7!y']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; + __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; + const __ΩA = [() => __ɵΩrxjs.Observable, 'P#7!y']; " `); }) @@ -358,7 +359,7 @@ test('runtime type name clashing', () => { }, }); - expect(res.app).toContain('const __ɵΩSubscribable = ['); + expect(res.app).toContain('__ɵΩrxjs.Subscribable = ['); expect(res.app).toContain('const __ΩSubscribable = ['); }) @@ -397,8 +398,8 @@ test('only a single type is transformed', () => { }, }); - expect(res.app).toContain('const __ΩConfigEnv = ['); - expect(res.app).not.toContain('const __ΩCorsOrigin = ['); + expect(res.app).toContain('__ɵΩrxjs.ConfigEnv = ['); + expect(res.app).not.toContain('__ɵΩrxjs.CorsOrigin = ['); }) test('interface typeOf', () => { @@ -481,6 +482,6 @@ test('inline all external type imports for package', () => { }, }); - expect(res.app).toContain('const __ΩConfigEnv = ['); - expect(res.app).toContain('const __ΩCorsOrigin = ['); + expect(res.app).toContain('__ɵΩrxjs.ConfigEnv = ['); + expect(res.app).toContain('__ɵΩrxjs.CorsOrigin = ['); }); diff --git a/packages/type-compiler/tests/transform.spec.ts b/packages/type-compiler/tests/transform.spec.ts index 5694b83a2..f053917ea 100644 --- a/packages/type-compiler/tests/transform.spec.ts +++ b/packages/type-compiler/tests/transform.spec.ts @@ -112,7 +112,7 @@ test('globals', () => { ` }); - //we just make sure the global was detected and embedded + //we just make sure the global was detected and embeddedLibraryVariables expect(res.app).toContain('const __ΩPartial = '); expect(res.app).toContain('() => __ΩPartial'); }); From 6d88feb07794dc0742f23a69f0c00476cea02a52 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Thu, 7 Dec 2023 00:05:30 +0100 Subject: [PATCH 09/23] save --- package-lock.json | 19 +- packages/type-compiler/src/compiler.ts | 115 +- .../src/{externals.ts => external.ts} | 72 +- packages/type-compiler/src/reflection-ast.ts | 10 +- packages/type-compiler/src/resolver.ts | 1 - .../tests/inline-external-imports.spec.ts | 487 ------- .../inline-external-library-imports.spec.ts | 1262 +++++++++++++++++ 7 files changed, 1383 insertions(+), 583 deletions(-) rename packages/type-compiler/src/{externals.ts => external.ts} (52%) delete mode 100644 packages/type-compiler/tests/inline-external-imports.spec.ts create mode 100644 packages/type-compiler/tests/inline-external-library-imports.spec.ts diff --git a/package-lock.json b/package-lock.json index be54ebd33..a4d06443e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13712,7 +13712,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -13722,7 +13721,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -13860,6 +13858,7 @@ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "optional": true, + "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -20081,6 +20080,7 @@ "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, "optional": true, + "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -20094,6 +20094,7 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "optional": true, + "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -20108,6 +20109,7 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true, + "peer": true, "bin": { "mime": "cli.js" }, @@ -20121,6 +20123,7 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -20131,6 +20134,7 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "optional": true, + "peer": true, "bin": { "semver": "bin/semver" } @@ -20141,6 +20145,7 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21665,6 +21670,7 @@ "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, "optional": true, + "peer": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.6.3", @@ -21683,6 +21689,7 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -21693,6 +21700,7 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -24062,7 +24070,8 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "node_modules/psl": { "version": "1.9.0", @@ -25162,7 +25171,7 @@ "version": "3.29.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "dev": true, + "devOptional": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -27800,7 +27809,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -31086,6 +31094,7 @@ "strip-json-comments": "^3.1.1" }, "bin": { + "deepkit-compiler-debug": "deepkit-compiler-debug.js", "deepkit-type-install": "deepkit-type-install.js" }, "devDependencies": { diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 9459b2a1a..0d3d393ef 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -13,7 +13,6 @@ import type { ArrayTypeNode, ArrowFunction, Bundle, - CallExpression, CallSignatureDeclaration, ClassDeclaration, ClassElement, @@ -49,7 +48,7 @@ import type { Modifier, ModuleDeclaration, Node, - NodeFactory, ObjectLiteralExpression, + NodeFactory, ParseConfigHost, PropertyAccessExpression, PropertyDeclaration, @@ -69,24 +68,25 @@ import type { TypeParameterDeclaration, TypeQueryNode, TypeReferenceNode, - UnionTypeNode, VariableDeclaration, + UnionTypeNode, } from 'typescript'; import ts from 'typescript'; import { ensureImportIsEmitted, extractJSDocAttribute, - getEntityName, getExternalRuntimeTypeName, + getEntityName, + getExternalRuntimeTypeName, getGlobalsOfSourceFile, getIdentifierName, getNameAsString, - getPropertyName, getRuntimeTypeName, + getPropertyName, + getRuntimeTypeName, hasModifier, isBuiltType, isNodeWithLocals, NodeConverter, PackExpression, - SerializedEntityNameAsExpression, serializeEntityNameAsExpression, } from './reflection-ast.js'; import { SourceFile } from './ts-types.js'; @@ -96,8 +96,7 @@ import stripJsonComments from 'strip-json-comments'; import { MappedModifier, ReflectionOp, TypeNumberBrand } from '@deepkit/type-spec'; import { patternMatch, ReflectionMode, reflectionModeMatcher, reflectionModes, Resolver } from './resolver.js'; import { knownLibFilesForCompilerOptions } from '@typescript/vfs'; -import { ExternalLibraryImport, Externals } from './externals'; -import { entity } from '@deepkit/type'; +import { External } from './external.js'; // don't use from @deepkit/core since we don't want to have a dependency to @deepkit/core export function isObject(obj: any): obj is { [key: string]: any } { @@ -547,7 +546,7 @@ export class ReflectionTransformer implements CustomTransformer { { name: EntityName, sourceFile: SourceFile, compiled?: Statement[] } >(); - protected externals: Externals; + protected external: External; /** * Types added to this map will get a type program at the top root level of the program. @@ -587,8 +586,8 @@ export class ReflectionTransformer implements CustomTransformer { this.compilerOptions = filterUndefined(context.getCompilerOptions()); this.host = createCompilerHost(this.compilerOptions); this.resolver = new Resolver(this.compilerOptions, this.host); - this.externals = new Externals(this.resolver); - this.nodeConverter = new NodeConverter(this.f, this.externals); + this.external = new External(this.resolver); + this.nodeConverter = new NodeConverter(this.f, this.external); } forHost(host: CompilerHost): this { @@ -654,9 +653,13 @@ export class ReflectionTransformer implements CustomTransformer { return Object.assign(configFile.config, { compilerOptions: parsed.options }); } - transformSourceFile(sourceFile: SourceFile): SourceFile { + protected setSourceFile(sourceFile: SourceFile) { this.sourceFile = sourceFile; + this.external.sourceFile = sourceFile; + } + transformSourceFile(sourceFile: SourceFile): SourceFile { + this.setSourceFile(sourceFile); //if it's not a TS/TSX file, we do not transform it if (sourceFile.scriptKind !== ScriptKind.TS && sourceFile.scriptKind !== ScriptKind.TSX) return sourceFile; @@ -960,7 +963,7 @@ export class ReflectionTransformer implements CustomTransformer { return node; }; - this.sourceFile = visitNode(this.sourceFile, visitor); + this.setSourceFile(visitNode(this.sourceFile, visitor)); const newTopStatements: Statement[] = []; @@ -972,7 +975,7 @@ export class ReflectionTransformer implements CustomTransformer { break; } - if (this.embedDeclarations.size === 0 && allCompiled) break; + if (this.embedDeclarations.size === 0 && this.external.libraryImports.size === 0 && allCompiled) break; for (const [node, d] of [...this.compileDeclarations.entries()]) { if (d.compiled) continue; @@ -990,17 +993,16 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (this.externals.libraryImports.size) { - for (const imports of this.externals.libraryImports.values()) { + if (this.external.libraryImports.size) { + for (const imports of this.external.libraryImports.values()) { for (const { declaration } of imports) { this.compiledDeclarations.add(declaration); } } - const entries = Array.from(this.externals.libraryImports.entries()); - this.externals.libraryImports.clear(); - + const entries = Array.from(this.external.libraryImports.entries()); + this.external.libraryImports.clear(); for (const [library, imports] of entries) { - if (!this.externals.embeddedLibraryVariables.has(library)) { + if (!this.external.embeddedLibraryVariables.has(library)) { const objectLiteral = this.f.createObjectLiteralExpression(); const variableDeclaration = this.f.createVariableDeclaration( this.f.createIdentifier(getExternalRuntimeTypeName(library)), @@ -1015,16 +1017,16 @@ export class ReflectionTransformer implements CustomTransformer { ], NodeFlags.Const), ); newTopStatements.unshift(variableStatement); - this.externals.embeddedLibraryVariables.add(library); + this.external.embeddedLibraryVariables.add(library); } for (const value of imports) { - this.externals.setEmbeddingLibraryImport(value); + this.external.setEmbeddingExternalLibraryImport(value); newTopStatements.push(this.createProgramVarForExternalLibraryImport(value.declaration, value.name, value.sourceFile, value.module.packageId.name)); - this.externals.finishEmbeddingLibraryImport(); + this.external.finishEmbeddingExternalLibraryImport(); } } - } + } } //externalize type aliases @@ -1045,7 +1047,7 @@ export class ReflectionTransformer implements CustomTransformer { return node; }; - this.sourceFile = visitNode(this.sourceFile, compileDeclarations); + this.setSourceFile(visitNode(this.sourceFile, compileDeclarations)); if (this.addImports.length) { const handledIdentifier: string[] = []; @@ -1832,7 +1834,7 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as TypeQueryNode; // if (program.importSpecifier) { - // //if this is set, the current program is embeddedLibraryVariables into another file. All locally used symbols like a variable in `typeof` need to be imported + // //if this is set, the current program is embedded into another file. All locally used symbols like a variable in `typeof` need to be imported // //in the other file as well. // if (isIdentifier(narrowed.exprName)) { // const originImportStatement = program.importSpecifier.parent.parent.parent; @@ -1846,7 +1848,6 @@ export class ReflectionTransformer implements CustomTransformer { expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } - console.log(getNameAsString(narrowed.exprName)); program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); break; } @@ -2005,6 +2006,7 @@ export class ReflectionTransformer implements CustomTransformer { if (importDeclaration) { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); + //might be an external library if (!declaration) { sourceFile = importDeclaration.getSourceFile(); declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, sourceFile); @@ -2043,33 +2045,16 @@ export class ReflectionTransformer implements CustomTransformer { protected getDeclarationVariableName(typeName: EntityName): Identifier { const name = getNameAsString(typeName); - return this.externals.isEmbeddingLibraryImport() && !this.externals.globalTypes.has(name) - ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.externals.getEmbeddingLibraryImport().module.packageId.name)}.${name}`) + return this.external.isEmbeddingExternalLibraryImport() && !this.external.globalTypeNames.has(name) + ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.external.getEmbeddingExternalLibraryImport().module.packageId.name)}.${name}`) : this.f.createIdentifier(getRuntimeTypeName(name)); } - protected embedExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { - let externalLibraryImport: ExternalLibraryImport; - if (importDeclaration) { - const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); - externalLibraryImport = this.externals.addLibraryImport(typeName, declaration, sourceFile, resolvedModule); - } else { - externalLibraryImport = this.externals.addLibraryImport(typeName, declaration, sourceFile); - } - - this.externals.addRuntimeTypeName(typeName); - - if (sourceFile.fileName !== this.sourceFile.fileName) { - this.externals.addSourceFile(sourceFile); - } - - return externalLibraryImport; - } - protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: Expression, program: CompilerProgram): Expression { ensureImportIsEmitted(importDeclaration, typeName); - if (isTypeAliasDeclaration(declaration)) { + // these will be inferred at runtime + if (isTypeAliasDeclaration(declaration) || isVariableDeclaration(declaration)) { return expression; } @@ -2082,10 +2067,14 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); - if (this.externals.isEmbeddingLibraryImport() || (!builtType && this.externals.shouldInlineLibraryImport(importDeclaration, typeName, declarationReflection))) { - const { module } = this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); - return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); - // return this.wrapWithAssignType(expression, this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(embedLibrary.packageId.name)), typeName)); + const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); + + if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { + const { module } = this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) + // TODO: figure out what to do with referenced classes/functions in external declaration files + ? this.wrapWithAssignType(expression, this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName)) + : this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); } } @@ -2251,15 +2240,17 @@ export class ReflectionTransformer implements CustomTransformer { return; } - if (this.externals.hasSourceFile(declarationSourceFile)) { - this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile); + if (this.external.hasSourceFile(declarationSourceFile)) { + if (this.external.isEmbeddingExternalLibraryImport()) { + this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + } } else { const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; const isFromImport = resolved.importDeclaration !== undefined; if (isGlobal) { - if (this.externals.isEmbeddingLibraryImport()) { - this.externals.addGlobalType(getNameAsString(typeName)); + if (this.external.isEmbeddingExternalLibraryImport()) { + this.external.addGlobalType(getNameAsString(typeName)); } this.embedDeclarations.set(declaration, { name: typeName, @@ -2289,8 +2280,8 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { - if (!this.externals.shouldInlineLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + if (!this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; + this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); } else { //check if the referenced file has reflection info emitted. if not, any is emitted for that reference const reflection = this.findReflectionFromPath(found.fileName); @@ -2352,6 +2343,8 @@ export class ReflectionTransformer implements CustomTransformer { return; } + const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); + let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); if (resolved.importDeclaration && isIdentifier(typeName)) { body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); @@ -2917,7 +2910,7 @@ export class DeclarationTransformer extends ReflectionTransformer { if ((sourceFile as any).deepkitDeclarationTransformed) return sourceFile; (sourceFile as any).deepkitDeclarationTransformed = true; - this.sourceFile = sourceFile; + this.setSourceFile(sourceFile); this.addExports = []; const reflection = this.findReflectionConfig(sourceFile); @@ -2938,7 +2931,7 @@ export class DeclarationTransformer extends ReflectionTransformer { return node; }; - this.sourceFile = visitNode(this.sourceFile, visitor); + this.setSourceFile(visitNode(this.sourceFile, visitor)); if (this.addExports.length) { const exports: Statement[] = []; @@ -2957,7 +2950,7 @@ export class DeclarationTransformer extends ReflectionTransformer { )); } - this.sourceFile = this.f.updateSourceFile(this.sourceFile, [...this.sourceFile.statements, ...exports]); + this.setSourceFile(this.f.updateSourceFile(this.sourceFile, [...this.sourceFile.statements, ...exports])); } return this.sourceFile; diff --git a/packages/type-compiler/src/externals.ts b/packages/type-compiler/src/external.ts similarity index 52% rename from packages/type-compiler/src/externals.ts rename to packages/type-compiler/src/external.ts index 789152a8c..e0b04c0c9 100644 --- a/packages/type-compiler/src/externals.ts +++ b/packages/type-compiler/src/external.ts @@ -12,62 +12,69 @@ import { getEntityName, getNameAsString } from './reflection-ast.js'; import { ReflectionConfig } from './compiler.js'; import { Resolver } from './resolver.js'; -export interface ExternalLibraryImport { declaration: Node; name: EntityName; sourceFile: SourceFile; module: Required; } +export interface ExternalLibraryImport { + declaration: Node; + name: EntityName; + sourceFile: SourceFile; + module: Required; +} -export class Externals { +export class External { public sourceFileNames = new Set(); public runtimeTypeNames = new Set(); public libraryImports = new Map>; - protected embeddingLibraryImport?: ExternalLibraryImport; - public embeddedLibraryVariables = new Set(); - public globalTypes = new Set(); + public globalTypeNames = new Set(); + + public sourceFile?: SourceFile; + + protected embeddingExternalLibraryImport?: ExternalLibraryImport; constructor(protected resolver: Resolver) {} - setEmbeddingLibraryImport(value: ExternalLibraryImport): void { - if (this.embeddingLibraryImport) { + setEmbeddingExternalLibraryImport(value: ExternalLibraryImport): void { + if (this.embeddingExternalLibraryImport) { throw new Error('Already embedding module'); } - this.embeddingLibraryImport = value; + this.embeddingExternalLibraryImport = value; } - getEmbeddingLibraryImport(): ExternalLibraryImport { - if (!this.embeddingLibraryImport) { + getEmbeddingExternalLibraryImport(): ExternalLibraryImport { + if (!this.embeddingExternalLibraryImport) { throw new Error('Not embedding external library import'); } - return this.embeddingLibraryImport; + return this.embeddingExternalLibraryImport; } addGlobalType(typeName: string) { - this.globalTypes.add(typeName); + this.globalTypeNames.add(typeName); } - isEmbeddingLibraryImport(): boolean { - return !!this.embeddingLibraryImport; + isEmbeddingExternalLibraryImport(): boolean { + return !!this.embeddingExternalLibraryImport; } - finishEmbeddingLibraryImport(): void { - delete this.embeddingLibraryImport; + finishEmbeddingExternalLibraryImport(): void { + delete this.embeddingExternalLibraryImport; } - public hasLibraryImport(entityName: EntityName, module?: Required): boolean { - if (!module) { - module = this.getEmbeddingLibraryImport().module; - } + public hasExternalLibraryImport( + entityName: EntityName, + module: Required = this.getEmbeddingExternalLibraryImport().module, + ): boolean { const imports = this.libraryImports.get(module.packageId.name); if (!imports) return false; const typeName = getEntityName(entityName); return [...imports].some(d => getNameAsString(d.name) === typeName) } - public addLibraryImport(name: EntityName, declaration: Node, sourceFile: SourceFile, module?: Required): ExternalLibraryImport { + public addExternalLibraryImport(name: EntityName, declaration: Node, sourceFile: SourceFile, module?: Required): ExternalLibraryImport { if (!module) { - module = this.getEmbeddingLibraryImport().module; + module = this.getEmbeddingExternalLibraryImport().module; } const imports = this.libraryImports.get(module.packageId.name) || new Set(); const externalLibraryImport: ExternalLibraryImport = { @@ -77,7 +84,6 @@ export class Externals { module, } this.libraryImports.set(module.packageId.name, imports.add(externalLibraryImport)); - // this.embeddingModule = module; return externalLibraryImport; } @@ -93,7 +99,7 @@ export class Externals { return this.sourceFileNames.has(sourceFile.fileName); } - public shouldInlineLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + public shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; if (config.options.inlineExternalLibraryImports === true) return true; const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); @@ -104,4 +110,22 @@ export class Externals { const typeName = getEntityName(entityName); return imports.includes(typeName); } + + public embedExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { + let externalLibraryImport: ExternalLibraryImport; + if (importDeclaration) { + const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); + externalLibraryImport = this.addExternalLibraryImport(typeName, declaration, sourceFile, resolvedModule); + } else { + externalLibraryImport = this.addExternalLibraryImport(typeName, declaration, sourceFile); + } + + this.addRuntimeTypeName(typeName); + + if (sourceFile.fileName !== this.sourceFile?.fileName) { + this.addSourceFile(sourceFile); + } + + return externalLibraryImport; + } } diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index 0a33983f8..6c092b3ac 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -33,7 +33,7 @@ import type { import ts from 'typescript'; import { cloneNode as tsNodeClone, CloneNodeHook } from '@marcj/ts-clone-node'; import { SourceFile } from './ts-types.js'; -import { Externals } from './externals'; +import { External } from './external.js'; const { isArrowFunction, @@ -131,7 +131,7 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo }; export class NodeConverter { - constructor(protected f: NodeFactory, protected externals: Externals) {} + constructor(protected f: NodeFactory, protected external: External) {} toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -156,9 +156,9 @@ export class NodeConverter { switch (node.kind) { case SyntaxKind.Identifier: const name = getIdentifierName(node as Identifier); - return this.externals.isEmbeddingLibraryImport() && !this.externals.globalTypes.has(name) - ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.externals.getEmbeddingLibraryImport().module.packageId.name)}.${name}`) - : this.f.createIdentifier(getRuntimeTypeName(name)); + return this.external.isEmbeddingExternalLibraryImport() && !this.external.globalTypeNames.has(name) + ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.external.getEmbeddingExternalLibraryImport().module.packageId.name)}.${name}`) + : finish(node, this.f.createIdentifier(getRuntimeTypeName(name))); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: diff --git a/packages/type-compiler/src/resolver.ts b/packages/type-compiler/src/resolver.ts index ce82febbb..20f37e1bf 100644 --- a/packages/type-compiler/src/resolver.ts +++ b/packages/type-compiler/src/resolver.ts @@ -73,7 +73,6 @@ export class Resolver { resolveExternalLibraryImport(importDeclaration: ImportDeclaration): Required { const resolvedModule = this.resolveImport(importDeclaration); - console.log(resolvedModule); if (!resolvedModule.packageId) { throw new Error('Missing package id for resolved module'); /*resolvedModule.packageId = { diff --git a/packages/type-compiler/tests/inline-external-imports.spec.ts b/packages/type-compiler/tests/inline-external-imports.spec.ts deleted file mode 100644 index c538aaeef..000000000 --- a/packages/type-compiler/tests/inline-external-imports.spec.ts +++ /dev/null @@ -1,487 +0,0 @@ -import { test, expect } from '@jest/globals'; -import { ReflectionKind, TypeClass, TypeFunction } from '@deepkit/type'; -import { Unsubscribable } from 'rxjs'; - -import { transpile, transpileAndRun } from './utils'; - -test('string type alias', () => { - const res = transpile({ - app: `import { NIL } from 'uuid'; - - type T = typeof NIL; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'uuid': ['NIL'], - }, - }); - - expect(res.app).not.toContain('const __ΩNIL = ['); - expect(res.app).not.toContain('() => __assignType(uuid_1.NIL, __ΩNIL)'); - expect(res.app).toContain('() => uuid_1.NIL'); -}); - -test('typeOf string type alias', () => { - const res = transpileAndRun({ - app: `import { typeOf } from '@deepkit/type'; - import { NIL } from 'uuid'; - - typeOf(); - ` - }); - - expect(res).toMatchInlineSnapshot(` - { - "kind": 13, - "literal": "00000000-0000-0000-0000-000000000000", - "typeName": undefined, - } - `); -}); - -test('object type alias', () => { - const res = transpile({ - app: `import { config } from 'rxjs'; - - type A = typeof config; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['config'], - }, - }); - - expect(res.app).not.toContain('const __Ωconfig = ['); - expect(res.app).not.toContain('() => __assignType(rxjs_1.config, __Ωconfig)'); - expect(res.app).toContain('() => rxjs_1.config'); -}); - -test('typeOf object type alias', () => { - const res = transpileAndRun({ - app: `import { typeOf } from '@deepkit/type'; - import { config } from 'rxjs'; - - typeOf(); - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['config'], - }, - }); - - expect(res).toMatchInlineSnapshot(` - { - "annotations": {}, - "id": 2, - "kind": 30, - "typeName": undefined, - "types": [ - { - "kind": 32, - "name": "onUnhandledError", - "parent": [Circular], - "type": { - "kind": 10, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "onStoppedNotification", - "parent": [Circular], - "type": { - "kind": 10, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "Promise", - "parent": [Circular], - "type": { - "kind": 11, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "useDeprecatedSynchronousErrorHandling", - "parent": [Circular], - "type": { - "jit": {}, - "kind": 7, - "origin": { - "kind": 13, - "literal": false, - }, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "useDeprecatedNextContext", - "parent": [Circular], - "type": { - "jit": {}, - "kind": 7, - "origin": { - "kind": 13, - "literal": false, - }, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "__type", - "parent": [Circular], - "type": { - "kind": 25, - "parent": [Circular], - "type": { - "jit": {}, - "kind": 5, - "origin": { - "kind": 13, - "literal": "!", - }, - }, - }, - }, - ], - } - `); -}); - -test('removes import', () => { - -}); - -test('declares scoped variable', () => { - const res = transpile({ - app: `import { map } from 'rxjs/operators'; - - type A = typeof map; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs/operators': ['map'], - }, - }); - - expect(res.app).toContain('__ɵΩrxjs_operators = {}'); -}) - -test('function type alias', () => { - const res = transpile({ - app: `import { map } from 'rxjs/operators'; - - type A = typeof map; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['map'], - }, - }); - - expect(res.app).toContain('__ɵΩrxjs_operators.Ωmap = ['); - expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); -}); - -test('typeOf function type alias', () => { - const res = transpileAndRun({ - app: `import { map } from 'rxjs/operators'; - import { typeOf } from '@deepkit/type'; - - typeOf(); - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs/operators': ['map', 'OperatorFunction'], - }, - }) as TypeFunction; - - expect(res.return.kind).not.toBe(ReflectionKind.never); - - console.log(res.return); - - expect(res).toMatchInlineSnapshot(` - { - "function": [Function], - "inlined": true, - "kind": 17, - "name": "map", - "parameters": [ - { - "kind": 18, - "name": "project", - "parent": { - "function": [Function], - "kind": 17, - "name": "map", - "parameters": [Circular], - "return": { - "kind": 0, - "parent": [Circular], - }, - "typeName": undefined, - }, - "type": { - "kind": 17, - "name": undefined, - "parameters": [ - { - "kind": 18, - "name": "value", - "parent": [Circular], - "type": { - "kind": 1, - "parent": [Circular], - }, - }, - { - "kind": 18, - "name": "index", - "parent": [Circular], - "type": { - "kind": 6, - "parent": [Circular], - }, - }, - ], - "parent": [Circular], - "return": { - "kind": 1, - "parent": [Circular], - }, - }, - }, - ], - "return": { - "kind": 0, - "parent": { - "function": [Function], - "kind": 17, - "name": "map", - "parameters": [ - { - "kind": 18, - "name": "project", - "parent": [Circular], - "type": { - "kind": 17, - "name": undefined, - "parameters": [ - { - "kind": 18, - "name": "value", - "parent": [Circular], - "type": { - "kind": 1, - "parent": [Circular], - }, - }, - { - "kind": 18, - "name": "index", - "parent": [Circular], - "type": { - "kind": 6, - "parent": [Circular], - }, - }, - ], - "parent": [Circular], - "return": { - "kind": 1, - "parent": [Circular], - }, - }, - }, - ], - "return": [Circular], - "typeName": undefined, - }, - }, - "typeName": undefined, - } - `); -}) - -test('class type var', () => { - const res = transpile({ - app: `import { Observable } from 'rxjs'; - - type A = Observable; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['Observable'], - }, - }); - - expect(res.app).toMatchInlineSnapshot(` - ""use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - const __ɵΩrxjs = {}; - __ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ɵΩrxjs.Partial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; - const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; - __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; - __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; - __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; - __ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ɵΩrxjs.Exclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; - const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; - __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; - const __ΩA = [() => __ɵΩrxjs.Observable, 'P#7!y']; - " - `); -}) - -test('runtime type name clashing', () => { - const res = transpile({ - app: `import { Observable } from 'rxjs'; - - type Subscribable = any; - - type A = Observable; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['Observable'], - }, - }); - - expect(res.app).toContain('__ɵΩrxjs.Subscribable = ['); - expect(res.app).toContain('const __ΩSubscribable = ['); -}) - -test('class typeOf', () => { - const res = transpileAndRun({ - app: `import { Observable } from 'rxjs'; - import { typeOf } from '@deepkit/type'; - - typeOf>(); - ` - }, undefined, { - inlineExternalLibraryImports: { - 'rxjs': ['Observable'], - }, - }) as TypeClass; - - expect(res.implements![0]).toMatchObject({ - kind: 30, - typeName: 'Subscribable', - }); - expect(res.typeArguments).toHaveLength(1); - expect(res.types).toHaveLength(1); -}) - -test('only a single type is transformed', () => { - const res = transpile({ - app: `import { ConfigEnv, CorsOrigin } from 'vite'; - - type A = ConfigEnv; - - type B = CorsOrigin; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'vite': ['ConfigEnv'], - }, - }); - - expect(res.app).toContain('__ɵΩrxjs.ConfigEnv = ['); - expect(res.app).not.toContain('__ɵΩrxjs.CorsOrigin = ['); -}) - -test('interface typeOf', () => { - const res = transpileAndRun({ - app: `import { ConfigEnv, CorsOrigin } from 'vite'; - import { typeOf } from '@deepkit/type'; - - typeOf(); - ` - }, undefined, { - inlineExternalLibraryImports: { - 'vite': ['ConfigEnv'], - }, - }); - - expect(res).toMatchInlineSnapshot(` - { - "annotations": {}, - "id": 2, - "kind": 30, - "typeArguments": undefined, - "typeName": "ConfigEnv", - "types": [ - { - "kind": 32, - "name": "command", - "parent": [Circular], - "type": { - "kind": 23, - "parent": [Circular], - "types": [ - { - "kind": 13, - "literal": "build", - "parent": [Circular], - }, - { - "kind": 13, - "literal": "serve", - "parent": [Circular], - }, - ], - }, - }, - { - "kind": 32, - "name": "mode", - "parent": [Circular], - "type": { - "kind": 5, - "parent": [Circular], - }, - }, - { - "kind": 32, - "name": "ssrBuild", - "optional": true, - "parent": [Circular], - "type": { - "kind": 7, - "parent": [Circular], - }, - }, - ], - } - `); -}); - -test('inline all external type imports for package', () => { - const res = transpile({ - app: `import { ConfigEnv, CorsOrigin } from 'vite'; - import { typeOf } from '@deepkit/type'; - - type A = ConfigEnv; - type B = CorsOrigin; - ` - }, undefined, { - inlineExternalLibraryImports: { - 'vite': true, - }, - }); - - expect(res.app).toContain('__ɵΩrxjs.ConfigEnv = ['); - expect(res.app).toContain('__ɵΩrxjs.CorsOrigin = ['); -}); diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts new file mode 100644 index 000000000..dfcd43c4a --- /dev/null +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -0,0 +1,1262 @@ +import { test, expect } from '@jest/globals'; +import { ReflectionKind, TypeClass, TypeFunction } from '@deepkit/type'; +import { Unsubscribable } from 'rxjs'; + +import { transpile, transpileAndRun } from './utils'; + +test('string type alias', () => { + const res = transpile({ + app: `import { NIL } from 'uuid'; + + type T = typeof NIL; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'uuid': ['NIL'], + }, + }); + + expect(res.app).not.toContain('const __ΩNIL = ['); + expect(res.app).not.toContain('() => __assignType(uuid_1.NIL, __ΩNIL)'); + expect(res.app).toContain('() => uuid_1.NIL'); +}); + +test('typeOf string type alias', () => { + const res = transpileAndRun({ + app: `import { typeOf } from '@deepkit/type'; + import { NIL } from 'uuid'; + + typeOf(); + ` + }); + + expect(res).toMatchInlineSnapshot(` + { + "kind": 13, + "literal": "00000000-0000-0000-0000-000000000000", + "typeName": undefined, + } + `); +}); + +test('object type alias', () => { + const res = transpile({ + app: `import { config } from 'rxjs'; + + type A = typeof config; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['config'], + }, + }); + + expect(res.app).not.toContain('const __Ωconfig = ['); + expect(res.app).not.toContain('() => __assignType(rxjs_1.config, __Ωconfig)'); + expect(res.app).toContain('() => rxjs_1.config'); +}); + +test('typeOf object type alias', () => { + const res = transpileAndRun({ + app: `import { typeOf } from '@deepkit/type'; + import { config } from 'rxjs'; + + typeOf(); + ` + }); + + expect(res).toMatchInlineSnapshot(` + { + "annotations": {}, + "id": 2, + "kind": 30, + "typeName": undefined, + "types": [ + { + "kind": 32, + "name": "onUnhandledError", + "parent": [Circular], + "type": { + "kind": 10, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "onStoppedNotification", + "parent": [Circular], + "type": { + "kind": 10, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "Promise", + "parent": [Circular], + "type": { + "kind": 11, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "useDeprecatedSynchronousErrorHandling", + "parent": [Circular], + "type": { + "jit": {}, + "kind": 7, + "origin": { + "kind": 13, + "literal": false, + }, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "useDeprecatedNextContext", + "parent": [Circular], + "type": { + "jit": {}, + "kind": 7, + "origin": { + "kind": 13, + "literal": false, + }, + "parent": [Circular], + }, + }, + ], + } + `); +}); + +test('declares scoped variable', () => { + const res = transpile({ + app: `import { map } from 'rxjs/operators'; + + type A = typeof map; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs/operators': ['map'], + }, + }); + + expect(res.app).toContain('__ɵΩrxjs_operators = {}'); +}) + +test('function type alias', () => { + const res = transpile({ + app: `import { map } from 'rxjs/operators'; + + type A = typeof map; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['map'], + }, + }); + + expect(res.app).toContain('__ɵΩrxjs_operators.Ωmap = ['); + expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); +}); + +test('typeOf function type alias', () => { + const res = transpileAndRun({ + app: `import { map } from 'rxjs'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['map'], + }, + }) as TypeFunction; + + expect(res.return.kind).not.toBe(ReflectionKind.never); + + expect(res).toMatchInlineSnapshot(` +{ + "function": [Function], + "inlined": true, + "kind": 17, + "name": "map", + "parameters": [ + { + "kind": 18, + "name": "project", + "parent": { + "function": [Function], + "kind": 17, + "name": "map", + "parameters": [Circular], + "return": { + "annotations": {}, + "id": 4, + "implements": [ + { + "annotations": {}, + "id": 2, + "kind": 30, + "typeArguments": [ + { + "classType": [ + "T", + [Function], + "source", + "operator", + [Function], + "this", + [Function], + "subscriber", + [Function], + "", + "subscribe", + "constructor", + "args", + "create", + [Function], + "lift", + [Function], + [Function], + "observer", + [Function], + "value", + "next", + "forEach", + [Function], + "pipe", + "toPromise", + [Function], + "Observable", + "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w __ɵΩrxjs.UnaryFunction", + "types": [ + { + "kind": 35, + "parameters": [ + { + "kind": 18, + "name": "source", + "parent": [Circular], + "type": { + "classType": [ + "T", + [Function], + "source", + "operator", + [Function], + "this", + [Function], + "subscriber", + [Function], + "", + "subscribe", + "constructor", + "args", + "create", + [Function], + "lift", + [Function], + [Function], + "observer", + [Function], + "value", + "next", + "forEach", + [Function], + "pipe", + "toPromise", + [Function], + "Observable", + "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w __ɵΩrxjs.OperatorFunction", + "types": [ + { + "kind": 35, + "parameters": [ + { + "kind": 18, + "name": "source", + "parent": [Circular], + "type": { + "classType": [ + "T", + [Function], + "source", + "operator", + [Function], + "this", + [Function], + "subscriber", + [Function], + "", + "subscribe", + "constructor", + "args", + "create", + [Function], + "lift", + [Function], + [Function], + "observer", + [Function], + "value", + "next", + "forEach", + [Function], + "pipe", + "toPromise", + [Function], + "Observable", + "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w __ɵΩrxjs.UnaryFunction", + "types": [ + { + "kind": 35, + "parameters": [ + { + "kind": 18, + "name": "source", + "parent": [Circular], + "type": { + "classType": [ + "T", + [Function], + "source", + "operator", + [Function], + "this", + [Function], + "subscriber", + [Function], + "", + "subscribe", + "constructor", + "args", + "create", + [Function], + "lift", + [Function], + [Function], + "observer", + [Function], + "value", + "next", + "forEach", + [Function], + "pipe", + "toPromise", + [Function], + "Observable", + "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w __ɵΩrxjs.OperatorFunction", + "types": [ + { + "kind": 35, + "parameters": [ + { + "kind": 18, + "name": "source", + "parent": [Circular], + "type": { + "classType": [ + "T", + [Function], + "source", + "operator", + [Function], + "this", + [Function], + "subscriber", + [Function], + "", + "subscribe", + "constructor", + "args", + "create", + [Function], + "lift", + [Function], + [Function], + "observer", + [Function], + "value", + "next", + "forEach", + [Function], + "pipe", + "toPromise", + [Function], + "Observable", + "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { + const res = transpile({ + app: `import { Observable } from 'rxjs'; + + type A = Observable; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['Observable'], + }, + }); + + expect(res.app).toMatchInlineSnapshot(` + ""use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + const __ɵΩrxjs = {}; + __ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ɵΩrxjs.Partial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; + const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; + __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; + __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; + __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; + __ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ɵΩrxjs.Exclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; + const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; + __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; + __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; + __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; + function __assignType(fn, args) { + fn.__type = args; + return fn; + } + const rxjs_1 = require("rxjs"); + const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩrxjs.Observable), 'P#7!y']; + " + `); +}) + +test('runtime type name clashing', () => { + const res = transpile({ + app: `import { Observable } from 'rxjs'; + + type Subscribable = any; + + type A = Observable; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['Observable'], + }, + }); + + expect(res.app).toContain('__ɵΩrxjs.Subscribable = ['); + expect(res.app).toContain('const __ΩSubscribable = ['); +}); + +test('class typeOf', () => { + const res = transpileAndRun({ + app: `import { Observable } from 'rxjs'; + import { typeOf } from '@deepkit/type'; + + typeOf>(); + ` + }, undefined, { + inlineExternalLibraryImports: { + 'rxjs': ['Observable'], + }, + }) as TypeClass; + + console.log(res); + + expect(res.implements![0]).toMatchObject({ + kind: 30, + // typeName: 'Subscribable', + typeName: 'UnknownTypeName:() => __ɵΩrxjs.Subscribable', + }); + expect(res.typeArguments).toHaveLength(1); + expect(res.types).toHaveLength(1); +}) + +test('only a single type is transformed', () => { + const res = transpile({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + + type A = ConfigEnv; + + type B = CorsOrigin; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'vite': ['ConfigEnv'], + }, + }); + + expect(res.app).toContain('__ɵΩvite.ConfigEnv = ['); + expect(res.app).not.toContain('__ɵΩvite.CorsOrigin = ['); +}) + +test('interface typeOf', () => { + const res = transpileAndRun({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + import { typeOf } from '@deepkit/type'; + + typeOf(); + ` + }, undefined, { + inlineExternalLibraryImports: { + 'vite': ['ConfigEnv'], + }, + }); + + expect(res).toMatchInlineSnapshot(` + { + "annotations": {}, + "id": 2, + "kind": 30, + "typeArguments": undefined, + "typeName": "ConfigEnv", + "types": [ + { + "kind": 32, + "name": "command", + "parent": [Circular], + "type": { + "kind": 23, + "parent": [Circular], + "types": [ + { + "kind": 13, + "literal": "build", + "parent": [Circular], + }, + { + "kind": 13, + "literal": "serve", + "parent": [Circular], + }, + ], + }, + }, + { + "kind": 32, + "name": "mode", + "parent": [Circular], + "type": { + "kind": 5, + "parent": [Circular], + }, + }, + { + "kind": 32, + "name": "ssrBuild", + "optional": true, + "parent": [Circular], + "type": { + "kind": 7, + "parent": [Circular], + }, + }, + ], + } + `); +}); + +test('inline all external type imports for package', () => { + const res = transpile({ + app: `import { ConfigEnv, CorsOrigin } from 'vite'; + import { typeOf } from '@deepkit/type'; + + type A = ConfigEnv; + type B = CorsOrigin; + ` + }, undefined, { + inlineExternalLibraryImports: { + 'vite': true, + }, + }); + + expect(res.app).toContain('__ɵΩvite.ConfigEnv = ['); + expect(res.app).toContain('__ɵΩvite.CorsOrigin = ['); +}); From f8b1505888f62cee9f159de830420c87f2f61fb1 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Thu, 7 Dec 2023 17:13:46 +0100 Subject: [PATCH 10/23] improve --- packages/type-compiler/src/compiler.ts | 102 ++- packages/type-compiler/src/external.ts | 90 ++- packages/type-compiler/src/reflection-ast.ts | 50 +- .../inline-external-library-imports.spec.ts | 707 ++---------------- 4 files changed, 243 insertions(+), 706 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 0d3d393ef..09d759bb1 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -975,7 +975,7 @@ export class ReflectionTransformer implements CustomTransformer { break; } - if (this.embedDeclarations.size === 0 && this.external.libraryImports.size === 0 && allCompiled) break; + if (this.embedDeclarations.size === 0 && this.external.compileExternalLibraryImports.size === 0 && allCompiled) break; for (const [node, d] of [...this.compileDeclarations.entries()]) { if (d.compiled) continue; @@ -993,14 +993,14 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (this.external.libraryImports.size) { - for (const imports of this.external.libraryImports.values()) { - for (const { declaration } of imports) { + if (this.external.compileExternalLibraryImports.size) { + for (const imports of this.external.compileExternalLibraryImports.values()) { + for (const { declaration } of imports.values()) { this.compiledDeclarations.add(declaration); } } - const entries = Array.from(this.external.libraryImports.entries()); - this.external.libraryImports.clear(); + const entries = Array.from(this.external.compileExternalLibraryImports.entries()); + this.external.compileExternalLibraryImports.clear(); for (const [library, imports] of entries) { if (!this.external.embeddedLibraryVariables.has(library)) { const objectLiteral = this.f.createObjectLiteralExpression(); @@ -1020,8 +1020,8 @@ export class ReflectionTransformer implements CustomTransformer { this.external.embeddedLibraryVariables.add(library); } - for (const value of imports) { - this.external.setEmbeddingExternalLibraryImport(value); + for (const value of imports.values()) { + this.external.startEmbeddingExternalLibraryImport(value); newTopStatements.push(this.createProgramVarForExternalLibraryImport(value.declaration, value.name, value.sourceFile, value.module.packageId.name)); this.external.finishEmbeddingExternalLibraryImport(); } @@ -1132,6 +1132,23 @@ export class ReflectionTransformer implements CustomTransformer { newTopStatements.push(assignType); } + if (this.tempResultIdentifier) { + newTopStatements.push( + this.f.createVariableStatement( + undefined, + this.f.createVariableDeclarationList( + [this.f.createVariableDeclaration( + this.tempResultIdentifier, + undefined, + undefined, + undefined + )], + ts.NodeFlags.None + ) + ) + ); + } + if (newTopStatements.length) { // we want to keep "use strict", or "use client", etc at the very top const indexOfFirstLiteralExpression = this.sourceFile.statements.findIndex(v => isExpressionStatement(v) && isStringLiteral(v.expression)); @@ -1326,6 +1343,12 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as ClassDeclaration | ClassExpression; //class nodes have always their own program, so the start is always fresh, means we don't need a frame + if (this.external.isEmbeddingExternalLibraryImport()) { + const declaration = this.nodeConverter.convertClassToInterface(narrowed); + this.extractPackStructOfType(declaration, program); + break; + } + if (node) { const members: ClassElement[] = []; @@ -1673,6 +1696,10 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorTypeNode | ConstructSignatureDeclaration | ConstructorDeclaration | ArrowFunction | FunctionExpression | FunctionTypeNode | FunctionDeclaration; + if(this.external.isEmbeddingExternalLibraryImport() && (isFunctionDeclaration(node) || isFunctionExpression(node) || isMethodDeclaration(node))) { + console.log(getNameAsString(narrowed.name)); + } + const config = this.findReflectionConfig(narrowed, program); if (config.mode === 'never') return; @@ -2043,11 +2070,19 @@ export class ReflectionTransformer implements CustomTransformer { // return node; // } + protected getRuntimeTypeName(typeName: EntityName): Identifier { + return this.f.createIdentifier(getRuntimeTypeName(getNameAsString(typeName))); + } + + protected getExternalRuntimeTypeName(typeName: EntityName): Identifier { + const { module } = this.external.getEmbeddingExternalLibraryImport(); + return this.f.createIdentifier(`${getExternalRuntimeTypeName(module.packageId.name)}.${getNameAsString(typeName)}`); + } + protected getDeclarationVariableName(typeName: EntityName): Identifier { - const name = getNameAsString(typeName); - return this.external.isEmbeddingExternalLibraryImport() && !this.external.globalTypeNames.has(name) - ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.external.getEmbeddingExternalLibraryImport().module.packageId.name)}.${name}`) - : this.f.createIdentifier(getRuntimeTypeName(name)); + return this.external.isEmbeddingExternalLibraryImport() && !this.external.knownGlobalTypeNames.has(getNameAsString(typeName)) + ? this.getExternalRuntimeTypeName(typeName) + : this.getRuntimeTypeName(typeName); } protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: Expression, program: CompilerProgram): Expression { @@ -2063,18 +2098,18 @@ export class ReflectionTransformer implements CustomTransformer { if (declarationReflection.mode !== 'never') { const declarationSourceFile = importDeclaration.getSourceFile(); - const runtimeTypeName = this.getDeclarationVariableName(typeName); + const runtimeTypeName = this.getRuntimeTypeName(typeName); const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { - const { module } = this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + const { module } = this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) - // TODO: figure out what to do with referenced classes/functions in external declaration files - ? this.wrapWithAssignType(expression, this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName)) - : this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); + ? this.wrapWithAssignType(expression, newExpression) + : newExpression } } @@ -2180,6 +2215,7 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { + console.log(2, getNameAsString(typeName)); expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } @@ -2228,8 +2264,7 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const runtimeTypeName = this.getDeclarationVariableName(typeName) - // const runtimeTypeName = this.f.createIdentifier(getRuntimeTypeName(getNameAsString(typeName))); + const runtimeTypeName = this.getRuntimeTypeName(typeName); //to break recursion, we track which declaration has already been compiled if (!this.compiledDeclarations.has(declaration) && !this.compileDeclarations.has(declaration)) { @@ -2240,18 +2275,14 @@ export class ReflectionTransformer implements CustomTransformer { return; } - if (this.external.hasSourceFile(declarationSourceFile)) { - if (this.external.isEmbeddingExternalLibraryImport()) { - this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - } + if (this.external.hasSourceFile(declarationSourceFile) && this.external.isEmbeddingExternalLibraryImport()) { + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); } else { const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; const isFromImport = resolved.importDeclaration !== undefined; if (isGlobal) { - if (this.external.isEmbeddingExternalLibraryImport()) { - this.external.addGlobalType(getNameAsString(typeName)); - } + this.external.knownGlobalTypeNames.add(getNameAsString(typeName)); this.embedDeclarations.set(declaration, { name: typeName, sourceFile: declarationSourceFile @@ -2281,7 +2312,7 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { if (!this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.external.embedExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); } else { //check if the referenced file has reflection info emitted. if not, any is emitted for that reference const reflection = this.findReflectionFromPath(found.fileName); @@ -2310,7 +2341,7 @@ export class ReflectionTransformer implements CustomTransformer { } const index = program.pushStack( - program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, runtimeTypeName) + program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, this.getDeclarationVariableName(typeName)) ); if (type.typeArguments) { for (const argument of type.typeArguments) { @@ -2343,8 +2374,6 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); - let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); if (resolved.importDeclaration && isIdentifier(typeName)) { body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); @@ -2355,8 +2384,17 @@ export class ReflectionTransformer implements CustomTransformer { this.extractPackStructOfType(typeArgument, program); } } - const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); - program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); + if (this.external.isEmbeddingExternalLibraryImport()) { + if (isClassDeclaration(declaration)) { + program.pushOp(ReflectionOp.objectLiteral); + } else { + const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); + program.pushOp(ReflectionOp.function, index); + } + } else { + const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); + program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); + } program.popFrameImplicit(); } else if (isTypeParameterDeclaration(declaration)) { this.resolveTypeParameter(declaration, type, program); diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index e0b04c0c9..5cb076e4f 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -20,15 +20,15 @@ export interface ExternalLibraryImport { } export class External { - public sourceFileNames = new Set(); + protected sourceFileNames = new Set(); - public runtimeTypeNames = new Set(); + public compileExternalLibraryImports = new Map>; - public libraryImports = new Map>; + protected processedEntities = new Set; public embeddedLibraryVariables = new Set(); - public globalTypeNames = new Set(); + public knownGlobalTypeNames = new Set(); public sourceFile?: SourceFile; @@ -36,7 +36,7 @@ export class External { constructor(protected resolver: Resolver) {} - setEmbeddingExternalLibraryImport(value: ExternalLibraryImport): void { + startEmbeddingExternalLibraryImport(value: ExternalLibraryImport): void { if (this.embeddingExternalLibraryImport) { throw new Error('Already embedding module'); } @@ -50,10 +50,6 @@ export class External { return this.embeddingExternalLibraryImport; } - addGlobalType(typeName: string) { - this.globalTypeNames.add(typeName); - } - isEmbeddingExternalLibraryImport(): boolean { return !!this.embeddingExternalLibraryImport; } @@ -62,35 +58,6 @@ export class External { delete this.embeddingExternalLibraryImport; } - public hasExternalLibraryImport( - entityName: EntityName, - module: Required = this.getEmbeddingExternalLibraryImport().module, - ): boolean { - const imports = this.libraryImports.get(module.packageId.name); - if (!imports) return false; - const typeName = getEntityName(entityName); - return [...imports].some(d => getNameAsString(d.name) === typeName) - } - - public addExternalLibraryImport(name: EntityName, declaration: Node, sourceFile: SourceFile, module?: Required): ExternalLibraryImport { - if (!module) { - module = this.getEmbeddingExternalLibraryImport().module; - } - const imports = this.libraryImports.get(module.packageId.name) || new Set(); - const externalLibraryImport: ExternalLibraryImport = { - name, - declaration, - sourceFile, - module, - } - this.libraryImports.set(module.packageId.name, imports.add(externalLibraryImport)); - return externalLibraryImport; - } - - public addRuntimeTypeName(typeName: EntityName): void { - this.runtimeTypeNames.add(getNameAsString(typeName)); - } - public addSourceFile(sourceFile: SourceFile): void { this.sourceFileNames.add(sourceFile.fileName); } @@ -111,21 +78,50 @@ export class External { return imports.includes(typeName); } - public embedExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { - let externalLibraryImport: ExternalLibraryImport; - if (importDeclaration) { - const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); - externalLibraryImport = this.addExternalLibraryImport(typeName, declaration, sourceFile, resolvedModule); - } else { - externalLibraryImport = this.addExternalLibraryImport(typeName, declaration, sourceFile); + public processExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { + const module = importDeclaration + ? this.resolver.resolveExternalLibraryImport(importDeclaration) + : this.getEmbeddingExternalLibraryImport().module; + + const entityName = getNameAsString(typeName); + if (this.processedEntities.has(entityName)) { + return { + name: typeName, + declaration, + sourceFile, + module, + } } - this.addRuntimeTypeName(typeName); + this.processedEntities.add(entityName); + // const libraryFiles = this.processedExternalLibraryImports.get(module.packageId.name) || new Map(); + // const libraryFileEntities = libraryFiles.get(module.resolvedFileName) || new Set(); + // if (libraryFileEntities.has(entityName)) { + // return { + // name: typeName, + // declaration, + // sourceFile, + // module, + // } + // } + // + // libraryFileEntities.add(entityName); + // libraryFiles.set(module.resolvedFileName, libraryFileEntities); + // this.processedExternalLibraryImports.set(module.packageId.name, libraryFiles); + + const imports = this.compileExternalLibraryImports.get(module.packageId.name) || new Map(); + const externalLibraryImport: ExternalLibraryImport = { + name: typeName, + declaration, + sourceFile, + module, + } + this.compileExternalLibraryImports.set(module.packageId.name, imports.set(entityName, externalLibraryImport)); if (sourceFile.fileName !== this.sourceFile?.fileName) { this.addSourceFile(sourceFile); } - return externalLibraryImport; + return externalLibraryImport!; } } diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index 6c092b3ac..bbc4c6485 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -29,6 +29,11 @@ import type { StringLiteral, StringLiteralLike, SymbolTable, + ClassDeclaration, + ClassElement, + InterfaceDeclaration, + Modifier, + TypeElement, ClassExpression, } from 'typescript'; import ts from 'typescript'; import { cloneNode as tsNodeClone, CloneNodeHook } from '@marcj/ts-clone-node'; @@ -36,6 +41,10 @@ import { SourceFile } from './ts-types.js'; import { External } from './external.js'; const { + isInterfaceDeclaration, + isConstructorDeclaration, + isMethodDeclaration, + isPropertyDeclaration, isArrowFunction, isComputedPropertyName, isIdentifier, @@ -133,6 +142,45 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo export class NodeConverter { constructor(protected f: NodeFactory, protected external: External) {} + public convertedNodes = new Map; + + private convertClassElementToTypeElement(node: ClassElement): TypeElement { + if (isPropertyDeclaration(node)) { + return this.f.createPropertySignature( + node.modifiers as readonly Modifier[] | undefined, + node.name, + node.questionToken, + node.type, + ); + } else if (isMethodDeclaration(node)) { + return this.f.createMethodSignature( + node.modifiers as readonly Modifier[] | undefined, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + ); + } else if (isConstructorDeclaration(node)) { + return this.f.createConstructSignature(node.typeParameters, node.parameters, node.type); + } + + throw new Error('Unsupported type'); + } + + convertClassToInterface(node: ClassDeclaration | ClassExpression): InterfaceDeclaration { + if (!node.name) { + throw new Error('Class name is required'); + } + return this.f.createInterfaceDeclaration( + node.modifiers as readonly Modifier[] | undefined, + node.name, + node.typeParameters, + node.heritageClauses, //node.heritageClauses.map(heritageClause => isInterfaceDeclaration(heritageClause.) ? heritageClause : this.f.createh(this.convertClassToInterface(heritageClause))), + node.members.map(member => this.convertClassElementToTypeElement(member)), + ); + } + toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -156,7 +204,7 @@ export class NodeConverter { switch (node.kind) { case SyntaxKind.Identifier: const name = getIdentifierName(node as Identifier); - return this.external.isEmbeddingExternalLibraryImport() && !this.external.globalTypeNames.has(name) + return this.external.isEmbeddingExternalLibraryImport() && !this.external.knownGlobalTypeNames.has(name) ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.external.getEmbeddingExternalLibraryImport().module.packageId.name)}.${name}`) : finish(node, this.f.createIdentifier(getRuntimeTypeName(name))); case SyntaxKind.StringLiteral: diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index dfcd43c4a..33ad23047 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -149,7 +149,7 @@ test('declares scoped variable', () => { test('function type alias', () => { const res = transpile({ - app: `import { map } from 'rxjs/operators'; + app: `import { map } from 'rxjs'; type A = typeof map; ` @@ -163,6 +163,8 @@ test('function type alias', () => { expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); }); +import { map } from 'rxjs'; + test('typeOf function type alias', () => { const res = transpileAndRun({ app: `import { map } from 'rxjs'; @@ -195,46 +197,17 @@ test('typeOf function type alias', () => { "parameters": [Circular], "return": { "annotations": {}, - "id": 4, + "id": 6, "implements": [ { "annotations": {}, - "id": 2, + "id": 4, "kind": 30, "typeArguments": [ { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { ], "parent": [Circular], "return": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "parent": [Circular], "return": [Circular], }, - "typeArguments": [ - { - "kind": 1, - }, - ], "types": [], }, ], @@ -399,88 +265,20 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { ], "return": { "annotations": {}, - "id": 4, + "id": 6, "implements": [ { "annotations": {}, - "id": 2, + "id": 4, "kind": 30, "typeArguments": [ { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { ], "parent": [Circular], "return": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "parent": [Circular], "return": [Circular], }, - "typeArguments": [ - { - "kind": 1, - }, - ], "types": [], }, ], @@ -833,88 +427,20 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { "name": "source", "parent": [Circular], "type": { - "classType": [ - "T", - [Function], - "source", - "operator", - [Function], - "this", - [Function], - "subscriber", - [Function], - "", - "subscribe", - "constructor", - "args", - "create", - [Function], - "lift", - [Function], - [Function], - "observer", - [Function], - "value", - "next", - "forEach", - [Function], - "pipe", - "toPromise", - [Function], - "Observable", - "b!PP"7"-J3#P-J3$PPPe$!7%2&Pe$!7'2(n)/*2+8"0,P"@2-"/*3.sP2$8P"7/00Pe"!o2"o1"238P740+PPe#!25$/*26$\`07PPe#!7809PPe#!-J\`0:5e!!o;"x"w { }); expect(res.app).toMatchInlineSnapshot(` - ""use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - const __ɵΩrxjs = {}; - __ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ɵΩrxjs.Partial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; - const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; - __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; - __ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; - __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; - __ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ɵΩrxjs.Exclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; - const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; - __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; - __ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; - __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; - function __assignType(fn, args) { - fn.__type = args; - return fn; - } - const rxjs_1 = require("rxjs"); - const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩrxjs.Observable), 'P#7!y']; - " - `); +""use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const __ɵΩrxjs = {}; +__ɵΩrxjs.Observable = ['source', () => __ɵΩrxjs.Operator, 'operator', 'this', 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'new', 'args', 'create', () => __ɵΩrxjs.Operator, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', 'value', 'next', 'error', 'complete', 'forEach', () => __ΩPromiseConstructorLike, 'promiseCtor', 'pipe', () => __ɵΩrxjs.OperatorFunction, 'op1', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op2', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op3', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op4', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op5', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op6', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op7', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op8', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op9', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'operations', 'toPromise', () => Promise, 'PromiseCtor', () => __ΩPromiseConstructorLike, 'PPP"M-J4!P"!o"#-J4#PPP!M2$P!M2%n&/\\'2(8"1)P"@2*"/\\'4+P!"o,#2#8P"M1-P!o/"o."208PM1(PP!21$/\\'22PM1(PPP!21$/\\',J228PP"23$/\\',J238PP$/\\',J248PM1(PP!21$/\\'22$\`15PP!21$/\\'22n627$\`15PP!M18P!"o9#2:P"M18P!"o;#2:""o<#2=P"M18P!"o>#2:""o?#2=""o@#2AP"M18P!"oB#2:""oC#2=""oD#2A""oE#2FP"M18P!"oG#2:""oH#2=""oI#2A""oJ#2F""oK#2LP"M18P!"oM#2:""oN#2=""oO#2A""oP#2F""oQ#2L""oR#2SP"M18P!"oT#2:""oU#2=""oV#2A""oW#2F""oX#2L""oY#2S""oZ#2[P"M18P!"o\\\\#2:""o]#2=""o^#2A""o_#2F""o\`#2L""oa#2S""ob#2[""oc#2dP"M18P!"oe#2:""of#2=""og#2A""oh#2F""oi#2L""oj#2S""ok#2[""ol#2d""om#2nP"M18P!"oo#2:""op#2=""oq#2A""or#2F""os#2L""ot#2S""ou#2[""ov#2d""ow#2n""ox#@2yP#M18PP!-J\`1zPi{2|P!-J\`1zPn}2|P!-J\`1zMy']; +const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; +const __ΩPromiseConstructorLike = [() => __ΩPromiseLike, 'value', '', 'resolve', 'reason', 'reject', 'executor', () => __ΩPromiseLike, 'new', 'PPPP""o!"J2"$/#2$P"2%8$/#2&$/#2\\'"o("/)y']; +__ɵΩrxjs.Operator = ['T', 'R', 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"M2#"2$n%1&My']; +__ɵΩrxjs.Subscriber = ['x', '', 'next', 'e', 'error', 'complete', 'create', 'isStopped', () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Observer, 'new', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', 'PPMPP"2!8$/"2#8P"2$8$/"2%8P$/"2&8P"M1\\')4(PP"M"o)"J4*PPP"M"o+"J2*8"1,P!2-8$1#P"2.8$1%P$1&P$1/P!2-$10P"2.$11P$12My']; +__ɵΩrxjs.TeardownLogic = [() => __ɵΩrxjs.Unsubscribable, '', 'PPMn!P$/"$Jy']; +__ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; +__ɵΩrxjs.Subscription = ['EMPTY', 'closed', '', 'initialTeardown', 'new', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', 'PPM4!)4"PPP$/#-J2$8"1%P$1&Pn\\'2($1)Pn+$o*#2($1,My']; +__ɵΩrxjs.OperatorFunction = ['T', 'R', () => __ɵΩrxjs.UnaryFunction, 'b!b"PPe#!MPe#"Mo##My']; +const __ΩPromiseLike = ['T', 'value', 0, '', 'onfulfilled', 'reason', 0, 'onrejected', 0, 'then', 'b!PPPPe%!2"P""o#"J/$-,J2%8PP"2&P""o\\'"J/$-,J2(8P""Jo)"1*My']; +const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; +__ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; +__ɵΩrxjs.UnaryFunction = ['T', 'R', 'source', '', 'b!b"PPe#!2#e#"v$My']; +function __assignType(fn, args) { + fn.__type = args; + return fn; +} +const rxjs_1 = require("rxjs"); +const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩrxjs.Observable), 'P#7!y']; +" +`); }) test('runtime type name clashing', () => { @@ -1152,8 +607,8 @@ test('class typeOf', () => { expect(res.implements![0]).toMatchObject({ kind: 30, - // typeName: 'Subscribable', - typeName: 'UnknownTypeName:() => __ɵΩrxjs.Subscribable', + typeName: 'Subscribable', + // typeName: 'UnknownTypeName:() => __ɵΩrxjs.Subscribable', }); expect(res.typeArguments).toHaveLength(1); expect(res.types).toHaveLength(1); From bda91599a0c37064ddf15fbddafecb7f9c21a2e0 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 01:15:32 +0100 Subject: [PATCH 11/23] build: update tsconfig.json --- examples/rpc-websockets-esm/tsconfig.json | 4 ++- examples/rpc-websockets/tsconfig.json | 4 ++- package.json | 2 +- packages/angular-universal/dist/.gitkeep | 0 packages/angular-universal/tsconfig.json | 4 ++- packages/api-console-api/dist/.gitkeep | 0 packages/api-console-api/tsconfig.json | 4 ++- packages/api-console-gui/dist/.gitkeep | 0 .../src/app/components/inputs/registry.ts | 12 +++++++-- packages/api-console-gui/src/app/utils.ts | 12 +++++++-- packages/api-console-module/dist/.gitkeep | 0 packages/api-console-module/tsconfig.json | 4 ++- packages/app/dist/.gitkeep | 0 packages/app/tsconfig.json | 4 ++- packages/broker/dist/.gitkeep | 0 packages/broker/tsconfig.json | 4 ++- packages/bson/dist/.gitkeep | 0 packages/bson/src/bson-parser.ts | 4 +-- packages/bson/tsconfig.json | 4 ++- packages/bun/dist/.gitkeep | 0 packages/core-rxjs/dist/.gitkeep | 0 packages/core/tsconfig.json | 4 ++- packages/create-app/dist/.gitkeep | 0 packages/create-app/files/tsconfig.json | 4 ++- packages/create-app/tsconfig.json | 4 ++- packages/event/dist/.gitkeep | 0 packages/event/tsconfig.json | 4 ++- packages/example-app/tsconfig.json | 4 ++- packages/filesystem-aws-s3/dist/.gitkeep | 0 packages/filesystem-ftp/dist/.gitkeep | 0 packages/filesystem-google/dist/.gitkeep | 0 packages/filesystem-sftp/dist/.gitkeep | 0 packages/filesystem/dist/.gitkeep | 0 packages/filesystem/tsconfig.json | 4 ++- packages/framework-debug-api/dist/.gitkeep | 0 packages/framework-debug-api/tsconfig.json | 4 ++- packages/framework-examples/dist/.gitkeep | 0 packages/framework-examples/tsconfig.json | 4 ++- packages/framework-integration/dist/.gitkeep | 0 packages/framework-integration/tsconfig.json | 4 ++- packages/framework/dist/.gitkeep | 0 packages/framework/dist/esm/package.json | 1 - packages/framework/tsconfig.json | 4 ++- packages/fs/dist/.gitkeep | 0 packages/http/dist/.gitkeep | 0 packages/http/tsconfig.json | 4 ++- packages/injector/src/injector.ts | 27 ++++++++++--------- packages/injector/src/types.ts | 4 +-- packages/injector/tsconfig.json | 4 ++- packages/logger/dist/.gitkeep | 0 packages/logger/tsconfig.json | 4 ++- packages/mongo/tsconfig.json | 4 ++- packages/mysql/dist/.gitkeep | 0 packages/orm-browser-api/dist/.gitkeep | 0 packages/orm-browser-api/tsconfig.json | 4 ++- packages/orm-browser-example/dist/.gitkeep | 0 packages/orm-browser-example/tsconfig.json | 4 ++- packages/orm-browser-gui/dist/.gitkeep | 0 packages/orm-browser-gui/src/app/registry.ts | 6 ++--- packages/orm-browser/dist/.gitkeep | 0 packages/orm-browser/tsconfig.json | 4 ++- packages/orm-integration/dist/.gitkeep | 0 packages/orm-integration/tsconfig.json | 4 ++- packages/orm/dist/.gitkeep | 0 packages/orm/tsconfig.json | 4 ++- packages/postgres/dist/.gitkeep | 0 packages/rpc-tcp/dist/.gitkeep | 0 packages/rpc/dist/.gitkeep | 0 packages/rpc/tsconfig.json | 4 ++- packages/skeleton/dist/.gitkeep | 0 packages/sql/dist/.gitkeep | 0 packages/sql/src/platform/default-platform.ts | 6 ++--- packages/sql/tsconfig.json | 4 ++- packages/sqlite/dist/.gitkeep | 0 packages/stopwatch/dist/.gitkeep | 0 packages/stopwatch/tsconfig.json | 4 ++- packages/template/dist/.gitkeep | 0 packages/template/tsconfig.json | 4 ++- packages/topsort/dist/.gitkeep | 0 packages/type-angular/dist/.gitkeep | 0 packages/type-compiler/tsconfig.json | 4 ++- packages/type/tsconfig.json | 4 ++- packages/vite/dist/.gitkeep | 0 packages/workflow/dist/.gitkeep | 0 packages/workflow/tsconfig.json | 4 ++- 85 files changed, 147 insertions(+), 63 deletions(-) delete mode 100644 packages/angular-universal/dist/.gitkeep delete mode 100644 packages/api-console-api/dist/.gitkeep delete mode 100644 packages/api-console-gui/dist/.gitkeep delete mode 100644 packages/api-console-module/dist/.gitkeep delete mode 100644 packages/app/dist/.gitkeep delete mode 100644 packages/broker/dist/.gitkeep delete mode 100644 packages/bson/dist/.gitkeep delete mode 100644 packages/bun/dist/.gitkeep delete mode 100644 packages/core-rxjs/dist/.gitkeep delete mode 100644 packages/create-app/dist/.gitkeep delete mode 100644 packages/event/dist/.gitkeep delete mode 100644 packages/filesystem-aws-s3/dist/.gitkeep delete mode 100644 packages/filesystem-ftp/dist/.gitkeep delete mode 100644 packages/filesystem-google/dist/.gitkeep delete mode 100644 packages/filesystem-sftp/dist/.gitkeep delete mode 100644 packages/filesystem/dist/.gitkeep delete mode 100644 packages/framework-debug-api/dist/.gitkeep delete mode 100644 packages/framework-examples/dist/.gitkeep delete mode 100644 packages/framework-integration/dist/.gitkeep delete mode 100644 packages/framework/dist/.gitkeep delete mode 100644 packages/framework/dist/esm/package.json delete mode 100644 packages/fs/dist/.gitkeep delete mode 100644 packages/http/dist/.gitkeep delete mode 100644 packages/logger/dist/.gitkeep delete mode 100644 packages/mysql/dist/.gitkeep delete mode 100644 packages/orm-browser-api/dist/.gitkeep delete mode 100644 packages/orm-browser-example/dist/.gitkeep delete mode 100644 packages/orm-browser-gui/dist/.gitkeep delete mode 100644 packages/orm-browser/dist/.gitkeep delete mode 100644 packages/orm-integration/dist/.gitkeep delete mode 100644 packages/orm/dist/.gitkeep delete mode 100644 packages/postgres/dist/.gitkeep delete mode 100644 packages/rpc-tcp/dist/.gitkeep delete mode 100644 packages/rpc/dist/.gitkeep delete mode 100644 packages/skeleton/dist/.gitkeep delete mode 100644 packages/sql/dist/.gitkeep delete mode 100644 packages/sqlite/dist/.gitkeep delete mode 100644 packages/stopwatch/dist/.gitkeep delete mode 100644 packages/template/dist/.gitkeep delete mode 100644 packages/topsort/dist/.gitkeep delete mode 100644 packages/type-angular/dist/.gitkeep delete mode 100644 packages/vite/dist/.gitkeep delete mode 100644 packages/workflow/dist/.gitkeep diff --git a/examples/rpc-websockets-esm/tsconfig.json b/examples/rpc-websockets-esm/tsconfig.json index 755dbd57e..51119804d 100644 --- a/examples/rpc-websockets-esm/tsconfig.json +++ b/examples/rpc-websockets-esm/tsconfig.json @@ -7,5 +7,7 @@ "esModuleInterop": true, "module": "esnext" }, - "reflection": true + "deepkitTypeCompilerOptions": { + "reflection": true + } } diff --git a/examples/rpc-websockets/tsconfig.json b/examples/rpc-websockets/tsconfig.json index 7fabbf2dd..b12cbe291 100644 --- a/examples/rpc-websockets/tsconfig.json +++ b/examples/rpc-websockets/tsconfig.json @@ -7,5 +7,7 @@ "esModuleInterop": true, "module": "CommonJS" }, - "reflection": true + "deepkitTypeCompilerOptions": { + "reflection": true + }, } diff --git a/package.json b/package.json index d1bd318d8..17be3a1ba 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build": "tsc --build tsconfig.json && tsc --build tsconfig.esm.json && lerna run build", "build:esm": "tsc --build tsconfig.esm.json", "tsc": "tsc --build", - "install": "sh install-compiler.sh", + "postinstall": "sh install-compiler.sh", "tsc-watch": "tsc --build --watch", "tsc-watch:esm": "tsc --build --watch tsconfig.esm.json", "clean:all": "npm run clean && npm run clean:modules && npm run clean:lock", diff --git a/packages/angular-universal/dist/.gitkeep b/packages/angular-universal/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/angular-universal/tsconfig.json b/packages/angular-universal/tsconfig.json index 02ce0e3b2..11eb6682c 100644 --- a/packages/angular-universal/tsconfig.json +++ b/packages/angular-universal/tsconfig.json @@ -17,7 +17,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/api-console-api/dist/.gitkeep b/packages/api-console-api/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/api-console-api/tsconfig.json b/packages/api-console-api/tsconfig.json index be0b6352c..1d273c302 100644 --- a/packages/api-console-api/tsconfig.json +++ b/packages/api-console-api/tsconfig.json @@ -18,7 +18,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "index.ts", "src" diff --git a/packages/api-console-gui/dist/.gitkeep b/packages/api-console-gui/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/api-console-gui/src/app/components/inputs/registry.ts b/packages/api-console-gui/src/app/components/inputs/registry.ts index d16d5ea70..79661c6a7 100644 --- a/packages/api-console-gui/src/app/components/inputs/registry.ts +++ b/packages/api-console-gui/src/app/components/inputs/registry.ts @@ -1,4 +1,12 @@ -import { isMapType, isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; +import { + getClassType, + isMapType, + isMongoIdType, + isSetType, + isUUIDType, + ReflectionKind, + TypeRegistry, +} from '@deepkit/type'; import { ClassType, getClassName } from '@deepkit/core'; import { StringInputComponent } from './string-input.component'; import { ArrayInputComponent } from './array-input.component'; @@ -38,5 +46,5 @@ inputRegistry.set(type => { return isMapType(type); }, MapInputComponent); inputRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; }, BinaryInputComponent); diff --git a/packages/api-console-gui/src/app/utils.ts b/packages/api-console-gui/src/app/utils.ts index 05dc5547e..811d9422e 100644 --- a/packages/api-console-gui/src/app/utils.ts +++ b/packages/api-console-gui/src/app/utils.ts @@ -1,7 +1,15 @@ //@ts-ignore import objectInspect from 'object-inspect'; import { getClassName } from '@deepkit/core'; -import { getTypeJitContainer, isBackReferenceType, isReferenceType, ReflectionKind, stringifyType, Type } from '@deepkit/type'; +import { + getClassType, + getTypeJitContainer, + isBackReferenceType, + isReferenceType, + ReflectionKind, + stringifyType, + Type, +} from '@deepkit/type'; export function trackByIndex(index: number) { return index; @@ -12,7 +20,7 @@ export function isReferenceLike(type: Type): boolean { } function manualTypeStringify(type: Type): string | undefined { - if (type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile') return 'UploadedFile'; + if (type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile') return 'UploadedFile'; //we are not interested in the methods if (type.kind === ReflectionKind.method || type.kind === ReflectionKind.methodSignature) return ''; return; diff --git a/packages/api-console-module/dist/.gitkeep b/packages/api-console-module/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/api-console-module/tsconfig.json b/packages/api-console-module/tsconfig.json index e0a06d39d..a25cca570 100644 --- a/packages/api-console-module/tsconfig.json +++ b/packages/api-console-module/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts", diff --git a/packages/app/dist/.gitkeep b/packages/app/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json index d6c24d2a5..6aa87f89c 100644 --- a/packages/app/tsconfig.json +++ b/packages/app/tsconfig.json @@ -17,7 +17,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts" diff --git a/packages/broker/dist/.gitkeep b/packages/broker/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/broker/tsconfig.json b/packages/broker/tsconfig.json index 26320a0aa..33e168255 100644 --- a/packages/broker/tsconfig.json +++ b/packages/broker/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/bson/dist/.gitkeep b/packages/bson/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/bson/src/bson-parser.ts b/packages/bson/src/bson-parser.ts index 07afd522c..2c6574ca3 100644 --- a/packages/bson/src/bson-parser.ts +++ b/packages/bson/src/bson-parser.ts @@ -10,7 +10,7 @@ import { BSON_BINARY_SUBTYPE_BYTE_ARRAY, BSON_BINARY_SUBTYPE_UUID, BSONType, digitByteSize, TWO_PWR_32_DBL_N } from './utils.js'; import { buildStringDecoder, decodeUTF8 } from './strings.js'; -import { nodeBufferToArrayBuffer, ReflectionKind, SerializationError, Type } from '@deepkit/type'; +import { getClassType, nodeBufferToArrayBuffer, ReflectionKind, SerializationError, Type } from '@deepkit/type'; import { hexTable } from './model.js'; declare var Buffer: any; @@ -159,7 +159,7 @@ export class BaseParser { return nodeBufferToArrayBuffer(b); } if (type && type.kind === ReflectionKind.class) { - const typedArrayConstructor = type.classType; + const typedArrayConstructor = getClassType(type); return new typedArrayConstructor(nodeBufferToArrayBuffer(b)); } diff --git a/packages/bson/tsconfig.json b/packages/bson/tsconfig.json index 87fad66a4..66919c3a8 100644 --- a/packages/bson/tsconfig.json +++ b/packages/bson/tsconfig.json @@ -20,7 +20,9 @@ "node" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "benchmarks", "src", diff --git a/packages/bun/dist/.gitkeep b/packages/bun/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/core-rxjs/dist/.gitkeep b/packages/core-rxjs/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index f74ad9daa..c5039a837 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -19,7 +19,9 @@ "dot-prop" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts", diff --git a/packages/create-app/dist/.gitkeep b/packages/create-app/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/create-app/files/tsconfig.json b/packages/create-app/files/tsconfig.json index 3bd236193..1805c27cf 100644 --- a/packages/create-app/files/tsconfig.json +++ b/packages/create-app/files/tsconfig.json @@ -8,7 +8,9 @@ "module": "CommonJS", "moduleResolution": "node" }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "files": [ "client.rpc.ts", "app.ts" diff --git a/packages/create-app/tsconfig.json b/packages/create-app/tsconfig.json index 7b3432dc9..5b31b6f51 100644 --- a/packages/create-app/tsconfig.json +++ b/packages/create-app/tsconfig.json @@ -22,7 +22,9 @@ "main.ts", "index.ts" ], - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "references": [ { "path": "../core/tsconfig.json" diff --git a/packages/event/dist/.gitkeep b/packages/event/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/event/tsconfig.json b/packages/event/tsconfig.json index 30ffe145d..3659a8708 100644 --- a/packages/event/tsconfig.json +++ b/packages/event/tsconfig.json @@ -21,7 +21,9 @@ "tests", "index.ts" ], - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "references": [ { "path": "../core/tsconfig.json" diff --git a/packages/example-app/tsconfig.json b/packages/example-app/tsconfig.json index 0bd71a2fe..39607ca72 100644 --- a/packages/example-app/tsconfig.json +++ b/packages/example-app/tsconfig.json @@ -21,7 +21,9 @@ "ts-node": { "experimentalResolver": true }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "includes": [ "*.ts", "*.tsx" diff --git a/packages/filesystem-aws-s3/dist/.gitkeep b/packages/filesystem-aws-s3/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/filesystem-ftp/dist/.gitkeep b/packages/filesystem-ftp/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/filesystem-google/dist/.gitkeep b/packages/filesystem-google/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/filesystem-sftp/dist/.gitkeep b/packages/filesystem-sftp/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/filesystem/dist/.gitkeep b/packages/filesystem/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/filesystem/tsconfig.json b/packages/filesystem/tsconfig.json index 7ab3cf055..9f54ab341 100644 --- a/packages/filesystem/tsconfig.json +++ b/packages/filesystem/tsconfig.json @@ -21,7 +21,9 @@ "tests", "index.ts" ], - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "references": [ { "path": "../core/tsconfig.json" diff --git a/packages/framework-debug-api/dist/.gitkeep b/packages/framework-debug-api/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/framework-debug-api/tsconfig.json b/packages/framework-debug-api/tsconfig.json index 745d02376..c4a3e40bb 100644 --- a/packages/framework-debug-api/tsconfig.json +++ b/packages/framework-debug-api/tsconfig.json @@ -18,7 +18,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "jsx", diff --git a/packages/framework-examples/dist/.gitkeep b/packages/framework-examples/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/framework-examples/tsconfig.json b/packages/framework-examples/tsconfig.json index eedcc9507..7ad2b937b 100644 --- a/packages/framework-examples/tsconfig.json +++ b/packages/framework-examples/tsconfig.json @@ -19,7 +19,9 @@ "jsxImportSource": "@deepkit/framework", "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "./src/**/*.ts" ], diff --git a/packages/framework-integration/dist/.gitkeep b/packages/framework-integration/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/framework-integration/tsconfig.json b/packages/framework-integration/tsconfig.json index b8f2340b7..eacbdb152 100644 --- a/packages/framework-integration/tsconfig.json +++ b/packages/framework-integration/tsconfig.json @@ -21,7 +21,9 @@ "ws" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "files": [ "tests/util.ts", "tests/controller-basic.spec.ts", diff --git a/packages/framework/dist/.gitkeep b/packages/framework/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/framework/dist/esm/package.json b/packages/framework/dist/esm/package.json deleted file mode 100644 index 6990891ff..000000000 --- a/packages/framework/dist/esm/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "module"} diff --git a/packages/framework/tsconfig.json b/packages/framework/tsconfig.json index 1911566f1..cf3c3deeb 100644 --- a/packages/framework/tsconfig.json +++ b/packages/framework/tsconfig.json @@ -27,7 +27,9 @@ "node" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "jsx", diff --git a/packages/fs/dist/.gitkeep b/packages/fs/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/http/dist/.gitkeep b/packages/http/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/http/tsconfig.json b/packages/http/tsconfig.json index 01eb00aed..35b2418f5 100644 --- a/packages/http/tsconfig.json +++ b/packages/http/tsconfig.json @@ -19,7 +19,9 @@ "send" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/injector/src/injector.ts b/packages/injector/src/injector.ts index 12ba04aeb..c6456048a 100644 --- a/packages/injector/src/injector.ts +++ b/packages/injector/src/injector.ts @@ -13,6 +13,7 @@ import { import { AbstractClassType, ClassType, CompilerContext, CustomError, getClassName, getPathValue, isArray, isClass, isFunction, isPrototypeOfBase } from '@deepkit/core'; import { findModuleForConfig, getScope, InjectorModule, PreparedProvider } from './module.js'; import { + getClassType, hasTypeInformation, isExtendable, isOptional, @@ -26,7 +27,7 @@ import { ReflectionKind, resolveReceiveType, stringifyType, - Type + Type, } from '@deepkit/type'; export class InjectorError extends CustomError { @@ -608,7 +609,7 @@ export class Injector implements InjectorInterface { const destinationVar = compiler.reserveConst({ token: fromProvider.provide }); if (options.type.kind === ReflectionKind.class) { - const found = findModuleForConfig(options.type.classType, resolveDependenciesFrom); + const found = findModuleForConfig(getClassType(options.type), resolveDependenciesFrom); if (found) { return compiler.reserveVariable('fullConfig', getPathValue(found.module.getConfig(), found.path)); } @@ -628,14 +629,14 @@ export class Injector implements InjectorInterface { return compiler.reserveVariable('tagRegistry', this.buildContext.tagRegistry); } - if (options.type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof options.type.classType) { + if (options.type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof getClassType(options.type)) { return compiler.reserveConst(resolveDependenciesFrom[0], 'module'); } if (options.type.kind === ReflectionKind.class && isPrototypeOfBase(options.type.classType, Tag)) { const tokenVar = compiler.reserveVariable('token', options.type.classType); const resolvedVar = compiler.reserveVariable('tagResolved'); - const entries = this.buildContext.tagRegistry.resolve(options.type.classType); + const entries = this.buildContext.tagRegistry.resolve(getClassType(options.type)); const args: string[] = []; for (const entry of entries) { args.push(`${compiler.reserveConst(entry.module)}.injector.resolver(${compiler.reserveConst(getContainerToken(entry.tagProvider.provider.provide))}, scope, ${destinationVar})`); @@ -654,7 +655,7 @@ export class Injector implements InjectorInterface { const pickArguments = getPickArguments(options.type); if (pickArguments) { if (pickArguments[0].kind === ReflectionKind.class) { - const found = findModuleForConfig(pickArguments[0].classType, resolveDependenciesFrom); + const found = findModuleForConfig(getClassType(pickArguments[0]), resolveDependenciesFrom); if (found) { const fullConfig = compiler.reserveVariable('fullConfig', getPathValue(found.module.getConfig(), found.path)); let index = pickArguments[1]; @@ -685,7 +686,7 @@ export class Injector implements InjectorInterface { while (current && current.indexAccessOrigin) { let found: { module: InjectorModule, path: string } | undefined = undefined; if (current.indexAccessOrigin.container.kind === ReflectionKind.class) { - found = findModuleForConfig(current.indexAccessOrigin.container.classType, resolveDependenciesFrom); + found = findModuleForConfig(getClassType(current.indexAccessOrigin.container), resolveDependenciesFrom); } if (current.indexAccessOrigin.index.kind === ReflectionKind.literal) { accesses.unshift(`[${JSON.stringify(current.indexAccessOrigin.index.literal)}]`); @@ -777,24 +778,24 @@ export class Injector implements InjectorInterface { // } if (type.kind === ReflectionKind.class) { - const found = findModuleForConfig(type.classType, resolveDependenciesFrom); + const found = findModuleForConfig(getClassType(type), resolveDependenciesFrom); if (found) return () => getPathValue(found.module.getConfig(), found.path); } if (type.kind === ReflectionKind.class && type.classType === TagRegistry) return () => this.buildContext.tagRegistry; - if (type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof type.classType) { + if (type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof getClassType(type)) { return () => resolveDependenciesFrom[0]; } if (type.kind === ReflectionKind.class && isPrototypeOfBase(type.classType, Tag)) { - const entries = this.buildContext.tagRegistry.resolve(type.classType); + const entries = this.buildContext.tagRegistry.resolve(getClassType(type)); const args: any[] = []; for (const entry of entries) { args.push(entry.module.injector!.resolver!(entry.tagProvider.provider.provide, scope)); } - return new type.classType(args); + return new (getClassType(type))(args); } if (type.kind === ReflectionKind.function && type.typeName === 'PartialFactory') { @@ -808,7 +809,7 @@ export class Injector implements InjectorInterface { const pickArguments = getPickArguments(type); if (pickArguments) { if (pickArguments[0].kind === ReflectionKind.class) { - const found = findModuleForConfig(pickArguments[0].classType, resolveDependenciesFrom); + const found = findModuleForConfig(getClassType(pickArguments[0]), resolveDependenciesFrom); if (found) { const fullConfig = getPathValue(found.module.getConfig(), found.path); let index = pickArguments[1]; @@ -837,7 +838,7 @@ export class Injector implements InjectorInterface { while (current && current.indexAccessOrigin) { if (current.indexAccessOrigin.container.kind === ReflectionKind.class) { - const found = findModuleForConfig(current.indexAccessOrigin.container.classType, resolveDependenciesFrom); + const found = findModuleForConfig(getClassType(current.indexAccessOrigin.container), resolveDependenciesFrom); if (!found) return () => undefined; config = getPathValue(found.module.getConfig(), found.path); } @@ -1026,7 +1027,7 @@ export function partialFactory( } if (type.kind === ReflectionKind.class) { - const classType = type.classType; + const classType = getClassType(type); const reflectionClass = ReflectionClass.from(classType); const args: { name: string; resolve: (scope?: Scope) => ReturnType> }[] = []; diff --git a/packages/injector/src/types.ts b/packages/injector/src/types.ts index ad01d226c..f5bb7b051 100644 --- a/packages/injector/src/types.ts +++ b/packages/injector/src/types.ts @@ -1,4 +1,4 @@ -import { reflect, ReflectionKind, Type } from '@deepkit/type'; +import { getClassType, reflect, ReflectionKind, Type } from '@deepkit/type'; import { getParentClass } from '@deepkit/core'; export type InjectMeta = { __meta?: never & ['inject', T] } @@ -47,7 +47,7 @@ export function nominalCompatibility(token: Type, provider: Type): number { } if (current.kind === ReflectionKind.class) { - const parent = getParentClass(current.classType); + const parent = getParentClass(getClassType(current)); if (parent && (parent as any).__type) { const next = reflect(parent); stack.push({ spec: entry.spec + 1, type: next }); diff --git a/packages/injector/tsconfig.json b/packages/injector/tsconfig.json index b022b4259..ae29aba68 100644 --- a/packages/injector/tsconfig.json +++ b/packages/injector/tsconfig.json @@ -17,7 +17,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/logger/dist/.gitkeep b/packages/logger/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/logger/tsconfig.json b/packages/logger/tsconfig.json index e952a3e2d..2d9cc8c06 100644 --- a/packages/logger/tsconfig.json +++ b/packages/logger/tsconfig.json @@ -18,7 +18,9 @@ "format-util" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/mongo/tsconfig.json b/packages/mongo/tsconfig.json index 2c6ebae36..b51fd3da6 100644 --- a/packages/mongo/tsconfig.json +++ b/packages/mongo/tsconfig.json @@ -21,7 +21,9 @@ "node" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts" diff --git a/packages/mysql/dist/.gitkeep b/packages/mysql/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-browser-api/dist/.gitkeep b/packages/orm-browser-api/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-browser-api/tsconfig.json b/packages/orm-browser-api/tsconfig.json index 80b68585c..4d0dafa60 100644 --- a/packages/orm-browser-api/tsconfig.json +++ b/packages/orm-browser-api/tsconfig.json @@ -17,7 +17,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "jsx", diff --git a/packages/orm-browser-example/dist/.gitkeep b/packages/orm-browser-example/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-browser-example/tsconfig.json b/packages/orm-browser-example/tsconfig.json index c7c18c9e5..0aa922920 100644 --- a/packages/orm-browser-example/tsconfig.json +++ b/packages/orm-browser-example/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "database.ts", "./bookstore/*ts" diff --git a/packages/orm-browser-gui/dist/.gitkeep b/packages/orm-browser-gui/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-browser-gui/src/app/registry.ts b/packages/orm-browser-gui/src/app/registry.ts index 4f5f0e31e..4d47f1cbe 100644 --- a/packages/orm-browser-gui/src/app/registry.ts +++ b/packages/orm-browser-gui/src/app/registry.ts @@ -1,5 +1,5 @@ import { ClassType, getClassName } from '@deepkit/core'; -import { isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; +import { getClassType, isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; import { ClassCellComponent } from './components/cell/class-cell.component'; import { DateCellComponent } from './components/cell/date-cell.component'; import { EnumCellComponent } from './components/cell/enum-cell.component'; @@ -43,7 +43,7 @@ inputRegistry.set(isMongoIdType, StringInputComponent); // return isMapType(type); // }, MapInputComponent); inputRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; }, BinaryInputComponent); @@ -81,5 +81,5 @@ cellRegistry.set(isMongoIdType, StringCellComponent); // return isMapType(type); // }, MapCellComponent); cellRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; }, BinaryCellComponent); diff --git a/packages/orm-browser/dist/.gitkeep b/packages/orm-browser/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-browser/tsconfig.json b/packages/orm-browser/tsconfig.json index 189879367..9c2a49cf2 100644 --- a/packages/orm-browser/tsconfig.json +++ b/packages/orm-browser/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts" diff --git a/packages/orm-integration/dist/.gitkeep b/packages/orm-integration/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm-integration/tsconfig.json b/packages/orm-integration/tsconfig.json index dd78b96f3..06a38bd51 100644 --- a/packages/orm-integration/tsconfig.json +++ b/packages/orm-integration/tsconfig.json @@ -17,7 +17,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts" diff --git a/packages/orm/dist/.gitkeep b/packages/orm/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/orm/tsconfig.json b/packages/orm/tsconfig.json index 5d36efa3b..0b264e2ba 100644 --- a/packages/orm/tsconfig.json +++ b/packages/orm/tsconfig.json @@ -18,7 +18,9 @@ "sqlstring" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/postgres/dist/.gitkeep b/packages/postgres/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/rpc-tcp/dist/.gitkeep b/packages/rpc-tcp/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/rpc/dist/.gitkeep b/packages/rpc/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/rpc/tsconfig.json b/packages/rpc/tsconfig.json index d6509cac2..27f802516 100644 --- a/packages/rpc/tsconfig.json +++ b/packages/rpc/tsconfig.json @@ -20,7 +20,9 @@ "node" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "index.ts" diff --git a/packages/skeleton/dist/.gitkeep b/packages/skeleton/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/sql/dist/.gitkeep b/packages/sql/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/sql/src/platform/default-platform.ts b/packages/sql/src/platform/default-platform.ts index 27b6cc65e..a65a7a40b 100644 --- a/packages/sql/src/platform/default-platform.ts +++ b/packages/sql/src/platform/default-platform.ts @@ -17,7 +17,7 @@ import { SQLFilterBuilder } from '../sql-filter-builder.js'; import { Sql } from '../sql-builder.js'; import { binaryTypes, - databaseAnnotation, + databaseAnnotation, getClassType, getTypeJitContainer, isReferenceType, ReflectionClass, @@ -26,7 +26,7 @@ import { resolvePath, resolveProperty, Serializer, - Type + Type, } from '@deepkit/type'; import { DatabaseEntityRegistry, MigrateOptions } from '@deepkit/orm'; import { splitDotPath } from '../sql-adapter.js'; @@ -130,7 +130,7 @@ export abstract class DefaultPlatform { addBinaryType(sqlType: string, size?: number, scale?: number) { this.addType((type: Type) => { - return type.kind === ReflectionKind.class && binaryTypes.includes(type.classType); + return type.kind === ReflectionKind.class && binaryTypes.includes(getClassType(type)); }, sqlType, size, scale); } diff --git a/packages/sql/tsconfig.json b/packages/sql/tsconfig.json index 36b2f15ed..d1913af7c 100644 --- a/packages/sql/tsconfig.json +++ b/packages/sql/tsconfig.json @@ -19,7 +19,9 @@ "sqlstring" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "benchmarks", "src", diff --git a/packages/sqlite/dist/.gitkeep b/packages/sqlite/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/stopwatch/dist/.gitkeep b/packages/stopwatch/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/stopwatch/tsconfig.json b/packages/stopwatch/tsconfig.json index de8cee768..791e5bebb 100644 --- a/packages/stopwatch/tsconfig.json +++ b/packages/stopwatch/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/template/dist/.gitkeep b/packages/template/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/template/tsconfig.json b/packages/template/tsconfig.json index d28903c3b..81d48ed81 100644 --- a/packages/template/tsconfig.json +++ b/packages/template/tsconfig.json @@ -18,7 +18,9 @@ "jsxImportSource": "..", "types": ["estree"] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/topsort/dist/.gitkeep b/packages/topsort/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/type-angular/dist/.gitkeep b/packages/type-angular/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/type-compiler/tsconfig.json b/packages/type-compiler/tsconfig.json index b2700c9ae..95c75a39d 100644 --- a/packages/type-compiler/tsconfig.json +++ b/packages/type-compiler/tsconfig.json @@ -16,7 +16,8 @@ "composite": true, "types": [ "lz-string", - "micromatch" + "micromatch", + "node" ] }, "include": [ @@ -26,6 +27,7 @@ "compiler-debug.ts", "index.ts" ], + "exclude": ["tests"], "references": [ { "path": "../type-spec/tsconfig.json" diff --git a/packages/type/tsconfig.json b/packages/type/tsconfig.json index 87ef3c066..67043b0b5 100644 --- a/packages/type/tsconfig.json +++ b/packages/type/tsconfig.json @@ -20,7 +20,9 @@ "node" ] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", diff --git a/packages/vite/dist/.gitkeep b/packages/vite/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/workflow/dist/.gitkeep b/packages/workflow/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/workflow/tsconfig.json b/packages/workflow/tsconfig.json index 37c3201ef..1fd6456c9 100644 --- a/packages/workflow/tsconfig.json +++ b/packages/workflow/tsconfig.json @@ -16,7 +16,9 @@ "composite": true, "types": [] }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "include": [ "src", "tests", From f16b6e460d8f1aaa4c20ba50889623e12d5ce237 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 01:16:07 +0100 Subject: [PATCH 12/23] save --- packages/type-compiler/dist/.gitkeep | 0 packages/type-compiler/src/compiler.ts | 62 ++--- packages/type-compiler/src/external.ts | 3 +- packages/type-compiler/src/reflection-ast.ts | 5 + .../inline-external-library-imports.spec.ts | 214 ++++++++++++------ .../tests/setup/suite1/tsconfig.json | 4 +- packages/type/dist/.gitkeep | 0 packages/type/src/default.ts | 5 +- packages/type/src/reference.ts | 4 +- packages/type/src/reflection/extends.ts | 6 +- packages/type/src/reflection/processor.ts | 14 +- packages/type/src/reflection/reflection.ts | 4 +- packages/type/src/reflection/type.ts | 32 ++- packages/type/src/registry.ts | 6 +- packages/type/src/serializer.ts | 8 +- packages/type/src/type-serialization.ts | 9 +- .../type/tests/type-serialization.spec.ts | 16 +- packages/type/tests/typedarray.spec.ts | 4 +- 18 files changed, 257 insertions(+), 139 deletions(-) delete mode 100644 packages/type-compiler/dist/.gitkeep delete mode 100644 packages/type/dist/.gitkeep diff --git a/packages/type-compiler/dist/.gitkeep b/packages/type-compiler/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 09d759bb1..5884ad2d1 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -82,7 +82,7 @@ import { getNameAsString, getPropertyName, getRuntimeTypeName, - hasModifier, + hasModifier, hasSourceFile, isBuiltType, isNodeWithLocals, NodeConverter, @@ -465,7 +465,7 @@ class CompilerProgram { return frame.variables.length - 1; } - pushTemplateParameter(name: string, withDefault: boolean = false): number { + pushTemplateParameter(name: string, withDefault: boolean = false): number { this.pushOp(withDefault ? ReflectionOp.typeParameterDefault : ReflectionOp.typeParameter, this.findOrAddStackEntry(name)); this.frame.variables.push({ index: this.frame.variables.length, @@ -1343,11 +1343,11 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as ClassDeclaration | ClassExpression; //class nodes have always their own program, so the start is always fresh, means we don't need a frame - if (this.external.isEmbeddingExternalLibraryImport()) { + /*if (this.external.isEmbeddingExternalLibraryImport()) { const declaration = this.nodeConverter.convertClassToInterface(narrowed); this.extractPackStructOfType(declaration, program); break; - } + }*/ if (node) { const members: ClassElement[] = []; @@ -1363,7 +1363,7 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (narrowed.heritageClauses) { + if (!this.external.isEmbeddingExternalLibraryImport() && narrowed.heritageClauses) { for (const heritage of narrowed.heritageClauses) { if (heritage.token === SyntaxKind.ExtendsKeyword) { for (const extendType of heritage.types) { @@ -1394,7 +1394,8 @@ export class ReflectionTransformer implements CustomTransformer { this.extractPackStructOfType(member, program); } - program.pushOp(ReflectionOp.class); + program.pushOp(ReflectionOp.class) + // program.pushOp(!this.external.isEmbeddingExternalLibraryImport() ? ReflectionOp.class : ReflectionOp.objectLiteral); if (narrowed.heritageClauses) { for (const heritageClause of narrowed.heritageClauses) { @@ -1416,7 +1417,9 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (narrowed.name) this.resolveTypeName(getIdentifierName(narrowed.name), program); + if (narrowed.name) { + this.resolveTypeName(getIdentifierName(narrowed.name), program); + } const description = extractJSDocAttribute(narrowed, 'description'); if (description) program.pushOp(ReflectionOp.description, program.findOrAddStackEntry(description)); @@ -1696,10 +1699,6 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorTypeNode | ConstructSignatureDeclaration | ConstructorDeclaration | ArrowFunction | FunctionExpression | FunctionTypeNode | FunctionDeclaration; - if(this.external.isEmbeddingExternalLibraryImport() && (isFunctionDeclaration(node) || isFunctionExpression(node) || isMethodDeclaration(node))) { - console.log(getNameAsString(narrowed.name)); - } - const config = this.findReflectionConfig(narrowed, program); if (config.mode === 'never') return; @@ -2034,7 +2033,7 @@ export class ReflectionTransformer implements CustomTransformer { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); //might be an external library - if (!declaration) { + if (!declaration && hasSourceFile(importDeclaration)) { sourceFile = importDeclaration.getSourceFile(); declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, sourceFile); } @@ -2096,6 +2095,7 @@ export class ReflectionTransformer implements CustomTransformer { // check if the referenced declaration has reflection disabled const declarationReflection = this.findReflectionConfig(declaration, program); if (declarationReflection.mode !== 'never') { + if (!hasSourceFile(importDeclaration)) return expression; const declarationSourceFile = importDeclaration.getSourceFile(); const runtimeTypeName = this.getRuntimeTypeName(typeName); @@ -2106,10 +2106,11 @@ export class ReflectionTransformer implements CustomTransformer { if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { const { module } = this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); - const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); - return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) - ? this.wrapWithAssignType(expression, newExpression) - : newExpression + return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); + // const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); + // return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) + // ? this.wrapWithAssignType(expression, newExpression) + // : newExpression } } @@ -2215,7 +2216,6 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - console.log(2, getNameAsString(typeName)); expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } @@ -2309,19 +2309,20 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const builtType = isBuiltType(runtimeTypeName, found); - if (!builtType) { - if (!this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) return; - this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + const reflection = this.findReflectionFromPath(found.fileName); + if (reflection.mode !== 'never') { + this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); + return; } else { - //check if the referenced file has reflection info emitted. if not, any is emitted for that reference - const reflection = this.findReflectionFromPath(found.fileName); - if (reflection.mode === 'never') { - program.pushOp(ReflectionOp.any); - return; + const builtType = isBuiltType(runtimeTypeName, found); + if (!builtType) { + if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + } else { + program.pushOp(ReflectionOp.any); + return; + } } - - this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); } } } else { @@ -2384,14 +2385,15 @@ export class ReflectionTransformer implements CustomTransformer { this.extractPackStructOfType(typeArgument, program); } } - if (this.external.isEmbeddingExternalLibraryImport()) { + /*if (this.external.isEmbeddingExternalLibraryImport()) { if (isClassDeclaration(declaration)) { program.pushOp(ReflectionOp.objectLiteral); } else { const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); program.pushOp(ReflectionOp.function, index); } - } else { + this.resolveTypeName(getNameAsString(typeName), program); + } else */{ const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); } diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index 5cb076e4f..6e27ff491 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -8,7 +8,7 @@ const { isStringLiteral, } = ts; -import { getEntityName, getNameAsString } from './reflection-ast.js'; +import { getEntityName, getNameAsString, hasSourceFile } from './reflection-ast.js'; import { ReflectionConfig } from './compiler.js'; import { Resolver } from './resolver.js'; @@ -68,6 +68,7 @@ export class External { public shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; + if (!hasSourceFile(importDeclaration)) return false; if (config.options.inlineExternalLibraryImports === true) return true; const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index bbc4c6485..e5d1e3535 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -64,6 +64,10 @@ export function getIdentifierName(node: Identifier | PrivateIdentifier): string return ts.unescapeLeadingUnderscores(node.escapedText); } +export function hasSourceFile(node: Node): boolean { + return typeof node.getSourceFile === 'function'; +} + export function joinQualifiedName(name: EntityName): string { if (isIdentifier(name)) return getIdentifierName(name); return joinQualifiedName(name.left) + '_' + getIdentifierName(name.right); @@ -162,6 +166,7 @@ export class NodeConverter { node.type, ); } else if (isConstructorDeclaration(node)) { + // return this.f.createm return this.f.createConstructSignature(node.typeParameters, node.parameters, node.type); } diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index 33ad23047..b559cb6d4 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -1,6 +1,5 @@ import { test, expect } from '@jest/globals'; -import { ReflectionKind, TypeClass, TypeFunction } from '@deepkit/type'; -import { Unsubscribable } from 'rxjs'; +import {ReflectionKind, TypeClass, TypeFunction, } from '@deepkit/type'; import { transpile, transpileAndRun } from './utils'; @@ -163,8 +162,6 @@ test('function type alias', () => { expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); }); -import { map } from 'rxjs'; - test('typeOf function type alias', () => { const res = transpileAndRun({ app: `import { map } from 'rxjs'; @@ -197,17 +194,17 @@ test('typeOf function type alias', () => { "parameters": [Circular], "return": { "annotations": {}, - "id": 6, + "id": 4, "implements": [ { "annotations": {}, - "id": 4, + "id": 2, "kind": 30, "typeArguments": [ { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": { "kind": 18, "name": "source", @@ -218,21 +215,31 @@ test('typeOf function type alias', () => { ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, "type": [Circular], }, + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": { "kind": 35, "parameters": [ @@ -241,10 +248,15 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -252,6 +264,11 @@ test('typeOf function type alias', () => { "parent": [Circular], "return": [Circular], }, + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, ], @@ -265,20 +282,30 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -305,20 +332,30 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -359,17 +396,17 @@ test('typeOf function type alias', () => { ], "return": { "annotations": {}, - "id": 6, + "id": 4, "implements": [ { "annotations": {}, - "id": 4, + "id": 2, "kind": 30, "typeArguments": [ { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": { "kind": 18, "name": "source", @@ -380,21 +417,31 @@ test('typeOf function type alias', () => { ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, "type": [Circular], }, + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": { "kind": 35, "parameters": [ @@ -403,10 +450,15 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -414,6 +466,11 @@ test('typeOf function type alias', () => { "parent": [Circular], "return": [Circular], }, + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, ], @@ -427,20 +484,30 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -509,20 +576,30 @@ test('typeOf function type alias', () => { "name": "source", "parent": [Circular], "type": { - "annotations": {}, - "id": 1, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, ], "parent": [Circular], "return": { - "annotations": {}, - "id": 2, - "kind": 30, + "classType": undefined, + "external": true, + "kind": 20, "parent": [Circular], + "typeArguments": [ + { + "kind": 1, + }, + ], "types": [], }, }, @@ -549,19 +626,17 @@ test('class type var', () => { ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const __ɵΩrxjs = {}; -__ɵΩrxjs.Observable = ['source', () => __ɵΩrxjs.Operator, 'operator', 'this', 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'new', 'args', 'create', () => __ɵΩrxjs.Operator, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', 'value', 'next', 'error', 'complete', 'forEach', () => __ΩPromiseConstructorLike, 'promiseCtor', 'pipe', () => __ɵΩrxjs.OperatorFunction, 'op1', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op2', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op3', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op4', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op5', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op6', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op7', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op8', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'op9', () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, () => __ɵΩrxjs.OperatorFunction, 'operations', 'toPromise', () => Promise, 'PromiseCtor', () => __ΩPromiseConstructorLike, 'PPP"M-J4!P"!o"#-J4#PPP!M2$P!M2%n&/\\'2(8"1)P"@2*"/\\'4+P!"o,#2#8P"M1-P!o/"o."208PM1(PP!21$/\\'22PM1(PPP!21$/\\',J228PP"23$/\\',J238PP$/\\',J248PM1(PP!21$/\\'22$\`15PP!21$/\\'22n627$\`15PP!M18P!"o9#2:P"M18P!"o;#2:""o<#2=P"M18P!"o>#2:""o?#2=""o@#2AP"M18P!"oB#2:""oC#2=""oD#2A""oE#2FP"M18P!"oG#2:""oH#2=""oI#2A""oJ#2F""oK#2LP"M18P!"oM#2:""oN#2=""oO#2A""oP#2F""oQ#2L""oR#2SP"M18P!"oT#2:""oU#2=""oV#2A""oW#2F""oX#2L""oY#2S""oZ#2[P"M18P!"o\\\\#2:""o]#2=""o^#2A""o_#2F""o\`#2L""oa#2S""ob#2[""oc#2dP"M18P!"oe#2:""of#2=""og#2A""oh#2F""oi#2L""oj#2S""ok#2[""ol#2d""om#2nP"M18P!"oo#2:""op#2=""oq#2A""or#2F""os#2L""ot#2S""ou#2[""ov#2d""ow#2n""ox#@2yP#M18PP!-J\`1zPi{2|P!-J\`1zPn}2|P!-J\`1zMy']; +__ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; -const __ΩPromiseConstructorLike = [() => __ΩPromiseLike, 'value', '', 'resolve', 'reason', 'reject', 'executor', () => __ΩPromiseLike, 'new', 'PPPP""o!"J2"$/#2$P"2%8$/#2&$/#2\\'"o("/)y']; -__ɵΩrxjs.Operator = ['T', 'R', 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"M2#"2$n%1&My']; -__ɵΩrxjs.Subscriber = ['x', '', 'next', 'e', 'error', 'complete', 'create', 'isStopped', () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Observer, 'new', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', 'PPMPP"2!8$/"2#8P"2$8$/"2%8P$/"2&8P"M1\\')4(PP"M"o)"J4*PPP"M"o+"J2*8"1,P!2-8$1#P"2.8$1%P$1&P$1/P!2-$10P"2.$11P$12My']; -__ɵΩrxjs.TeardownLogic = [() => __ɵΩrxjs.Unsubscribable, '', 'PPMn!P$/"$Jy']; +__ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; +__ɵΩrxjs.Subscriber = ['T', 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!PPe#!2"8$/#2$8P"2%8$/#2&8P$/#2\\'8Pe#!7(0)s)3* __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; -__ɵΩrxjs.Subscription = ['EMPTY', 'closed', '', 'initialTeardown', 'new', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', 'PPM4!)4"PPP$/#-J2$8"1%P$1&Pn\\'2($1)Pn+$o*#2($1,My']; -__ɵΩrxjs.OperatorFunction = ['T', 'R', () => __ɵΩrxjs.UnaryFunction, 'b!b"PPe#!MPe#"Mo##My']; -const __ΩPromiseLike = ['T', 'value', 0, '', 'onfulfilled', 'reason', 0, 'onrejected', 0, 'then', 'b!PPPPe%!2"P""o#"J/$-,J2%8PP"2&P""o\\'"J/$-,J2(8P""Jo)"1*My']; +__ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; +__ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; -__ɵΩrxjs.UnaryFunction = ['T', 'R', 'source', '', 'b!b"PPe#!2#e#"v$My']; +__ɵΩrxjs.SubscriptionLike = [() => __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; function __assignType(fn, args) { fn.__type = args; return fn; @@ -605,13 +680,18 @@ test('class typeOf', () => { console.log(res); + expect(res).toMatchObject({ + external: true, + classType: undefined, + }); + expect(res.implements![0]).toMatchObject({ kind: 30, typeName: 'Subscribable', // typeName: 'UnknownTypeName:() => __ɵΩrxjs.Subscribable', }); - expect(res.typeArguments).toHaveLength(1); - expect(res.types).toHaveLength(1); + // expect(res.typeArguments).toHaveLength(1); + // expect(res.types).toHaveLength(1); }) test('only a single type is transformed', () => { diff --git a/packages/type-compiler/tests/setup/suite1/tsconfig.json b/packages/type-compiler/tests/setup/suite1/tsconfig.json index d234bc79a..f2f76c67c 100644 --- a/packages/type-compiler/tests/setup/suite1/tsconfig.json +++ b/packages/type-compiler/tests/setup/suite1/tsconfig.json @@ -6,7 +6,9 @@ "module": "CommonJS", "esModuleInterop": true }, - "reflection": true, + "deepkitTypeCompilerOptions": { + "reflection": true + }, "files": [ "app.ts" ] diff --git a/packages/type/dist/.gitkeep b/packages/type/dist/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/type/src/default.ts b/packages/type/src/default.ts index 4671b16a3..b0507b3a5 100644 --- a/packages/type/src/default.ts +++ b/packages/type/src/default.ts @@ -1,4 +1,5 @@ -import { binaryTypes, ReflectionKind, resolveTypeMembers, Type } from './reflection/type.js'; +import { binaryTypes, getClassType, ReflectionKind, resolveTypeMembers, Type } from './reflection/type.js'; +import { ClassType } from '@deepkit/core'; /** * Returns a sensible default value for a given type. @@ -71,7 +72,7 @@ export function defaultValue(type: Type): any { if (type.classType === Date) return new Date; if (type.classType === Set) return new Set; if (type.classType === Map) return new Map; - if (binaryTypes.includes(type.classType)) return new type.classType; + if (binaryTypes.includes(getClassType(type))) return new (getClassType(type)); const result: any = {}; const types = resolveTypeMembers(type); diff --git a/packages/type/src/reference.ts b/packages/type/src/reference.ts index e3cac5a5c..a728777fe 100644 --- a/packages/type/src/reference.ts +++ b/packages/type/src/reference.ts @@ -11,7 +11,7 @@ import { ClassType, isObject } from '@deepkit/core'; import { ReflectionClass, reflectionClassSymbol } from './reflection/reflection.js'; import { typeSettings, UnpopulatedCheck, unpopulatedSymbol } from './core.js'; -import { ReflectionKind, Type } from './reflection/type.js'; +import { getClassType, ReflectionKind, Type } from './reflection/type.js'; export function isReferenceInstance(obj: any): boolean { return isObject(obj) && referenceSymbol in obj; @@ -71,7 +71,7 @@ export function createReferenceClass( ): ClassType { if (reflection.data.referenceClass) return reflection.data.referenceClass; - const Reference = reflection.type.kind === ReflectionKind.class ? class extends reflection.type.classType { + const Reference = reflection.type.kind === ReflectionKind.class ? class extends getClassType(reflection.type) { } : class { }; diff --git a/packages/type/src/reflection/extends.ts b/packages/type/src/reflection/extends.ts index 18264a3a1..81c9e0e99 100644 --- a/packages/type/src/reflection/extends.ts +++ b/packages/type/src/reflection/extends.ts @@ -11,7 +11,7 @@ import { addType, emptyObject, - flatten, getTypeJitContainer, + flatten, getClassType, getTypeJitContainer, indexAccess, isMember, isOptional, @@ -33,7 +33,7 @@ import { TypeString, TypeTemplateLiteral, TypeTuple, - TypeUnion + TypeUnion, } from './type.js'; import { isPrototypeOfBase } from '@deepkit/core'; import { typeInfer } from './processor.js'; @@ -274,7 +274,7 @@ export function _isExtendable(left: Type, right: Type, extendStack: StackEntry[] //class User extends Base {} //User extends Base = true if (left.classType === right.classType) return true; - return isPrototypeOfBase(left.classType, right.classType); + return isPrototypeOfBase(left.classType, getClassType(right)); } return true; diff --git a/packages/type/src/reflection/processor.ts b/packages/type/src/reflection/processor.ts index 4bbd85d39..2163f5269 100644 --- a/packages/type/src/reflection/processor.ts +++ b/packages/type/src/reflection/processor.ts @@ -590,7 +590,7 @@ export class Processor { break; case ReflectionOp.class: { const types = this.popFrame() as Type[]; - let t = { kind: ReflectionKind.class, id: state.nominalId++, classType: Object, types: [] } as TypeClass; + let t = { kind: ReflectionKind.class, id: state.nominalId++, types: [] } as TypeClass; function add(member: Type) { if (member.kind === ReflectionKind.propertySignature) { @@ -669,6 +669,8 @@ export class Processor { if (args.length) t.arguments = args; t.typeArguments = program.typeParameters; + console.log('class', t); + this.pushType(t); break; } @@ -712,13 +714,16 @@ export class Processor { case ReflectionOp.classReference: { const ref = this.eatParameter() as number; const classOrFunction = resolveFunction(program.stack[ref] as Function, program.object); + const external = isPack(classOrFunction); const inputs = this.popFrame() as Type[]; if (!classOrFunction) { this.pushType({ kind: ReflectionKind.unknown }); break; } - if (!classOrFunction.__type) { + const runtimeType = external ? classOrFunction : classOrFunction.__type; + + if (!runtimeType) { if (op === ReflectionOp.classReference) { this.pushType({ kind: ReflectionKind.class, classType: classOrFunction, typeArguments: inputs, types: [] }); } else if (op === ReflectionOp.functionReference) { @@ -727,7 +732,7 @@ export class Processor { } else { //when it's just a simple reference resolution like typeOf() then enable cache re-use (so always the same type is returned) const directReference = !!(this.isEnded() && program.previous && program.previous.end === 0); - const result = this.reflect(classOrFunction, inputs, { inline: !directReference, reuseCached: directReference }); + const result = this.reflect(runtimeType, inputs, { inline: !directReference, reuseCached: directReference }); if (directReference) program.directReturn = true; this.push(result, program); @@ -1284,7 +1289,7 @@ export class Processor { if (isType(result)) { if (program.object) { if (result.kind === ReflectionKind.class && result.classType === Object) { - result.classType = program.object; + // result.classType = program.object; applyClassDecorators(result); } if (result.kind === ReflectionKind.function && !result.function) { @@ -1778,7 +1783,6 @@ export function typeInfer(value: any): Type { } if (isClass(value)) { - //unknown class return { kind: ReflectionKind.class, classType: value as ClassType, types: [] }; } diff --git a/packages/type/src/reflection/reflection.ts b/packages/type/src/reflection/reflection.ts index 4c48cb7d4..a68d6eb1c 100644 --- a/packages/type/src/reflection/reflection.ts +++ b/packages/type/src/reflection/reflection.ts @@ -983,7 +983,7 @@ export class ReflectionClass { } getClassType(): ClassType { - return this.type.kind === ReflectionKind.class ? this.type.classType : Object; + return this.type.kind === ReflectionKind.class ? getClassType(this.type) : Object; } getClassName(): string { @@ -1233,7 +1233,7 @@ export class ReflectionClass { if (classTypeIn.kind !== ReflectionKind.class) throw new Error(`TypeClass or TypeObjectLiteral expected, not ${ReflectionKind[classTypeIn.kind]}`); } - const classType = isType(classTypeIn) ? (classTypeIn as TypeClass).classType : (classTypeIn as any)['prototype'] ? classTypeIn as ClassType : classTypeIn.constructor as ClassType; + const classType = isType(classTypeIn) ? getClassType(classTypeIn) : (classTypeIn as any)['prototype'] ? classTypeIn as ClassType : classTypeIn.constructor as ClassType; if (!classType.prototype.hasOwnProperty(reflectionClassSymbol)) { Object.defineProperty(classType.prototype, reflectionClassSymbol, { writable: true, enumerable: false }); diff --git a/packages/type/src/reflection/type.ts b/packages/type/src/reflection/type.ts index c188814e3..914480023 100644 --- a/packages/type/src/reflection/type.ts +++ b/packages/type/src/reflection/type.ts @@ -8,7 +8,17 @@ * You should have received a copy of the MIT License along with this program. */ -import { AbstractClassType, arrayRemoveItem, ClassType, getClassName, getParentClass, indent, isArray, isClass } from '@deepkit/core'; +import { + AbstractClassType, + arrayRemoveItem, + ClassType, + getClassName, + getParentClass, + indent, + isArray, + isClass, + isFunction, +} from '@deepkit/core'; import { TypeNumberBrand } from '@deepkit/type-spec'; import { getProperty, ReceiveType, reflect, ReflectionClass, resolveReceiveType, toSignature } from './reflection.js'; import { isExtendable } from './extends.js'; @@ -69,6 +79,8 @@ export enum ReflectionKind { infer, callSignature, + + externalClass, } export type TypeDecorator = (annotations: Annotations, decorator: TypeObjectLiteral) => boolean; @@ -307,6 +319,7 @@ export interface TypeFunction extends TypeAnnotations { parent?: Type; name?: number | string | symbol, description?: string; + external?: boolean; function?: Function; //reference to the real function if available parameters: TypeParameter[]; return: Type; @@ -328,7 +341,8 @@ export interface TypePromise extends TypeAnnotations { export interface TypeClass extends TypeAnnotations { kind: ReflectionKind.class, parent?: Type; - classType: ClassType; + external?: boolean; + classType?: ClassType; // reference to the real class if available description?: string; /** @@ -510,8 +524,7 @@ export type Type = | TypeTupleMember | TypeRest | TypeRegexp - | TypeCallSignature - ; + | TypeCallSignature; export type Widen = T extends string ? string @@ -540,7 +553,7 @@ export function isType(entry: any): entry is Type { } export function isBinary(type: Type): boolean { - return type.kind === ReflectionKind.class && binaryTypes.includes(type.classType); + return type.kind === ReflectionKind.class && binaryTypes.includes(getClassType(type)); } export function isPrimitive(type: T): boolean { @@ -1331,6 +1344,9 @@ export function assertType(t: Type | undefined, kin export function getClassType(type: Type): ClassType { if (type.kind !== ReflectionKind.class) throw new Error(`Type needs to be TypeClass, but ${ReflectionKind[type.kind]} given.`); + if (!type.classType) { + throw new Error('TypeClass is missing classType'); + } return type.classType; } @@ -2265,6 +2281,9 @@ export const binaryTypes: ClassType[] = [ */ export function isGlobalTypeClass(type: Type): type is TypeClass { if (type.kind !== ReflectionKind.class) return false; + if (!type.classType) { + throw new Error('TypeClass is missing classType'); + } if ('undefined' !== typeof window) { return (window as any)[getClassName(type.classType)] === type.classType; } @@ -2478,6 +2497,9 @@ export function stringifyType(type: Type, stateIn: Partial stack.push({ type: type.arguments![0], depth: depth + 1 }); break; } + + if (!type.classType) break; + if (binaryTypes.includes(type.classType)) { result.push(getClassName(type.classType)); break; diff --git a/packages/type/src/registry.ts b/packages/type/src/registry.ts index 772f40ba9..98d6fbd70 100644 --- a/packages/type/src/registry.ts +++ b/packages/type/src/registry.ts @@ -1,5 +1,5 @@ import { ClassType, isArray, isFunction } from '@deepkit/core'; -import { binaryTypes, ReflectionKind, Type } from './reflection/type.js'; +import { binaryTypes, getClassType, ReflectionKind, Type } from './reflection/type.js'; interface RegistryDecorator { predicate: (type: Type) => boolean, @@ -22,9 +22,9 @@ export class TypeRegistry { } if (type.kind === ReflectionKind.class) { - const classResult = this.classes.get(type.classType); + const classResult = this.classes.get(getClassType(type)); if (classResult) return classResult; - if (type.classType === Set || type.classType === Map || binaryTypes.includes(type.classType)) return undefined; + if (type.classType === Set || type.classType === Map || binaryTypes.includes(getClassType(type))) return undefined; } return this.results[type.kind]; } diff --git a/packages/type/src/serializer.ts b/packages/type/src/serializer.ts index 39e71a5d7..00dee6451 100644 --- a/packages/type/src/serializer.ts +++ b/packages/type/src/serializer.ts @@ -33,7 +33,7 @@ import { embeddedAnnotation, EmbeddedOptions, excludedAnnotation, - FindType, + FindType, getClassType, getConstructorProperties, getTypeJitContainer, getTypeObjectLiteralFromTypeClass, @@ -65,7 +65,7 @@ import { typeToObject, TypeTuple, TypeUnion, - validationAnnotation + validationAnnotation, } from './reflection/type.js'; import { TypeNumberBrand } from '@deepkit/type-spec'; import { hasCircularReference, ReflectionClass, ReflectionProperty } from './reflection/reflection.js'; @@ -586,9 +586,9 @@ export class TemplateRegistry { get(type: Type): Template[] { if (type.kind === ReflectionKind.class) { - const classTemplates = this.classTemplates.get(type.classType); + const classTemplates = this.classTemplates.get(getClassType(type)); if (classTemplates && classTemplates.length) return classTemplates; - if (type.classType === Set || type.classType === Map || binaryTypes.includes(type.classType)) return []; + if (type.classType === Set || type.classType === Map || binaryTypes.includes(getClassType(type))) return []; } return this.templates[type.kind] ||= []; } diff --git a/packages/type/src/type-serialization.ts b/packages/type/src/type-serialization.ts index ccf0cca13..49f439068 100644 --- a/packages/type/src/type-serialization.ts +++ b/packages/type/src/type-serialization.ts @@ -2,6 +2,7 @@ import { entityAnnotation, EntityOptions, findMember, + getClassType, isSameType, isTypeIncluded, isWithAnnotations, @@ -20,7 +21,7 @@ import { TypeProperty, TypeRest, TypeTuple, - TypeTupleMember + TypeTupleMember, } from './reflection/type.js'; import { getClassName, getParentClass } from '@deepkit/core'; import { reflect, ReflectionClass, typeOf } from './reflection/reflection.js'; @@ -345,14 +346,14 @@ function serialize(type: Type, state: SerializerState): SerializedTypeReference } case ReflectionKind.class: { const types = state.disableMethods ? type.types.filter(filterRemoveFunctions) : type.types; - const parent = getParentClass(type.classType); + const parent = getParentClass(getClassType(type)); let superClass: SerializedTypeReference | undefined = undefined; try { superClass = parent ? serialize(reflect(parent), state) : undefined; } catch { } - const classType = getClassName(type.classType); + const classType = getClassName(getClassType(type)); const globalObject: boolean = envGlobal && envGlobal[classType] === type.classType; Object.assign(result, { @@ -638,7 +639,7 @@ function deserialize(type: SerializedType | SerializedTypeReference, state: Dese } const classType = type.globalObject ? envGlobal[type.classType] : newClass - ? (type.superClass ? class extends (deserialize(type.superClass, state) as TypeClass).classType { + ? (type.superClass ? class extends getClassType(deserialize(type.superClass, state) as TypeClass) { constructor(...args: any[]) { super(...args); for (const init of initialize) { diff --git a/packages/type/tests/type-serialization.spec.ts b/packages/type/tests/type-serialization.spec.ts index 8cef1f9b8..9e5e3edc9 100644 --- a/packages/type/tests/type-serialization.spec.ts +++ b/packages/type/tests/type-serialization.spec.ts @@ -5,7 +5,7 @@ import { assertType, Entity, entityAnnotation, - findMember, + findMember, getClassType, isSameType, PrimaryKey, primaryKeyAnnotation, @@ -13,7 +13,7 @@ import { ReflectionKind, Type, TypeClass, - TypeProperty + TypeProperty, } from '../src/reflection/type.js'; import { deserializeType, serializeType } from '../src/type-serialization.js'; import { entity } from '../src/decorator.js'; @@ -199,7 +199,7 @@ test('roundTrip class static', () => { { const type = roundTrip(); assertType(type, ReflectionKind.class); - expect(getClassName(type.classType)).toBe('MyClass'); + expect(getClassName(getClassType(type))).toBe('MyClass'); assertType(type.types[0], ReflectionKind.property); assertType(type.types[1], ReflectionKind.property); @@ -225,7 +225,7 @@ test('roundTrip class generic', () => { { const type = roundTrip>(); assertType(type, ReflectionKind.class); - expect(getClassName(type.classType)).toBe('MyClass'); + expect(getClassName(getClassType(type))).toBe('MyClass'); assertType(type.types[0], ReflectionKind.property); assertType(type.types[1], ReflectionKind.property); @@ -273,11 +273,11 @@ test('circular basics', () => { const type = deserializeType(json); assertType(type, ReflectionKind.class); - expect(getClassName(type.classType)).toBe('MyModel'); + expect(getClassName(getClassType(type))).toBe('MyModel'); assertType(type.types[0], ReflectionKind.property); expect(type.types[0].name).toBe('sub'); assertType(type.types[0].type, ReflectionKind.class); - expect(getClassName(type.types[0].type.classType)).toBe('MyModel'); + expect(getClassName(getClassType(type.types[0].type))).toBe('MyModel'); }); test('circular with decorators', () => { @@ -289,12 +289,12 @@ test('circular with decorators', () => { const type = deserializeType(json); assertType(type, ReflectionKind.class); - expect(getClassName(type.classType)).toBe('MyModel'); + expect(getClassName(getClassType(type))).toBe('MyModel'); expect(primaryKeyAnnotation.isPrimaryKey(type)).toBe(false); assertType(type.types[0], ReflectionKind.property); expect(type.types[0].name).toBe('sub'); assertType(type.types[0].type, ReflectionKind.class); - expect(getClassName(type.types[0].type.classType)).toBe('MyModel'); + expect(getClassName(getClassType(type.types[0].type))).toBe('MyModel'); expect(primaryKeyAnnotation.isPrimaryKey(type.types[0].type)).toBe(true); }); diff --git a/packages/type/tests/typedarray.spec.ts b/packages/type/tests/typedarray.spec.ts index 1303e9eb1..edf51b02e 100644 --- a/packages/type/tests/typedarray.spec.ts +++ b/packages/type/tests/typedarray.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@jest/globals'; import { Buffer } from 'buffer'; import { ReflectionClass } from '../src/reflection/reflection.js'; -import { assertType, binaryTypes, ReflectionKind } from '../src/reflection/type.js'; +import { assertType, binaryTypes, getClassType, ReflectionKind } from '../src/reflection/type.js'; import { base64ToArrayBuffer, base64ToTypedArray, typedArrayToBase64, typedArrayToBuffer } from '../src/core.js'; import { deserialize, serialize } from '../src/serializer-facade.js'; @@ -25,7 +25,7 @@ test('mapping', async () => { for (const property of classSchema.getProperties()) { assertType(property.type, ReflectionKind.class); - expect(binaryTypes.includes(property.type.classType)).toBe(true); + expect(binaryTypes.includes(getClassType(property.type))).toBe(true); expect(typeof (json as any)[property.getNameAsString()]).toBe('string'); expect((back as any)[property.getNameAsString()]).toBeInstanceOf(property.type.classType); } From b980dcb77bd2f0443503c5f103c98dbfeb13ee0c Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 12:11:47 +0100 Subject: [PATCH 13/23] save --- package-lock.json | 18 ++--- .../src/app/components/inputs/registry.ts | 3 +- packages/api-console-gui/src/app/utils.ts | 3 +- packages/bson/src/bson-parser.ts | 2 +- packages/injector/src/injector.ts | 20 ++--- packages/orm-browser-gui/src/app/registry.ts | 4 +- packages/sql/src/platform/default-platform.ts | 2 +- packages/type-compiler/src/compiler.ts | 73 ++++++++++--------- packages/type-compiler/src/external.ts | 5 +- packages/type-compiler/src/reflection-ast.ts | 9 ++- packages/type-compiler/src/resolver.ts | 1 + .../inline-external-library-imports.spec.ts | 19 +---- packages/type/src/default.ts | 2 +- packages/type/src/reference.ts | 2 +- packages/type/src/reflection/extends.ts | 2 +- packages/type/src/reflection/processor.ts | 15 ++-- packages/type/src/reflection/reflection.ts | 4 +- packages/type/src/reflection/type.ts | 28 +------ packages/type/src/registry.ts | 6 +- packages/type/src/serializer.ts | 6 +- packages/type/src/type-serialization.ts | 7 +- .../type/tests/type-serialization.spec.ts | 12 +-- packages/type/tests/typedarray.spec.ts | 2 +- 23 files changed, 101 insertions(+), 144 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4d06443e..549db92bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13712,6 +13712,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -13721,6 +13722,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -13858,7 +13860,6 @@ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "optional": true, - "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -20080,7 +20081,6 @@ "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, "optional": true, - "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -20094,7 +20094,6 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "optional": true, - "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -20109,7 +20108,6 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true, - "peer": true, "bin": { "mime": "cli.js" }, @@ -20123,7 +20121,6 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "optional": true, - "peer": true, "engines": { "node": ">=6" } @@ -20134,7 +20131,6 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "optional": true, - "peer": true, "bin": { "semver": "bin/semver" } @@ -20145,7 +20141,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -21670,7 +21665,6 @@ "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, "optional": true, - "peer": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.6.3", @@ -21689,7 +21683,6 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "optional": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -21700,7 +21693,6 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "optional": true, - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -24070,8 +24062,7 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "optional": true, - "peer": true + "optional": true }, "node_modules/psl": { "version": "1.9.0", @@ -25171,7 +25162,7 @@ "version": "3.29.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "devOptional": true, + "dev": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -27809,6 +27800,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/packages/api-console-gui/src/app/components/inputs/registry.ts b/packages/api-console-gui/src/app/components/inputs/registry.ts index 79661c6a7..6a52d25a7 100644 --- a/packages/api-console-gui/src/app/components/inputs/registry.ts +++ b/packages/api-console-gui/src/app/components/inputs/registry.ts @@ -1,5 +1,4 @@ import { - getClassType, isMapType, isMongoIdType, isSetType, @@ -46,5 +45,5 @@ inputRegistry.set(type => { return isMapType(type); }, MapInputComponent); inputRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; }, BinaryInputComponent); diff --git a/packages/api-console-gui/src/app/utils.ts b/packages/api-console-gui/src/app/utils.ts index 811d9422e..a095baf37 100644 --- a/packages/api-console-gui/src/app/utils.ts +++ b/packages/api-console-gui/src/app/utils.ts @@ -2,7 +2,6 @@ import objectInspect from 'object-inspect'; import { getClassName } from '@deepkit/core'; import { - getClassType, getTypeJitContainer, isBackReferenceType, isReferenceType, @@ -20,7 +19,7 @@ export function isReferenceLike(type: Type): boolean { } function manualTypeStringify(type: Type): string | undefined { - if (type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile') return 'UploadedFile'; + if (type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile') return 'UploadedFile'; //we are not interested in the methods if (type.kind === ReflectionKind.method || type.kind === ReflectionKind.methodSignature) return ''; return; diff --git a/packages/bson/src/bson-parser.ts b/packages/bson/src/bson-parser.ts index 2c6574ca3..230555337 100644 --- a/packages/bson/src/bson-parser.ts +++ b/packages/bson/src/bson-parser.ts @@ -159,7 +159,7 @@ export class BaseParser { return nodeBufferToArrayBuffer(b); } if (type && type.kind === ReflectionKind.class) { - const typedArrayConstructor = getClassType(type); + const typedArrayConstructor = type.classType; return new typedArrayConstructor(nodeBufferToArrayBuffer(b)); } diff --git a/packages/injector/src/injector.ts b/packages/injector/src/injector.ts index c6456048a..1306bdacc 100644 --- a/packages/injector/src/injector.ts +++ b/packages/injector/src/injector.ts @@ -609,7 +609,7 @@ export class Injector implements InjectorInterface { const destinationVar = compiler.reserveConst({ token: fromProvider.provide }); if (options.type.kind === ReflectionKind.class) { - const found = findModuleForConfig(getClassType(options.type), resolveDependenciesFrom); + const found = findModuleForConfig(options.type.classType, resolveDependenciesFrom); if (found) { return compiler.reserveVariable('fullConfig', getPathValue(found.module.getConfig(), found.path)); } @@ -629,14 +629,14 @@ export class Injector implements InjectorInterface { return compiler.reserveVariable('tagRegistry', this.buildContext.tagRegistry); } - if (options.type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof getClassType(options.type)) { + if (options.type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof options.type.classType) { return compiler.reserveConst(resolveDependenciesFrom[0], 'module'); } if (options.type.kind === ReflectionKind.class && isPrototypeOfBase(options.type.classType, Tag)) { const tokenVar = compiler.reserveVariable('token', options.type.classType); const resolvedVar = compiler.reserveVariable('tagResolved'); - const entries = this.buildContext.tagRegistry.resolve(getClassType(options.type)); + const entries = this.buildContext.tagRegistry.resolve(options.type.classType); const args: string[] = []; for (const entry of entries) { args.push(`${compiler.reserveConst(entry.module)}.injector.resolver(${compiler.reserveConst(getContainerToken(entry.tagProvider.provider.provide))}, scope, ${destinationVar})`); @@ -655,7 +655,7 @@ export class Injector implements InjectorInterface { const pickArguments = getPickArguments(options.type); if (pickArguments) { if (pickArguments[0].kind === ReflectionKind.class) { - const found = findModuleForConfig(getClassType(pickArguments[0]), resolveDependenciesFrom); + const found = findModuleForConfig(pickArguments[0].classType, resolveDependenciesFrom); if (found) { const fullConfig = compiler.reserveVariable('fullConfig', getPathValue(found.module.getConfig(), found.path)); let index = pickArguments[1]; @@ -778,24 +778,24 @@ export class Injector implements InjectorInterface { // } if (type.kind === ReflectionKind.class) { - const found = findModuleForConfig(getClassType(type), resolveDependenciesFrom); + const found = findModuleForConfig(type.l, resolveDependenciesFrom); if (found) return () => getPathValue(found.module.getConfig(), found.path); } if (type.kind === ReflectionKind.class && type.classType === TagRegistry) return () => this.buildContext.tagRegistry; - if (type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof getClassType(type)) { + if (type.kind === ReflectionKind.class && resolveDependenciesFrom[0] instanceof type.classType) { return () => resolveDependenciesFrom[0]; } if (type.kind === ReflectionKind.class && isPrototypeOfBase(type.classType, Tag)) { - const entries = this.buildContext.tagRegistry.resolve(getClassType(type)); + const entries = this.buildContext.tagRegistry.resolve(type.classType); const args: any[] = []; for (const entry of entries) { args.push(entry.module.injector!.resolver!(entry.tagProvider.provider.provide, scope)); } - return new (getClassType(type))(args); + return new (type.classType)(args); } if (type.kind === ReflectionKind.function && type.typeName === 'PartialFactory') { @@ -809,7 +809,7 @@ export class Injector implements InjectorInterface { const pickArguments = getPickArguments(type); if (pickArguments) { if (pickArguments[0].kind === ReflectionKind.class) { - const found = findModuleForConfig(getClassType(pickArguments[0]), resolveDependenciesFrom); + const found = findModuleForConfig(pickArguments[0].classType, resolveDependenciesFrom); if (found) { const fullConfig = getPathValue(found.module.getConfig(), found.path); let index = pickArguments[1]; @@ -1027,7 +1027,7 @@ export function partialFactory( } if (type.kind === ReflectionKind.class) { - const classType = getClassType(type); + const classType = type.classType; const reflectionClass = ReflectionClass.from(classType); const args: { name: string; resolve: (scope?: Scope) => ReturnType> }[] = []; diff --git a/packages/orm-browser-gui/src/app/registry.ts b/packages/orm-browser-gui/src/app/registry.ts index 4d47f1cbe..0b181a24e 100644 --- a/packages/orm-browser-gui/src/app/registry.ts +++ b/packages/orm-browser-gui/src/app/registry.ts @@ -43,7 +43,7 @@ inputRegistry.set(isMongoIdType, StringInputComponent); // return isMapType(type); // }, MapInputComponent); inputRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; }, BinaryInputComponent); @@ -81,5 +81,5 @@ cellRegistry.set(isMongoIdType, StringCellComponent); // return isMapType(type); // }, MapCellComponent); cellRegistry.set(type => { - return type.kind === ReflectionKind.class && getClassName(getClassType(type)) === 'UploadedFile'; + return type.kind === ReflectionKind.class && getClassName(type.classType) === 'UploadedFile'; }, BinaryCellComponent); diff --git a/packages/sql/src/platform/default-platform.ts b/packages/sql/src/platform/default-platform.ts index a65a7a40b..6abbfd1bb 100644 --- a/packages/sql/src/platform/default-platform.ts +++ b/packages/sql/src/platform/default-platform.ts @@ -130,7 +130,7 @@ export abstract class DefaultPlatform { addBinaryType(sqlType: string, size?: number, scale?: number) { this.addType((type: Type) => { - return type.kind === ReflectionKind.class && binaryTypes.includes(getClassType(type)); + return type.kind === ReflectionKind.class && binaryTypes.includes(type.classType); }, sqlType, size, scale); } diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 5884ad2d1..bb1261593 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -1363,7 +1363,7 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (!this.external.isEmbeddingExternalLibraryImport() && narrowed.heritageClauses) { + if (narrowed.heritageClauses) { for (const heritage of narrowed.heritageClauses) { if (heritage.token === SyntaxKind.ExtendsKeyword) { for (const extendType of heritage.types) { @@ -1871,7 +1871,8 @@ export class ReflectionTransformer implements CustomTransformer { if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); + ensureImportIsEmitted(resolved.importDeclaration, narrowed.exprName); + // expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); @@ -2033,10 +2034,10 @@ export class ReflectionTransformer implements CustomTransformer { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); //might be an external library - if (!declaration && hasSourceFile(importDeclaration)) { + /*if (!declaration && hasSourceFile(importDeclaration)) { sourceFile = importDeclaration.getSourceFile(); declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, sourceFile); - } + }*/ } if (declaration && declaration.kind === SyntaxKind.TypeParameter && declaration.parent.kind === SyntaxKind.TypeAliasDeclaration) { @@ -2074,8 +2075,7 @@ export class ReflectionTransformer implements CustomTransformer { } protected getExternalRuntimeTypeName(typeName: EntityName): Identifier { - const { module } = this.external.getEmbeddingExternalLibraryImport(); - return this.f.createIdentifier(`${getExternalRuntimeTypeName(module.packageId.name)}.${getNameAsString(typeName)}`); + return this.f.createIdentifier(this.nodeConverter.createExternalRuntimeTypePropertyAccessExpression(getNameAsString(typeName)).name.text); } protected getDeclarationVariableName(typeName: EntityName): Identifier { @@ -2087,15 +2087,14 @@ export class ReflectionTransformer implements CustomTransformer { protected resolveImportExpression(declaration: Node, importDeclaration: ImportDeclaration, typeName: Identifier, expression: Expression, program: CompilerProgram): Expression { ensureImportIsEmitted(importDeclaration, typeName); + if (!hasSourceFile(importDeclaration)) return expression; + // these will be inferred at runtime - if (isTypeAliasDeclaration(declaration) || isVariableDeclaration(declaration)) { - return expression; - } + if (isTypeAliasDeclaration(declaration) || isVariableDeclaration(declaration)) return expression; - // check if the referenced declaration has reflection disabled + // check if the referenced declaration has reflection disabled const declarationReflection = this.findReflectionConfig(declaration, program); if (declarationReflection.mode !== 'never') { - if (!hasSourceFile(importDeclaration)) return expression; const declarationSourceFile = importDeclaration.getSourceFile(); const runtimeTypeName = this.getRuntimeTypeName(typeName); @@ -2105,8 +2104,8 @@ export class ReflectionTransformer implements CustomTransformer { const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { - const { module } = this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); - return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + return this.nodeConverter.createExternalRuntimeTypePropertyAccessExpression(getNameAsString(typeName)); // const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); // return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) // ? this.wrapWithAssignType(expression, newExpression) @@ -2216,7 +2215,8 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) + ensureImportIsEmitted(resolved.importDeclaration, typeName); + // expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } //we can not infer from module declaration, so do `typeof T` in runtime @@ -2275,9 +2275,9 @@ export class ReflectionTransformer implements CustomTransformer { return; } - if (this.external.hasSourceFile(declarationSourceFile) && this.external.isEmbeddingExternalLibraryImport()) { + /*if (this.external.hasSourceFile(declarationSourceFile) && this.external.isEmbeddingExternalLibraryImport()) { this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - } else { + } else */{ const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; const isFromImport = resolved.importDeclaration !== undefined; @@ -2310,9 +2310,21 @@ export class ReflectionTransformer implements CustomTransformer { } const reflection = this.findReflectionFromPath(found.fileName); + if (reflection.mode === 'never') { + if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { + console.log('inline'); + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + } else { + program.pushOp(ReflectionOp.any); + return; + } + } + + this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); + + /*const reflection = this.findReflectionFromPath(found.fileName); if (reflection.mode !== 'never') { this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); - return; } else { const builtType = isBuiltType(runtimeTypeName, found); if (!builtType) { @@ -2323,7 +2335,7 @@ export class ReflectionTransformer implements CustomTransformer { return; } } - } + }*/ } } else { //it's a reference type inside the same file. Make sure its type is reflected @@ -2342,7 +2354,7 @@ export class ReflectionTransformer implements CustomTransformer { } const index = program.pushStack( - program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, this.getDeclarationVariableName(typeName)) + program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, runtimeTypeName) ); if (type.typeArguments) { for (const argument of type.typeArguments) { @@ -2374,29 +2386,18 @@ export class ReflectionTransformer implements CustomTransformer { this.resolveTypeOnlyImport(typeName, program); return; } - - let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); - if (resolved.importDeclaration && isIdentifier(typeName)) { - body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); - } program.pushFrame(); if (type.typeArguments) { for (const typeArgument of type.typeArguments) { this.extractPackStructOfType(typeArgument, program); } } - /*if (this.external.isEmbeddingExternalLibraryImport()) { - if (isClassDeclaration(declaration)) { - program.pushOp(ReflectionOp.objectLiteral); - } else { - const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); - program.pushOp(ReflectionOp.function, index); - } - this.resolveTypeName(getNameAsString(typeName), program); - } else */{ - const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); - program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); - } + let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); + /*if (resolved.importDeclaration && isIdentifier(typeName)) { + body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); + }*/ + const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); + program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); program.popFrameImplicit(); } else if (isTypeParameterDeclaration(declaration)) { this.resolveTypeParameter(declaration, type, program); diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index 6e27ff491..97de5ea06 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -38,7 +38,7 @@ export class External { startEmbeddingExternalLibraryImport(value: ExternalLibraryImport): void { if (this.embeddingExternalLibraryImport) { - throw new Error('Already embedding module'); + throw new Error('Already embedding external library import'); } this.embeddingExternalLibraryImport = value; } @@ -70,7 +70,8 @@ export class External { if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; if (!hasSourceFile(importDeclaration)) return false; if (config.options.inlineExternalLibraryImports === true) return true; - const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); + const resolvedModule = this.resolver.resolveImport(importDeclaration); + if (!resolvedModule.isExternalLibraryImport || !resolvedModule.packageId) return false; const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; if (!imports) return false; if (imports === true) return true; diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index e5d1e3535..cce7d3bce 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -186,6 +186,11 @@ export class NodeConverter { ); } + createExternalRuntimeTypePropertyAccessExpression(name: string): PropertyAccessExpression { + const { module } = this.external.getEmbeddingExternalLibraryImport(); + return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), name) + } + toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); @@ -210,8 +215,8 @@ export class NodeConverter { case SyntaxKind.Identifier: const name = getIdentifierName(node as Identifier); return this.external.isEmbeddingExternalLibraryImport() && !this.external.knownGlobalTypeNames.has(name) - ? this.f.createIdentifier(`${getExternalRuntimeTypeName(this.external.getEmbeddingExternalLibraryImport().module.packageId.name)}.${name}`) - : finish(node, this.f.createIdentifier(getRuntimeTypeName(name))); + ? this.createExternalRuntimeTypePropertyAccessExpression(name) + : finish(node, this.f.createIdentifier(name)); case SyntaxKind.StringLiteral: return finish(node, this.f.createStringLiteral((node as StringLiteral).text)); case SyntaxKind.NumericLiteral: diff --git a/packages/type-compiler/src/resolver.ts b/packages/type-compiler/src/resolver.ts index 20f37e1bf..e8df63886 100644 --- a/packages/type-compiler/src/resolver.ts +++ b/packages/type-compiler/src/resolver.ts @@ -74,6 +74,7 @@ export class Resolver { resolveExternalLibraryImport(importDeclaration: ImportDeclaration): Required { const resolvedModule = this.resolveImport(importDeclaration); if (!resolvedModule.packageId) { + // FIXME: packageId is undefined when module specifier text is `rxjs/operators` throw new Error('Missing package id for resolved module'); /*resolvedModule.packageId = { name: (importDeclaration.moduleSpecifier as StringLiteral).text.replace(/[^a-zA-Z0-9]+/g, '_'), diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index b559cb6d4..f7b028f53 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -637,12 +637,8 @@ __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'o const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; __ɵΩrxjs.SubscriptionLike = [() => __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; -function __assignType(fn, args) { - fn.__type = args; - return fn; -} const rxjs_1 = require("rxjs"); -const __ΩA = [() => __assignType(rxjs_1.Observable, __ɵΩrxjs.Observable), 'P#7!y']; +const __ΩA = [() => __ɵΩrxjs.Observable, 'P#7!y']; " `); }) @@ -679,19 +675,6 @@ test('class typeOf', () => { }) as TypeClass; console.log(res); - - expect(res).toMatchObject({ - external: true, - classType: undefined, - }); - - expect(res.implements![0]).toMatchObject({ - kind: 30, - typeName: 'Subscribable', - // typeName: 'UnknownTypeName:() => __ɵΩrxjs.Subscribable', - }); - // expect(res.typeArguments).toHaveLength(1); - // expect(res.types).toHaveLength(1); }) test('only a single type is transformed', () => { diff --git a/packages/type/src/default.ts b/packages/type/src/default.ts index b0507b3a5..b7095b5a0 100644 --- a/packages/type/src/default.ts +++ b/packages/type/src/default.ts @@ -72,7 +72,7 @@ export function defaultValue(type: Type): any { if (type.classType === Date) return new Date; if (type.classType === Set) return new Set; if (type.classType === Map) return new Map; - if (binaryTypes.includes(getClassType(type))) return new (getClassType(type)); + if (binaryTypes.includes(type.classType)) return new type.classType; const result: any = {}; const types = resolveTypeMembers(type); diff --git a/packages/type/src/reference.ts b/packages/type/src/reference.ts index a728777fe..9fd42a141 100644 --- a/packages/type/src/reference.ts +++ b/packages/type/src/reference.ts @@ -71,7 +71,7 @@ export function createReferenceClass( ): ClassType { if (reflection.data.referenceClass) return reflection.data.referenceClass; - const Reference = reflection.type.kind === ReflectionKind.class ? class extends getClassType(reflection.type) { + const Reference = reflection.type.kind === ReflectionKind.class ? class extends reflection.type.classType { } : class { }; diff --git a/packages/type/src/reflection/extends.ts b/packages/type/src/reflection/extends.ts index 81c9e0e99..376463ab2 100644 --- a/packages/type/src/reflection/extends.ts +++ b/packages/type/src/reflection/extends.ts @@ -274,7 +274,7 @@ export function _isExtendable(left: Type, right: Type, extendStack: StackEntry[] //class User extends Base {} //User extends Base = true if (left.classType === right.classType) return true; - return isPrototypeOfBase(left.classType, getClassType(right)); + return isPrototypeOfBase(left.classType, right.classType); } return true; diff --git a/packages/type/src/reflection/processor.ts b/packages/type/src/reflection/processor.ts index 2163f5269..4d01e7128 100644 --- a/packages/type/src/reflection/processor.ts +++ b/packages/type/src/reflection/processor.ts @@ -590,7 +590,7 @@ export class Processor { break; case ReflectionOp.class: { const types = this.popFrame() as Type[]; - let t = { kind: ReflectionKind.class, id: state.nominalId++, types: [] } as TypeClass; + let t = { kind: ReflectionKind.class, id: state.nominalId++, classType: Object, types: [] } as TypeClass; function add(member: Type) { if (member.kind === ReflectionKind.propertySignature) { @@ -669,8 +669,6 @@ export class Processor { if (args.length) t.arguments = args; t.typeArguments = program.typeParameters; - console.log('class', t); - this.pushType(t); break; } @@ -720,10 +718,10 @@ export class Processor { this.pushType({ kind: ReflectionKind.unknown }); break; } + const pack = external ? classOrFunction : classOrFunction.__type; - const runtimeType = external ? classOrFunction : classOrFunction.__type; - - if (!runtimeType) { + if (!classOrFunction.__type) { + console.log('unknown'); if (op === ReflectionOp.classReference) { this.pushType({ kind: ReflectionKind.class, classType: classOrFunction, typeArguments: inputs, types: [] }); } else if (op === ReflectionOp.functionReference) { @@ -732,7 +730,7 @@ export class Processor { } else { //when it's just a simple reference resolution like typeOf() then enable cache re-use (so always the same type is returned) const directReference = !!(this.isEnded() && program.previous && program.previous.end === 0); - const result = this.reflect(runtimeType, inputs, { inline: !directReference, reuseCached: directReference }); + const result = this.reflect(classOrFunction, inputs, { inline: !directReference, reuseCached: directReference }); if (directReference) program.directReturn = true; this.push(result, program); @@ -1193,6 +1191,7 @@ export class Processor { const p = isFunction(pOrFn) ? pOrFn() : pOrFn; // process.stdout.write(`inline ${pOrFn.toString()}\n`); if (p === undefined) { + console.log('unknown'); // console.log('inline with invalid reference', pOrFn.toString()); this.push({ kind: ReflectionKind.unknown }); } else if ('number' === typeof p) { @@ -1289,7 +1288,7 @@ export class Processor { if (isType(result)) { if (program.object) { if (result.kind === ReflectionKind.class && result.classType === Object) { - // result.classType = program.object; + result.classType = program.object; applyClassDecorators(result); } if (result.kind === ReflectionKind.function && !result.function) { diff --git a/packages/type/src/reflection/reflection.ts b/packages/type/src/reflection/reflection.ts index a68d6eb1c..4c48cb7d4 100644 --- a/packages/type/src/reflection/reflection.ts +++ b/packages/type/src/reflection/reflection.ts @@ -983,7 +983,7 @@ export class ReflectionClass { } getClassType(): ClassType { - return this.type.kind === ReflectionKind.class ? getClassType(this.type) : Object; + return this.type.kind === ReflectionKind.class ? this.type.classType : Object; } getClassName(): string { @@ -1233,7 +1233,7 @@ export class ReflectionClass { if (classTypeIn.kind !== ReflectionKind.class) throw new Error(`TypeClass or TypeObjectLiteral expected, not ${ReflectionKind[classTypeIn.kind]}`); } - const classType = isType(classTypeIn) ? getClassType(classTypeIn) : (classTypeIn as any)['prototype'] ? classTypeIn as ClassType : classTypeIn.constructor as ClassType; + const classType = isType(classTypeIn) ? (classTypeIn as TypeClass).classType : (classTypeIn as any)['prototype'] ? classTypeIn as ClassType : classTypeIn.constructor as ClassType; if (!classType.prototype.hasOwnProperty(reflectionClassSymbol)) { Object.defineProperty(classType.prototype, reflectionClassSymbol, { writable: true, enumerable: false }); diff --git a/packages/type/src/reflection/type.ts b/packages/type/src/reflection/type.ts index 914480023..855854ec3 100644 --- a/packages/type/src/reflection/type.ts +++ b/packages/type/src/reflection/type.ts @@ -8,17 +8,7 @@ * You should have received a copy of the MIT License along with this program. */ -import { - AbstractClassType, - arrayRemoveItem, - ClassType, - getClassName, - getParentClass, - indent, - isArray, - isClass, - isFunction, -} from '@deepkit/core'; +import { AbstractClassType, arrayRemoveItem, ClassType, getClassName, getParentClass, indent, isArray, isClass } from '@deepkit/core'; import { TypeNumberBrand } from '@deepkit/type-spec'; import { getProperty, ReceiveType, reflect, ReflectionClass, resolveReceiveType, toSignature } from './reflection.js'; import { isExtendable } from './extends.js'; @@ -79,8 +69,6 @@ export enum ReflectionKind { infer, callSignature, - - externalClass, } export type TypeDecorator = (annotations: Annotations, decorator: TypeObjectLiteral) => boolean; @@ -319,7 +307,6 @@ export interface TypeFunction extends TypeAnnotations { parent?: Type; name?: number | string | symbol, description?: string; - external?: boolean; function?: Function; //reference to the real function if available parameters: TypeParameter[]; return: Type; @@ -341,8 +328,7 @@ export interface TypePromise extends TypeAnnotations { export interface TypeClass extends TypeAnnotations { kind: ReflectionKind.class, parent?: Type; - external?: boolean; - classType?: ClassType; // reference to the real class if available + classType: ClassType; description?: string; /** @@ -553,7 +539,7 @@ export function isType(entry: any): entry is Type { } export function isBinary(type: Type): boolean { - return type.kind === ReflectionKind.class && binaryTypes.includes(getClassType(type)); + return type.kind === ReflectionKind.class && binaryTypes.includes(type.classType); } export function isPrimitive(type: T): boolean { @@ -1344,9 +1330,6 @@ export function assertType(t: Type | undefined, kin export function getClassType(type: Type): ClassType { if (type.kind !== ReflectionKind.class) throw new Error(`Type needs to be TypeClass, but ${ReflectionKind[type.kind]} given.`); - if (!type.classType) { - throw new Error('TypeClass is missing classType'); - } return type.classType; } @@ -2281,9 +2264,6 @@ export const binaryTypes: ClassType[] = [ */ export function isGlobalTypeClass(type: Type): type is TypeClass { if (type.kind !== ReflectionKind.class) return false; - if (!type.classType) { - throw new Error('TypeClass is missing classType'); - } if ('undefined' !== typeof window) { return (window as any)[getClassName(type.classType)] === type.classType; } @@ -2498,8 +2478,6 @@ export function stringifyType(type: Type, stateIn: Partial break; } - if (!type.classType) break; - if (binaryTypes.includes(type.classType)) { result.push(getClassName(type.classType)); break; diff --git a/packages/type/src/registry.ts b/packages/type/src/registry.ts index 98d6fbd70..772f40ba9 100644 --- a/packages/type/src/registry.ts +++ b/packages/type/src/registry.ts @@ -1,5 +1,5 @@ import { ClassType, isArray, isFunction } from '@deepkit/core'; -import { binaryTypes, getClassType, ReflectionKind, Type } from './reflection/type.js'; +import { binaryTypes, ReflectionKind, Type } from './reflection/type.js'; interface RegistryDecorator { predicate: (type: Type) => boolean, @@ -22,9 +22,9 @@ export class TypeRegistry { } if (type.kind === ReflectionKind.class) { - const classResult = this.classes.get(getClassType(type)); + const classResult = this.classes.get(type.classType); if (classResult) return classResult; - if (type.classType === Set || type.classType === Map || binaryTypes.includes(getClassType(type))) return undefined; + if (type.classType === Set || type.classType === Map || binaryTypes.includes(type.classType)) return undefined; } return this.results[type.kind]; } diff --git a/packages/type/src/serializer.ts b/packages/type/src/serializer.ts index 00dee6451..ba08180cc 100644 --- a/packages/type/src/serializer.ts +++ b/packages/type/src/serializer.ts @@ -33,7 +33,7 @@ import { embeddedAnnotation, EmbeddedOptions, excludedAnnotation, - FindType, getClassType, + FindType, getConstructorProperties, getTypeJitContainer, getTypeObjectLiteralFromTypeClass, @@ -586,9 +586,9 @@ export class TemplateRegistry { get(type: Type): Template[] { if (type.kind === ReflectionKind.class) { - const classTemplates = this.classTemplates.get(getClassType(type)); + const classTemplates = this.classTemplates.get(type.classType); if (classTemplates && classTemplates.length) return classTemplates; - if (type.classType === Set || type.classType === Map || binaryTypes.includes(getClassType(type))) return []; + if (type.classType === Set || type.classType === Map || binaryTypes.includes(type.classType)) return []; } return this.templates[type.kind] ||= []; } diff --git a/packages/type/src/type-serialization.ts b/packages/type/src/type-serialization.ts index 49f439068..063f51958 100644 --- a/packages/type/src/type-serialization.ts +++ b/packages/type/src/type-serialization.ts @@ -2,7 +2,6 @@ import { entityAnnotation, EntityOptions, findMember, - getClassType, isSameType, isTypeIncluded, isWithAnnotations, @@ -346,14 +345,14 @@ function serialize(type: Type, state: SerializerState): SerializedTypeReference } case ReflectionKind.class: { const types = state.disableMethods ? type.types.filter(filterRemoveFunctions) : type.types; - const parent = getParentClass(getClassType(type)); + const parent = getParentClass(type.classType); let superClass: SerializedTypeReference | undefined = undefined; try { superClass = parent ? serialize(reflect(parent), state) : undefined; } catch { } - const classType = getClassName(getClassType(type)); + const classType = getClassName(type.classType); const globalObject: boolean = envGlobal && envGlobal[classType] === type.classType; Object.assign(result, { @@ -639,7 +638,7 @@ function deserialize(type: SerializedType | SerializedTypeReference, state: Dese } const classType = type.globalObject ? envGlobal[type.classType] : newClass - ? (type.superClass ? class extends getClassType(deserialize(type.superClass, state) as TypeClass) { + ? (type.superClass ? class extends (deserialize(type.superClass, state) as TypeClass).classType { constructor(...args: any[]) { super(...args); for (const init of initialize) { diff --git a/packages/type/tests/type-serialization.spec.ts b/packages/type/tests/type-serialization.spec.ts index 9e5e3edc9..8cbee6407 100644 --- a/packages/type/tests/type-serialization.spec.ts +++ b/packages/type/tests/type-serialization.spec.ts @@ -199,7 +199,7 @@ test('roundTrip class static', () => { { const type = roundTrip(); assertType(type, ReflectionKind.class); - expect(getClassName(getClassType(type))).toBe('MyClass'); + expect(getClassName(type.classType)).toBe('MyClass'); assertType(type.types[0], ReflectionKind.property); assertType(type.types[1], ReflectionKind.property); @@ -225,7 +225,7 @@ test('roundTrip class generic', () => { { const type = roundTrip>(); assertType(type, ReflectionKind.class); - expect(getClassName(getClassType(type))).toBe('MyClass'); + expect(getClassName(type.classType)).toBe('MyClass'); assertType(type.types[0], ReflectionKind.property); assertType(type.types[1], ReflectionKind.property); @@ -273,11 +273,11 @@ test('circular basics', () => { const type = deserializeType(json); assertType(type, ReflectionKind.class); - expect(getClassName(getClassType(type))).toBe('MyModel'); + expect(getClassName(type.classType)).toBe('MyModel'); assertType(type.types[0], ReflectionKind.property); expect(type.types[0].name).toBe('sub'); assertType(type.types[0].type, ReflectionKind.class); - expect(getClassName(getClassType(type.types[0].type))).toBe('MyModel'); + expect(getClassName(type.types[0].type.classType)).toBe('MyModel'); }); test('circular with decorators', () => { @@ -289,12 +289,12 @@ test('circular with decorators', () => { const type = deserializeType(json); assertType(type, ReflectionKind.class); - expect(getClassName(getClassType(type))).toBe('MyModel'); + expect(getClassName(type.classType)).toBe('MyModel'); expect(primaryKeyAnnotation.isPrimaryKey(type)).toBe(false); assertType(type.types[0], ReflectionKind.property); expect(type.types[0].name).toBe('sub'); assertType(type.types[0].type, ReflectionKind.class); - expect(getClassName(getClassType(type.types[0].type))).toBe('MyModel'); + expect(getClassName(type.types[0].type.classType)).toBe('MyModel'); expect(primaryKeyAnnotation.isPrimaryKey(type.types[0].type)).toBe(true); }); diff --git a/packages/type/tests/typedarray.spec.ts b/packages/type/tests/typedarray.spec.ts index edf51b02e..1c80ffe25 100644 --- a/packages/type/tests/typedarray.spec.ts +++ b/packages/type/tests/typedarray.spec.ts @@ -25,7 +25,7 @@ test('mapping', async () => { for (const property of classSchema.getProperties()) { assertType(property.type, ReflectionKind.class); - expect(binaryTypes.includes(getClassType(property.type))).toBe(true); + expect(binaryTypes.includes(property.type.classType)).toBe(true); expect(typeof (json as any)[property.getNameAsString()]).toBe('string'); expect((back as any)[property.getNameAsString()]).toBeInstanceOf(property.type.classType); } From 10e6d04337eb0d9a9033e6b696a960b4c39d3d12 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 14:38:13 +0100 Subject: [PATCH 14/23] improve --- packages/injector/src/injector.ts | 2 +- packages/type-compiler/src/compiler.ts | 75 +-- packages/type-compiler/src/external.ts | 4 + .../inline-external-library-imports.spec.ts | 445 +----------------- packages/type/src/reflection/processor.ts | 12 +- 5 files changed, 69 insertions(+), 469 deletions(-) diff --git a/packages/injector/src/injector.ts b/packages/injector/src/injector.ts index 1306bdacc..21c67ce4a 100644 --- a/packages/injector/src/injector.ts +++ b/packages/injector/src/injector.ts @@ -778,7 +778,7 @@ export class Injector implements InjectorInterface { // } if (type.kind === ReflectionKind.class) { - const found = findModuleForConfig(type.l, resolveDependenciesFrom); + const found = findModuleForConfig(type.classType, resolveDependenciesFrom); if (found) return () => getPathValue(found.module.getConfig(), found.path); } diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index bb1261593..31f5377ff 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -1871,8 +1871,8 @@ export class ReflectionTransformer implements CustomTransformer { if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - ensureImportIsEmitted(resolved.importDeclaration, narrowed.exprName); - // expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); + // ensureImportIsEmitted(resolved.importDeclaration, narrowed.exprName); + expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } program.pushOp(ReflectionOp.typeof, program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, expression))); @@ -2034,10 +2034,10 @@ export class ReflectionTransformer implements CustomTransformer { if (importDeclaration.importClause && importDeclaration.importClause.isTypeOnly) typeOnly = true; declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, this.sourceFile); //might be an external library - /*if (!declaration && hasSourceFile(importDeclaration)) { + if (!declaration && hasSourceFile(importDeclaration)) { sourceFile = importDeclaration.getSourceFile(); declaration = this.resolveImportSpecifier(typeName.escapedText, importDeclaration, sourceFile); - }*/ + } } if (declaration && declaration.kind === SyntaxKind.TypeParameter && declaration.parent.kind === SyntaxKind.TypeAliasDeclaration) { @@ -2075,7 +2075,8 @@ export class ReflectionTransformer implements CustomTransformer { } protected getExternalRuntimeTypeName(typeName: EntityName): Identifier { - return this.f.createIdentifier(this.nodeConverter.createExternalRuntimeTypePropertyAccessExpression(getNameAsString(typeName)).name.text); + const { expression, name } = this.nodeConverter.createExternalRuntimeTypePropertyAccessExpression(getNameAsString(typeName)); + return this.f.createIdentifier(`${getNameAsString(expression as any)}.${getNameAsString(name)}`); } protected getDeclarationVariableName(typeName: EntityName): Identifier { @@ -2104,12 +2105,10 @@ export class ReflectionTransformer implements CustomTransformer { const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { - this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); - return this.nodeConverter.createExternalRuntimeTypePropertyAccessExpression(getNameAsString(typeName)); - // const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), typeName); - // return !isEmbeddingExternalLibraryImport && (isClassDeclaration(declaration) || isFunctionDeclaration(declaration)) - // ? this.wrapWithAssignType(expression, newExpression) - // : newExpression + const { module } = this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); + return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), getNameAsString(typeName)); + // const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), getNameAsString(typeName)); + // return isFunctionDeclaration(declaration) ? this.wrapWithAssignType(expression, newExpression) : newExpression; } } @@ -2215,8 +2214,8 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - ensureImportIsEmitted(resolved.importDeclaration, typeName); - // expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) + // ensureImportIsEmitted(resolved.importDeclaration, typeName); + expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } //we can not infer from module declaration, so do `typeof T` in runtime @@ -2275,9 +2274,9 @@ export class ReflectionTransformer implements CustomTransformer { return; } - /*if (this.external.hasSourceFile(declarationSourceFile) && this.external.isEmbeddingExternalLibraryImport()) { + if (this.external.hasSourceFile(declarationSourceFile) && this.external.isEmbeddingExternalLibraryImport()) { this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - } else */{ + } else { const isGlobal = resolved.importDeclaration === undefined && declarationSourceFile.fileName !== this.sourceFile.fileName; const isFromImport = resolved.importDeclaration !== undefined; @@ -2309,33 +2308,33 @@ export class ReflectionTransformer implements CustomTransformer { return; } - const reflection = this.findReflectionFromPath(found.fileName); - if (reflection.mode === 'never') { - if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { - console.log('inline'); - this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - } else { - program.pushOp(ReflectionOp.any); - return; - } - } - - this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); + // const reflection = this.findReflectionFromPath(found.fileName); + // if (reflection.mode === 'never') { + // if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { + // console.log('inline'); + // this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + // } else { + // program.pushOp(ReflectionOp.any); + // return; + // } + // } + // + // this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); - /*const reflection = this.findReflectionFromPath(found.fileName); + const reflection = this.findReflectionFromPath(found.fileName); if (reflection.mode !== 'never') { this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); } else { - const builtType = isBuiltType(runtimeTypeName, found); - if (!builtType) { + // const builtType = isBuiltType(runtimeTypeName, found); + // if (!builtType) { if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); } else { program.pushOp(ReflectionOp.any); return; } - } - }*/ + // } + } } } else { //it's a reference type inside the same file. Make sure its type is reflected @@ -2354,7 +2353,7 @@ export class ReflectionTransformer implements CustomTransformer { } const index = program.pushStack( - program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, runtimeTypeName) + program.forNode === declaration ? 0 : this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, this.getDeclarationVariableName(typeName)) ); if (type.typeArguments) { for (const argument of type.typeArguments) { @@ -2393,11 +2392,15 @@ export class ReflectionTransformer implements CustomTransformer { } } let body: Identifier | Expression = isIdentifier(typeName) ? typeName : this.createAccessorForEntityName(typeName); - /*if (resolved.importDeclaration && isIdentifier(typeName)) { + if (resolved.importDeclaration && isIdentifier(typeName)) { body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); - }*/ + } const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); - program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); + //if (this.external.isEmbeddingExternalLibraryImport() || this.external.hasProcessedEntity(typeName)) { + // program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.class : ReflectionOp.function, index); + //} else { + program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); + //} program.popFrameImplicit(); } else if (isTypeParameterDeclaration(declaration)) { this.resolveTypeParameter(declaration, type, program); diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index 97de5ea06..1a87aa9f6 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -80,6 +80,10 @@ export class External { return imports.includes(typeName); } + public hasProcessedEntity(typeName: EntityName): boolean { + return this.processedEntities.has(getNameAsString(typeName)); + } + public processExternalLibraryImport(typeName: EntityName, declaration: Node, sourceFile: SourceFile, importDeclaration?: ImportDeclaration): ExternalLibraryImport { const module = importDeclaration ? this.resolver.resolveExternalLibraryImport(importDeclaration) diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index f7b028f53..0a6e50a3c 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -175,432 +175,27 @@ test('typeOf function type alias', () => { }, }) as TypeFunction; - expect(res.return.kind).not.toBe(ReflectionKind.never); - expect(res).toMatchInlineSnapshot(` { - "function": [Function], - "inlined": true, - "kind": 17, - "name": "map", - "parameters": [ - { - "kind": 18, - "name": "project", - "parent": { - "function": [Function], - "kind": 17, - "name": "map", - "parameters": [Circular], - "return": { - "annotations": {}, - "id": 4, - "implements": [ - { - "annotations": {}, - "id": 2, - "kind": 30, - "typeArguments": [ - { - "classType": undefined, - "external": true, - "kind": 20, - "parent": { - "kind": 18, - "name": "source", - "parent": { - "kind": 35, - "parameters": [ - [Circular], - ], - "parent": [Circular], - "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - "type": [Circular], - }, - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - { - "classType": undefined, - "external": true, - "kind": 20, - "parent": { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], - "return": [Circular], - }, - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - ], - "typeName": "UnknownTypeName:() => __ɵΩrxjs.UnaryFunction", - "types": [ - { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], - "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - }, - ], - "kind": 30, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - { - "kind": 1, - }, - ], - "typeName": "UnknownTypeName:() => __ɵΩrxjs.OperatorFunction", - "types": [ - { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], - "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - }, - "typeName": undefined, - }, - "type": { - "kind": 17, - "name": undefined, - "parameters": [ - { - "kind": 18, - "name": "value", - "parent": [Circular], - "type": { - "kind": 1, - "parent": [Circular], - }, - }, - { - "kind": 18, - "name": "index", - "parent": [Circular], - "type": { - "kind": 6, - "parent": [Circular], - }, - }, - ], - "parent": [Circular], - "return": { - "kind": 1, - "parent": [Circular], - }, - }, - }, - ], - "return": { - "annotations": {}, - "id": 4, - "implements": [ + "kind": 25, + "type": { + "kind": 23, + "types": [ { - "annotations": {}, - "id": 2, - "kind": 30, - "typeArguments": [ - { - "classType": undefined, - "external": true, - "kind": 20, - "parent": { - "kind": 18, - "name": "source", - "parent": { - "kind": 35, - "parameters": [ - [Circular], - ], - "parent": [Circular], - "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - "type": [Circular], - }, - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - { - "classType": undefined, - "external": true, - "kind": 20, - "parent": { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], - "return": [Circular], - }, - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - ], - "typeName": "UnknownTypeName:() => __ɵΩrxjs.UnaryFunction", - "types": [ - { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], - "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - }, - ], - "kind": 30, - "parent": { - "function": [Function], - "kind": 17, - "name": "map", - "parameters": [ - { - "kind": 18, - "name": "project", - "parent": [Circular], - "type": { - "kind": 17, - "name": undefined, - "parameters": [ - { - "kind": 18, - "name": "value", - "parent": [Circular], - "type": { - "kind": 1, - "parent": [Circular], - }, - }, - { - "kind": 18, - "name": "index", - "parent": [Circular], - "type": { - "kind": 6, - "parent": [Circular], - }, - }, - ], - "parent": [Circular], - "return": { - "kind": 1, - "parent": [Circular], - }, - }, + "jit": {}, + "kind": 5, + "origin": { + "kind": 13, + "literal": "value", }, - ], - "return": [Circular], - "typeName": undefined, - }, - "typeArguments": [ - { - "kind": 1, - }, - { - "kind": 1, }, - ], - "typeName": "UnknownTypeName:() => __ɵΩrxjs.OperatorFunction", - "types": [ { - "kind": 35, - "parameters": [ - { - "kind": 18, - "name": "source", - "parent": [Circular], - "type": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], - }, - }, - ], - "parent": [Circular], + "function": [Function], + "kind": 17, + "name": "", + "parameters": [], "return": { - "classType": undefined, - "external": true, - "kind": 20, - "parent": [Circular], - "typeArguments": [ - { - "kind": 1, - }, - ], - "types": [], + "kind": 1, }, }, ], @@ -626,19 +221,19 @@ test('class type var', () => { ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const __ɵΩrxjs = {}; -__ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; +__ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"5"-J3#P"e"!o$#-J3%PPPe$!5&2\\'Pe$!5(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"5102Pe"!o4"o3"258P560,PPe#!27$/+28$\`09PPe#!5:0;PPe#!-J\`0<5e!!o="x"w>y']; const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; -__ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; -__ɵΩrxjs.Subscriber = ['T', 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!PPe#!2"8$/#2$8P"2%8$/#2&8P$/#2\\'8Pe#!7(0)s)3* __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; +__ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"5#2$"2%n&1\\'My']; +__ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!5)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP5!n"P$/#$Jy']; __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; -__ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; +__ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P5!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; __ɵΩrxjs.SubscriptionLike = [() => __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; const rxjs_1 = require("rxjs"); -const __ΩA = [() => __ɵΩrxjs.Observable, 'P#7!y']; +const __ΩA = [() => __ɵΩrxjs.Observable, 'P#5!y']; " `); }) diff --git a/packages/type/src/reflection/processor.ts b/packages/type/src/reflection/processor.ts index 4d01e7128..cf3ac2d04 100644 --- a/packages/type/src/reflection/processor.ts +++ b/packages/type/src/reflection/processor.ts @@ -712,16 +712,15 @@ export class Processor { case ReflectionOp.classReference: { const ref = this.eatParameter() as number; const classOrFunction = resolveFunction(program.stack[ref] as Function, program.object); - const external = isPack(classOrFunction); + const packed = isPack(classOrFunction); const inputs = this.popFrame() as Type[]; if (!classOrFunction) { this.pushType({ kind: ReflectionKind.unknown }); break; } - const pack = external ? classOrFunction : classOrFunction.__type; + const pack = packed ? classOrFunction : classOrFunction.__type; - if (!classOrFunction.__type) { - console.log('unknown'); + if (!pack) { if (op === ReflectionOp.classReference) { this.pushType({ kind: ReflectionKind.class, classType: classOrFunction, typeArguments: inputs, types: [] }); } else if (op === ReflectionOp.functionReference) { @@ -730,7 +729,7 @@ export class Processor { } else { //when it's just a simple reference resolution like typeOf() then enable cache re-use (so always the same type is returned) const directReference = !!(this.isEnded() && program.previous && program.previous.end === 0); - const result = this.reflect(classOrFunction, inputs, { inline: !directReference, reuseCached: directReference }); + const result = this.reflect(pack, inputs, { inline: !directReference, reuseCached: directReference }); if (directReference) program.directReturn = true; this.push(result, program); @@ -1191,7 +1190,6 @@ export class Processor { const p = isFunction(pOrFn) ? pOrFn() : pOrFn; // process.stdout.write(`inline ${pOrFn.toString()}\n`); if (p === undefined) { - console.log('unknown'); // console.log('inline with invalid reference', pOrFn.toString()); this.push({ kind: ReflectionKind.unknown }); } else if ('number' === typeof p) { @@ -1286,7 +1284,7 @@ export class Processor { // process.stdout.write(`Done ${program.depth} in ${Date.now() - program.started}ms with ${stringifyValueWithType(program.object)} -> ${stringifyShortResolvedType(result as Type)}\n`); if (isType(result)) { - if (program.object) { + if (program.object && !isPack(program.object)) { if (result.kind === ReflectionKind.class && result.classType === Object) { result.classType = program.object; applyClassDecorators(result); From c41b981dfa9d8ec696d2c40e9c50cd55a6be350a Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 14:45:50 +0100 Subject: [PATCH 15/23] revert: unnecessary changes --- .../src/app/components/inputs/registry.ts | 9 +-------- packages/api-console-gui/src/app/utils.ts | 9 +-------- packages/bson/src/bson-parser.ts | 2 +- packages/injector/src/injector.ts | 7 +++---- packages/injector/src/types.ts | 4 ++-- packages/orm-browser-gui/src/app/registry.ts | 2 +- packages/sql/src/platform/default-platform.ts | 4 ++-- packages/type/tests/type-serialization.spec.ts | 2 +- 8 files changed, 12 insertions(+), 27 deletions(-) diff --git a/packages/api-console-gui/src/app/components/inputs/registry.ts b/packages/api-console-gui/src/app/components/inputs/registry.ts index 6a52d25a7..d16d5ea70 100644 --- a/packages/api-console-gui/src/app/components/inputs/registry.ts +++ b/packages/api-console-gui/src/app/components/inputs/registry.ts @@ -1,11 +1,4 @@ -import { - isMapType, - isMongoIdType, - isSetType, - isUUIDType, - ReflectionKind, - TypeRegistry, -} from '@deepkit/type'; +import { isMapType, isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; import { ClassType, getClassName } from '@deepkit/core'; import { StringInputComponent } from './string-input.component'; import { ArrayInputComponent } from './array-input.component'; diff --git a/packages/api-console-gui/src/app/utils.ts b/packages/api-console-gui/src/app/utils.ts index a095baf37..05dc5547e 100644 --- a/packages/api-console-gui/src/app/utils.ts +++ b/packages/api-console-gui/src/app/utils.ts @@ -1,14 +1,7 @@ //@ts-ignore import objectInspect from 'object-inspect'; import { getClassName } from '@deepkit/core'; -import { - getTypeJitContainer, - isBackReferenceType, - isReferenceType, - ReflectionKind, - stringifyType, - Type, -} from '@deepkit/type'; +import { getTypeJitContainer, isBackReferenceType, isReferenceType, ReflectionKind, stringifyType, Type } from '@deepkit/type'; export function trackByIndex(index: number) { return index; diff --git a/packages/bson/src/bson-parser.ts b/packages/bson/src/bson-parser.ts index 230555337..07afd522c 100644 --- a/packages/bson/src/bson-parser.ts +++ b/packages/bson/src/bson-parser.ts @@ -10,7 +10,7 @@ import { BSON_BINARY_SUBTYPE_BYTE_ARRAY, BSON_BINARY_SUBTYPE_UUID, BSONType, digitByteSize, TWO_PWR_32_DBL_N } from './utils.js'; import { buildStringDecoder, decodeUTF8 } from './strings.js'; -import { getClassType, nodeBufferToArrayBuffer, ReflectionKind, SerializationError, Type } from '@deepkit/type'; +import { nodeBufferToArrayBuffer, ReflectionKind, SerializationError, Type } from '@deepkit/type'; import { hexTable } from './model.js'; declare var Buffer: any; diff --git a/packages/injector/src/injector.ts b/packages/injector/src/injector.ts index 21c67ce4a..a1080eec8 100644 --- a/packages/injector/src/injector.ts +++ b/packages/injector/src/injector.ts @@ -13,7 +13,6 @@ import { import { AbstractClassType, ClassType, CompilerContext, CustomError, getClassName, getPathValue, isArray, isClass, isFunction, isPrototypeOfBase } from '@deepkit/core'; import { findModuleForConfig, getScope, InjectorModule, PreparedProvider } from './module.js'; import { - getClassType, hasTypeInformation, isExtendable, isOptional, @@ -27,7 +26,7 @@ import { ReflectionKind, resolveReceiveType, stringifyType, - Type, + Type } from '@deepkit/type'; export class InjectorError extends CustomError { @@ -686,7 +685,7 @@ export class Injector implements InjectorInterface { while (current && current.indexAccessOrigin) { let found: { module: InjectorModule, path: string } | undefined = undefined; if (current.indexAccessOrigin.container.kind === ReflectionKind.class) { - found = findModuleForConfig(getClassType(current.indexAccessOrigin.container), resolveDependenciesFrom); + found = findModuleForConfig(current.indexAccessOrigin.container.classType, resolveDependenciesFrom); } if (current.indexAccessOrigin.index.kind === ReflectionKind.literal) { accesses.unshift(`[${JSON.stringify(current.indexAccessOrigin.index.literal)}]`); @@ -838,7 +837,7 @@ export class Injector implements InjectorInterface { while (current && current.indexAccessOrigin) { if (current.indexAccessOrigin.container.kind === ReflectionKind.class) { - const found = findModuleForConfig(getClassType(current.indexAccessOrigin.container), resolveDependenciesFrom); + const found = findModuleForConfig(current.indexAccessOrigin.container.classType, resolveDependenciesFrom); if (!found) return () => undefined; config = getPathValue(found.module.getConfig(), found.path); } diff --git a/packages/injector/src/types.ts b/packages/injector/src/types.ts index f5bb7b051..ad01d226c 100644 --- a/packages/injector/src/types.ts +++ b/packages/injector/src/types.ts @@ -1,4 +1,4 @@ -import { getClassType, reflect, ReflectionKind, Type } from '@deepkit/type'; +import { reflect, ReflectionKind, Type } from '@deepkit/type'; import { getParentClass } from '@deepkit/core'; export type InjectMeta = { __meta?: never & ['inject', T] } @@ -47,7 +47,7 @@ export function nominalCompatibility(token: Type, provider: Type): number { } if (current.kind === ReflectionKind.class) { - const parent = getParentClass(getClassType(current)); + const parent = getParentClass(current.classType); if (parent && (parent as any).__type) { const next = reflect(parent); stack.push({ spec: entry.spec + 1, type: next }); diff --git a/packages/orm-browser-gui/src/app/registry.ts b/packages/orm-browser-gui/src/app/registry.ts index 0b181a24e..4f5f0e31e 100644 --- a/packages/orm-browser-gui/src/app/registry.ts +++ b/packages/orm-browser-gui/src/app/registry.ts @@ -1,5 +1,5 @@ import { ClassType, getClassName } from '@deepkit/core'; -import { getClassType, isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; +import { isMongoIdType, isSetType, isUUIDType, ReflectionKind, TypeRegistry } from '@deepkit/type'; import { ClassCellComponent } from './components/cell/class-cell.component'; import { DateCellComponent } from './components/cell/date-cell.component'; import { EnumCellComponent } from './components/cell/enum-cell.component'; diff --git a/packages/sql/src/platform/default-platform.ts b/packages/sql/src/platform/default-platform.ts index 6abbfd1bb..27b6cc65e 100644 --- a/packages/sql/src/platform/default-platform.ts +++ b/packages/sql/src/platform/default-platform.ts @@ -17,7 +17,7 @@ import { SQLFilterBuilder } from '../sql-filter-builder.js'; import { Sql } from '../sql-builder.js'; import { binaryTypes, - databaseAnnotation, getClassType, + databaseAnnotation, getTypeJitContainer, isReferenceType, ReflectionClass, @@ -26,7 +26,7 @@ import { resolvePath, resolveProperty, Serializer, - Type, + Type } from '@deepkit/type'; import { DatabaseEntityRegistry, MigrateOptions } from '@deepkit/orm'; import { splitDotPath } from '../sql-adapter.js'; diff --git a/packages/type/tests/type-serialization.spec.ts b/packages/type/tests/type-serialization.spec.ts index 8cbee6407..7c365fd47 100644 --- a/packages/type/tests/type-serialization.spec.ts +++ b/packages/type/tests/type-serialization.spec.ts @@ -5,7 +5,7 @@ import { assertType, Entity, entityAnnotation, - findMember, getClassType, + findMember, isSameType, PrimaryKey, primaryKeyAnnotation, From 05dad77ece6f617896cb10c36abd57a02ce8f282 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 15:32:36 +0100 Subject: [PATCH 16/23] fix(type): processor --- .../tests/inline-external-library-imports.spec.ts | 12 ++++++------ packages/type/src/reflection/processor.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index 0a6e50a3c..d292cfeb3 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -221,19 +221,19 @@ test('class type var', () => { ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const __ɵΩrxjs = {}; -__ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"5"-J3#P"e"!o$#-J3%PPPe$!5&2\\'Pe$!5(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"5102Pe"!o4"o3"258P560,PPe#!27$/+28$\`09PPe#!5:0;PPe#!-J\`0<5e!!o="x"w>y']; +__ɵΩrxjs.Observable = ['T', () => __ɵΩrxjs.Observable, 'source', () => __ɵΩrxjs.Operator, 'operator', () => __ɵΩrxjs.Observable, 'this', () => __ɵΩrxjs.Subscriber, 'subscriber', () => __ɵΩrxjs.TeardownLogic, '', 'subscribe', 'constructor', 'args', 'create', () => __ɵΩrxjs.Operator, () => __ɵΩrxjs.Observable, 'lift', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Subscription, 'value', 'next', 'forEach', () => __ɵΩrxjs.Observable, 'pipe', 'toPromise', () => __ɵΩrxjs.Subscribable, 'Observable', 'b!PP"7"-J3#P"e"!o$#-J3%PPPe$!7&2\\'Pe$!7(2)n*/+2,8"0-P"@2."/+3/sPe"!"o0#2%8P"7102Pe"!o4"o3"258P760,PPe#!27$/+28$\`09PPe#!7:0;PPe#!-J\`0<5e!!o="x"w>y']; const __ΩPartial = ['T', 'l+e#!e"!fRb!Pde"!gN#"y']; -__ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"5#2$"2%n&1\\'My']; -__ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!5)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP5!n"P$/#$Jy']; +__ɵΩrxjs.Operator = ['T', 'R', () => __ɵΩrxjs.Subscriber, 'subscriber', 'source', () => __ɵΩrxjs.TeardownLogic, 'call', 'b!b"PPPe$"7#2$"2%n&1\\'My']; +__ɵΩrxjs.Subscriber = ['T', () => __ɵΩrxjs.Subscription, 'x', '', 'next', 'e', 'error', 'complete', () => __ɵΩrxjs.Subscriber, 'create', 'isStopped', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'destination', () => __ɵΩrxjs.Subscriber, () => __ɵΩrxjs.Observer, 'constructor', 'value', 'err', 'unsubscribe', '_next', '_error', '_complete', () => __ɵΩrxjs.Observer, 'Subscriber', 'b!P7"PPe#!2#8$/$2%8P"2&8$/$2\\'8P$/$2(8Pe#!7)0*s)3+ __ɵΩrxjs.Subscription, () => __ɵΩrxjs.Unsubscribable, '', 'PP7!n"P$/#$Jy']; __ɵΩrxjs.Observer = ['T', 'value', '', 'next', 'err', 'error', 'complete', 'b!PPe#!2"$/#4$P"2%$/#4&P$/#4\\'My']; -__ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P5!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; +__ɵΩrxjs.Subscription = [() => __ɵΩrxjs.Subscription, 'EMPTY', 'closed', '', 'initialTeardown', 'constructor', 'unsubscribe', () => __ɵΩrxjs.TeardownLogic, 'teardown', 'add', () => __ΩExclude, () => __ɵΩrxjs.TeardownLogic, 'remove', () => __ɵΩrxjs.SubscriptionLike, 'Subscription', 'P7!3"s)3#PPP$/$-J2%8"0&P$0\\'Pn(2)$0*Pn,$o+#2)$0-5n.x"w/y']; __ɵΩrxjs.Subscribable = ['T', () => __ΩPartial, () => __ɵΩrxjs.Observer, 'observer', () => __ɵΩrxjs.Unsubscribable, 'subscribe', 'b!PPe#!o#"o""2$n%1&My']; const __ΩExclude = ['T', 'U', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)y']; __ɵΩrxjs.Unsubscribable = ['unsubscribe', 'PP$1!My']; __ɵΩrxjs.SubscriptionLike = [() => __ɵΩrxjs.Unsubscribable, 'unsubscribe', 'closed', 'Pn!P$1")4#9My']; const rxjs_1 = require("rxjs"); -const __ΩA = [() => __ɵΩrxjs.Observable, 'P#5!y']; +const __ΩA = [() => __ɵΩrxjs.Observable, 'P#7!y']; " `); }) diff --git a/packages/type/src/reflection/processor.ts b/packages/type/src/reflection/processor.ts index cf3ac2d04..6bd47eb9f 100644 --- a/packages/type/src/reflection/processor.ts +++ b/packages/type/src/reflection/processor.ts @@ -712,15 +712,15 @@ export class Processor { case ReflectionOp.classReference: { const ref = this.eatParameter() as number; const classOrFunction = resolveFunction(program.stack[ref] as Function, program.object); + // will be packed if external library import const packed = isPack(classOrFunction); const inputs = this.popFrame() as Type[]; if (!classOrFunction) { this.pushType({ kind: ReflectionKind.unknown }); break; } - const pack = packed ? classOrFunction : classOrFunction.__type; - if (!pack) { + if (!packed && !classOrFunction.__type) { if (op === ReflectionOp.classReference) { this.pushType({ kind: ReflectionKind.class, classType: classOrFunction, typeArguments: inputs, types: [] }); } else if (op === ReflectionOp.functionReference) { @@ -729,7 +729,7 @@ export class Processor { } else { //when it's just a simple reference resolution like typeOf() then enable cache re-use (so always the same type is returned) const directReference = !!(this.isEnded() && program.previous && program.previous.end === 0); - const result = this.reflect(pack, inputs, { inline: !directReference, reuseCached: directReference }); + const result = this.reflect(classOrFunction, inputs, { inline: !directReference, reuseCached: directReference }); if (directReference) program.directReturn = true; this.push(result, program); From 8bd0027fb50ac510a39316f95790171c43a55e28 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 8 Dec 2023 16:33:34 +0100 Subject: [PATCH 17/23] build: update tsconfig --- packages/api-console-gui/tsconfig.json | 8 +++++--- packages/framework-debug-gui/tsconfig.json | 10 ++++++---- packages/mysql/tsconfig.json | 8 +++++--- packages/postgres/tsconfig.json | 8 +++++--- packages/sqlite/tsconfig.json | 8 +++++--- .../tests/setup/suite1/tsconfig.no-types.json | 8 +++++--- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/packages/api-console-gui/tsconfig.json b/packages/api-console-gui/tsconfig.json index ed08a84b6..8dd5e249e 100644 --- a/packages/api-console-gui/tsconfig.json +++ b/packages/api-console-gui/tsconfig.json @@ -26,9 +26,11 @@ "marked" ] }, - "reflection": [ - "src/app/store.ts" - ], + "deepkitTypeCompilerOptions": { + "reflection": [ + "src/app/store.ts" + ] + }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, diff --git a/packages/framework-debug-gui/tsconfig.json b/packages/framework-debug-gui/tsconfig.json index 77cfbd360..0545e5cdf 100644 --- a/packages/framework-debug-gui/tsconfig.json +++ b/packages/framework-debug-gui/tsconfig.json @@ -27,10 +27,12 @@ "marked" ] }, - "reflection": [ - "./src/app/state.ts", - "node_modules/@deepkit/api-console-gui/src/app/store.ts" - ], + "deepkitTypeCompilerOptions": { + "reflection": [ + "./src/app/state.ts", + "node_modules/@deepkit/api-console-gui/src/app/store.ts" + ] + }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, diff --git a/packages/mysql/tsconfig.json b/packages/mysql/tsconfig.json index 42786fa1a..00933b1eb 100644 --- a/packages/mysql/tsconfig.json +++ b/packages/mysql/tsconfig.json @@ -17,9 +17,11 @@ "composite": true, "types": [] }, - "reflection": [ - "tests/**/*.ts" - ], + "deepkitTypeCompilerOptions": { + "reflection": [ + "tests/**/*.ts" + ] + }, "include": [ "benchmarks", "src", diff --git a/packages/postgres/tsconfig.json b/packages/postgres/tsconfig.json index 64fa4ea09..0f940df73 100644 --- a/packages/postgres/tsconfig.json +++ b/packages/postgres/tsconfig.json @@ -20,9 +20,11 @@ "sqlstring" ] }, - "reflection": [ - "tests/**/*.ts" - ], + "deepkitTypeCompilerOptions": { + "reflection": [ + "tests/**/*.ts" + ] + }, "include": [ "src", "tests", diff --git a/packages/sqlite/tsconfig.json b/packages/sqlite/tsconfig.json index 80762e5ed..3d42f04c8 100644 --- a/packages/sqlite/tsconfig.json +++ b/packages/sqlite/tsconfig.json @@ -19,9 +19,11 @@ "better-sqlite3" ] }, - "reflection": [ - "tests/**/*.ts" - ], + "deepkitTypeCompilerOptions": { + "reflection": [ + "tests/**/*.ts" + ] + }, "include": [ "benchmarks", "src", diff --git a/packages/type-compiler/tests/setup/suite1/tsconfig.no-types.json b/packages/type-compiler/tests/setup/suite1/tsconfig.no-types.json index 0d630d445..66bac7b24 100644 --- a/packages/type-compiler/tests/setup/suite1/tsconfig.no-types.json +++ b/packages/type-compiler/tests/setup/suite1/tsconfig.no-types.json @@ -1,6 +1,8 @@ { "extends": "./tsconfig.json", - "reflection": [ - "**/*/file1.ts" - ] + "deepkitTypeCompilerOptions": { + "reflection": [ + "**/*/file1.ts" + ] + } } From 6ed8d2b10948fd495034f153459f8a210f306f80 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 12 Dec 2023 10:45:50 +0100 Subject: [PATCH 18/23] chore: revert unnecessary changes --- packages/angular-universal/dist/.gitkeep | 0 packages/api-console-api/dist/.gitkeep | 0 packages/api-console-module/dist/.gitkeep | 0 packages/app/dist/.gitkeep | 0 packages/broker/dist/.gitkeep | 0 packages/bson/dist/.gitkeep | 0 packages/bun/dist/.gitkeep | 0 packages/core-rxjs/dist/.gitkeep | 0 packages/core/dist/.gitkeep | 0 packages/create-app/dist/.gitkeep | 0 packages/desktop-ui/dist/.gitkeep | 0 packages/event/dist/.gitkeep | 0 packages/filesystem-aws-s3/dist/.gitkeep | 0 packages/filesystem-ftp/dist/.gitkeep | 0 packages/filesystem-google/dist/.gitkeep | 0 packages/filesystem-sftp/dist/.gitkeep | 0 packages/filesystem/dist/.gitkeep | 0 packages/framework-debug-api/dist/.gitkeep | 0 packages/framework/dist/.gitkeep | 0 packages/http/dist/.gitkeep | 0 packages/injector/dist/.gitkeep | 0 packages/logger/dist/.gitkeep | 0 packages/mysql/dist/.gitkeep | 0 packages/orm-browser-api/dist/.gitkeep | 0 packages/orm-browser-gui/dist/.gitkeep | 0 packages/orm-browser/dist/.gitkeep | 0 packages/orm-integration/dist/.gitkeep | 0 packages/orm/dist/.gitkeep | 0 packages/postgres/dist/.gitkeep | 0 packages/rpc-tcp/dist/.gitkeep | 0 packages/rpc/dist/.gitkeep | 0 packages/skeleton/dist/.gitkeep | 0 packages/sql/dist/.gitkeep | 0 packages/sqlite/dist/.gitkeep | 0 packages/stopwatch/dist/.gitkeep | 0 packages/template/dist/.gitkeep | 0 packages/topsort/dist/.gitkeep | 0 packages/type-angular/dist/.gitkeep | 0 packages/type-compiler/dist/.gitkeep | 0 packages/type-spec/dist/.gitkeep | 0 packages/type/dist/.gitkeep | 0 packages/type/src/default.ts | 3 +-- packages/type/src/reference.ts | 2 +- packages/type/src/reflection/extends.ts | 2 +- packages/type/tests/typedarray.spec.ts | 2 +- packages/vite/dist/.gitkeep | 0 packages/workflow/dist/.gitkeep | 0 47 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 packages/angular-universal/dist/.gitkeep create mode 100644 packages/api-console-api/dist/.gitkeep create mode 100644 packages/api-console-module/dist/.gitkeep create mode 100644 packages/app/dist/.gitkeep create mode 100644 packages/broker/dist/.gitkeep create mode 100644 packages/bson/dist/.gitkeep create mode 100644 packages/bun/dist/.gitkeep create mode 100644 packages/core-rxjs/dist/.gitkeep create mode 100644 packages/core/dist/.gitkeep create mode 100644 packages/create-app/dist/.gitkeep create mode 100644 packages/desktop-ui/dist/.gitkeep create mode 100644 packages/event/dist/.gitkeep create mode 100644 packages/filesystem-aws-s3/dist/.gitkeep create mode 100644 packages/filesystem-ftp/dist/.gitkeep create mode 100644 packages/filesystem-google/dist/.gitkeep create mode 100644 packages/filesystem-sftp/dist/.gitkeep create mode 100644 packages/filesystem/dist/.gitkeep create mode 100644 packages/framework-debug-api/dist/.gitkeep create mode 100644 packages/framework/dist/.gitkeep create mode 100644 packages/http/dist/.gitkeep create mode 100644 packages/injector/dist/.gitkeep create mode 100644 packages/logger/dist/.gitkeep create mode 100644 packages/mysql/dist/.gitkeep create mode 100644 packages/orm-browser-api/dist/.gitkeep create mode 100644 packages/orm-browser-gui/dist/.gitkeep create mode 100644 packages/orm-browser/dist/.gitkeep create mode 100644 packages/orm-integration/dist/.gitkeep create mode 100644 packages/orm/dist/.gitkeep create mode 100644 packages/postgres/dist/.gitkeep create mode 100644 packages/rpc-tcp/dist/.gitkeep create mode 100644 packages/rpc/dist/.gitkeep create mode 100644 packages/skeleton/dist/.gitkeep create mode 100644 packages/sql/dist/.gitkeep create mode 100644 packages/sqlite/dist/.gitkeep create mode 100644 packages/stopwatch/dist/.gitkeep create mode 100644 packages/template/dist/.gitkeep create mode 100644 packages/topsort/dist/.gitkeep create mode 100644 packages/type-angular/dist/.gitkeep create mode 100644 packages/type-compiler/dist/.gitkeep create mode 100644 packages/type-spec/dist/.gitkeep create mode 100644 packages/type/dist/.gitkeep create mode 100644 packages/vite/dist/.gitkeep create mode 100644 packages/workflow/dist/.gitkeep diff --git a/packages/angular-universal/dist/.gitkeep b/packages/angular-universal/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/api-console-api/dist/.gitkeep b/packages/api-console-api/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/api-console-module/dist/.gitkeep b/packages/api-console-module/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/app/dist/.gitkeep b/packages/app/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/broker/dist/.gitkeep b/packages/broker/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/bson/dist/.gitkeep b/packages/bson/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/bun/dist/.gitkeep b/packages/bun/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core-rxjs/dist/.gitkeep b/packages/core-rxjs/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/dist/.gitkeep b/packages/core/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/create-app/dist/.gitkeep b/packages/create-app/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/desktop-ui/dist/.gitkeep b/packages/desktop-ui/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/event/dist/.gitkeep b/packages/event/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/filesystem-aws-s3/dist/.gitkeep b/packages/filesystem-aws-s3/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/filesystem-ftp/dist/.gitkeep b/packages/filesystem-ftp/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/filesystem-google/dist/.gitkeep b/packages/filesystem-google/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/filesystem-sftp/dist/.gitkeep b/packages/filesystem-sftp/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/filesystem/dist/.gitkeep b/packages/filesystem/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/framework-debug-api/dist/.gitkeep b/packages/framework-debug-api/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/framework/dist/.gitkeep b/packages/framework/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/http/dist/.gitkeep b/packages/http/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/injector/dist/.gitkeep b/packages/injector/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/logger/dist/.gitkeep b/packages/logger/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/mysql/dist/.gitkeep b/packages/mysql/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/orm-browser-api/dist/.gitkeep b/packages/orm-browser-api/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/orm-browser-gui/dist/.gitkeep b/packages/orm-browser-gui/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/orm-browser/dist/.gitkeep b/packages/orm-browser/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/orm-integration/dist/.gitkeep b/packages/orm-integration/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/orm/dist/.gitkeep b/packages/orm/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/postgres/dist/.gitkeep b/packages/postgres/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/rpc-tcp/dist/.gitkeep b/packages/rpc-tcp/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/rpc/dist/.gitkeep b/packages/rpc/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/skeleton/dist/.gitkeep b/packages/skeleton/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/sql/dist/.gitkeep b/packages/sql/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/sqlite/dist/.gitkeep b/packages/sqlite/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/stopwatch/dist/.gitkeep b/packages/stopwatch/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/template/dist/.gitkeep b/packages/template/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/topsort/dist/.gitkeep b/packages/topsort/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/type-angular/dist/.gitkeep b/packages/type-angular/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/type-compiler/dist/.gitkeep b/packages/type-compiler/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/type-spec/dist/.gitkeep b/packages/type-spec/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/type/dist/.gitkeep b/packages/type/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/type/src/default.ts b/packages/type/src/default.ts index b7095b5a0..4671b16a3 100644 --- a/packages/type/src/default.ts +++ b/packages/type/src/default.ts @@ -1,5 +1,4 @@ -import { binaryTypes, getClassType, ReflectionKind, resolveTypeMembers, Type } from './reflection/type.js'; -import { ClassType } from '@deepkit/core'; +import { binaryTypes, ReflectionKind, resolveTypeMembers, Type } from './reflection/type.js'; /** * Returns a sensible default value for a given type. diff --git a/packages/type/src/reference.ts b/packages/type/src/reference.ts index 9fd42a141..e3cac5a5c 100644 --- a/packages/type/src/reference.ts +++ b/packages/type/src/reference.ts @@ -11,7 +11,7 @@ import { ClassType, isObject } from '@deepkit/core'; import { ReflectionClass, reflectionClassSymbol } from './reflection/reflection.js'; import { typeSettings, UnpopulatedCheck, unpopulatedSymbol } from './core.js'; -import { getClassType, ReflectionKind, Type } from './reflection/type.js'; +import { ReflectionKind, Type } from './reflection/type.js'; export function isReferenceInstance(obj: any): boolean { return isObject(obj) && referenceSymbol in obj; diff --git a/packages/type/src/reflection/extends.ts b/packages/type/src/reflection/extends.ts index 376463ab2..202b3d3c3 100644 --- a/packages/type/src/reflection/extends.ts +++ b/packages/type/src/reflection/extends.ts @@ -11,7 +11,7 @@ import { addType, emptyObject, - flatten, getClassType, getTypeJitContainer, + flatten, getTypeJitContainer, indexAccess, isMember, isOptional, diff --git a/packages/type/tests/typedarray.spec.ts b/packages/type/tests/typedarray.spec.ts index 1c80ffe25..1303e9eb1 100644 --- a/packages/type/tests/typedarray.spec.ts +++ b/packages/type/tests/typedarray.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@jest/globals'; import { Buffer } from 'buffer'; import { ReflectionClass } from '../src/reflection/reflection.js'; -import { assertType, binaryTypes, getClassType, ReflectionKind } from '../src/reflection/type.js'; +import { assertType, binaryTypes, ReflectionKind } from '../src/reflection/type.js'; import { base64ToArrayBuffer, base64ToTypedArray, typedArrayToBase64, typedArrayToBuffer } from '../src/core.js'; import { deserialize, serialize } from '../src/serializer-facade.js'; diff --git a/packages/vite/dist/.gitkeep b/packages/vite/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/workflow/dist/.gitkeep b/packages/workflow/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb From e849dfb56058244ea95b01bcf8da668504f15467 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 12 Dec 2023 10:57:27 +0100 Subject: [PATCH 19/23] refactor: cleanup --- packages/type-compiler/src/compiler.ts | 53 ++++--------------- packages/type-compiler/src/reflection-ast.ts | 42 --------------- .../type-compiler/tests/transform.spec.ts | 2 +- 3 files changed, 11 insertions(+), 86 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 31f5377ff..0f24f91ce 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -194,7 +194,7 @@ export const packSize: number = 2 ** packSizeByte; //64 export interface ReflectionOptions { /** * Allows to exclude type definitions/TS files from being included in the type compilation step. - * When a global .d.ts is matched, their types won't be embeddedLibraryVariables (useful to exclude DOM for example) + * When a global .d.ts is matched, their types won't be embedded (useful to exclude DOM for example) */ exclude?: string[]; /** @@ -465,7 +465,7 @@ class CompilerProgram { return frame.variables.length - 1; } - pushTemplateParameter(name: string, withDefault: boolean = false): number { + pushTemplateParameter(name: string, withDefault: boolean = false): number { this.pushOp(withDefault ? ReflectionOp.typeParameterDefault : ReflectionOp.typeParameter, this.findOrAddStackEntry(name)); this.frame.variables.push({ index: this.frame.variables.length, @@ -1343,12 +1343,6 @@ export class ReflectionTransformer implements CustomTransformer { const narrowed = node as ClassDeclaration | ClassExpression; //class nodes have always their own program, so the start is always fresh, means we don't need a frame - /*if (this.external.isEmbeddingExternalLibraryImport()) { - const declaration = this.nodeConverter.convertClassToInterface(narrowed); - this.extractPackStructOfType(declaration, program); - break; - }*/ - if (node) { const members: ClassElement[] = []; @@ -1395,7 +1389,6 @@ export class ReflectionTransformer implements CustomTransformer { } program.pushOp(ReflectionOp.class) - // program.pushOp(!this.external.isEmbeddingExternalLibraryImport() ? ReflectionOp.class : ReflectionOp.objectLiteral); if (narrowed.heritageClauses) { for (const heritageClause of narrowed.heritageClauses) { @@ -1871,7 +1864,6 @@ export class ReflectionTransformer implements CustomTransformer { if (isIdentifier(narrowed.exprName)) { const resolved = this.resolveDeclaration(narrowed.exprName); if (resolved && findSourceFile(resolved.declaration) !== this.sourceFile && resolved.importDeclaration) { - // ensureImportIsEmitted(resolved.importDeclaration, narrowed.exprName); expression = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, narrowed.exprName, expression, program); } } @@ -2102,13 +2094,9 @@ export class ReflectionTransformer implements CustomTransformer { const builtType = isBuiltType(runtimeTypeName, declarationSourceFile); - const isEmbeddingExternalLibraryImport = this.external.isEmbeddingExternalLibraryImport(); - - if (isEmbeddingExternalLibraryImport || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { + if (this.external.isEmbeddingExternalLibraryImport() || (!builtType && this.external.shouldInlineExternalLibraryImport(importDeclaration, typeName, declarationReflection))) { const { module } = this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, importDeclaration); return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), getNameAsString(typeName)); - // const newExpression = this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), getNameAsString(typeName)); - // return isFunctionDeclaration(declaration) ? this.wrapWithAssignType(expression, newExpression) : newExpression; } } @@ -2214,7 +2202,6 @@ export class ReflectionTransformer implements CustomTransformer { if (isModuleDeclaration(declaration) && resolved.importDeclaration) { let expression: Expression = serializeEntityNameAsExpression(this.f, typeName); if (isIdentifier(typeName)) { - // ensureImportIsEmitted(resolved.importDeclaration, typeName); expression = this.resolveImportExpression(declaration, resolved.importDeclaration, typeName, expression, program) } @@ -2308,32 +2295,16 @@ export class ReflectionTransformer implements CustomTransformer { return; } - // const reflection = this.findReflectionFromPath(found.fileName); - // if (reflection.mode === 'never') { - // if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { - // console.log('inline'); - // this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - // } else { - // program.pushOp(ReflectionOp.any); - // return; - // } - // } - // - // this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); - const reflection = this.findReflectionFromPath(found.fileName); if (reflection.mode !== 'never') { this.addImports.push({ identifier: runtimeTypeName, from: resolved.importDeclaration.moduleSpecifier }); } else { - // const builtType = isBuiltType(runtimeTypeName, found); - // if (!builtType) { - if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { - this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); - } else { - program.pushOp(ReflectionOp.any); - return; - } - // } + if (this.external.shouldInlineExternalLibraryImport(resolved.importDeclaration, typeName, declarationReflection)) { + this.external.processExternalLibraryImport(typeName, declaration, declarationSourceFile, resolved.importDeclaration); + } else { + program.pushOp(ReflectionOp.any); + return; + } } } } else { @@ -2396,11 +2367,7 @@ export class ReflectionTransformer implements CustomTransformer { body = this.resolveImportExpression(resolved.declaration, resolved.importDeclaration, typeName, body, program); } const index = program.pushStack(this.f.createArrowFunction(undefined, undefined, [], undefined, undefined, body)); - //if (this.external.isEmbeddingExternalLibraryImport() || this.external.hasProcessedEntity(typeName)) { - // program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.class : ReflectionOp.function, index); - //} else { - program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); - //} + program.pushOp(isClassDeclaration(declaration) ? ReflectionOp.classReference : ReflectionOp.functionReference, index); program.popFrameImplicit(); } else if (isTypeParameterDeclaration(declaration)) { this.resolveTypeParameter(declaration, type, program); diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index cce7d3bce..c84f82c08 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -145,52 +145,10 @@ const cloneHook = (node: T, payload: { depth: number }): CloneNo export class NodeConverter { constructor(protected f: NodeFactory, protected external: External) {} - - public convertedNodes = new Map; - - private convertClassElementToTypeElement(node: ClassElement): TypeElement { - if (isPropertyDeclaration(node)) { - return this.f.createPropertySignature( - node.modifiers as readonly Modifier[] | undefined, - node.name, - node.questionToken, - node.type, - ); - } else if (isMethodDeclaration(node)) { - return this.f.createMethodSignature( - node.modifiers as readonly Modifier[] | undefined, - node.name, - node.questionToken, - node.typeParameters, - node.parameters, - node.type, - ); - } else if (isConstructorDeclaration(node)) { - // return this.f.createm - return this.f.createConstructSignature(node.typeParameters, node.parameters, node.type); - } - - throw new Error('Unsupported type'); - } - - convertClassToInterface(node: ClassDeclaration | ClassExpression): InterfaceDeclaration { - if (!node.name) { - throw new Error('Class name is required'); - } - return this.f.createInterfaceDeclaration( - node.modifiers as readonly Modifier[] | undefined, - node.name, - node.typeParameters, - node.heritageClauses, //node.heritageClauses.map(heritageClause => isInterfaceDeclaration(heritageClause.) ? heritageClause : this.f.createh(this.convertClassToInterface(heritageClause))), - node.members.map(member => this.convertClassElementToTypeElement(member)), - ); - } - createExternalRuntimeTypePropertyAccessExpression(name: string): PropertyAccessExpression { const { module } = this.external.getEmbeddingExternalLibraryImport(); return this.f.createPropertyAccessExpression(this.f.createIdentifier(getExternalRuntimeTypeName(module.packageId.name)), name) } - toExpression(node?: T): Expression { if (node === undefined) return this.f.createIdentifier('undefined'); diff --git a/packages/type-compiler/tests/transform.spec.ts b/packages/type-compiler/tests/transform.spec.ts index f053917ea..5694b83a2 100644 --- a/packages/type-compiler/tests/transform.spec.ts +++ b/packages/type-compiler/tests/transform.spec.ts @@ -112,7 +112,7 @@ test('globals', () => { ` }); - //we just make sure the global was detected and embeddedLibraryVariables + //we just make sure the global was detected and embedded expect(res.app).toContain('const __ΩPartial = '); expect(res.app).toContain('() => __ΩPartial'); }); From 4eeb978dfccbbfe112f4d36df71828d5a2779314 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 12 Dec 2023 11:08:45 +0100 Subject: [PATCH 20/23] fix(type-compiler): resolve external library import package id name --- packages/type-compiler/src/external.ts | 25 +++++++++++-------- packages/type-compiler/src/reflection-ast.ts | 4 +-- packages/type-compiler/src/resolver.ts | 17 ++++++------- .../inline-external-library-imports.spec.ts | 14 +++++------ 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index 1a87aa9f6..43fe622dc 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -67,17 +67,20 @@ export class External { } public shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { - if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; - if (!hasSourceFile(importDeclaration)) return false; - if (config.options.inlineExternalLibraryImports === true) return true; - const resolvedModule = this.resolver.resolveImport(importDeclaration); - if (!resolvedModule.isExternalLibraryImport || !resolvedModule.packageId) return false; - const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; - if (!imports) return false; - if (imports === true) return true; - if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; - const typeName = getEntityName(entityName); - return imports.includes(typeName); + try { + if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; + if (!hasSourceFile(importDeclaration)) return false; + const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); + if (config.options.inlineExternalLibraryImports === true) return true; + const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; + if (!imports) return false; + if (imports === true) return true; + if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; + const typeName = getEntityName(entityName); + return imports.includes(typeName); + } catch { + return false; + } } public hasProcessedEntity(typeName: EntityName): boolean { diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index c84f82c08..31788d98a 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -123,8 +123,8 @@ export function hasModifier(node: { modifiers?: NodeArray }, modif return node.modifiers.some(v => v.kind === modifier); } -export function getExternalRuntimeTypeName(typeName: string): string { - return `__ɵΩ${typeName}`; +export function getExternalRuntimeTypeName(importPath: string): string { + return `__ɵΩ${importPath.replace(/[^a-zA-Z0-9]+/g, '_')}`; } export function getRuntimeTypeName(typeName: string): string { diff --git a/packages/type-compiler/src/resolver.ts b/packages/type-compiler/src/resolver.ts index e8df63886..7b249eaff 100644 --- a/packages/type-compiler/src/resolver.ts +++ b/packages/type-compiler/src/resolver.ts @@ -73,18 +73,17 @@ export class Resolver { resolveExternalLibraryImport(importDeclaration: ImportDeclaration): Required { const resolvedModule = this.resolveImport(importDeclaration); - if (!resolvedModule.packageId) { - // FIXME: packageId is undefined when module specifier text is `rxjs/operators` - throw new Error('Missing package id for resolved module'); - /*resolvedModule.packageId = { - name: (importDeclaration.moduleSpecifier as StringLiteral).text.replace(/[^a-zA-Z0-9]+/g, '_'), - subModuleName: '', - version: '', - };*/ - } if (!resolvedModule.isExternalLibraryImport) { throw new Error('Resolved module is not an external library import'); } + if (!resolvedModule.packageId) { + // packageId will be undefined when importing from sub-paths such as `rxjs/operators` + resolvedModule.packageId = { + name: (importDeclaration.moduleSpecifier as StringLiteral).text, + subModuleName: 'unknown', + version: 'unknown', + }; + } return resolvedModule as Required; } diff --git a/packages/type-compiler/tests/inline-external-library-imports.spec.ts b/packages/type-compiler/tests/inline-external-library-imports.spec.ts index d292cfeb3..ab47211bd 100644 --- a/packages/type-compiler/tests/inline-external-library-imports.spec.ts +++ b/packages/type-compiler/tests/inline-external-library-imports.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from '@jest/globals'; -import {ReflectionKind, TypeClass, TypeFunction, } from '@deepkit/type'; +import { TypeClass, TypeFunction } from '@deepkit/type'; import { transpile, transpileAndRun } from './utils'; @@ -148,30 +148,30 @@ test('declares scoped variable', () => { test('function type alias', () => { const res = transpile({ - app: `import { map } from 'rxjs'; + app: `import { map } from 'rxjs/operators'; type A = typeof map; ` }, undefined, { inlineExternalLibraryImports: { - 'rxjs': ['map'], + 'rxjs/operators': ['map'], }, }); - expect(res.app).toContain('__ɵΩrxjs_operators.Ωmap = ['); - expect(res.app).toContain('() => __ɵΩrxjs_operators.Ωmap)'); + expect(res.app).toContain('__ɵΩrxjs_operators.map = ['); + expect(res.app).toContain('() => __ɵΩrxjs_operators.map'); }); test('typeOf function type alias', () => { const res = transpileAndRun({ - app: `import { map } from 'rxjs'; + app: `import { map } from 'rxjs/operators'; import { typeOf } from '@deepkit/type'; typeOf(); ` }, undefined, { inlineExternalLibraryImports: { - 'rxjs': ['map'], + 'rxjs/operators': ['map'], }, }) as TypeFunction; From cf31773df983ea95c304d1cdb0e756118a8412a8 Mon Sep 17 00:00:00 2001 From: "Marcus S. Abildskov" <8391194+marcus-sa@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:34:39 +0100 Subject: [PATCH 21/23] revert(type-compiler): keep reflection options the same for package.json Signed-off-by: Marcus S. Abildskov <8391194+marcus-sa@users.noreply.github.com> --- packages/type-compiler/src/compiler.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index 0f24f91ce..f1e133e89 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -2882,11 +2882,11 @@ export class ReflectionTransformer implements CustomTransformer { } } - if (reflection === undefined && packageJson.deepkitTypeCompilerOptions !== undefined) { + if (reflection === undefined && packageJson.reflection !== undefined) { return { - mode: this.parseReflectionMode(packageJson.deepkitTypeCompilerOptions.reflection, currentDir), + mode: this.parseReflectionMode(packageJson.reflection, currentDir), baseDir: currentDir, - options: this.parseReflectionOptionsDefaults(packageJson.deepkitTypeCompilerOptions || {}) + options: this.parseReflectionOptionsDefaults(packageJson.reflection || {}) }; } From 65489e388598b977add96be750e8657f7fbc8537 Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Tue, 9 Jan 2024 14:50:38 +0100 Subject: [PATCH 22/23] refactor --- packages/type-compiler/src/compiler.ts | 4 +- packages/type-compiler/src/external.ts | 43 ++++++++------------ packages/type-compiler/src/reflection-ast.ts | 2 +- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/packages/type-compiler/src/compiler.ts b/packages/type-compiler/src/compiler.ts index f1e133e89..965b788fc 100644 --- a/packages/type-compiler/src/compiler.ts +++ b/packages/type-compiler/src/compiler.ts @@ -2738,7 +2738,7 @@ export class ReflectionTransformer implements CustomTransformer { * * where we embed assignType() at the beginning of the type. */ - public wrapWithAssignType(fn: Expression, type: Expression) { + protected wrapWithAssignType(fn: Expression, type: Expression) { this.embedAssignType = true; return this.f.createCallExpression( @@ -2886,7 +2886,7 @@ export class ReflectionTransformer implements CustomTransformer { return { mode: this.parseReflectionMode(packageJson.reflection, currentDir), baseDir: currentDir, - options: this.parseReflectionOptionsDefaults(packageJson.reflection || {}) + options: this.parseReflectionOptionsDefaults(packageJson.reflectionOptions || {}) }; } diff --git a/packages/type-compiler/src/external.ts b/packages/type-compiler/src/external.ts index 43fe622dc..7ccea8ea4 100644 --- a/packages/type-compiler/src/external.ts +++ b/packages/type-compiler/src/external.ts @@ -1,8 +1,11 @@ import type { + Node, + ResolvedModuleFull, EntityName, - ImportDeclaration, SourceFile, + ImportDeclaration, + SourceFile, } from 'typescript'; -import ts, { Node, ResolvedModuleFull } from 'typescript'; +import ts from 'typescript'; const { isStringLiteral, @@ -67,20 +70,22 @@ export class External { } public shouldInlineExternalLibraryImport(importDeclaration: ImportDeclaration, entityName: EntityName, config: ReflectionConfig): boolean { + if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; + if (!hasSourceFile(importDeclaration)) return false; + let resolvedModule; try { - if (!isStringLiteral(importDeclaration.moduleSpecifier)) return false; - if (!hasSourceFile(importDeclaration)) return false; - const resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); - if (config.options.inlineExternalLibraryImports === true) return true; - const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; - if (!imports) return false; - if (imports === true) return true; - if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; - const typeName = getEntityName(entityName); - return imports.includes(typeName); + // throws an error if import is not an external library + resolvedModule = this.resolver.resolveExternalLibraryImport(importDeclaration); } catch { return false; } + if (config.options.inlineExternalLibraryImports === true) return true; + const imports = config.options.inlineExternalLibraryImports?.[resolvedModule.packageId.name]; + if (!imports) return false; + if (imports === true) return true; + if (!importDeclaration.moduleSpecifier.text.startsWith(resolvedModule.packageId.name)) return true; + const typeName = getEntityName(entityName); + return imports.includes(typeName); } public hasProcessedEntity(typeName: EntityName): boolean { @@ -103,20 +108,6 @@ export class External { } this.processedEntities.add(entityName); - // const libraryFiles = this.processedExternalLibraryImports.get(module.packageId.name) || new Map(); - // const libraryFileEntities = libraryFiles.get(module.resolvedFileName) || new Set(); - // if (libraryFileEntities.has(entityName)) { - // return { - // name: typeName, - // declaration, - // sourceFile, - // module, - // } - // } - // - // libraryFileEntities.add(entityName); - // libraryFiles.set(module.resolvedFileName, libraryFileEntities); - // this.processedExternalLibraryImports.set(module.packageId.name, libraryFiles); const imports = this.compileExternalLibraryImports.get(module.packageId.name) || new Map(); const externalLibraryImport: ExternalLibraryImport = { diff --git a/packages/type-compiler/src/reflection-ast.ts b/packages/type-compiler/src/reflection-ast.ts index 31788d98a..9d63f7f60 100644 --- a/packages/type-compiler/src/reflection-ast.ts +++ b/packages/type-compiler/src/reflection-ast.ts @@ -273,7 +273,7 @@ export function serializeEntityNameAsExpression(f: NodeFactory, node: EntityName return node; } -export type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression; +type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression; /** * Serializes an qualified name as an expression for decorator type metadata. From 749d1182f67b5bc21abef7bb0a6478021a716a3c Mon Sep 17 00:00:00 2001 From: marcus-sa Date: Fri, 12 Jan 2024 15:05:45 +0100 Subject: [PATCH 23/23] feat(type): update extractTypeNameFromFunction to match external library imports --- packages/type/src/reflection/reflection.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/type/src/reflection/reflection.ts b/packages/type/src/reflection/reflection.ts index 7a457de01..477d13563 100644 --- a/packages/type/src/reflection/reflection.ts +++ b/packages/type/src/reflection/reflection.ts @@ -1435,8 +1435,10 @@ export class ReflectionClass { export function extractTypeNameFromFunction(fn: Function): string { const str = fn.toString(); - //either it starts with __Ω* or __\u{3a9}* (bun.js) - const match = str.match(/(?:__Ω|__\\u\{3a9\})([\w]+)/); + // either it starts with + // __Ω* or __ɵΩ* (node.js) + // __\u{3a9}* or __\u{275}\u{3a9}* (bun.js) + const match = str.match(/(?:__Ω|__\\u\{3a9\}|__ɵΩ|__\\u{275}\\u{3a9}*)([\w]+)/); if (match) { return match[1]; }