Skip to content

Commit

Permalink
#36, getTypeAugmentedStructure, part 1.
Browse files Browse the repository at this point in the history
  • Loading branch information
ajvincent committed Jan 12, 2024
1 parent 2099c16 commit 894b619
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 0 deletions.
18 changes: 18 additions & 0 deletions stage_1_bootstrap/build/BuildClassesDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,24 @@ async function defineExistingExports(
isType: true
});

dictionaries.publicExports.addExports({
absolutePathToModule: path.join(distDir, "source/bootstrap/getTypeAugmentedStructure.ts"),
exportNames: [
"getTypeAugmentedStructure",
],
isDefaultExport: true,
isType: false
});

dictionaries.publicExports.addExports({
absolutePathToModule: path.join(distDir, "source/bootstrap/getTypeAugmentedStructure.ts"),
exportNames: [
"TypeNodeToTypeStructureConsole"
],
isDefaultExport: false,
isType: true
});

dictionaries.publicExports.addExports({
absolutePathToModule: path.join(distDir, "source/toolbox/ClassMembersMap.ts"),
exportNames: ["ClassMembersMap"],
Expand Down
82 changes: 82 additions & 0 deletions stage_1_integration/bootstrap/getTypeAugmentedStructure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// #region preamble
import assert from "node:assert/strict";

import {
Node
} from "ts-morph";

import type {
StructureImpls,
} from "../snapshot/source/exports.js";

import {
structureImplToNodeMap
} from "./structureToNodeMap.js";

import buildTypesForStructures from "./buildTypesForStructures.js";

import convertTypeNode from "./convertTypeNode.js";

import type {
BuildTypesForStructureFailures,
NodeWithStructures,
RootStructureWithConvertFailures,
TypeNodeToTypeStructureConsole,
} from "./types/conversions.js";
// #endregion preamble

export type {
TypeNodeToTypeStructureConsole
};

/**
* Get a structure for a node, with type structures installed throughout its descendants.
* @param rootNode - The node to start from.
* @param userConsole - a callback for conversion failures.
* @param assertNoFailures - if true, assert there are no conversion failures.
* @returns the root structure, the root node, and any failures during recursion.
*/
export default function getTypeAugmentedStructure(
rootNode: NodeWithStructures,
userConsole: TypeNodeToTypeStructureConsole,
assertNoFailures: boolean,
): RootStructureWithConvertFailures
{
const map: ReadonlyMap<StructureImpls, Node> = structureImplToNodeMap(rootNode);
assert(map.size > 0, "we should have some structures");

let rootStructure: StructureImpls | undefined;
for (const [structure, node] of map.entries()) {
if (node === rootNode) {
rootStructure = structure;
break;
}
}
assert(rootStructure, "we should have a root structure");

const subFailures: BuildTypesForStructureFailures[] = [];

const failures = buildTypesForStructures(
map,
userConsole,
(nodeWithStructure: NodeWithStructures): StructureImpls => {
const subStructureResults: RootStructureWithConvertFailures = getTypeAugmentedStructure(
nodeWithStructure, userConsole, false
);
subFailures.push(...subStructureResults.failures);
return subStructureResults.rootStructure;
},
convertTypeNode
);
failures.push(...subFailures);

if (assertNoFailures) {
assert(failures.length === 0, "caller required no failures, but we did fail");
}

return {
rootStructure,
rootNode,
failures,
}
}
6 changes: 6 additions & 0 deletions stage_1_integration/bootstrap/types/conversions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ export type TypeNodeToTypeStructure = (
_console: TypeNodeToTypeStructureConsole,
subStructureResolver: SubstructureResolver,
) => stringTypeStructuresOrNull

export interface RootStructureWithConvertFailures {
rootStructure: StructureImpls;
rootNode: NodeWithStructures;
failures: readonly BuildTypesForStructureFailures[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// #region preamble
import assert from "node:assert/strict";

import {
Node
} from "ts-morph";

import type {
StructureImpls,
} from "../exports.js";

import {
structureImplToNodeMap
} from "./structureToNodeMap.js";

import buildTypesForStructures from "./buildTypesForStructures.js";

import convertTypeNode from "./convertTypeNode.js";

import type {
BuildTypesForStructureFailures,
NodeWithStructures,
RootStructureWithConvertFailures,
TypeNodeToTypeStructureConsole,
} from "./types/conversions.js";
// #endregion preamble

export type {
TypeNodeToTypeStructureConsole
};

/**
* Get a structure for a node, with type structures installed throughout its descendants.
* @param rootNode - The node to start from.
* @param userConsole - a callback for conversion failures.
* @param assertNoFailures - if true, assert there are no conversion failures.
* @returns the root structure, the root node, and any failures during recursion.
*/
export default function getTypeAugmentedStructure(
rootNode: NodeWithStructures,
userConsole: TypeNodeToTypeStructureConsole,
assertNoFailures: boolean,
): RootStructureWithConvertFailures
{
const map: ReadonlyMap<StructureImpls, Node> = structureImplToNodeMap(rootNode);
assert(map.size > 0, "we should have some structures");

let rootStructure: StructureImpls | undefined;
for (const [structure, node] of map.entries()) {
if (node === rootNode) {
rootStructure = structure;
break;
}
}
assert(rootStructure, "we should have a root structure");

const subFailures: BuildTypesForStructureFailures[] = [];

const failures = buildTypesForStructures(
map,
userConsole,
(nodeWithStructure: NodeWithStructures): StructureImpls => {
const subStructureResults: RootStructureWithConvertFailures = getTypeAugmentedStructure(
nodeWithStructure, userConsole, false
);
subFailures.push(...subStructureResults.failures);
return subStructureResults.rootStructure;
},
convertTypeNode
);
failures.push(...subFailures);

if (assertNoFailures) {
assert(failures.length === 0, "caller required no failures, but we did fail");
}

return {
rootStructure,
rootNode,
failures,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ export type TypeNodeToTypeStructure = (
_console: TypeNodeToTypeStructureConsole,
subStructureResolver: SubstructureResolver,
) => stringTypeStructuresOrNull

export interface RootStructureWithConvertFailures {
rootStructure: StructureImpls;
rootNode: NodeWithStructures;
failures: readonly BuildTypesForStructureFailures[];
}
4 changes: 4 additions & 0 deletions stage_2_fullset/snapshot/source/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ export {
type KindedTypeStructure,
TypeStructureKind,
} from "./base/TypeStructureKind.js";
export {
default as getTypeAugmentedStructure,
type TypeNodeToTypeStructureConsole,
} from "./bootstrap/getTypeAugmentedStructure.js";
export { default as CallSignatureDeclarationImpl } from "./structures/CallSignatureDeclarationImpl.js";
export { default as ClassDeclarationImpl } from "./structures/ClassDeclarationImpl.js";
export { default as ClassStaticBlockDeclarationImpl } from "./structures/ClassStaticBlockDeclarationImpl.js";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {
TypeNode,
} from "ts-morph";

import type {
ModuleSourceDirectory,
} from "#utilities/source/AsyncSpecModules.js";

import getTS_SourceFile from "#utilities/source/getTS_SourceFile.js";

import {
ClassDeclarationImpl,
/*
FunctionTypeStructureImpl,
*/
getTypeAugmentedStructure,
MethodDeclarationImpl,
TypeArgumentedTypeStructureImpl,
TypeNodeToTypeStructureConsole,
TypeParameterDeclarationImpl,
} from "#stage_two/snapshot/source/exports.js";

it("getTypeAugmentedStructure gets structures having type structures for types", () => {
const stageDir: ModuleSourceDirectory = {
isAbsolutePath: true,
pathToDirectory: "#stage_two",
};

const sourceFile = getTS_SourceFile(stageDir, "fixtures/stage_utilities/DefaultMap.ts");
const DefaultWeakMapClass = sourceFile.getClassOrThrow("DefaultWeakMap");

function typeStructureConsole(
message: string,
failingTypeNode: TypeNode
): void {
void(message);
void(failingTypeNode);
}
typeStructureConsole satisfies TypeNodeToTypeStructureConsole;

const {
rootNode,
rootStructure,
failures
} = getTypeAugmentedStructure(DefaultWeakMapClass, typeStructureConsole, false);
expect(rootNode).toBe(DefaultWeakMapClass);

expect(rootStructure).toBeInstanceOf(ClassDeclarationImpl);
if (!(rootStructure instanceof ClassDeclarationImpl))
return;

expect(rootStructure.typeParameters.length).toBe(2);
if (rootStructure.typeParameters.length === 2) {
const [firstParam, secondParam] = rootStructure.typeParameters;
expect(firstParam).toBeInstanceOf(TypeParameterDeclarationImpl);
if (firstParam instanceof TypeParameterDeclarationImpl) {
expect(firstParam.name).toBe("K");
expect(firstParam.constraintStructure).toBe("object");
}

expect(secondParam).toBeInstanceOf(TypeParameterDeclarationImpl);
if (secondParam instanceof TypeParameterDeclarationImpl) {
expect(secondParam.name).toBe("V");
expect(secondParam.constraintStructure).toBe(undefined);
expect(secondParam.constraint).toBe(undefined);
}
}

const { extendsStructure } = rootStructure;

expect(extendsStructure).toBeInstanceOf(TypeArgumentedTypeStructureImpl);
if (extendsStructure instanceof TypeArgumentedTypeStructureImpl) {
expect(extendsStructure.objectType).toBe("WeakMap");
expect(extendsStructure.childTypes[0]).toBe("K");
expect(extendsStructure.childTypes[1]).toBe("V");
}

expect(rootStructure.methods.length).toBe(1);

const getDefaultMethod = rootStructure.methods[0];
expect(getDefaultMethod).toBeInstanceOf(MethodDeclarationImpl);
if (getDefaultMethod instanceof MethodDeclarationImpl) {
expect(getDefaultMethod.typeParameters.length).toBe(0);
expect(getDefaultMethod.parameters.length).toBe(2);
/*
if (getDefaultMethod.parameters.length === 2) {
const [key, builder] = getDefaultMethod.parameters;
expect(key.typeStructure).toBe("K");
expect(builder.typeStructure).toBeInstanceOf(FunctionTypeStructureImpl)
if (builder.typeStructure instanceof FunctionTypeStructureImpl) {
expect(builder.typeStructure.typeParameters.length).toBe(0)
expect(builder.typeStructure.parameters.length).toBe(0);
expect(builder.typeStructure.returnType).toBe("V");
}
}
*/
}

expect(failures.length).withContext("failure count").toBe(0);
});

0 comments on commit 894b619

Please sign in to comment.