From 63b4b5fe60e80f1c8a2f59784121e58353d10608 Mon Sep 17 00:00:00 2001 From: Evan Sellers Date: Mon, 29 Apr 2024 13:15:01 -0400 Subject: [PATCH 1/2] Added Exported Variables --- package-lock.json | 193 ++++++------------ package.json | 5 +- src/compiler/bundler/platforms/abstract.ts | 12 +- src/compiler/structure/endpoint/index.ts | 20 +- src/compiler/structure/index.ts | 2 +- src/compiler/utilities/kv/index.ts | 67 ++++++ .../tooling/exported-variables/index.test.ts | 49 +++++ .../tooling/exported-variables/index.ts | 46 +++++ .../tooling/exported-variables/tests/test1.ts | 2 + .../tooling/exported-variables/tests/test2.ts | 1 + .../tooling/exported-variables/tests/test3.ts | 14 ++ src/compiler/utilities/tooling/index.ts | 10 +- .../utilities/tooling/ts-validation.ts | 4 +- .../tooling/type-validation/index.ts | 38 ++++ 14 files changed, 307 insertions(+), 156 deletions(-) create mode 100644 src/compiler/utilities/kv/index.ts create mode 100644 src/compiler/utilities/tooling/exported-variables/index.test.ts create mode 100644 src/compiler/utilities/tooling/exported-variables/index.ts create mode 100644 src/compiler/utilities/tooling/exported-variables/tests/test1.ts create mode 100644 src/compiler/utilities/tooling/exported-variables/tests/test2.ts create mode 100644 src/compiler/utilities/tooling/exported-variables/tests/test3.ts create mode 100644 src/compiler/utilities/tooling/type-validation/index.ts diff --git a/package-lock.json b/package-lock.json index db70a61..1ace6cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,12 @@ "license": "ISC", "dependencies": { "@types/fs-extra": "^11.0.4", - "ajv": "^8.12.0", + "checksum": "^1.0.0", "colorette": "^2.0.20", "commander": "^11.1.0", "es-module-lexer": "^1.5.0", "esbuild": "^0.19.10", - "fs-extra": "^11.2.0", "parse-imports": "^1.1.2", - "ts-morph": "^21.0.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, @@ -25,6 +23,7 @@ "sherpa": "dist/src/cli/index.js" }, "devDependencies": { + "@types/checksum": "^0.1.35", "@types/eslint": "^8.56.2", "@types/jest": "^29.5.12", "@types/node": "^20.12.4", @@ -1566,6 +1565,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1578,6 +1578,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -1586,6 +1587,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1618,39 +1620,6 @@ "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@ts-morph/common": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", - "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", - "dependencies": { - "fast-glob": "^3.3.2", - "minimatch": "^9.0.3", - "mkdirp": "^3.0.1", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -1712,6 +1681,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/checksum": { + "version": "0.1.35", + "resolved": "https://registry.npmjs.org/@types/checksum/-/checksum-0.1.35.tgz", + "integrity": "sha512-Tm3eaZOW4viqdSPa1Y3HFJBqzmTqgChTfeFqBV8Xyevvf3IIG5Uo8WOHFRLhdUTADnz5waK7KC11V+tBfXnqkw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.56.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", @@ -2077,21 +2052,6 @@ "node": ">=0.4.0" } }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2295,7 +2255,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -2311,6 +2272,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2440,6 +2402,17 @@ "node": ">=10" } }, + "node_modules/checksum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/checksum/-/checksum-1.0.0.tgz", + "integrity": "sha512-68bHejnM/sBQhjXcXd2mFusICnqAwikZ9RVMURIacWh7moNjgOdHKimS6yk30Np/PwfR00dceY4b1GwWanu5cg==", + "dependencies": { + "optimist": "~0.3.5" + }, + "bin": { + "checksum": "bin/checksum-cli.js" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2485,11 +2458,6 @@ "node": ">= 0.12.0" } }, - "node_modules/code-block-writer": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", - "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==" - }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -2999,12 +2967,14 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -3020,6 +2990,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -3043,6 +3014,7 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -3072,6 +3044,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3115,19 +3088,6 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3266,7 +3226,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/graphemer": { "version": "1.4.0", @@ -3401,6 +3362,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -3427,6 +3389,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -3438,6 +3401,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -4132,11 +4096,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -4155,17 +4114,6 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4290,6 +4238,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -4298,6 +4247,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -4327,20 +4277,6 @@ "node": "*" } }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4410,6 +4346,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "dependencies": { + "wordwrap": "~0.0.2" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4508,11 +4452,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4565,6 +4504,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -4697,6 +4637,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } @@ -4721,6 +4662,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -4751,14 +4693,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4819,6 +4753,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4843,6 +4778,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -5101,6 +5037,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -5163,15 +5100,6 @@ } } }, - "node_modules/ts-morph": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", - "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", - "dependencies": { - "@ts-morph/common": "~0.22.0", - "code-block-writer": "^12.0.0" - } - }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -5264,14 +5192,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -5306,6 +5226,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -5353,6 +5274,14 @@ "node": ">= 8" } }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 59d87db..82f6d66 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "devDependencies": { + "@types/checksum": "^0.1.35", "@types/eslint": "^8.56.2", "@types/jest": "^29.5.12", "@types/node": "^20.12.4", @@ -44,14 +45,12 @@ "license": "ISC", "dependencies": { "@types/fs-extra": "^11.0.4", - "ajv": "^8.12.0", + "checksum": "^1.0.0", "colorette": "^2.0.20", "commander": "^11.1.0", "es-module-lexer": "^1.5.0", "esbuild": "^0.19.10", - "fs-extra": "^11.2.0", "parse-imports": "^1.1.2", - "ts-morph": "^21.0.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" } diff --git a/src/compiler/bundler/platforms/abstract.ts b/src/compiler/bundler/platforms/abstract.ts index a403428..e6e1348 100644 --- a/src/compiler/bundler/platforms/abstract.ts +++ b/src/compiler/bundler/platforms/abstract.ts @@ -12,7 +12,6 @@ import fs from "fs"; -import { remove } from "fs-extra"; import { BuildOptions, EndpointStructure } from "../../models.js"; import { Logger } from "../../utilities/logger/index.js"; import { Path } from "../../utilities/path/index.js"; @@ -46,10 +45,17 @@ export abstract class Bundler { } - async clean() { + async clean():Promise { try { if (fs.existsSync(this.getFilepath())) { - await remove(this.getFilepath()); + return new Promise((resolve) => { + fs.rm(this.getFilepath(), { recursive: true }, (error) => { + if (error) { + throw error; + } + resolve(); + }); + }); } } catch (error) { Logger.raise({ diff --git a/src/compiler/structure/endpoint/index.ts b/src/compiler/structure/endpoint/index.ts index 32706f8..bbe94bf 100644 --- a/src/compiler/structure/endpoint/index.ts +++ b/src/compiler/structure/endpoint/index.ts @@ -11,7 +11,7 @@ */ -import { Tooling } from "../../utilities/tooling/index.js"; +import { ExportedVariable, Tooling } from "../../utilities/tooling/index.js"; import { Level, Message } from "../../utilities/logger/model.js"; import { EndpointTree, ModuleConfigFile, Segment, @@ -19,9 +19,9 @@ import { } from "../../models.js"; -export function getEndpoint(module:ModuleConfigFile, filepath:string, segments:Segment[]):{ logs:Message[], endpoints?:EndpointTree } { +export async function getEndpoint(module:ModuleConfigFile, filepath:string, segments:Segment[]):Promise<{ logs:Message[], endpoints?:EndpointTree }> { let logs:Message[] = []; - let variables = Tooling.getExportedVariableNames(filepath); + let variables = await Tooling.getExportedVariables(filepath); logs.push(...validateExports(filepath, variables)); if (!hasExportMethodHandlers(variables)) return { logs }; @@ -40,10 +40,10 @@ export function getEndpoint(module:ModuleConfigFile, filepath:string, segments:S } -function validateExports(filepath:string, variables:string[]):Message[] { +function validateExports(filepath:string, variables:ExportedVariable[]):Message[] { let logs:Message[] = []; for (let variable of variables) { - if (!EXPORT_VARIABLES.includes(variable)) { + if (!EXPORT_VARIABLES.includes(variable.name)) { logs.push({ level: Level.WARN, text: `Invalid Export "${variable}" will be ignored.`, @@ -64,15 +64,15 @@ function validateExports(filepath:string, variables:string[]):Message[] { } -function getExportMethods(variables:string[]):Method[] { +function getExportMethods(variables:ExportedVariable[]):Method[] { return variables.filter(variable => { - return EXPORT_VARIABLES_METHODS.includes(variable) - }).map(variable => Method[variable as keyof typeof Method]); + return EXPORT_VARIABLES_METHODS.includes(variable.name); + }).map(variable => Method[variable.name as keyof typeof Method]); } -function hasExportMethodHandlers(variables:string[]):boolean { - return variables.some((name) => EXPORT_VARIABLES_METHODS.includes(name)); +function hasExportMethodHandlers(variables:ExportedVariable[]):boolean { + return variables.some((variable) => EXPORT_VARIABLES_METHODS.includes(variable.name)); } diff --git a/src/compiler/structure/index.ts b/src/compiler/structure/index.ts index 47d33c3..697c673 100644 --- a/src/compiler/structure/index.ts +++ b/src/compiler/structure/index.ts @@ -137,7 +137,7 @@ async function getEndpointFile(module:ModuleConfigFile, filepath:string, segment if (await Tooling.hasExportedLoader(filepath)) { return await getEndpointFileByModule(filepath, segments); } - return getEndpointFileByDeclaration(module, filepath, segments); + return await getEndpointFileByDeclaration(module, filepath, segments); } diff --git a/src/compiler/utilities/kv/index.ts b/src/compiler/utilities/kv/index.ts new file mode 100644 index 0000000..1a09933 --- /dev/null +++ b/src/compiler/utilities/kv/index.ts @@ -0,0 +1,67 @@ +import fs from "fs"; +import { Path } from "../path/index.js"; + +const FILENAME = "SHERPA-KV.json"; +const FILEPATH = Path.join(Path.getRootDirectory(), FILENAME); + + +export class KV { + + + static get(key:string):unknown { + return this.load()[key]; + } + + + static has(key:string):boolean { + return Object.keys(this.load()).includes(key); + } + + + static set(key:string, value:unknown) { + this.store({ ...this.load(), [key]: value }); + } + + + static delete(key:string) { + let data = this.load(); + delete data[key]; + this.store(data); + } + + + static getKeys():string[] { + return Object.keys(this.load()); + } + + + static getValues():unknown[] { + return Object.values(this.load()); + } + + + static getAll():Record { + return this.load(); + } + + + static getFilepath():string { + return FILEPATH; + } + + + private static load():Record { + try { + return JSON.parse(fs.readFileSync(this.getFilepath(), "utf8")); + } catch (error) { + return {}; + } + } + + + private static store(data:Record) { + fs.writeFileSync(this.getFilepath(), JSON.stringify(data, null, 4), "utf8"); + } + + +} diff --git a/src/compiler/utilities/tooling/exported-variables/index.test.ts b/src/compiler/utilities/tooling/exported-variables/index.test.ts new file mode 100644 index 0000000..0a93f93 --- /dev/null +++ b/src/compiler/utilities/tooling/exported-variables/index.test.ts @@ -0,0 +1,49 @@ +import { Path } from "../../path/index"; +import { getExportedVariables } from "./index"; + + +const DIRNAME = Path.getDirectory(import.meta.url); + + +describe("Tooling Exported Variables", () => { + + + test("Non-Existent File", async () => { + let file = Path.join(DIRNAME, "./tests/foo.ts"); + let res = await getExportedVariables(file); + expect(res).toEqual([]); + }); + + + test("Standard Default Export", async () => { + let file = Path.join(DIRNAME, "./tests/test1.ts"); + let res = await getExportedVariables(file); + expect(res).toEqual([{ + name: "default" + }]); + }); + + + test("Standard Single Export", async () => { + let file = Path.join(DIRNAME, "./tests/test2.ts"); + let res = await getExportedVariables(file); + expect(res).toEqual([{ + name: "foo" + }]); + }); + + + test("Standard Multiple Export", async () => { + let file = Path.join(DIRNAME, "./tests/test3.ts"); + let res = await getExportedVariables(file); + expect(res).toEqual([{ + name: "POST" + }, { + name: "GET" + }, { + name: "FOO" + }]); + }); + + +}); diff --git a/src/compiler/utilities/tooling/exported-variables/index.ts b/src/compiler/utilities/tooling/exported-variables/index.ts new file mode 100644 index 0000000..c4f69ef --- /dev/null +++ b/src/compiler/utilities/tooling/exported-variables/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 Sellers Industries, Inc. + * distributed under the MIT License + * + * author: Evan Sellers + * date: Mon Apr 29 2024 + * file: index.ts + * project: SherpaJS - Module Microservice Platform + * purpose: Exported Loaders + * + */ + + +import fs from "fs"; +import { parse } from "es-module-lexer"; + + +export type ExportedVariable = { + name: string; +} + + +export async function getExportedVariables(filepath:string):Promise { + let [, exports] = await parse(getBuffer(filepath)!); // note: await is required + return exports.map(_export => { + return { + name: _export.n + }; + }); +} + + +function getBuffer(filepath:string):string { + if (!fs.existsSync(filepath)) { + return ""; + } + try { + return fs.readFileSync(filepath, "utf8"); + } catch { + return ""; + } +} + + +// As water reflects the face, so one's life reflects the heart. +// - Proverbs 27:19 diff --git a/src/compiler/utilities/tooling/exported-variables/tests/test1.ts b/src/compiler/utilities/tooling/exported-variables/tests/test1.ts new file mode 100644 index 0000000..81deec9 --- /dev/null +++ b/src/compiler/utilities/tooling/exported-variables/tests/test1.ts @@ -0,0 +1,2 @@ +const foo = 2 +export default foo; \ No newline at end of file diff --git a/src/compiler/utilities/tooling/exported-variables/tests/test2.ts b/src/compiler/utilities/tooling/exported-variables/tests/test2.ts new file mode 100644 index 0000000..d207914 --- /dev/null +++ b/src/compiler/utilities/tooling/exported-variables/tests/test2.ts @@ -0,0 +1 @@ +export const foo = 2; \ No newline at end of file diff --git a/src/compiler/utilities/tooling/exported-variables/tests/test3.ts b/src/compiler/utilities/tooling/exported-variables/tests/test3.ts new file mode 100644 index 0000000..3208aa1 --- /dev/null +++ b/src/compiler/utilities/tooling/exported-variables/tests/test3.ts @@ -0,0 +1,14 @@ + + +export function POST() { + return "Hello World"; +}; + +export function GET() { + return "Hello World"; +}; + +export function FOO() { + return "Hello World"; +}; + diff --git a/src/compiler/utilities/tooling/index.ts b/src/compiler/utilities/tooling/index.ts index 85b453c..5f79be5 100644 --- a/src/compiler/utilities/tooling/index.ts +++ b/src/compiler/utilities/tooling/index.ts @@ -14,15 +14,15 @@ import vm from "vm"; import path from "path"; import { BuildOptions } from "../../models.js"; -import { Project as TSMorphProject } from "ts-morph"; import { build, BuildOptions as ESBuildOptions } from "esbuild"; import { TypeValidation } from "./ts-validation.js"; import { Message } from "../logger/model.js"; import { getEnvironmentVariables } from "./dot-env/index.js"; import { ExportLoaderModule, getExportedLoader } from "./exported-loader/index.js"; +import { ExportedVariable, getExportedVariables } from "./exported-variables/index.js"; -export type { ExportLoaderModule }; +export type { ExportLoaderModule, ExportedVariable }; export const DEFAULT_ESBUILD_TARGET:Partial = { format: "esm", target: "es2022", @@ -40,10 +40,8 @@ export const DEFAULT_ESBUILD_TARGET:Partial = { export class Tooling { - static getExportedVariableNames(filepath:string):string[] { - let project = new TSMorphProject(); - let sourceFile = project.addSourceFileAtPath(filepath); - return Array.from(sourceFile.getExportedDeclarations().keys()); + static async getExportedVariables(filepath:string):Promise { + return await getExportedVariables(filepath); } diff --git a/src/compiler/utilities/tooling/ts-validation.ts b/src/compiler/utilities/tooling/ts-validation.ts index 8fcb498..3ec1b32 100644 --- a/src/compiler/utilities/tooling/ts-validation.ts +++ b/src/compiler/utilities/tooling/ts-validation.ts @@ -45,7 +45,9 @@ export class TypeValidation { private getDiagnostics():readonly ts.Diagnostic[] { let program = ts.createProgram({ rootNames: [this.filepath], - options: {}, + options: { + noEmit: true + }, host: { ...ts.createCompilerHost({}), writeFile: () => {} diff --git a/src/compiler/utilities/tooling/type-validation/index.ts b/src/compiler/utilities/tooling/type-validation/index.ts new file mode 100644 index 0000000..b68d043 --- /dev/null +++ b/src/compiler/utilities/tooling/type-validation/index.ts @@ -0,0 +1,38 @@ +import fs from "fs"; +import { Message } from "../../logger/model.js"; +import { KV } from "../../kv/index.js"; +import checksum from "checksum"; +import { Path } from "../../path/index.js"; + + +export async function typeValidation(filepath:string, fileTypeName:string):Promise { + let cachedLogs = await cache(filepath); + if (cachedLogs) { + return cachedLogs; + } + + +} + + +async function cache(filepath:string):Promise { + let key = `type-validation-${Path.unix(filepath)}`; + if (KV.has(key)) { + let data = KV.get(key) as { checksum: string, logs: Message[] }; + if (data.checksum == await getChecksum(filepath)) { + return data.logs; + } + } + return undefined; +} + + +async function getChecksum(filepath:string):Promise { + return new Promise((resolve) => { + checksum.file(filepath, { algorithm: "sha1" }, (error, hash) => { + resolve(hash); + }); + }); + +} + From 6696c7b6ef9758a4f43fd9ba60ca035a3d7781ef Mon Sep 17 00:00:00 2001 From: Evan Sellers Date: Mon, 29 Apr 2024 15:39:27 -0400 Subject: [PATCH 2/2] Added Cache to Type Validation --- .gitignore | 3 +- src/compiler/structure/config-module/index.ts | 2 +- src/compiler/structure/config-server/index.ts | 4 +- src/compiler/structure/index.ts | 2 +- src/compiler/utilities/kv/index.ts | 77 +++++++++++---- .../tooling/exported-variables/tests/test3.ts | 6 +- src/compiler/utilities/tooling/index.ts | 12 +-- .../utilities/tooling/ts-validation.ts | 94 ------------------ .../tooling/type-validation/index.ts | 99 +++++++++++++++++-- tests/servers/pass-primary/sherpa.server.ts | 2 + 10 files changed, 169 insertions(+), 132 deletions(-) delete mode 100644 src/compiler/utilities/tooling/ts-validation.ts diff --git a/.gitignore b/.gitignore index fa22d2e..1ac4fed 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ **/.sherpa/ **/sherpa.TS_VALIDATION_BUFFER.ts /node_modules -/dist \ No newline at end of file +/dist +SHERPA-KV.json \ No newline at end of file diff --git a/src/compiler/structure/config-module/index.ts b/src/compiler/structure/config-module/index.ts index e51a6cf..67fa6fe 100644 --- a/src/compiler/structure/config-module/index.ts +++ b/src/compiler/structure/config-module/index.ts @@ -76,7 +76,7 @@ async function getInstance(filepath:string):Promise<{ logs:Message[], instance?: } try { return { - logs: Tooling.typeCheck(filepath, "Module Config"), + logs: await Tooling.typeValidation(filepath, "Module Config"), instance: await Tooling.getDefaultExport(filepath) as ModuleConfig, unknown> } } catch (e) { diff --git a/src/compiler/structure/config-server/index.ts b/src/compiler/structure/config-server/index.ts index d2f3dbf..78b9f64 100644 --- a/src/compiler/structure/config-server/index.ts +++ b/src/compiler/structure/config-server/index.ts @@ -28,7 +28,7 @@ export async function getServerConfig(entry:string):Promise<{ logs:Message[], se logs.push(...logsInstance); if (!instance) return { logs }; - let errorsTypes = Tooling.typeCheck(filepath, "Server config"); + let errorsTypes = await Tooling.typeValidation(filepath, "Server config"); return { server: { @@ -68,7 +68,7 @@ async function getInstance(filepath:string):Promise<{ logs:Message[], instance?: } try { return { - logs: Tooling.typeCheck(filepath, "Server Config"), + logs: await Tooling.typeValidation(filepath, "Server Config"), instance: await Tooling.getDefaultExport(filepath) as ServerConfig } } catch (e) { diff --git a/src/compiler/structure/index.ts b/src/compiler/structure/index.ts index 697c673..13981fd 100644 --- a/src/compiler/structure/index.ts +++ b/src/compiler/structure/index.ts @@ -164,7 +164,7 @@ async function getEndpointFileByModule(filepath:string, segments:Segment[]):Prom let entry = Path.resolve(module.filepath, Path.getDirectory(filepath)); let components = await getComponents(entry, moduleLoader.context, filepath, segments, false); - let typeErrors = Tooling.typeCheck(filepath, "Module Loader"); + let typeErrors = await Tooling.typeValidation(filepath, "Module Loader"); logs.push(...components.logs, ...typeErrors); if (Logger.hasError(logs)) { return { logs }; diff --git a/src/compiler/utilities/kv/index.ts b/src/compiler/utilities/kv/index.ts index 1a09933..ea73404 100644 --- a/src/compiler/utilities/kv/index.ts +++ b/src/compiler/utilities/kv/index.ts @@ -1,47 +1,84 @@ +/* + * Copyright (C) 2024 Sellers Industries, Inc. + * distributed under the MIT License + * + * author: Evan Sellers + * date: Mon Apr 29 2024 + * file: index.ts + * project: SherpaJS - Module Microservice Platform + * purpose: Key Value Cache + * + */ + + import fs from "fs"; import { Path } from "../path/index.js"; + const FILENAME = "SHERPA-KV.json"; const FILEPATH = Path.join(Path.getRootDirectory(), FILENAME); +type KVStructure = Record>; + + export class KV { + private namespace:string; - static get(key:string):unknown { - return this.load()[key]; + constructor(namespace:string) { + this.namespace = namespace; } - static has(key:string):boolean { - return Object.keys(this.load()).includes(key); + getNamespace():string { + return this.namespace; } - static set(key:string, value:unknown) { - this.store({ ...this.load(), [key]: value }); + get(key:string):unknown { + return KV.load()[this.namespace][key].data; } - static delete(key:string) { - let data = this.load(); - delete data[key]; - this.store(data); + has(key:string):boolean { + if (!KV.load()[this.namespace]) { + return false; + } + return Object.keys(KV.load()[this.namespace]).includes(key); } - static getKeys():string[] { - return Object.keys(this.load()); + set(key:string, value:unknown) { + let data = KV.load(); + if (!data[this.namespace]) { + data[this.namespace] = {}; + } + data[this.namespace][key] = { + data: value, + timestamp: new Date().toISOString() + }; + KV.store(data); } - static getValues():unknown[] { - return Object.values(this.load()); + delete(key:string) { + let data = KV.load(); + delete data[this.namespace][key]; + if (Object.keys(data[this.namespace]).length === 0) { + delete data[this.namespace]; + } + KV.store(data); + } + + + getKeys():string[] { + return Object.keys(KV.load()[this.namespace]); } - static getAll():Record { - return this.load(); + getValues():unknown[] { + return Object.values(KV.load()[this.namespace]).map(o => o["data"]); } @@ -50,7 +87,7 @@ export class KV { } - private static load():Record { + private static load():KVStructure { try { return JSON.parse(fs.readFileSync(this.getFilepath(), "utf8")); } catch (error) { @@ -59,9 +96,13 @@ export class KV { } - private static store(data:Record) { + private static store(data:KVStructure) { fs.writeFileSync(this.getFilepath(), JSON.stringify(data, null, 4), "utf8"); } } + + +// He replied, "Blessed rather are those who hear the word of God and obey it." +// - Luke 11:28 diff --git a/src/compiler/utilities/tooling/exported-variables/tests/test3.ts b/src/compiler/utilities/tooling/exported-variables/tests/test3.ts index 3208aa1..4d22e6d 100644 --- a/src/compiler/utilities/tooling/exported-variables/tests/test3.ts +++ b/src/compiler/utilities/tooling/exported-variables/tests/test3.ts @@ -2,13 +2,13 @@ export function POST() { return "Hello World"; -}; +} export function GET() { return "Hello World"; -}; +} export function FOO() { return "Hello World"; -}; +} diff --git a/src/compiler/utilities/tooling/index.ts b/src/compiler/utilities/tooling/index.ts index 5f79be5..57af464 100644 --- a/src/compiler/utilities/tooling/index.ts +++ b/src/compiler/utilities/tooling/index.ts @@ -15,8 +15,8 @@ import vm from "vm"; import path from "path"; import { BuildOptions } from "../../models.js"; import { build, BuildOptions as ESBuildOptions } from "esbuild"; -import { TypeValidation } from "./ts-validation.js"; import { Message } from "../logger/model.js"; +import { typeValidation } from "./type-validation/index.js"; import { getEnvironmentVariables } from "./dot-env/index.js"; import { ExportLoaderModule, getExportedLoader } from "./exported-loader/index.js"; import { ExportedVariable, getExportedVariables } from "./exported-variables/index.js"; @@ -55,6 +55,11 @@ export class Tooling { } + static async typeValidation(filepath:string, fileTypeName:string):Promise { + return await typeValidation(filepath, fileTypeName); + } + + static async getDefaultExport(filepath:string):Promise { let result = await build({ ...DEFAULT_ESBUILD_TARGET, @@ -89,11 +94,6 @@ export class Tooling { } - static typeCheck(filepath:string, fileTypeName:string):Message[] { - return new TypeValidation(filepath, fileTypeName).apply(); - } - - } diff --git a/src/compiler/utilities/tooling/ts-validation.ts b/src/compiler/utilities/tooling/ts-validation.ts deleted file mode 100644 index 3ec1b32..0000000 --- a/src/compiler/utilities/tooling/ts-validation.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2024 Sellers Industries, Inc. - * distributed under the MIT License - * - * author: Evan Sellers - * date: Mon Mar 04 2024 - * file: ts-validation.ts - * project: SherpaJS - Module Microservice Platform - * purpose: Validate Typescript - * - */ - - -import fs from "fs"; -import ts from "typescript"; -import { Level, Message } from "../logger/model.js"; - - -export class TypeValidation { - - private filepath: string; - private fileTypeName: string; - - - constructor(filepath:string, fileTypeName:string) { - this.filepath = filepath; - this.fileTypeName = fileTypeName; - } - - - public apply():Message[] { - try { - return this.processDiagnostics(this.getDiagnostics()); - } catch (error) { - return [{ - level: Level.ERROR, - text: `Failed to parse ${this.fileTypeName}.`, - content: error.message, - file: { filepath: this.filepath } - }]; - } - } - - - private getDiagnostics():readonly ts.Diagnostic[] { - let program = ts.createProgram({ - rootNames: [this.filepath], - options: { - noEmit: true - }, - host: { - ...ts.createCompilerHost({}), - writeFile: () => {} - } - }); - return ts.getPreEmitDiagnostics(program); - } - - - private processDiagnostics(diagnostic:readonly ts.Diagnostic[]):Message[] { - return diagnostic.filter(diagnostic => { - return !diagnostic.messageText.toString().includes("--target"); // NOTE: Remove warning about targeting ES2022 - }).map((diagnostic):Message => { - let position = this.getLineNumber(diagnostic.start); - let message = diagnostic.messageText.toString(); - if (diagnostic.relatedInformation && diagnostic.relatedInformation.length > 0) { - let context = diagnostic.relatedInformation[0].messageText; - message += " " + context.toString(); - } - return { - level: Level.WARN, - text: `${this.fileTypeName} Type Error - ${message}`, - file: { - filepath: this.filepath, - line: position.line, - character: position.character - } - }; - }); - } - - - private getLineNumber(position:number):ts.LineAndCharacter { - let buffer = fs.readFileSync(this.filepath, "utf8"); - let source = ts.createSourceFile(this.filepath, buffer, ts.ScriptTarget.Latest); - return source.getLineAndCharacterOfPosition(position); - } - - -} - - -// Because you know that the testing of your faith produces perseverance. -// - James 1:3 diff --git a/src/compiler/utilities/tooling/type-validation/index.ts b/src/compiler/utilities/tooling/type-validation/index.ts index b68d043..9d05e58 100644 --- a/src/compiler/utilities/tooling/type-validation/index.ts +++ b/src/compiler/utilities/tooling/type-validation/index.ts @@ -1,24 +1,103 @@ +/* + * Copyright (C) 2024 Sellers Industries, Inc. + * distributed under the MIT License + * + * author: Evan Sellers + * date: Mon Mar 04 2024 + * file: index.ts + * project: SherpaJS - Module Microservice Platform + * purpose: Validate Typescript + * + */ + import fs from "fs"; -import { Message } from "../../logger/model.js"; -import { KV } from "../../kv/index.js"; +import ts from "typescript"; import checksum from "checksum"; +import { KV as KVStorage } from "../../kv/index.js"; import { Path } from "../../path/index.js"; +import { Level, Message } from "../../logger/model.js"; +const KV = new KVStorage("TYPE-VALIDATION"); export async function typeValidation(filepath:string, fileTypeName:string):Promise { - let cachedLogs = await cache(filepath); + let cachedLogs = await getCache(filepath); if (cachedLogs) { return cachedLogs; } + try { + let logs = processDiagnostics(filepath, fileTypeName, getDiagnostics(filepath)); + setCache(filepath, logs); + return logs; + } catch (error) { + return [{ + level: Level.ERROR, + text: `Failed to parse ${this.fileTypeName}.`, + content: error.message, + file: { filepath: this.filepath } + }]; + } +} + + +function getDiagnostics(filepath:string):readonly ts.Diagnostic[] { + let program = ts.createProgram({ + rootNames: [filepath], + options: { + noEmit: true + }, + host: { + ...ts.createCompilerHost({}), + writeFile: () => {} + } + }); + return ts.getPreEmitDiagnostics(program); +} + + +function processDiagnostics(filepath:string, fileTypeName:string, diagnostic:readonly ts.Diagnostic[]):Message[] { + return diagnostic.filter(diagnostic => { + return !diagnostic.messageText.toString().includes("--target"); // NOTE: Remove warning about targeting ES2022 + }).map((diagnostic):Message => { + let position = getLineNumber(filepath, diagnostic.start as number); + let message = diagnostic.messageText.toString(); + if (diagnostic.relatedInformation && diagnostic.relatedInformation.length > 0) { + let context = diagnostic.relatedInformation[0].messageText; + message += " " + context.toString(); + } + return { + level: Level.WARN, + text: `${fileTypeName} Type Error - ${message}`, + file: { + filepath: filepath, + line: position.line, + character: position.character + } + }; + }); +} + +function getLineNumber(filepath:string, position:number):ts.LineAndCharacter { + let buffer = fs.readFileSync(filepath, "utf8"); + let source = ts.createSourceFile(filepath, buffer, ts.ScriptTarget.Latest); + return source.getLineAndCharacterOfPosition(position); } -async function cache(filepath:string):Promise { - let key = `type-validation-${Path.unix(filepath)}`; +async function setCache(filepath:string, logs:Message[]):Promise { + KV.set(getCacheKey(filepath), { + filepath: filepath, + checksum: await getChecksum(filepath), + logs: logs + }); +} + + +async function getCache(filepath:string):Promise { + let key = getCacheKey(filepath); if (KV.has(key)) { - let data = KV.get(key) as { checksum: string, logs: Message[] }; + let data = KV.get(key) as { filepath:string, checksum: string, logs: Message[] }; if (data.checksum == await getChecksum(filepath)) { return data.logs; } @@ -27,6 +106,11 @@ async function cache(filepath:string):Promise { } +function getCacheKey(filepath:string):string { + return btoa(Path.unix(filepath)); +} + + async function getChecksum(filepath:string):Promise { return new Promise((resolve) => { checksum.file(filepath, { algorithm: "sha1" }, (error, hash) => { @@ -36,3 +120,6 @@ async function getChecksum(filepath:string):Promise { } + +// Because you know that the testing of your faith produces perseverance. +// - James 1:3 diff --git a/tests/servers/pass-primary/sherpa.server.ts b/tests/servers/pass-primary/sherpa.server.ts index 2bdd71c..458491e 100644 --- a/tests/servers/pass-primary/sherpa.server.ts +++ b/tests/servers/pass-primary/sherpa.server.ts @@ -5,3 +5,5 @@ import { SherpaJS } from "../../../index"; export default SherpaJS.New.server({ context: "foo" }); + +