From e3641f95ac493262016ea98f015b53d6100d4fbb Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 4 Nov 2022 13:29:30 -0230 Subject: [PATCH 1/2] Update TypeScript to the latest stable version TypeScript has been updated to the latest stable version. Additionally, the version range has been updated to use `~` because TypeScript does not follow SemVer (they make breaking changes as minor updates). The configuration has been updated to match the module template, except that two options (`exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`) have been omitted temporarily to reduce the number of changes required for this update. They can be added in later PRs. Just as in the module template, a separate `tsconfig` file has been created to distinguish build settings from settings used to compile unit tests. The one configuration difference is the compilation target. The target is ES2019 here because this is a developer tool, so we don't need to stick to ES2017 for browser compatibility. [1]: https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/ --- package.json | 4 +-- src/cli.ts | 59 +++++++++++++++++++++++++++++---------------- tsconfig.build.json | 13 ++++++++++ tsconfig.json | 16 +++++------- yarn.lock | 18 +++++++------- 5 files changed, 68 insertions(+), 42 deletions(-) create mode 100644 tsconfig.build.json diff --git a/package.json b/package.json index 20ef916..37e5ec3 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "lint": "yarn lint:eslint && yarn lint:misc --check", "lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write", "build:clean": "rimraf dist && yarn build", - "build": "tsc --project .", + "build": "tsc --project tsconfig.build.json", "changelog": "node dist/cli.js" }, "dependencies": { @@ -61,7 +61,7 @@ "prettier": "^2.2.1", "rimraf": "^3.0.2", "ts-jest": "^26.5.6", - "typescript": "^4.2.4" + "typescript": "~4.8.4" }, "lavamoat": { "allowScripts": { diff --git a/src/cli.ts b/src/cli.ts index 03604e6..68b70f4 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -183,6 +183,19 @@ async function validate({ } } +/** + * Returns whether an error has an error code or not. + * + * @param error - The error to check. + * @returns True if the error is a real error and has a code property, false otherwise. + */ +function hasErrorCode(error: unknown): error is Error & { code: unknown } { + return ( + error instanceof Error && + Object.prototype.hasOwnProperty.call(error, 'code') + ); +} + type InitOptions = { changelogPath: string; repoUrl: string; @@ -303,14 +316,16 @@ async function main() { ); } } catch (error) { - if (error.code === 'ENOENT') { - return exitWithError( - `Root directory specified does not exist: '${projectRootDirectory}'`, - ); - } else if (error.code === 'EACCES') { - return exitWithError( - `Access to root directory is forbidden by file access permissions: '${projectRootDirectory}'`, - ); + if (hasErrorCode(error)) { + if (error.code === 'ENOENT') { + return exitWithError( + `Root directory specified does not exist: '${projectRootDirectory}'`, + ); + } else if (error.code === 'EACCES') { + return exitWithError( + `Access to root directory is forbidden by file access permissions: '${projectRootDirectory}'`, + ); + } } throw error; } @@ -328,18 +343,20 @@ async function main() { const manifest = JSON.parse(manifestText); currentVersion = manifest.version; } catch (error) { - if (error.code === 'ENOENT') { - return exitWithError( - `Package manifest not found at path: '${manifestPath}'\nRun this script from the project root directory, or set the project directory using the '--root' flag.`, - ); - } else if (error.code === 'EACCES') { - return exitWithError( - `Access to package manifest is forbidden by file access permissions: '${manifestPath}'`, - ); - } else if (error.name === 'SyntaxError') { - return exitWithError( - `Package manifest cannot be parsed as JSON: '${manifestPath}'`, - ); + if (hasErrorCode(error)) { + if (error.code === 'ENOENT') { + return exitWithError( + `Package manifest not found at path: '${manifestPath}'\nRun this script from the project root directory, or set the project directory using the '--root' flag.`, + ); + } else if (error.code === 'EACCES') { + return exitWithError( + `Access to package manifest is forbidden by file access permissions: '${manifestPath}'`, + ); + } else if (error.name === 'SyntaxError') { + return exitWithError( + `Package manifest cannot be parsed as JSON: '${manifestPath}'`, + ); + } } throw error; } @@ -376,7 +393,7 @@ async function main() { // eslint-disable-next-line no-bitwise await fs.access(changelogPath, fsConstants.F_OK | fsConstants.W_OK); } catch (error) { - if (error.code === 'ENOENT') { + if (hasErrorCode(error) && error.code === 'ENOENT') { return exitWithError(`File does not exist: '${changelogPath}'`); } return exitWithError(`File is not writable: '${changelogPath}'`); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..c6e00d6 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "inlineSources": true, + "noEmit": false, + "outDir": "dist", + "rootDir": "src", + "sourceMap": true + }, + "include": ["./src/**/*.ts"], + "exclude": ["./src/**/*.test.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index f27b02c..8f2082b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,14 @@ { "compilerOptions": { - "declaration": true, "esModuleInterop": true, - "inlineSources": true, + "forceConsistentCasingInFileNames": true, "lib": ["ES2020"], "module": "CommonJS", - "moduleResolution": "Node", - "outDir": "dist", - "rootDir": "src", - "sourceMap": true, + "moduleResolution": "node", + "noEmit": true, + "noErrorTruncation": true, "strict": true, - "target": "ES2019", - "typeRoots": ["./node_modules/@types"] + "target": "ES2019" }, - "exclude": ["**/*.test.ts"], - "include": ["./src/**/*.ts"] + "exclude": ["./dist/**/*"] } diff --git a/yarn.lock b/yarn.lock index 33d5d7a..de5bfb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -739,7 +739,7 @@ __metadata: rimraf: ^3.0.2 semver: ^7.3.5 ts-jest: ^26.5.6 - typescript: ^4.2.4 + typescript: ~4.8.4 yargs: ^17.0.1 bin: auto-changelog: dist/cli.js @@ -7181,23 +7181,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.2.4": - version: 4.2.4 - resolution: "typescript@npm:4.2.4" +"typescript@npm:~4.8.4": + version: 4.8.4 + resolution: "typescript@npm:4.8.4" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 89c397df192f239359ad798b96d8e8d552e12c0c189ac5676cec4c20c410d6eec636b8e59a88f2aef0a56d961a9678d99c400099be9b7cae2f7b062eb4b7b171 + checksum: 3e4f061658e0c8f36c820802fa809e0fd812b85687a9a2f5430bc3d0368e37d1c9605c3ce9b39df9a05af2ece67b1d844f9f6ea8ff42819f13bcb80f85629af0 languageName: node linkType: hard -"typescript@patch:typescript@^4.2.4#~builtin": - version: 4.2.4 - resolution: "typescript@patch:typescript@npm%3A4.2.4#~builtin::version=4.2.4&hash=701156" +"typescript@patch:typescript@~4.8.4#~builtin": + version: 4.8.4 + resolution: "typescript@patch:typescript@npm%3A4.8.4#~builtin::version=4.8.4&hash=701156" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: eb86e0e8022e5297f7a7b871b6edfbf33b57049416ada8bf97c358760125c7c79f074fbebd1b8e8230f858ae05eb22ad0e805e8f6acd5eae1fa886681624c15e + checksum: 301459fc3eb3b1a38fe91bf96d98eb55da88a9cb17b4ef80b4d105d620f4d547ba776cc27b44cc2ef58b66eda23fe0a74142feb5e79a6fb99f54fc018a696afa languageName: node linkType: hard From d16296b63f1da4bb098f834230f52821dc2ad5a0 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Tue, 8 Nov 2022 09:20:27 -0330 Subject: [PATCH 2/2] Fix handling of SyntaxError in CLI --- src/cli.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 68b70f4..2d438fa 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -352,12 +352,14 @@ async function main() { return exitWithError( `Access to package manifest is forbidden by file access permissions: '${manifestPath}'`, ); - } else if (error.name === 'SyntaxError') { - return exitWithError( - `Package manifest cannot be parsed as JSON: '${manifestPath}'`, - ); } } + + if (error instanceof Error && error.name === 'SyntaxError') { + return exitWithError( + `Package manifest cannot be parsed as JSON: '${manifestPath}'`, + ); + } throw error; } }