From 1165a9b2c00a682b241ca4a8da6831bd9d759ce5 Mon Sep 17 00:00:00 2001 From: Mirko Kruschke Date: Sun, 19 Feb 2023 20:56:11 +0100 Subject: [PATCH] feat: preserve comments after tsconfig update --- .gitignore | 1 + .npmignore | 4 ++- README.md | 6 ---- package.json | 6 ++-- scripts/prepareTests.ps1 | 2 +- scripts/prepareTests.sh | 2 +- src/index.js | 3 -- src/update-ts-references.js | 51 ++++++++---------------------- tests/update-ts-references.test.js | 28 ++++++++-------- yarn.lock | 26 +++++++++++++++ 10 files changed, 62 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 8eff151..821dc4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ #IDE's .idea +.vscode # Logs logs diff --git a/.npmignore b/.npmignore index cc9d8f6..62f7f49 100644 --- a/.npmignore +++ b/.npmignore @@ -6,4 +6,6 @@ node_modules test-run test-scenarios .github -*.log \ No newline at end of file +*.log +.vscode +.eslintrc.js \ No newline at end of file diff --git a/README.md b/README.md index f5e124a..38e3246 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ npx update-ts-references --help --check Checks if updates would be necessary (without applying them) --help Show help --cwd Set working directory. Default: [current path] - --discardComments Discards comments when updating tsconfigs. Default: false --verbose Show verbose output. Default: false ``` @@ -44,11 +43,6 @@ or you add it as dev dependency and include it in the `postinstall` script in th _update-ts-references_ is currently not supporting [Referencing workspace packages through aliases](https://pnpm.js.org/workspaces#referencing-workspace-packages-through-aliases) yet. See issue #13 -### Where are the comments from my tsconfig? - -_update-ts-references_ is **not** able to preserve comments in tsconfig files when it is updating the references. If you need comments for the case like, explaining why compiler options are set, please move this part including comments into a second file and use the `extends` functionallity (see [here](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#tsconfig-bases)). - - # License Copyright 2023 mobile.de diff --git a/package.json b/package.json index f767a93..5c8be7f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-ts-references", - "version": "2.5.1", + "version": "2.6.0", "description": "Updates TypeScript references automatically while using workspaces", "bin": "src/index.js", "scripts": { @@ -20,6 +20,7 @@ ], "dependencies": { "@formatjs/cli": "^2.3.1", + "comment-json": "^4.2.3", "glob": "^7.1.6", "js-yaml": "^4.0.0", "minimatch": "^3.0.4", @@ -33,9 +34,6 @@ "exec-sh": "^0.3.4", "jest": "^26.4.0" }, - "peerDependencies": { - "typescript": ">=3.8.0" - }, "engines": { "node": ">=14.0.0" }, diff --git a/scripts/prepareTests.ps1 b/scripts/prepareTests.ps1 index 3f12a63..a744e23 100644 --- a/scripts/prepareTests.ps1 +++ b/scripts/prepareTests.ps1 @@ -2,5 +2,5 @@ Invoke-Expression "yarn link" Remove-Item .\test-run -Confirm:$false -Force -Recurse -ErrorAction Ignore Copy-Item .\test-scenarios -Destination .\test-run -Recurse $prevLocation = Get-Location -Get-ChildItem .\test-run | ForEach-Object { Set-Location $_.FullName; Invoke-Expression "yarn"; Invoke-Expression "yarn link update-ts-references" } +Get-ChildItem .\test-run | ForEach-Object { Set-Location $_.FullName; Invoke-Expression "yarn link update-ts-references" } Set-Location $prevLocation \ No newline at end of file diff --git a/scripts/prepareTests.sh b/scripts/prepareTests.sh index 092f2cc..d0b9c56 100755 --- a/scripts/prepareTests.sh +++ b/scripts/prepareTests.sh @@ -2,4 +2,4 @@ yarn link rm -rf test-run cp -R test-scenarios test-run -find test-run -maxdepth 1 -type d \( ! -name 'test-run' \) -exec bash -c "cd {} && yarn && yarn link update-ts-references " \; \ No newline at end of file +find test-run -maxdepth 1 -type d \( ! -name 'test-run' \) -exec bash -c "cd {} && yarn link update-ts-references " \; \ No newline at end of file diff --git a/src/index.js b/src/index.js index ee61ecc..afe44a9 100755 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,6 @@ const { verbose = defaultOptions.verbose, help = defaultOptions.help, h = defaultOptions.help, - discardComments = defaultOptions.discardComments, check = defaultOptions.check, } = minimist(process.argv.slice(2)); @@ -22,7 +21,6 @@ if (help || h) { --check Checks if updates would be necessary (without applying them) --help Show help --cwd Set working directory. Default: ${defaultOptions.cwd} - --discardComments Discards comments when updating tsconfigs. Default: ${defaultOptions.discardComments} --verbose Show verbose output. Default: ${defaultOptions.verbose} `); process.exit(0); @@ -33,7 +31,6 @@ const run = async () => { const changesCount = await execute({ cwd, verbose, - discardComments, check, configName, }); diff --git a/src/update-ts-references.js b/src/update-ts-references.js index 36c3a35..16d8e4f 100644 --- a/src/update-ts-references.js +++ b/src/update-ts-references.js @@ -1,10 +1,13 @@ const glob = require('glob'); const path = require('path'); const fs = require('fs'); -const ts = require('typescript'); const yaml = require('js-yaml'); const minimatch = require('minimatch'); -const readlineSync = require('readline-sync'); +const { + parse, + stringify, + assign +} = require('comment-json') const assert = require('assert').strict; const PACKAGE_JSON = 'package.json'; @@ -14,7 +17,6 @@ const defaultOptions = { configName: 'tsconfig.json', cwd: process.cwd(), verbose: false, - discardComments: false, help: false, check: false, }; @@ -137,35 +139,14 @@ const ensurePosixPathStyle = (reference) => ({ const updateTsConfig = ( configName, win32OrPosixReferences, - discardComments, check, { packageDir } = { packageDir: process.cwd() } ) => { const references = (win32OrPosixReferences || []).map(ensurePosixPathStyle); const tsconfigFilePath = path.join(packageDir, configName); - let pureJson = true; - try { - require(tsconfigFilePath); - } catch (e) { - pureJson = false; - } - - const { config, error } = ts.readConfigFile( - tsconfigFilePath, - ts.sys.readFile - ); - if (!error) { - if (check === false && pureJson === false && discardComments === false) { - if ( - !readlineSync.keyInYN( - `Found comments in the tsconfig.${tsconfigFilePath} -Do you want to discard them and proceed ? ` - ) - ) { - process.exit(0); - } - } + try { + const config = parse(fs.readFileSync(tsconfigFilePath).toString()); const currentReferences = config.references || []; @@ -176,27 +157,24 @@ Do you want to discard them and proceed ? ` let isEqual = false; try { - assert.deepEqual(currentReferences, mergedReferences); + assert.deepEqual(JSON.parse(JSON.stringify(currentReferences)), mergedReferences); isEqual = true; } catch (e) { // ignore me } if (!isEqual) { if (check === false) { - const newTsConfig = JSON.stringify( + const newTsConfig = assign(config, { - ...config, references: mergedReferences.length ? mergedReferences : undefined, - }, - null, - 2 + } ); - fs.writeFileSync(tsconfigFilePath, newTsConfig + '\n'); + fs.writeFileSync(tsconfigFilePath, stringify(newTsConfig, null, 2) + '\n'); } return 1; } return 0; - } else { + } catch (error) { console.error(`could not read ${tsconfigFilePath}`, error); } }; @@ -204,7 +182,6 @@ Do you want to discard them and proceed ? ` const execute = async ({ cwd, verbose, - discardComments, check, configName, }) => { @@ -228,7 +205,7 @@ const execute = async ({ if (!workspaces) { throw new Error( - 'could not detect yarn workspaces or lerna in this repository' + 'could not detect yarn/npm/pnpm workspaces or lerna in this repository' ); } @@ -268,7 +245,6 @@ const execute = async ({ changesCount += updateTsConfig( detectedConfig, references, - discardComments, check, packageEntry ); @@ -284,7 +260,6 @@ const execute = async ({ changesCount += updateTsConfig( configName, rootReferences, - discardComments, check ); diff --git a/tests/update-ts-references.test.js b/tests/update-ts-references.test.js index 17072ce..cbf75c4 100644 --- a/tests/update-ts-references.test.js +++ b/tests/update-ts-references.test.js @@ -1,6 +1,7 @@ const execSh = require('exec-sh').promise; const path = require('path'); const fs = require('fs'); +const { parse } = require("comment-json") const rootFolderYarn = path.join(process.cwd(), 'test-run', 'yarn-ws'); const rootFolderYarnNohoist = path.join( @@ -35,7 +36,7 @@ const setup = async (rootFolder, configName) => { try { await execSh( - `npx update-ts-references --verbose --discardComments${ + `npx update-ts-references --verbose${ configName ? ` --configName ${configName}` : '' }`, { @@ -195,9 +196,13 @@ test('Support yarn and npm workspaces', async () => { const [configPath, config] = tsconfig; expect( - require(path.join(rootFolderYarn, configPath, 'tsconfig.json')) + parse(fs.readFileSync(path.join(rootFolderYarn, configPath, 'tsconfig.json')).toString()) ).toEqual(config); + + }); + // still has the comment + expect(fs.readFileSync(path.join(rootFolderYarn, 'tsconfig.json')).toString()).toMatch(/\/\* Basic Options \*\//) }); test('Support lerna', async () => { @@ -207,7 +212,7 @@ test('Support lerna', async () => { const [configPath, config] = tsconfig; expect( - require(path.join(rootFolderLerna, configPath, 'tsconfig.json')) + parse(fs.readFileSync(path.join(rootFolderLerna, configPath, 'tsconfig.json')).toString()) ).toEqual(config); }); }); @@ -219,7 +224,7 @@ test('Support yarn and npm workspaces with noHoist', async () => { const [configPath, config] = tsconfig; expect( - require(path.join(rootFolderYarnNohoist, configPath, 'tsconfig.json')) + parse(fs.readFileSync(path.join(rootFolderYarnNohoist, configPath, 'tsconfig.json')).toString()) ).toEqual(config); }); }); @@ -231,7 +236,7 @@ test('Support pnpm workspaces', async () => { const [configPath, config] = tsconfig; expect( - require(path.join(rootFolderPnpm, configPath, 'tsconfig.json')) + parse(fs.readFileSync(path.join(rootFolderPnpm, configPath, 'tsconfig.json')).toString()) ).toEqual(config); }); }); @@ -253,8 +258,7 @@ test('Detect changes with the --check option', async () => { const [configPath] = tsconfig; expect( - require(path.join(rootFolderYarnCheck, configPath, 'tsconfig.json')) - .references + parse(fs.readFileSync(path.join(rootFolderYarnCheck, configPath, 'tsconfig.json')).toString()).references ).toBeFalsy(); }); }); @@ -276,11 +280,7 @@ test('No changes detected with the --check option', async () => { const [configPath, config] = tsconfig; expect( - require(path.join( - rootFolderYarnCheckNoChanges, - configPath, - 'tsconfig.json' - )) + parse(fs.readFileSync(path.join(rootFolderYarnCheckNoChanges, configPath, 'tsconfig.json')).toString()) ).toEqual(config); }); }); @@ -376,7 +376,9 @@ test('Support custom tsconfig names', async () => { tsconfigs.forEach((tsconfig) => { const [configPath, config, configNameOverride] = tsconfig; - expect(require(path.join(rootFolder, configPath, configNameOverride || configName))).toEqual( + expect( + parse(fs.readFileSync(path.join(rootFolder, configPath, configNameOverride || configName)).toString()) + ).toEqual( config ); }); diff --git a/yarn.lock b/yarn.lock index 958b1e0..3081747 100644 --- a/yarn.lock +++ b/yarn.lock @@ -814,6 +814,11 @@ array-find-index@^1.0.1: resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= +array-timsort@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" + integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" @@ -1141,6 +1146,17 @@ commander@5.1.0: resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +comment-json@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" + integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw== + dependencies: + array-timsort "^1.0.3" + core-util-is "^1.0.3" + esprima "^4.0.1" + has-own-prop "^2.0.0" + repeat-string "^1.6.1" + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" @@ -1168,6 +1184,11 @@ core-util-is@1.0.2: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" @@ -1884,6 +1905,11 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-own-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" + integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== + has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz"