From 01851727900478896ceae07bfb91209528df93d8 Mon Sep 17 00:00:00 2001 From: "Alexander J. Vincent" Date: Fri, 12 Jan 2024 06:57:06 -0800 Subject: [PATCH] #41, integration test (doesn't compile yet) --- .../spec-snapshot/source/integration.ts.txt | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 stage_2_fullset/spec-snapshot/source/integration.ts.txt diff --git a/stage_2_fullset/spec-snapshot/source/integration.ts.txt b/stage_2_fullset/spec-snapshot/source/integration.ts.txt new file mode 100644 index 00000000..f22dcbb5 --- /dev/null +++ b/stage_2_fullset/spec-snapshot/source/integration.ts.txt @@ -0,0 +1,232 @@ +// #region preamble +import { + ModuleKind, + ModuleResolutionKind, + Project, + ProjectOptions, + ScriptTarget, + SourceFile, + Structure, + forEachStructureChild, +} from "ts-morph"; + +import getTS_SourceFile from "#utilities/source/getTS_SourceFile.js"; +import { + ModuleSourceDirectory, +} from "#utilities/source/AsyncSpecModules.js"; + +import { + ArrayTypeStructureImpl, + ClassDeclarationImpl, + ConditionalTypeStructureImpl, + FunctionTypeStructureImpl, + ImportDeclarationImpl, + ImportSpecifierImpl, + IndexedAccessTypeStructureImpl, + InterfaceDeclarationImpl, + MappedTypeStructureImpl, + MethodDeclarationImpl, + MemberedObjectTypeStructureImpl, + ParameterTypeStructureImpl, + PrefixOperatorsTypeStructureImpl, + PropertySignatureImpl, + SourceFileImpl, + TypeAliasDeclarationImpl, + TypeArgumentedTypeStructureImpl, + TypeParameterDeclarationImpl, + getTypeAugmentedStructure +} from "#stage_two/snapshot/source/exports.js"; + +// #endregion preamble + +it("ts-morph-structures: integration test", () => { + const stageDir: ModuleSourceDirectory = { + pathToDirectory: "#stage_one", + isAbsolutePath: true + }; + + // get the NumberStringType interface + let NST_InterfaceStructure = new InterfaceDeclarationImpl("notUsed"); + { + const NumberStringClassFile = getTS_SourceFile( + stageDir, "fixtures/ecma_references/NumberStringClass.ts" + ); + const NST_Node = NumberStringClassFile.getInterfaceOrThrow("NumberStringType"); + + const result = getTypeAugmentedStructure( + NST_Node, (message, failingTypeNode) => { + void(message); + void(failingTypeNode); + }, true + ); + expect(result.failures.length).toBe(0); + expect(result.rootStructure).toBeInstanceOf(InterfaceDeclarationImpl); + + if (result.rootStructure instanceof InterfaceDeclarationImpl) + NST_InterfaceStructure = result.rootStructure; + else + return; + } + + const newSourceStructure = new SourceFileImpl; + + // imports + { + const SetReturnTypeImport = new ImportDeclarationImpl("type-fest"); + SetReturnTypeImport.namedImports.push(new ImportSpecifierImpl("SetReturnType")); + SetReturnTypeImport.isTypeOnly = true; + + const NST_Type_Import = new ImportDeclarationImpl("./NumberStringClass.js"); + const NST_Specifier = new ImportSpecifierImpl("NumberStringType"); + NST_Specifier.isTypeOnly = true; + NST_Type_Import.namedImports.push(NST_Specifier); + + newSourceStructure.statements.push(SetReturnTypeImport, NST_Type_Import); + } + + // type ValueWrapper = { value: T }; + { + const ValueWrapperAlias = new TypeAliasDeclarationImpl("ValueWrapper", "T"); + newSourceStructure.statements.push(ValueWrapperAlias); + + const valueProperty = new PropertySignatureImpl("value"); + valueProperty.type = "T"; + ValueWrapperAlias.typeStructure = new MemberedObjectTypeStructureImpl(); + ValueWrapperAlias.typeStructure.properties.push(valueProperty); + } + + /* + type ObjectWrapper = { + [key in keyof Type]: Type[key] extends (...args: any[]) => any ? + SetReturnType< + Type[key], + ValueWrapper< + ReturnType + > + > : Type[key]; + } + */ + { + const ObjectWrapperAlias = new TypeAliasDeclarationImpl("ObjectWrapper", "Type"); + newSourceStructure.statements.push(ObjectWrapperAlias); + + const TypeKeyIndexed = new IndexedAccessTypeStructureImpl( + "Type", "key" + ); + + const SetReturnType_Structure = new TypeArgumentedTypeStructureImpl( + "SetReturnType", [TypeKeyIndexed, new TypeArgumentedTypeStructureImpl("ValueWrapper", [ + new TypeArgumentedTypeStructureImpl("ReturnType", [TypeKeyIndexed]) + ])] + ); + + const RestAnyFunction_Structure = new FunctionTypeStructureImpl({ + restParameter: new ParameterTypeStructureImpl( + "args", + new ArrayTypeStructureImpl("any") + ), + returnType: "any", + }); + + const conditionalStructure = new ConditionalTypeStructureImpl({ + checkType: TypeKeyIndexed, + extendsType: RestAnyFunction_Structure, + trueType: SetReturnType_Structure, + falseType: TypeKeyIndexed + }); + + const keyInKeyofStructure = new TypeParameterDeclarationImpl("key"); + keyInKeyofStructure.constraintStructure = new PrefixOperatorsTypeStructureImpl( + ["keyof"], "Type" + ); + + const mappedTypeStructure = new MappedTypeStructureImpl( + keyInKeyofStructure + ); + mappedTypeStructure.type = conditionalStructure; + + ObjectWrapperAlias.typeStructure = mappedTypeStructure; + } + + /* + export default class NumberStringWrapper + implements ObjectWrapper + { + repeatForward(s: string, n: number): ValueWrapper { + return { value: s.repeat(n) }; + } + repeatBack(n: number, s: string): ValueWrapper { + return { value: s.repeat(n) }; + } + } + */ + { + const classDeclaration = new ClassDeclarationImpl; + newSourceStructure.statements.push(classDeclaration); + + classDeclaration.name = "NumberStringWrapper"; + classDeclaration.isExported = true; + classDeclaration.isDefaultExport = true; + + classDeclaration.implementsSet.add(new TypeArgumentedTypeStructureImpl( + "ObjectWrapper", ["NumberStringType"] + )); + + const ValueWrapperString = new TypeArgumentedTypeStructureImpl( + "ValueWrapper", ["string"] + ); + + const methods: MethodDeclarationImpl[] = NST_InterfaceStructure.methods.map( + signature => MethodDeclarationImpl.clone(signature) + ); + + methods.forEach(method => { + method.returnTypeStructure = ValueWrapperString; + method.statements.push("return { value: s.repeat(n) };"); + }); + + classDeclaration.methods.push(...methods); + } + + // create the source file + let NumberStringWrapper_File: SourceFile; + { + const TSC_CONFIG: ProjectOptions = { + "compilerOptions": { + "lib": ["es2022"], + "module": ModuleKind.ESNext, + "target": ScriptTarget.ESNext, + "moduleResolution": ModuleResolutionKind.NodeNext, + }, + skipAddingFilesFromTsConfig: true, + useInMemoryFileSystem: true, + }; + + const project = new Project(TSC_CONFIG); + NumberStringWrapper_File = project.createSourceFile("NumberStringWrapper.ts", newSourceStructure); + + const source = NumberStringWrapper_File.print(); + project.removeSourceFile(NumberStringWrapper_File); + + NumberStringWrapper_File = project.createSourceFile("NumberStringWrapper.ts", source); + } + + // reference structure + const referenceStructure = getTS_SourceFile( + stageDir, "fixtures/ecma_references/NumberStringWrapped.ts" + ).getStructure(); + + const actualStructure = NumberStringWrapper_File.getStructure(); + + // whitespace cleanup + forEachStructureChild(referenceStructure, structure => { + if (Structure.isTyped(structure)) + structure.type = (structure.type as string).replace(/\s+/gm, " "); + }); + forEachStructureChild(actualStructure, structure => { + if (Structure.isTyped(structure)) + structure.type = (structure.type as string).replace(/\s+/gm, " "); + }); + + expect(actualStructure).toEqual(referenceStructure); +});