diff --git a/.dependency-cruiser.js b/.dependency-cruiser.js index 319f06f..5c8320e 100644 --- a/.dependency-cruiser.js +++ b/.dependency-cruiser.js @@ -9,7 +9,7 @@ module.exports = { path: "^src/utils/", }, to: { - path: "^src/classses/", + path: "^src/classes/", }, }, // @@ -153,7 +153,7 @@ module.exports = { "section of your package.json. If this module is development only - add it to the " + "from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration", from: { - path: "^(src/classses)", + path: "^(src/classes)", pathNot: "[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$", }, to: { @@ -384,7 +384,7 @@ module.exports = { attributes: { fillcolor: "#FFA726", fontcolor: "black" }, }, { - criteria: { source: "classses" }, + criteria: { source: "classes" }, attributes: { fillcolor: "#EF5350", fontcolor: "black" }, }, { @@ -402,7 +402,7 @@ module.exports = { ], dependencies: [ { - criteria: { resolved: "classses" }, + criteria: { resolved: "classes" }, attributes: { color: "#EF5350" }, }, { diff --git a/index.html b/index.html index 85bf6f0..51fb571 100644 --- a/index.html +++ b/index.html @@ -125,177 +125,207 @@ - - + + dependency-cruiser output - + cluster_src - -src + +src cluster_src/classses - -classses + +classses cluster_src/classses/Lax - -Lax + +Lax cluster_src/classses/Strict - -Strict + +Strict -cluster_src/classses/types - -types +cluster_src/classses/generated + +generated -cluster_src/classses/utils - -utils +cluster_src/classses/generated/TypeMirror + +TypeMirror -cluster_src/coreTypes - -coreTypes +cluster_src/classses/types + +types -cluster_src/coreTypes/errors - -errors +cluster_src/classses/utils + +utils -cluster_src/coreTypes/trace - -trace +cluster_src/coreTypes + +coreTypes -cluster_src/coreTypes/validators - -validators +cluster_src/coreTypes/errors + +errors -cluster_src/coreTypes/validators/flatValidate - -flatValidate +cluster_src/coreTypes/trace + +trace -cluster_src/coreTypes/validators/validate - -validate +cluster_src/coreTypes/validators + +validators -cluster_src/coreTypes/validators/validateArr - -validateArr +cluster_src/coreTypes/validators/flatValidate + +flatValidate -cluster_src/coreTypes/validators/validateComputedGenerics - -validateComputedGenerics +cluster_src/coreTypes/validators/validate + +validate -cluster_src/coreTypes/validators/validateEmtpyString - -validateEmtpyString +cluster_src/coreTypes/validators/validateArr + +validateArr -cluster_src/coreTypes/validators/validateLiteral - -validateLiteral +cluster_src/coreTypes/validators/validateComputedGenerics + +validateComputedGenerics -cluster_src/coreTypes/validators/validateType - -validateType +cluster_src/coreTypes/validators/validateEmtpyString + +validateEmtpyString -cluster_src/coreTypes/validators/validateUsableSting - -validateUsableSting +cluster_src/coreTypes/validators/validateLiteral + +validateLiteral -cluster_src/regexes - -regexes +cluster_src/coreTypes/validators/validateType + +validateType -cluster_src/services - -services +cluster_src/coreTypes/validators/validateUsableSting + +validateUsableSting -cluster_src/services/ImportRegistry - -ImportRegistry +cluster_src/regexes + +regexes -cluster_src/testData - -testData +cluster_src/scripts + +scripts -cluster_src/tsc - -tsc +cluster_src/scripts/generateTypeMirrorClass + +generateTypeMirrorClass -cluster_src/utilTypes - -utilTypes +cluster_src/scripts/generateTypeMirrorClass/typeProcessing + +typeProcessing -cluster_src/utils - -utils +cluster_src/scripts/generateTypeMirrorClass/utils + +utils -cluster_src/utils/consts - -consts +cluster_src/services + +services -cluster_src/utils/createJsDocs - -createJsDocs +cluster_src/services/ImportRegistry + +ImportRegistry -cluster_src/utils/parseTypeDeclarations - -parseTypeDeclarations +cluster_src/testData + +testData -cluster_src/utils/reTypeError - -reTypeError +cluster_src/tsc + +tsc -cluster_src/utils/resolveGenerics - -resolveGenerics +cluster_src/utilTypes + +utilTypes -cluster_src/utils/typeBuilder - -typeBuilder +cluster_src/utils + +utils +cluster_src/utils/consts + +consts + + +cluster_src/utils/createJsDocs + +createJsDocs + + +cluster_src/utils/parseTypeDeclarations + +parseTypeDeclarations + + +cluster_src/utils/reTypeError + +reTypeError + + +cluster_src/utils/resolveGenerics + +resolveGenerics + + +cluster_src/utils/typeBuilder + +typeBuilder + + cluster_src/utils/typeBuilder/utils - -utils + +utils src/buildTypes.ts - -buildTypes.ts + +buildTypes.ts @@ -303,946 +333,1102 @@ src/classses/Lax/index.ts - -index.ts + +index.ts src/buildTypes.ts->src/classses/Lax/index.ts - - + + src/classses/Strict/index.ts - -index.ts + +index.ts src/buildTypes.ts->src/classses/Strict/index.ts - - + + src/services/ImportRegistry/index.ts - -index.ts + +index.ts src/buildTypes.ts->src/services/ImportRegistry/index.ts - - + + src/classses/types/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/classses/types/index.ts - - + + src/classses/utils/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/classses/utils/index.ts - - + + src/utils/createJsDocs/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/utils/createJsDocs/index.ts - - + + src/utils/parseTypeDeclarations/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + src/utils/resolveGenerics/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/utils/resolveGenerics/index.ts - - + + src/utils/typeBuilder/index.ts - -index.ts + +index.ts src/classses/Lax/index.ts->src/utils/typeBuilder/index.ts - - + + src/classses/Strict/index.ts->src/services/ImportRegistry/index.ts - - + + src/classses/Strict/index.ts->src/classses/utils/index.ts - - + + src/classses/Strict/index.ts->src/utils/createJsDocs/index.ts - - + + src/classses/Strict/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + src/classses/Strict/index.ts->src/utils/resolveGenerics/index.ts - - + + src/classses/Strict/index.ts->src/utils/typeBuilder/index.ts - - + + src/utils/reTypeError/trace.ts - -trace.ts + +trace.ts src/classses/Strict/index.ts->src/utils/reTypeError/trace.ts - - + + src/classses/Lax/index.test.ts - -index.test.ts + +index.test.ts src/classses/Lax/index.test.ts->src/classses/Lax/index.ts - - + + - + src/classses/utils/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/consts/index.ts - - -index.ts + + +index.ts - + src/classses/utils/index.ts->src/utils/consts/index.ts - - + + - + src/utils/createJsDocs/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utilTypes/index.ts - - -index.ts + + +index.ts - + src/utils/createJsDocs/index.ts->src/utilTypes/index.ts - - + + - + src/regexes/index.ts - - -index.ts + + +index.ts - + src/utils/parseTypeDeclarations/index.ts->src/regexes/index.ts - - + + - + src/utils/resolveGenerics/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/resolveGenerics/index.ts->src/utils/consts/index.ts - - + + - + src/utils/resolveGenerics/index.ts->src/utilTypes/index.ts - - + + - + src/utils/typeBuilder/genericArgs.ts - - -genericArgs.ts + + +genericArgs.ts - + src/utils/typeBuilder/index.ts->src/utils/typeBuilder/genericArgs.ts - - + + - + src/utils/typeBuilder/relaxConstraints.ts - - -relaxConstraints.ts + + +relaxConstraints.ts - + src/utils/typeBuilder/index.ts->src/utils/typeBuilder/relaxConstraints.ts - - + + - + src/utils/typeBuilder/typeDefinitions.ts - - -typeDefinitions.ts + + +typeDefinitions.ts - + src/utils/typeBuilder/index.ts->src/utils/typeBuilder/typeDefinitions.ts - - + + src/classses/Strict/index.test.ts - -index.test.ts + +index.test.ts src/classses/Strict/index.test.ts->src/classses/Strict/index.ts - - + + - + src/utils/reTypeError/trace.ts->src/utils/consts/index.ts - - + + - + src/utils/reTypeError/uuid.ts - - -uuid.ts + + +uuid.ts - + src/utils/reTypeError/trace.ts->src/utils/reTypeError/uuid.ts - - + + - - -src/utils/consts/index.ts->src/utils/parseTypeDeclarations/index.ts - - - - - -src/coreTypes/errors/errors.ts - - -errors.ts + + +src/classses/generated/TypeMirror/index.ts + + +index.ts - - -src/coreTypes/errors/errors.ts->src/utilTypes/index.ts - - - - - -src/coreTypes/trace/index.ts - - -index.ts + + +src/coreTypes/errors/index.ts + + +index.ts - - -src/coreTypes/errors/errors.ts->src/coreTypes/trace/index.ts - - + + +src/classses/generated/TypeMirror/index.ts->src/coreTypes/errors/index.ts + + - - -src/utilTypes/unionToArray.ts - - -unionToArray.ts + + +src/coreTypes/validators/index.ts + + +index.ts - - -src/utilTypes/index.ts->src/utilTypes/unionToArray.ts - - + + +src/classses/generated/TypeMirror/index.ts->src/coreTypes/validators/index.ts + + - + -src/coreTypes/errors/index.ts - - -index.ts +src/coreTypes/errors/errors.ts + + +errors.ts - + src/coreTypes/errors/index.ts->src/coreTypes/errors/errors.ts - - + + - + src/coreTypes/errors/utils.ts - - -utils.ts + + +utils.ts - + src/coreTypes/errors/index.ts->src/coreTypes/errors/utils.ts - - + + + + + +src/coreTypes/validators/consts.ts + + +consts.ts + + + + + +src/coreTypes/validators/index.ts->src/coreTypes/validators/consts.ts + + + + + +src/coreTypes/validators/validate/index.ts + + +index.ts + + + + + +src/coreTypes/validators/index.ts->src/coreTypes/validators/validate/index.ts + + + + + +src/utils/consts/index.ts->src/utils/parseTypeDeclarations/index.ts + + + + + +src/coreTypes/errors/errors.ts->src/utilTypes/index.ts + + + + + +src/coreTypes/trace/index.ts + + +index.ts + + + + + +src/coreTypes/errors/errors.ts->src/coreTypes/trace/index.ts + + + + + +src/utilTypes/unionToArray.ts + + +unionToArray.ts + + + + + +src/utilTypes/index.ts->src/utilTypes/unionToArray.ts + + - + src/coreTypes/errors/utils.ts->src/coreTypes/errors/errors.ts - - + + - + src/coreTypes/index.ts - - -index.ts + + +index.ts - - -src/coreTypes/index.ts->src/coreTypes/trace/index.ts - - - - + src/coreTypes/index.ts->src/coreTypes/errors/index.ts - - + + + + + +src/coreTypes/index.ts->src/coreTypes/trace/index.ts + + - + src/coreTypes/validators/validateArr/index.ts - - -index.ts + + +index.ts - + src/coreTypes/index.ts->src/coreTypes/validators/validateArr/index.ts - - + + - + src/coreTypes/validators/validateArr/index.ts->src/coreTypes/trace/index.ts - - + + - + src/coreTypes/validators/flatValidate/index.ts - - -index.ts + + +index.ts - + src/coreTypes/validators/validateArr/index.ts->src/coreTypes/validators/flatValidate/index.ts - - - - - -src/coreTypes/validators/consts.ts - - -consts.ts - - + + - -src/coreTypes/validators/consts.ts->src/utilTypes/index.ts - - - - -src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/trace/index.ts - - +src/coreTypes/validators/consts.ts->src/utilTypes/index.ts + + - -src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/errors/index.ts - - - - -src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/validators/consts.ts - - - - - -src/coreTypes/validators/index.ts - - -index.ts - - +src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/errors/index.ts + + - + -src/coreTypes/validators/index.ts->src/coreTypes/validators/consts.ts - - - - - -src/coreTypes/validators/validate/index.ts - - -index.ts - - +src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/trace/index.ts + + - + -src/coreTypes/validators/index.ts->src/coreTypes/validators/validate/index.ts - - +src/coreTypes/validators/flatValidate/index.ts->src/coreTypes/validators/consts.ts + + - + src/coreTypes/validators/validate/index.ts->src/coreTypes/trace/index.ts - - + + - + src/coreTypes/validators/validate/index.ts->src/coreTypes/validators/consts.ts - - + + - + src/coreTypes/validators/validate/index.ts->src/coreTypes/validators/flatValidate/index.ts - - + + - + src/coreTypes/validators/validateComputedGenerics/index.ts - - -index.ts + + +index.ts - + src/coreTypes/validators/validate/index.ts->src/coreTypes/validators/validateComputedGenerics/index.ts - - + + - + src/coreTypes/validators/validateComputedGenerics/index.ts->src/utilTypes/index.ts - - + + - + src/coreTypes/validators/validateComputedGenerics/index.ts->src/coreTypes/trace/index.ts - - + + - + src/coreTypes/validators/validateComputedGenerics/index.ts->src/coreTypes/validators/flatValidate/index.ts - - + + - + src/coreTypes/validators/validateEmtpyString/index.ts - - -index.ts + + +index.ts - + src/coreTypes/validators/validateEmtpyString/index.ts->src/coreTypes/errors/index.ts - - - - - -src/coreTypes/validators/validateEmtpyString/index.ts->src/coreTypes/errors/utils.ts - - + + - + src/coreTypes/validators/validateEmtpyString/index.ts->src/coreTypes/validators/index.ts - - + + + + + +src/coreTypes/validators/validateEmtpyString/index.ts->src/coreTypes/errors/utils.ts + + - + src/coreTypes/validators/validateLiteral/index.ts - - -index.ts + + +index.ts - + src/coreTypes/validators/validateLiteral/index.ts->src/coreTypes/errors/index.ts - - - - - -src/coreTypes/validators/validateLiteral/index.ts->src/coreTypes/errors/utils.ts - - + + - + src/coreTypes/validators/validateLiteral/index.ts->src/coreTypes/validators/index.ts - - + + + + + +src/coreTypes/validators/validateLiteral/index.ts->src/coreTypes/errors/utils.ts + + - + src/coreTypes/validators/validateType/index.ts - - -index.ts + + +index.ts - - -src/coreTypes/validators/validateType/index.ts->src/coreTypes/trace/index.ts - - - - + src/coreTypes/validators/validateType/index.ts->src/coreTypes/errors/index.ts - - - - - -src/coreTypes/validators/validateType/index.ts->src/coreTypes/errors/utils.ts - - + + - + src/coreTypes/validators/validateType/index.ts->src/coreTypes/validators/index.ts - - + + + + + +src/coreTypes/validators/validateType/index.ts->src/coreTypes/trace/index.ts + + + + + +src/coreTypes/validators/validateType/index.ts->src/coreTypes/errors/utils.ts + + - + src/coreTypes/validators/validateUsableSting/index.ts - - -index.ts + + +index.ts - + src/coreTypes/validators/validateUsableSting/index.ts->src/coreTypes/errors/utils.ts - - + + - + src/coreTypes/validators/validateUsableSting/index.ts->src/coreTypes/validators/validate/index.ts - - + + - + src/coreTypes/validators/validateUsableSting/index.ts->src/coreTypes/validators/validateEmtpyString/index.ts - - + + - + src/coreTypes/validators/validateUsableSting/index.ts->src/coreTypes/validators/validateLiteral/index.ts - - + + - + src/run.ts - - -run.ts + + +run.ts - + src/run.ts->src/services/ImportRegistry/index.ts - - + + - - -src/testData/index.ts - - -index.ts + + +src/scripts/generateTypeMirrorClass/codegen.ts + + +codegen.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/types.ts + + +types.ts + + + + + +src/scripts/generateTypeMirrorClass/codegen.ts->src/scripts/generateTypeMirrorClass/typeProcessing/types.ts + + + + + +src/scripts/generateTypeMirrorClass/utils/import.ts + + +import.ts + + + + + +src/scripts/generateTypeMirrorClass/codegen.ts->src/scripts/generateTypeMirrorClass/utils/import.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/types.ts->src/utils/parseTypeDeclarations/index.ts + + + + + +src/scripts/generateTypeMirrorClass/utils/import.ts->src/services/ImportRegistry/index.ts + + + + + +src/scripts/generateTypeMirrorClass/index.ts + + +index.ts + + + + + +src/scripts/generateTypeMirrorClass/index.ts->src/scripts/generateTypeMirrorClass/codegen.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts + + +processing.ts + + +src/scripts/generateTypeMirrorClass/index.ts->src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts + + + - + src/tsc/collectTsFilePaths.ts - - -collectTsFilePaths.ts + + +collectTsFilePaths.ts + + + + + +src/scripts/generateTypeMirrorClass/index.ts->src/tsc/collectTsFilePaths.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts->src/utils/parseTypeDeclarations/index.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts->src/scripts/generateTypeMirrorClass/typeProcessing/types.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/guards.ts + + +guards.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts->src/scripts/generateTypeMirrorClass/typeProcessing/guards.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/sanitize.ts + + +sanitize.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts->src/scripts/generateTypeMirrorClass/typeProcessing/sanitize.ts + + + + + +src/scripts/generateTypeMirrorClass/typeProcessing/sanitize.ts->src/regexes/index.ts + + + + + +src/testData/index.ts + + +index.ts - + src/tsc/findTypeDeclarations.ts - - -findTypeDeclarations.ts + + +findTypeDeclarations.ts - + src/tsc/findTypeDeclarations.ts->src/tsc/collectTsFilePaths.ts - - + + - + src/tsc/index.ts - - -index.ts + + +index.ts - + src/tsc/index.ts->src/tsc/findTypeDeclarations.ts - - + + - + src/utils/parseTypeDeclarations/index.test.ts - - -index.test.ts + + +index.test.ts - + src/utils/parseTypeDeclarations/index.test.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/reTypeError/index.ts - - -index.ts + + +index.ts - + src/utils/reTypeError/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/reTypeError/index.ts->src/utils/reTypeError/trace.ts - - - - - -src/utils/reTypeError/index.ts->src/utilTypes/index.ts - - + + - + src/utils/reTypeError/index.ts->src/coreTypes/errors/index.ts - - + + + + + +src/utils/reTypeError/index.ts->src/utilTypes/index.ts + + - + src/utils/typeBuilder/genericArgs.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/typeBuilder/genericArgs.ts->src/utils/reTypeError/trace.ts - - + + - + src/utils/typeBuilder/genericArgs.ts->src/utils/consts/index.ts - - + + - + src/utils/typeBuilder/utils/index.ts - - -index.ts + + +index.ts - + src/utils/typeBuilder/genericArgs.ts->src/utils/typeBuilder/utils/index.ts - - + + - + src/utils/typeBuilder/utils/index.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/typeBuilder/utils/index.ts->src/utils/reTypeError/trace.ts - - + + - + src/utils/typeBuilder/utils/index.ts->src/utils/consts/index.ts - - + + - + src/utils/typeBuilder/relaxConstraints.ts->src/services/ImportRegistry/index.ts - - + + - + src/utils/typeBuilder/relaxConstraints.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/typeBuilder/relaxConstraints.ts->src/utils/reTypeError/trace.ts - - + + - + src/utils/typeBuilder/relaxConstraints.ts->src/utils/reTypeError/index.ts - - + + - + src/utils/typeBuilder/typeDefinitions.ts->src/utils/parseTypeDeclarations/index.ts - - + + - + src/utils/typeBuilder/typeDefinitions.ts->src/utils/reTypeError/trace.ts - - + + - + src/utils/typeBuilder/typeDefinitions.ts->src/utilTypes/index.ts - - + + - + src/utils/typeBuilder/typeDefinitions.ts->src/utils/typeBuilder/genericArgs.ts - - + + diff --git a/package-lock.json b/package-lock.json index 0e19107..d44de14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@eslint/js": "^9.25.1", + "@types/node": "^24.0.3", "@types/ramda": "^0.30.2", "eslint-config-prettier": "^10.1.2", "globals": "^16.0.0", @@ -968,13 +969,11 @@ "peer": true }, "node_modules/@types/node": { - "version": "22.14.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", - "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", - "dev": true, - "peer": true, + "version": "24.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz", + "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.8.0" } }, "node_modules/@types/ramda": { @@ -3976,11 +3975,9 @@ "dev": true }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "peer": true + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==" }, "node_modules/union": { "version": "0.5.0", diff --git a/package.json b/package.json index 8e62b4b..183f75d 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "build:types": "nodemon --watch src --ext ts --exec \"tsx ./src/buildTypes.ts\"", "build:findTypeDeclarations": "nodemon --watch src --ext ts --exec \"tsx ./scripts/findTypeDeclarations.ts\"", + "build:typeMirror": "nodemon --watch src --ext ts --exec \"npx tsx src/scripts/generateTypeMirrorClass\"", "graph:build": "depcruise src --output-type dot | dot -T svg | depcruise-wrap-stream-in-html > index.html", "graph:test": "depcruise src", "graph:watch": "nodemon --watch src --ext ts --exec \"npm run graph:build\"", @@ -32,6 +33,7 @@ }, "dependencies": { "@eslint/js": "^9.25.1", + "@types/node": "^24.0.3", "@types/ramda": "^0.30.2", "eslint-config-prettier": "^10.1.2", "globals": "^16.0.0", diff --git a/scripts/findTypeDeclarations.ts b/scripts/findTypeDeclarations.ts index 5dc041b..56b1886 100644 --- a/scripts/findTypeDeclarations.ts +++ b/scripts/findTypeDeclarations.ts @@ -15,9 +15,8 @@ import { findTypeDeclarations } from "../src/tsc" // printer.printNode(ts.EmitHint.Unspecified, typeStringAlias, ts.createSourceFile("", "", ts.ScriptTarget.Latest)), // ) -const rootDir = "./src" -const dirsToScan = ["./src", "./tests", "./lib"] -const myType = "ValidateFlatTuple$" -const declarationPaths = findTypeDeclarations(rootDir, dirsToScan, myType) +const dirsToScan = "./src" +const typesToFind = ["ValidateFlatTuple$", "ReTypeError"] +const declarationPaths = findTypeDeclarations(dirsToScan, typesToFind) console.log("declarationPaths", declarationPaths) diff --git a/src/buildTypes.ts b/src/buildTypes.ts index f90e693..b262208 100644 --- a/src/buildTypes.ts +++ b/src/buildTypes.ts @@ -1,5 +1,5 @@ -import { Lax } from "classses/Lax" -import { Strict } from "classses/Strict" +import { Lax } from "classes/Lax" +import { Strict } from "classes/Strict" import fs from "node:fs" import { toPairs } from "ramda" import { ImportRegistry } from "services/ImportRegistry" diff --git a/src/classses/Lax/index.test.ts b/src/classes/Lax/index.test.ts similarity index 100% rename from src/classses/Lax/index.test.ts rename to src/classes/Lax/index.test.ts diff --git a/src/classses/Lax/index.ts b/src/classes/Lax/index.ts similarity index 89% rename from src/classses/Lax/index.ts rename to src/classes/Lax/index.ts index c26c4fb..aa73f02 100644 --- a/src/classses/Lax/index.ts +++ b/src/classes/Lax/index.ts @@ -1,4 +1,4 @@ -import { resolveEitherName, resolveLaxName } from "classses/utils" +import { resolveEitherName, resolveLaxName } from "classes/utils" import { prop } from "ramda" import { createJsDocs } from "utils/createJsDocs" import type { PARSED_TYPE_DECLARATION } from "utils/parseTypeDeclarations" @@ -6,8 +6,12 @@ import { parseTypeDeclaration } from "utils/parseTypeDeclarations" import type { WITH_CONTEXT } from "utils/resolveGenerics" import { resolveGenerics } from "utils/resolveGenerics" import { typeBuilder } from "utils/typeBuilder" +import { eitherBody } from "utils/typeBuilder/eitherBody" +import type { Brand } from "utilTypes" import type { WITH_COMMENTS } from "../types" +export type LAX_BODY = Brand + export class Lax { protected parsedType: PARSED_TYPE_DECLARATION @@ -48,9 +52,7 @@ export class Lax { currentTypeName: typeName, }) - const body = `[_Error] extends [never] - ? ${typeInvocation} - : _Error` + const body = eitherBody(typeInvocation) return typeBuilder.typeDeclaration({ docs, @@ -62,7 +64,7 @@ export class Lax { // --- PROTECTED ---------------------------------------------------------------------- - protected makeLaxBody({ withContext, withComments }: WITH_COMMENTS & WITH_CONTEXT): string { + protected makeLaxBody({ withContext, withComments }: WITH_COMMENTS & WITH_CONTEXT): LAX_BODY { // TODO: mismatch error could be more detailed and reuse validation (what it should be) // TODO: inside validation missing (before return) @@ -82,7 +84,7 @@ export class Lax { generics: resolveGenerics({ withContext, generics }), // currentTypeName: "laxName", }), - ) + ) as LAX_BODY if (withComments) { return ( @@ -90,7 +92,7 @@ export class Lax { ` // --- ${laxName} START --- ${conditionalTypeBody} - // --- ${laxName} END ---` + // --- ${laxName} END ---` as LAX_BODY ) } diff --git a/src/classses/Strict/index.test.ts b/src/classes/Strict/index.test.ts similarity index 100% rename from src/classses/Strict/index.test.ts rename to src/classes/Strict/index.test.ts diff --git a/src/classses/Strict/index.ts b/src/classes/Strict/index.ts similarity index 92% rename from src/classses/Strict/index.ts rename to src/classes/Strict/index.ts index dd25074..77017e0 100644 --- a/src/classses/Strict/index.ts +++ b/src/classes/Strict/index.ts @@ -1,4 +1,4 @@ -import { rejectContext, resolveEitherLaxName, resolveStrictLaxName } from "classses/utils" +import { rejectContext, resolveEitherLaxName, resolveStrictLaxName } from "classes/utils" import { ImportRegistry } from "services/ImportRegistry" import { createJsDocs } from "utils/createJsDocs" import type { PARSED_TYPE_DECLARATION } from "utils/parseTypeDeclarations" @@ -8,6 +8,9 @@ import { resolveGenerics } from "utils/resolveGenerics" import type { CurrentTypeName } from "utils/reTypeError/trace" import { trace } from "utils/reTypeError/trace" import { typeBuilder } from "utils/typeBuilder" +import type { Brand } from "utilTypes" + +export type STRICT_LAX_BODY = Brand export class Strict { protected parsedType: PARSED_TYPE_DECLARATION @@ -34,7 +37,7 @@ export class Strict { } // TODO: import validation modules keys - protected makeStrictLaxBody({ currentTypeName }: { currentTypeName: CurrentTypeName }): string { + protected makeStrictLaxBody({ currentTypeName }: { currentTypeName: CurrentTypeName }): STRICT_LAX_BODY { // TODO: mismatch error could be more detailed and reuse validation (what it should be) // TODO: Kamils class const ValidationType = "ValidateFlatTuple$" @@ -57,7 +60,7 @@ export class Strict { >, // Pass original generics ${genericsInvocationWithoutContext} ->` +>` as STRICT_LAX_BODY return typeDef } diff --git a/src/classses/types/index.ts b/src/classes/types/index.ts similarity index 100% rename from src/classses/types/index.ts rename to src/classes/types/index.ts diff --git a/src/classses/utils/index.ts b/src/classes/utils/index.ts similarity index 100% rename from src/classses/utils/index.ts rename to src/classes/utils/index.ts diff --git a/src/coreTypes/errors/errors.ts b/src/coreTypes/errors/errors.ts index b4502b0..9864bf4 100644 --- a/src/coreTypes/errors/errors.ts +++ b/src/coreTypes/errors/errors.ts @@ -20,7 +20,7 @@ export const ERROR_TYPE = { export type ErrorType = ValueOf // TODO: do we need js here? -export const ERRORS_LOOKUP = { +export const ErrorsLookup = { // input -------------------------------- OpenTypeError: { msg: "input: is open types (any, unknown, never)", @@ -60,36 +60,36 @@ export const ERRORS_LOOKUP = { { msg: string; url: string } > -export type ErrorsLookup = typeof ERRORS_LOOKUP +export type ERRORS_LOOKUP = typeof ErrorsLookup // TODO: js docs export type ReTypeError< - _ErrorType extends keyof ErrorsLookup, + _ErrorType extends keyof ERRORS_LOOKUP, Context extends string, Value, - Constraint = unknown + _Constraint = "TODO:unknown" > = { - __type: _ErrorType - __message: ErrorsLookup[_ErrorType]["msg"] - __context: Context - __value: Value & {} // TODO: pretty - __constraint?: Constraint & {} // TODO: pretty - __url: ErrorsLookup[_ErrorType]["url"] + readonly __type: _ErrorType + readonly __message: ERRORS_LOOKUP[_ErrorType]["msg"] + readonly __context: Context + readonly __value: Value & {} // TODO: pretty + readonly __constraint?: _Constraint & {} // TODO: pretty + readonly __url: ERRORS_LOOKUP[_ErrorType]["url"] } // ----------------------- // prettier-ignore -export type NeverError = ReTypeError<"NeverError", Trace, T, Constraint> +export type NeverError = ReTypeError<"NeverError", Trace, T, _Constraint> // prettier-ignore -export type AnyError = ReTypeError<"AnyError", Trace, T, Constraint> +export type AnyError = ReTypeError<"AnyError", Trace, T, _Constraint> // prettier-ignore -export type UnknownError = ReTypeError<"UnknownError", Trace, T, Constraint> +export type UnknownError = ReTypeError<"UnknownError", Trace, T, _Constraint> // prettier-ignore -export type MismatchError = ReTypeError<"MismatchError", Trace, T, Constraint> +export type MismatchError = ReTypeError<"MismatchError", Trace, T, _Constraint> // prettier-ignore -export type NonLiteralError = ReTypeError<"NonLiteralError", Trace, T, Constraint> +export type NonLiteralError = ReTypeError<"NonLiteralError", Trace, T, _Constraint> // prettier-ignore -export type EmptyStringError = ReTypeError<"EmptyStringError", Trace, T, Constraint> +export type EmptyStringError = ReTypeError<"EmptyStringError", Trace, T, _Constraint> // prettier-ignore -export type OpenTypeError = ReTypeError<"OpenTypeError", Trace, T, Constraint> +export type OpenTypeError = ReTypeError<"OpenTypeError", Trace, T, _Constraint> diff --git a/src/coreTypes/errors/utils.ts b/src/coreTypes/errors/utils.ts index 15f4622..acadc66 100644 --- a/src/coreTypes/errors/utils.ts +++ b/src/coreTypes/errors/utils.ts @@ -1,15 +1,15 @@ import type { - ErrorsLookup, + ERRORS_LOOKUP, NeverError, } from "./errors" export type GENERIC_ERROR = { - __type: keyof ErrorsLookup - __message: ErrorsLookup[keyof ErrorsLookup]["msg"] - __url: ErrorsLookup[keyof ErrorsLookup]["url"] - __context: string + readonly __type: keyof ERRORS_LOOKUP + readonly __message: ERRORS_LOOKUP[keyof ERRORS_LOOKUP]["msg"] + readonly __url: ERRORS_LOOKUP[keyof ERRORS_LOOKUP]["url"] + readonly __context: string // eslint-disable-next-line @typescript-eslint/no-explicit-any - __value: any + readonly __value: any } // ----------------------------------------------------------------- diff --git a/src/regexes/index.ts b/src/regexes/index.ts index 1443bff..c8b4773 100644 --- a/src/regexes/index.ts +++ b/src/regexes/index.ts @@ -1,3 +1,4 @@ export const regexes = { - extractTypesAndValidations: /type ([\w$]*)<([^<>]*)>\s*=\s*(.*)/, + blockComment: /\/\*\*[\s\S]*?\*\//g, + lineComment: /\/\/.*/g, } diff --git a/src/run.ts b/src/run.ts index c1efca6..9d411a3 100644 --- a/src/run.ts +++ b/src/run.ts @@ -45,7 +45,7 @@ async function analyzeTypeScriptFiles(): Promise { console.log("🔍 Analyzing TypeScript files in the project...") // Find all TypeScript files in the classes directory - const classesDir = path.resolve(process.cwd(), "src", "classses") + const classesDir = path.resolve(process.cwd(), "src", "classes") const tsFiles = await findAllTsFiles(classesDir) console.log(`Found ${tsFiles.length} TypeScript files`) diff --git a/src/scripts/generateTypeMirrorClass/codegen.ts b/src/scripts/generateTypeMirrorClass/codegen.ts new file mode 100644 index 0000000..5f32135 --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/codegen.ts @@ -0,0 +1,56 @@ +import { ImportRegistry } from "services/ImportRegistry" +import { findTypeDeclarations } from "tsc" +import type { GENERIC, PARSED_TYPE_DECLARATION } from "utils/parseTypeDeclarations" +import { deconstructConstraint, isPrimitiveConstraint } from "./utils/import" + +// import type { ErrorsLookup } from "coreTypes/errors" // TODO: Hardcoded path, should be replaced with a dynamic import +// import type { BYPASS_MODES } from "coreTypes/validators" + +export const generateParamsDeclaration = (generics: GENERIC[]): string => + generics + .map((g) => `${g.name}${g.constraint ? `: ${g.constraint}` : ""}${g.defaultValue ? ` = ${g.defaultValue}` : ""}`) + // .map((g) => `${g.name}`) // ${g.constraint}`) + .join(", ") + +export const generateParamsInterpolation = (generics: GENERIC[]): string => + generics.map((g) => `\${${g.name}}`).join(", ") + +export const generateMethod = ({ typeName, generics }: PARSED_TYPE_DECLARATION): string => { + const paramsDecl = generateParamsDeclaration(generics) + const paramsInterp = generateParamsInterpolation(generics) + + generics.forEach(({ constraint: _constraint }) => { + if (_constraint) { + const constraint = deconstructConstraint(_constraint) + + if (!isPrimitiveConstraint(constraint)) { + ImportRegistry.addImport(constraint) + } + } + }) + + return ` + ${typeName}(${paramsDecl}): string { + return \`${typeName}<${paramsInterp}>\` + }` +} + +export const generateClassBody = (methods: PARSED_TYPE_DECLARATION[]): string => methods.map(generateMethod).join("\n") + +export const generateOutput = (methods: PARSED_TYPE_DECLARATION[]): string => { + const utilClass = `export class TypeUtils { + ${generateClassBody(methods)} +}` + + const imports = ImportRegistry.getImports() + console.log("imports --->", imports) + + const declarations = findTypeDeclarations("./src", imports) + + console.log("declarations --->", declarations) + + return ` + ${declarations.join("\n")} + ${utilClass} + ` +} diff --git a/src/scripts/generateTypeMirrorClass/index.ts b/src/scripts/generateTypeMirrorClass/index.ts new file mode 100644 index 0000000..1748f34 --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/index.ts @@ -0,0 +1,23 @@ +import * as fs from "fs" +import * as path from "path" + +import { pipe } from "ramda" +import { collectTsFilePaths } from "tsc/collectTsFilePaths" +import { generateOutput } from "./codegen" +import { processAllFiles } from "./typeProcessing/processing" + +const main = (dirToScan: string, outputFilePath: string): void => { + pipe( + // + collectTsFilePaths, + processAllFiles, + generateOutput, + (code: string) => fs.writeFileSync(outputFilePath, code), + )(dirToScan) +} + +main( + // + path.resolve(process.cwd(), "src/coreTypes"), + path.resolve(process.cwd(), "dist/TypeMirror.ts"), +) diff --git a/src/scripts/generateTypeMirrorClass/typeProcessing/guards.ts b/src/scripts/generateTypeMirrorClass/typeProcessing/guards.ts new file mode 100644 index 0000000..9b6ddfd --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/typeProcessing/guards.ts @@ -0,0 +1,19 @@ +import * as ts from "typescript" + +const isTypeAlias = (node: ts.Node): node is ts.TypeAliasDeclaration => ts.isTypeAliasDeclaration(node) + +export const isTypeFunction = (node: ts.Node): node is ts.TypeAliasDeclaration => { + if (isTypeAlias(node)) { + return !!node.typeParameters && node.typeParameters.length > 0 + } + + return false +} + +export const isExportedTypeFunction = (node: ts.Node): node is ts.TypeAliasDeclaration => { + if (isTypeAlias(node) && isTypeFunction(node)) { + return !!node.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword) + } + + return false +} diff --git a/src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts b/src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts new file mode 100644 index 0000000..78d5d9e --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/typeProcessing/processing.ts @@ -0,0 +1,28 @@ +import { createSourceFileFromPath } from "tsc/utils" +import { type PARSED_TYPE_DECLARATION, parseNode } from "utils/parseTypeDeclarations" +import { isExportedTypeFunction } from "./guards" + +const processSingleFile = (filePath: string): PARSED_TYPE_DECLARATION[] => { + const { sourceText, sourceFile } = createSourceFileFromPath(filePath) + + // TODO: convert to SET + const parsed: PARSED_TYPE_DECLARATION[] = [] + + sourceFile.forEachChild((node) => { + if (isExportedTypeFunction(node)) { + const result = parseNode(sourceText, node) + + parsed.push(result) + } + }) + + // TODO: check lengths + return parsed +} + +export const processAllFiles = (filePaths: string[]): PARSED_TYPE_DECLARATION[] => + filePaths.reduce((acc, filePath) => { + const parsed = processSingleFile(filePath) + + return [...acc, ...parsed] + }, []) diff --git a/src/scripts/generateTypeMirrorClass/typeProcessing/test-type-params.ts b/src/scripts/generateTypeMirrorClass/typeProcessing/test-type-params.ts new file mode 100644 index 0000000..f9b1d93 --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/typeProcessing/test-type-params.ts @@ -0,0 +1,60 @@ +import * as fs from "fs" +import { getGenericsFromNode } from "tsc/utils" +import * as ts from "typescript" + +// Example type declarations with different parameter patterns +const exampleCode = ` +// Type with no defaults +export type SimpleGeneric = T[]; + +// Type with constraint but no default +export type ConstrainedGeneric = Record; + +// Type with default +export type DefaultGeneric = T | null; + +// Type with constraint and default +export type ConstrainedDefaultGeneric = T | undefined; + +// Type with multiple parameters +export type MultiParamGeneric = { + prop1: T; + prop2: U; + prop3: V; +}; +` + +// Function to parse and analyze the example code +function analyzeTypeParameters() { + // Write the example code to a temporary file + const tempFilePath = "/tmp/type-params-test.ts" + fs.writeFileSync(tempFilePath, exampleCode) + + // Create a SourceFile object + const program = ts.createProgram([tempFilePath], {}) + const sourceFile = program.getSourceFile(tempFilePath) + + if (!sourceFile) { + console.error("Failed to parse source file") + return + } + + // Get the text content of the source file + const sourceText = sourceFile.getFullText() + + // Process each type alias declaration + sourceFile.forEachChild((node) => { + if (ts.isTypeAliasDeclaration(node)) { + const typeName = node.name.text + const typeParams = getGenericsFromNode(node, sourceText) + + console.warn(`Type '${typeName}' parameters:`, JSON.stringify(typeParams, null, 2)) + } + }) + + // Clean up the temporary file + fs.unlinkSync(tempFilePath) +} + +// Run the analysis +analyzeTypeParameters() diff --git a/src/scripts/generateTypeMirrorClass/utils/import.ts b/src/scripts/generateTypeMirrorClass/utils/import.ts new file mode 100644 index 0000000..d295ebe --- /dev/null +++ b/src/scripts/generateTypeMirrorClass/utils/import.ts @@ -0,0 +1,29 @@ +import { flip, includes, pipe, trim } from "ramda" + +const primitiveConstraints: string[] = [ + "string", + "number", + "boolean", + "null", + "undefined", + "symbol", + "void", + "never", + "any", + "unknown", +] + +const stripKeyof = (constraint: string): string => constraint.replace(/^keyof\s+/, "") +const stripArray = (constraint: string): string => constraint.replace(/\[\]$/, "") + +export const deconstructConstraint: (constraint: string) => string = pipe( + // + stripKeyof, + stripArray, + trim, +) + +export const isPrimitiveConstraint: (constraint: string) => boolean = pipe( + deconstructConstraint, + flip(includes)(primitiveConstraints), +) diff --git a/src/tsc/collectTsFilePaths.ts b/src/tsc/collectTsFilePaths.ts index 5f2796b..d5377e2 100644 --- a/src/tsc/collectTsFilePaths.ts +++ b/src/tsc/collectTsFilePaths.ts @@ -1,33 +1,21 @@ import * as fs from "fs" import * as path from "path" -export const collectTsFilePaths = (dirsToScan: string[]): string[] => { - const tsFileAbsolutePaths: string[] = [] +const isTypeScriptFile = (fileName: string): boolean => fileName.endsWith(".ts") && !fileName.endsWith(".d.ts") - function addFilesFromDirectory(_path: string): void { - try { - const entries = fs.readdirSync(_path, { withFileTypes: true }) +export const collectTsFilePaths = (dirPath: string): string[] => { + const filePaths: string[] = [] + const entries = fs.readdirSync(dirPath, { withFileTypes: true }) - for (const entry of entries) { - const srcPath = path.join(_path, entry.name) + for (const entry of entries) { + const fullPath = path.join(dirPath, entry.name) - console.log("src", _path) - - if (entry.isDirectory() && !["node_modules", ".git"].includes(entry.name)) { - addFilesFromDirectory(srcPath) - } else if (entry.isFile() && /\.tsx?$/.test(entry.name)) { - tsFileAbsolutePaths.push(path.resolve(srcPath)) - } - } - } catch (error) { - console.error(`Cannot scan directory ${_path}:`, error) + if (entry.isDirectory()) { + filePaths.push(...collectTsFilePaths(fullPath)) + } else if (entry.isFile() && isTypeScriptFile(entry.name)) { + filePaths.push(fullPath) } } - dirsToScan - // - .filter(fs.existsSync) - .forEach(addFilesFromDirectory) - - return tsFileAbsolutePaths + return filePaths } diff --git a/src/tsc/findTypeDeclarations.ts b/src/tsc/findTypeDeclarations.ts index d96d9c3..359875d 100644 --- a/src/tsc/findTypeDeclarations.ts +++ b/src/tsc/findTypeDeclarations.ts @@ -1,40 +1,77 @@ -import * as fs from "fs" import * as ts from "typescript" import { collectTsFilePaths } from "./collectTsFilePaths" +import { createSourceFileFromPath, getNodeText } from "./utils" -export const findTypeDeclarations = (rootDir: string, dirsToScan: string[], myType: string): string[] => { - const filePaths = collectTsFilePaths(dirsToScan) +// Helper functions to identify static types +const isTypeAlias = (node: ts.Node): node is ts.TypeAliasDeclaration => ts.isTypeAliasDeclaration(node) +const isInterface = (node: ts.Node): node is ts.InterfaceDeclaration => ts.isInterfaceDeclaration(node) +const isExported = (node: ts.Node): boolean => { + if (ts.canHaveModifiers(node) && node.modifiers) { + return node.modifiers.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword) + } + return false +} + +// Check if node is an exported static type (type alias without type parameters) +const isExportedStaticTypeAlias = (node: ts.Node): node is ts.TypeAliasDeclaration => { + if (isTypeAlias(node) && isExported(node)) { + // Static types have no type parameters or empty type parameters + return !node.typeParameters || node.typeParameters.length === 0 + } + return false +} - // console.log(`Total TypeScript files found: ${filePaths.length}`) - // filePaths.forEach((file) => console.log(` ${file}`)) +// Check if node is an exported interface +const isExportedInterface = (node: ts.Node): node is ts.InterfaceDeclaration => isInterface(node) && isExported(node) - const defPaths: string[] = [] +export const findTypeDeclarations = (dirsToScan: string, providedTypeDeclaration: string[]): string[] => { + const importPaths: string[] = [] + const allFoundTypes: { name: string; path: string }[] = [] - for (const filePath of filePaths) { - const sourceFile = ts.createSourceFile(filePath, fs.readFileSync(filePath, "utf8"), ts.ScriptTarget.Latest) + const filePaths = collectTsFilePaths(dirsToScan) + console.warn("Scanning files:", filePaths.length) - // print source file - // console.log( - // printer.printNode(ts.EmitHint.Unspecified, sourceFile, ts.createSourceFile("", "", ts.ScriptTarget.Latest)), - // ) + for (const filePath of filePaths) { + const { sourceFile, sourceText } = createSourceFileFromPath(filePath) + const relativePath = filePath.replace(/\.ts$/, "") ts.forEachChild(sourceFile, (node) => { - if (ts.isTypeAliasDeclaration(node) && node.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword)) { - const typeName = node.name.escapedText - console.log( - typeName, - rootDir, - node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword), - ) - - // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison - if (typeName === myType) { - // defPaths.push(filePath.replace(rootDir, ".").replace(rootDir.replace("./", ""), ".")) - defPaths.push(filePath) ///.replace(rootDir, ".").replace(rootDir.replace("./", ""), ".")) + // Check for exported static type aliases + if (isExportedStaticTypeAlias(node)) { + const currentTypeName = node.name.escapedText.toString() + + // if (node.name.parent.parent) { + // const x = node.name.parent.parent?.text + // } + + console.log("node.name", getNodeText(sourceText)(node.name)) + + // try { + // console.log("node.name", getNodeBody(sourceFile as unknown as any, node)) + // } catch (error) {} + + allFoundTypes.push({ name: currentTypeName, path: relativePath }) + + if (providedTypeDeclaration.includes(currentTypeName)) { + importPaths.push(`import { ${currentTypeName} } from "${relativePath}"`) + } + } + // Check for exported interfaces + else if (isExportedInterface(node)) { + console.log("DEAD") + + const currentTypeName = node.name.escapedText.toString() + allFoundTypes.push({ name: currentTypeName, path: relativePath }) + + if (providedTypeDeclaration.includes(currentTypeName)) { + importPaths.push(`import { ${currentTypeName} } from "${relativePath}"`) } } }) } - return defPaths + console.warn("Found exported static types:", allFoundTypes.length) + allFoundTypes.forEach((type) => console.warn(`${type.name} - ${type.path}`)) + + return importPaths } diff --git a/src/tsc/utils/index.ts b/src/tsc/utils/index.ts new file mode 100644 index 0000000..2d13f80 --- /dev/null +++ b/src/tsc/utils/index.ts @@ -0,0 +1,49 @@ +import { regexes } from "regexes" +import ts from "typescript" +import { maybe, readFileSync } from "utils/funcProg" +import type { GENERIC } from "utils/parseTypeDeclarations" + +const sanitize = (nodeText: string): string => + nodeText + // + .replace(regexes.blockComment, "") + .replace(regexes.lineComment, "") + .trim() + +export const getNodeText = + (sourceText: string) => + (node: ts.Node): string => + sanitize(sourceText.slice(node.pos, node.end)) + +export const getNodeBody = (node: ts.TypeAliasDeclaration, sourceText: string): string => + getNodeText(sourceText)(node.type) + +export const createSourceFile = (sourceText: string, filePath: string = "any.ts"): ts.SourceFile => + // TODO: do we need true below? + ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.ESNext, true) + +export const createSourceFileFromPath = (filePath: string): { sourceText: string; sourceFile: ts.SourceFile } => { + const sourceText = readFileSync(filePath) + const sourceFile = createSourceFile(sourceText) + + return { sourceText, sourceFile } +} + +export const getGenericsFromNode = ( + node: ts.InterfaceDeclaration | ts.TypeAliasDeclaration, + sourceText: string, +): GENERIC[] => { + if (!node.typeParameters || node.typeParameters.length === 0) { + return [] + } + + return node.typeParameters.map((tp): GENERIC => { + const maybeGetNodeText = maybe(getNodeText(sourceText)) + + return { + name: tp.name.text, + constraint: maybeGetNodeText(tp.constraint), + defaultValue: maybeGetNodeText(tp.default), + } + }) +} diff --git a/src/utilTypes/index.ts b/src/utilTypes/index.ts index c046dbd..22bfc95 100644 --- a/src/utilTypes/index.ts +++ b/src/utilTypes/index.ts @@ -5,3 +5,6 @@ export type DEAD_BRANCH = never export type ValueOf = T[keyof T] export type SafeOmit = Omit export type SafePick = Pick + +declare const __brand: unique symbol +export type Brand = BrandType & { readonly [__brand]: BrandName } diff --git a/src/utils/consts/index.ts b/src/utils/consts/index.ts index e03d89d..7bec9ef 100644 --- a/src/utils/consts/index.ts +++ b/src/utils/consts/index.ts @@ -8,7 +8,7 @@ export const CONTEXT_GENERIC = { constraint: "string", } as const satisfies GENERIC -const ERROR = "_Error" as const +export const ERROR = "_Error" as const // const ERROR_DECLARATION = `${ERROR} extends GENERIC_ERROR` as const export const ERROR_GENERIC = { name: ERROR, diff --git a/src/utils/createJsDocs/index.ts b/src/utils/createJsDocs/index.ts index c43c227..691050a 100644 --- a/src/utils/createJsDocs/index.ts +++ b/src/utils/createJsDocs/index.ts @@ -1,7 +1,9 @@ -import type { SafeOmit } from "utilTypes" +import type { Brand, SafeOmit } from "utilTypes" import type { PARSED_TYPE_DECLARATION } from "../parseTypeDeclarations" -export const createJsDocs = ({ typeName: name, generics }: SafeOmit): string => { +export type JS_DOCS = Brand + +export const createJsDocs = ({ typeName: name, generics }: SafeOmit): JS_DOCS => { const params = generics .map((generic) => { const defaultValue = generic.defaultValue ? `any, fallbacks to ${generic.defaultValue}` : "any" @@ -15,5 +17,5 @@ export const createJsDocs = ({ typeName: name, generics }: SafeOmit = T extends [infer Head, ...infer Tail] + ? // + [Head?, ...PartialTuple] + : [] + +export function maybe any>(func: Func) { + return >>( + ...args: MaybeArgs + ): MaybeArgs extends Parameters + ? ReturnType + : MaybeArgs["length"] extends Parameters["length"] + ? ReturnType | undefined + : undefined => { + if (args.some((arg) => arg === undefined)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return undefined as any + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return func(...args) + } +} + +// + +// GOOD +const id = (_a: T, _b: U): T => _a +// BAD +// const id = (_a: string = '01', _b: number = 10) => _a; + +// --------------------------------------------- + +const test = maybe(id) + +// 1. no args +const a = test() +// ^? + +// 2. no enough args +const b = test("1") +// ^? + +// 3. correct args +const c = test("1", 1) +// ^? + +// 4. optional args +const d = test(Math.random() > 0.5 ? "" : undefined, Math.random() > 0.5 ? 1 : undefined) +const _d = d +// ^? + +// 5. to many args +// @ts-expect-error too many args +const e = test("1", 1, "") +// ^? + +// + +export const readFileSync = (filePath: string): string => _readFileSync(filePath, "utf-8") diff --git a/src/utils/parseTypeDeclarations/index.ts b/src/utils/parseTypeDeclarations/index.ts index c0d6bf4..2e903cb 100644 --- a/src/utils/parseTypeDeclarations/index.ts +++ b/src/utils/parseTypeDeclarations/index.ts @@ -1,4 +1,6 @@ -import { regexes } from "regexes" +import { isTypeFunction } from "scripts/generateTypeMirrorClass/typeProcessing/guards" +import { createSourceFile, getGenericsFromNode, getNodeBody, getNodeText } from "tsc/utils" +import type ts from "typescript" export type GENERIC = { name: string @@ -12,46 +14,47 @@ export type PARSED_TYPE_DECLARATION = { body: string } -export const parseTypeDeclaration = (_typeFunc: string): PARSED_TYPE_DECLARATION => { - const typeFunc = _typeFunc.trim() - const match = typeFunc.match(regexes.extractTypesAndValidations) +const _parseNode = (node: ts.TypeAliasDeclaration, typeFuncDef: string): PARSED_TYPE_DECLARATION => ({ + typeName: node.name.text, + generics: getGenericsFromNode(node, typeFuncDef), + body: getNodeBody(node, typeFuncDef), +}) + +export const parseTypeDeclaration = (typeFuncDef: string): PARSED_TYPE_DECLARATION => { + // TODO: use SET instead of array + const _parsed: PARSED_TYPE_DECLARATION[] = [] + + createSourceFile(typeFuncDef) + // + .forEachChild((node) => { + // TODO: isExportedTypeFunction instead? + if (isTypeFunction(node)) { + _parsed.push(_parseNode(node, typeFuncDef)) + } + }) - if (!match || !match[1] || !match[2] || !match[3]) { - throw new Error(`parseTypeDeclarations: Type function not found in type definition: ${typeFunc}`) - } + const parsed = _parsed[0] - const typeName = match[1] - const rawArgs = match[2].split(",") - const body = match[3] + if (!parsed) { + throw new Error(`parseTypeDeclarations: Type function not found in type definition: ${typeFuncDef}`) + } - if (!typeName) { - throw new Error(`parseTypeDeclarations: Type function name not found in type definition: ${typeFunc}`) + if (!parsed.typeName) { + throw new Error(`parseTypeDeclarations: Type function NAME not found in type definition: ${typeFuncDef}`) } - if (!rawArgs) { - throw new Error(`parseTypeDeclarations: Type function args not found in type definition: ${typeFunc}`) + if (!parsed.generics) { + throw new Error(`parseTypeDeclarations: Type function ARGS not found in type definition: ${typeFuncDef}`) } - if (!body) { - throw new Error(`parseTypeDeclarations: Type function body not found in type definition: ${typeFunc}`) + if (!parsed.body) { + throw new Error(`parseTypeDeclarations: Type function BODY not found in type definition: ${typeFuncDef}`) } - const generics: GENERIC[] = [] - - for (let i = 0; i < rawArgs.length; i++) { - const arg = rawArgs[i] + return parsed +} - generics.push({ - // @ts-expect-error arg is not undefined - name: arg.split("extends")[0].split("=")[0].trim(), - // @ts-expect-error arg is not undefined - constraint: arg.split("extends")[1]?.split("=")[0].trim(), - // @ts-expect-error arg is not undefined - defaultValue: arg.split("=")[1]?.trim(), - }) - } +// TODO: cumbersome logic: node -> text -> node -> _parseNode +export const parseNode = (sourceText: string, node: ts.Node): PARSED_TYPE_DECLARATION => { + const typeFuncDef = getNodeText(sourceText)(node) - return { - typeName, - generics, - body, - } + return parseTypeDeclaration(typeFuncDef) } diff --git a/src/utils/reTypeError/index.ts b/src/utils/reTypeError/index.ts index 49e1020..aca2e2d 100644 --- a/src/utils/reTypeError/index.ts +++ b/src/utils/reTypeError/index.ts @@ -1,6 +1,6 @@ import type { GENERIC } from "utils/parseTypeDeclarations" -import type { ErrorType, ErrorsLookup, ReTypeError } from "../../coreTypes/errors" -import { ERRORS_LOOKUP, ERROR_TYPE } from "../../coreTypes/errors" +import type { ERRORS_LOOKUP, ErrorType, ReTypeError } from "../../coreTypes/errors" +import { ERROR_TYPE, ErrorsLookup } from "../../coreTypes/errors" import type { SafeOmit } from "../../utilTypes" import type { TraceProps } from "./trace" import { traceArg } from "./trace" @@ -17,7 +17,7 @@ type ErrorHandler = { const buildReTypeError = < // - _ErrorType extends keyof ErrorsLookup, + _ErrorType extends keyof ERRORS_LOOKUP, Context extends string, _Generic extends GENERIC, >( @@ -27,8 +27,8 @@ const buildReTypeError = < ): string => { const e: ReTypeError<_ErrorType, Context, _Generic["name"], _Generic["constraint"]> = { __type, - __message: ERRORS_LOOKUP[__type]["msg"], - __url: ERRORS_LOOKUP[__type]["url"], + __message: ErrorsLookup[__type]["msg"], + __url: ErrorsLookup[__type]["url"], __context, __value: generic.name, __constraint: generic.constraint, diff --git a/src/utils/typeBuilder/eitherBody.ts b/src/utils/typeBuilder/eitherBody.ts new file mode 100644 index 0000000..759c735 --- /dev/null +++ b/src/utils/typeBuilder/eitherBody.ts @@ -0,0 +1,10 @@ +import { ERROR } from "utils/consts" +import type { Brand } from "utilTypes" +import type { TYPE_INVOCATION } from "./typeDefinitions" + +export type EITHER_BODY = Brand + +export const eitherBody = (typeInvocation: TYPE_INVOCATION): EITHER_BODY => + `[${ERROR}] extends [never] +? ${typeInvocation} +: ${ERROR}` as EITHER_BODY diff --git a/src/utils/typeBuilder/genericArgs.ts b/src/utils/typeBuilder/genericArgs.ts index cf98c30..670c915 100644 --- a/src/utils/typeBuilder/genericArgs.ts +++ b/src/utils/typeBuilder/genericArgs.ts @@ -2,13 +2,23 @@ import { P, match } from "ts-pattern" import { CONTEXT, CONTEXT_DECLARATION } from "utils/consts" import type { GENERIC } from "utils/parseTypeDeclarations" import type { CurrentTypeName } from "utils/reTypeError/trace" +import type { Brand } from "utilTypes" import { supportContextTracing } from "./utils" -export const genericArgsDeclaration = ({ generics, lax }: { generics: GENERIC[]; lax?: boolean }): string => +export type GENERIC_ARGS_DECLARATION = Brand + +export const genericArgsDeclaration = ({ + generics, + lax, +}: { + generics: GENERIC[] + lax?: boolean +}): GENERIC_ARGS_DECLARATION => generics .map((generic) => // TODO: dirty, support context appropriately match([lax || false, generic]) + .returnType() // LAX TRUE .with([true, { name: P.string, defaultValue: P.string }], ([_, g]) => `${g.name} = ${g.defaultValue}`) // .with([true, { name: P.string, constraint: P.string }], ([_, g]) => `${g.name} extends ${g.constraint}`) @@ -23,10 +33,15 @@ export const genericArgsDeclaration = ({ generics, lax }: { generics: GENERIC[]; .with([false, { name: P.string }], ([_, g]) => g.name) .exhaustive(), ) - .join(", ") + .join(", ") as GENERIC_ARGS_DECLARATION + +export type GENERIC_ARGS_INVOCATION = Brand -export const genericArgsInvocation = (generics: GENERIC[], currentTypeName?: CurrentTypeName): string => +export const genericArgsInvocation = ( + generics: GENERIC[], + currentTypeName?: CurrentTypeName, +): GENERIC_ARGS_INVOCATION => generics // .map(supportContextTracing(currentTypeName)) - .join(", ") + .join(", ") as GENERIC_ARGS_INVOCATION diff --git a/src/utils/typeBuilder/typeDefinitions.ts b/src/utils/typeBuilder/typeDefinitions.ts index 173d940..37dea2a 100644 --- a/src/utils/typeBuilder/typeDefinitions.ts +++ b/src/utils/typeBuilder/typeDefinitions.ts @@ -1,7 +1,11 @@ -import type { SafeOmit } from "utilTypes" +import type { LAX_BODY } from "classes/Lax" +import type { STRICT_LAX_BODY } from "classes/Strict" +import type { Brand, SafeOmit } from "utilTypes" +import type { JS_DOCS } from "utils/createJsDocs" import type { PARSED_TYPE_DECLARATION } from "utils/parseTypeDeclarations" import type { CurrentTypeName } from "utils/reTypeError/trace" -import { genericArgsInvocation } from "./genericArgs" +import type { EITHER_BODY } from "./eitherBody" +import { type GENERIC_ARGS_DECLARATION, genericArgsInvocation } from "./genericArgs" export const typeDeclaration = ({ docs, @@ -9,14 +13,16 @@ export const typeDeclaration = ({ genericsDeclarations, body, }: { - docs: string + docs: JS_DOCS typeName: string - genericsDeclarations: string - body: string + genericsDeclarations: GENERIC_ARGS_DECLARATION + body: EITHER_BODY | LAX_BODY | STRICT_LAX_BODY }): string => `${docs} type ${typeName}<${genericsDeclarations}> = ${body}` type Props = SafeOmit & { currentTypeName?: CurrentTypeName } -export const typeInvocation = ({ typeName, generics, currentTypeName }: Props): string => - `${typeName}<${genericArgsInvocation(generics, currentTypeName)}>` +export type TYPE_INVOCATION = Brand + +export const typeInvocation = ({ typeName, generics, currentTypeName }: Props): TYPE_INVOCATION => + `${typeName}<${genericArgsInvocation(generics, currentTypeName)}>` as TYPE_INVOCATION