From e21d32cb9d3cf3e1e367759fd1e8bfc1f5850447 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Fri, 29 Sep 2023 22:02:29 +0900 Subject: [PATCH] Improve reference correctness check --- .../batcher/address-validator/tsconfig.json | 8 +- .../batcher/batcher-standalone/tsconfig.json | 5 +- .../batcher-transaction-poster/tsconfig.json | 8 +- .../game-input-validator/tsconfig.json | 7 +- packages/batcher/runtime/tsconfig.json | 3 +- packages/batcher/utils/tsconfig.json | 6 +- packages/batcher/webserver/tsconfig.json | 5 +- packages/engine/paima-funnel/tsconfig.json | 11 +- packages/engine/paima-runtime/tsconfig.json | 6 +- packages/engine/paima-sm/tsconfig.json | 8 ++ .../engine/paima-standalone/tsconfig.json | 9 +- packages/paima-sdk/paima-db/tsconfig.json | 2 +- .../paima-utils-backend/tsconfig.json | 5 +- tools/scripts/check-implicit-dependencies.ts | 105 ++++++++++++------ 14 files changed, 139 insertions(+), 49 deletions(-) diff --git a/packages/batcher/address-validator/tsconfig.json b/packages/batcher/address-validator/tsconfig.json index c8a0918e3..6f1141c81 100644 --- a/packages/batcher/address-validator/tsconfig.json +++ b/packages/batcher/address-validator/tsconfig.json @@ -5,5 +5,11 @@ "outDir": "build" }, "include": ["src/**/*"], - "references": [{ "path": "../utils" }] + "references": [ + { "path": "../utils" }, + { "path": "../db" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-crypto/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + ] } diff --git a/packages/batcher/batcher-standalone/tsconfig.json b/packages/batcher/batcher-standalone/tsconfig.json index f1886e653..30c68c905 100644 --- a/packages/batcher/batcher-standalone/tsconfig.json +++ b/packages/batcher/batcher-standalone/tsconfig.json @@ -5,5 +5,8 @@ "outDir": "build", "resolveJsonModule": true }, - "include": ["src/**/*", "src/**/*.json"] + "include": ["src/**/*", "src/**/*.json"], + "references": [ + { "path": "../runtime" }, + ] } diff --git a/packages/batcher/batcher-transaction-poster/tsconfig.json b/packages/batcher/batcher-transaction-poster/tsconfig.json index c8a0918e3..e61ffd106 100644 --- a/packages/batcher/batcher-transaction-poster/tsconfig.json +++ b/packages/batcher/batcher-transaction-poster/tsconfig.json @@ -5,5 +5,11 @@ "outDir": "build" }, "include": ["src/**/*"], - "references": [{ "path": "../utils" }] + "references": [ + { "path": "../utils" }, + { "path": "../db" }, + { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + ] } diff --git a/packages/batcher/game-input-validator/tsconfig.json b/packages/batcher/game-input-validator/tsconfig.json index 227980c12..925a7bc4b 100644 --- a/packages/batcher/game-input-validator/tsconfig.json +++ b/packages/batcher/game-input-validator/tsconfig.json @@ -5,5 +5,10 @@ "outDir": "build" }, "include": ["src/**/*"], - "references": [{ "path": "../utils" }, { "path": "../db" }] + "references": [ + { "path": "../utils" }, + { "path": "../db" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + ] } diff --git a/packages/batcher/runtime/tsconfig.json b/packages/batcher/runtime/tsconfig.json index 19c7ee7af..a4088e531 100644 --- a/packages/batcher/runtime/tsconfig.json +++ b/packages/batcher/runtime/tsconfig.json @@ -9,6 +9,7 @@ { "path": "../webserver/" }, { "path": "../game-input-validator/" }, { "path": "../utils" }, - { "path": "../batcher-transaction-poster" } + { "path": "../batcher-transaction-poster" }, + { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, ] } diff --git a/packages/batcher/utils/tsconfig.json b/packages/batcher/utils/tsconfig.json index 60fed0528..2aa24af7b 100644 --- a/packages/batcher/utils/tsconfig.json +++ b/packages/batcher/utils/tsconfig.json @@ -4,5 +4,9 @@ "rootDir": "src", "outDir": "build" }, - "include": ["src/**/*"] + "include": ["src/**/*"], + "references": [ + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, + ] } diff --git a/packages/batcher/webserver/tsconfig.json b/packages/batcher/webserver/tsconfig.json index 67262e892..73e5db230 100644 --- a/packages/batcher/webserver/tsconfig.json +++ b/packages/batcher/webserver/tsconfig.json @@ -8,6 +8,9 @@ "references": [ { "path": "../address-validator/" }, { "path": "../db/" }, - { "path": "../utils" } + { "path": "../utils" }, + { "path": "../../paima-sdk/paima-providers/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, ] } diff --git a/packages/engine/paima-funnel/tsconfig.json b/packages/engine/paima-funnel/tsconfig.json index 60fed0528..354dd91d4 100644 --- a/packages/engine/paima-funnel/tsconfig.json +++ b/packages/engine/paima-funnel/tsconfig.json @@ -4,5 +4,14 @@ "rootDir": "src", "outDir": "build" }, - "include": ["src/**/*"] + "include": ["src/**/*"], + "references": [ + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + { "path": "../paima-runtime" }, + { "path": "../../paima-sdk/paima-prando" }, + { "path": "../../paima-sdk/paima-db" }, + { "path": "../../paima-sdk/paima-utils-backend" }, + { "path": "../../paima-sdk/paima-crypto/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + ] } diff --git a/packages/engine/paima-runtime/tsconfig.json b/packages/engine/paima-runtime/tsconfig.json index 60fed0528..c88568f8f 100644 --- a/packages/engine/paima-runtime/tsconfig.json +++ b/packages/engine/paima-runtime/tsconfig.json @@ -4,5 +4,9 @@ "rootDir": "src", "outDir": "build" }, - "include": ["src/**/*"] + "include": ["src/**/*"], + "references": [ + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-db" }, + ] } diff --git a/packages/engine/paima-sm/tsconfig.json b/packages/engine/paima-sm/tsconfig.json index 4e7c4d606..e7d57f2cc 100644 --- a/packages/engine/paima-sm/tsconfig.json +++ b/packages/engine/paima-sm/tsconfig.json @@ -5,4 +5,12 @@ "outDir": "build" }, "include": ["src/**/*"], + "references": [ + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + { "path": "../paima-runtime" }, + { "path": "../../paima-sdk/paima-db" }, + { "path": "../../paima-sdk/paima-prando" }, + { "path": "../../paima-sdk/paima-concise/tsconfig.build.json" }, + { "path": "../../paima-sdk/paima-utils-backend" }, + ] } diff --git a/packages/engine/paima-standalone/tsconfig.json b/packages/engine/paima-standalone/tsconfig.json index f1886e653..b2346dae7 100644 --- a/packages/engine/paima-standalone/tsconfig.json +++ b/packages/engine/paima-standalone/tsconfig.json @@ -5,5 +5,12 @@ "outDir": "build", "resolveJsonModule": true }, - "include": ["src/**/*", "src/**/*.json"] + "include": ["src/**/*", "src/**/*.json"], + "references": [ + { "path": "../../batcher/batcher-standalone/tsconfig.build.json" }, + { "path": "../paima-runtime" }, + { "path": "../paima-sm" }, + { "path": "../../paima-sdk/paima-utils/tsconfig.build.json" }, + { "path": "../paima-funnel" }, + ] } diff --git a/packages/paima-sdk/paima-db/tsconfig.json b/packages/paima-sdk/paima-db/tsconfig.json index e541203ab..88e133d29 100644 --- a/packages/paima-sdk/paima-db/tsconfig.json +++ b/packages/paima-sdk/paima-db/tsconfig.json @@ -10,6 +10,6 @@ "src/**/*.json" ], "references": [ - { "path": "../paima-utils" } + { "path": "../paima-utils/tsconfig.build.json" } ] } \ No newline at end of file diff --git a/packages/paima-sdk/paima-utils-backend/tsconfig.json b/packages/paima-sdk/paima-utils-backend/tsconfig.json index 9e26ea257..023b460ac 100644 --- a/packages/paima-sdk/paima-utils-backend/tsconfig.json +++ b/packages/paima-sdk/paima-utils-backend/tsconfig.json @@ -6,5 +6,8 @@ "resolveJsonModule": true }, "include": ["src/**/*"], - "references": [{ "path": "../utils" }, { "path": "../db" }] + "references": [ + { "path": "../utils/tsconfig.build.json" }, + { "path": "../db" } + ] } diff --git a/tools/scripts/check-implicit-dependencies.ts b/tools/scripts/check-implicit-dependencies.ts index 51b4568af..7db6d07cc 100644 --- a/tools/scripts/check-implicit-dependencies.ts +++ b/tools/scripts/check-implicit-dependencies.ts @@ -1,7 +1,8 @@ -const { createProjectGraphAsync } = require('@nx/workspace/src/core/project-graph'); -const fs = require('fs'); -const JSON5 = require('json5'); -const path = require('path'); +const { createProjectGraphAsync } = + require('@nx/workspace/src/core/project-graph') as typeof import('@nx/workspace/src/core/project-graph'); +const fs = require('fs') as typeof import('fs'); +const JSON5 = require('json5') as typeof import('json5'); +const path = require('path') as typeof import('path'); /** * NPM requires us that all packages properly references each other in package.json @@ -23,8 +24,20 @@ type DepAndPath = { dep: string; }; -const libFolders = ['paima-sdk']; +const packageFolders = fs + .readdirSync('./packages', { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name); +function isPackage(path: string): boolean { + for (const pkg of packageFolders) { + if (path.includes(`packages/${pkg}`)) { + return true; + } + } + return false; +} +const libFolders = ['paima-sdk']; function isLib(path: string): boolean { for (const lib of libFolders) { if (path.includes(`packages/${lib}`)) { @@ -38,7 +51,7 @@ let hasError = false; async function main() { const graph = await createProjectGraphAsync(); - const ownPkgs = Object.keys(graph.nodes).filter(key => isLib(graph.nodes[key].data.root)); + const ownPkgs = Object.keys(graph.nodes).filter(key => isPackage(graph.nodes[key].data.root)); const ownPkgSet = new Set(ownPkgs); // cache the content of each package so we can look it up faster later @@ -55,6 +68,7 @@ async function main() { for (const pkg of ownPkgs) { const pkgJson = packageContent[pkg]; + const ownRoot = graph.nodes[pkg].data.root; const analyzedDeps = new Set( (graph.dependencies[pkg] as Dep[]).map(dep => dep.target).filter(dep => ownPkgSet.has(dep)) @@ -85,26 +99,31 @@ async function main() { } if (mismatches.length > 0) { hasError = true; - console.error(`Package ${pkg} has some version mismatches`); + console.error( + `Package ${purpleText(`${ownRoot}/package.json`)} has some version mismatches` + ); for (const mismatch of mismatches) { - console.log(`- "${mismatch.name}": ${mismatch.used}"`); - console.log(`+ "${mismatch.name}": ${mismatch.expected}"`); + console.log(redText(`- "${mismatch.name}": ${mismatch.used}"`)); + console.log(greenText(`+ "${mismatch.name}": ${mismatch.expected}"`)); } console.log(); } } // 2) Check that packages are present - { + // Note: adding to package.json is only required if this is a lib we intend to publish + if (isLib(pkg)) { const remainingDeps = new Set(analyzedDeps); for (const declaredDep of Object.keys(declaredDeps)) { remainingDeps.delete(declaredDep); } if (remainingDeps.size > 0) { hasError = true; - console.error(`Package ${pkg} is missing some dependencies`); + console.error( + `Package ${purpleText(`${ownRoot}/package.json`)} is missing some dependencies` + ); for (const dep of Array.from(remainingDeps)) { - console.error(`"${dep}": "${packageContent[dep].version}",`); + console.error(greenText(`"${dep}": "${packageContent[dep].version}",`)); } console.log(); } @@ -117,11 +136,14 @@ async function main() { dep, })); + // console.log(`=== ${pkg} ===`); + // console.log(depAndPaths); + const extra: string[] = []; // references that aren't necessary const wrongPath: { pkg: string; path: string }[] = []; // allow require to support trailing commas (used in tsconfig.json) - const jsonString = fs.readFileSync(`./${graph.nodes[pkg].data.root}/tsconfig.json`, 'utf-8'); + const jsonString = fs.readFileSync(`./${ownRoot}/tsconfig.json`, 'utf-8'); const tsconfigJson = JSON5.parse(jsonString); for (const ref of tsconfigJson['references'] ?? []) { const { path } = ref; @@ -129,11 +151,13 @@ async function main() { const indexOfMatch = depAndPaths.findIndex(depthAndPath => depthAndPath.path.endsWith(folder) ); + // console.log(folder, indexOfMatch); if (indexOfMatch === -1) { extra.push(folder); } else { const fileRef = getFilenameFromPath(path); - if (hasBuildConfig[pkg]) { + // console.log(fileRef, pkg, hasBuildConfig[depAndPaths[indexOfMatch].dep]); + if (hasBuildConfig[depAndPaths[indexOfMatch].dep]) { if (fileRef !== 'tsconfig.build.json') { wrongPath.push({ pkg, path: path }); hasError = true; @@ -144,25 +168,39 @@ async function main() { } if (wrongPath.length > 0) { hasError = true; - console.error(`Package ${pkg} tsconfig.json has some incorrect references`); + console.error( + `Package ${purpleText(`${ownRoot}/tsconfig.json`)} has some incorrect references` + ); for (const path of wrongPath) { - console.error(`${path.path} → ${path.path}/tsconfig.build.json`); + console.error(`${redText(path.path)} → ${greenText(`${path.path}/tsconfig.build.json`)}`); } console.log(); } if (extra.length > 0) { hasError = true; - console.error(`Package ${pkg} tsconfig.json has unnecessary references`); + console.error( + `Package ${purpleText(`${ownRoot}/tsconfig.json`)} has unnecessary references` + ); for (const ref of extra) { - console.error(ref); + console.error(redText(ref)); } console.log(); } if (depAndPaths.length > 0) { hasError = true; - console.error(`Package ${pkg} tsconfig.json is missing some references`); - for (const dep of depAndPaths) { - console.error(dep.dep); + console.error( + `Package ${purpleText(`${ownRoot}/tsconfig.json`)} is missing some references` + ); + for (const depAndPath of depAndPaths) { + const basePath = path.relative(ownRoot, depAndPath.path); + hasBuildConfig[depAndPath.dep]; + console.error( + greenText( + `{ "path": "${ + hasBuildConfig[depAndPath.dep] ? `${basePath}/tsconfig.build.json` : basePath + }" },` + ) + ); } console.log(); } @@ -189,24 +227,13 @@ function getMeaningfulPartOfPath(inputPath: string) { pathParts.pop(); } - return pathParts.join(path.sep); -} - -function getFileForPath(inputPath: string) { - const normalizedPath = path.normalize(inputPath); - const pathParts = normalizedPath.split(path.sep); - - // Remove '..' and '.' from the beginning - while (pathParts.length && (pathParts[0] === '..' || pathParts[0] === '.')) { - pathParts.shift(); - } + const result = pathParts.join(path.sep); - // Remove the filename - if (pathParts.length && path.extname(pathParts[pathParts.length - 1]) !== '') { - pathParts.pop(); + // normalize by removing any trailing slash + if (result.endsWith('/')) { + return result.slice(0, -1); } - - return pathParts.join(path.sep); + return result; } function getFilenameFromPath(filePath: string): string | null { @@ -216,4 +243,8 @@ function getFilenameFromPath(filePath: string): string | null { return baseName && baseName.includes('.') ? baseName : null; } +const greenText = (text: string) => `\x1b[32m${text}\x1b[0m`; +const redText = (text: string) => `\x1b[31m${text}\x1b[0m`; +const purpleText = (text: string) => `\x1b[35m${text}\x1b[0m`; + void main();