From c1513e5a90b0fbbb8bbd4823a9b4241e282d9294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Dewitte?= Date: Sat, 31 Aug 2024 11:04:37 +0200 Subject: [PATCH] feat(cli): add tsx support (#1021) Co-authored-by: Shinigami92 --- .github/workflows/postgres-test.yml | 57 +++++++++++++++++++++++++++-- bin/node-pg-migrate.ts | 57 +++++++++++++++++++++++------ package.json | 1 + pnpm-lock.yaml | 36 ++++++++++++++++-- 4 files changed, 133 insertions(+), 18 deletions(-) diff --git a/.github/workflows/postgres-test.yml b/.github/workflows/postgres-test.yml index 601b7f21..d634f0de 100644 --- a/.github/workflows/postgres-test.yml +++ b/.github/workflows/postgres-test.yml @@ -573,7 +573,7 @@ jobs: DATABASE_URL: postgres://ubuntu:ubuntu@localhost:5432/integration_test SCHEMA: myschema - typescript-migration-test: + typescript-migration-via-ts-node-test: runs-on: ubuntu-latest strategy: matrix: @@ -599,7 +599,7 @@ jobs: # Maps tcp port 5432 on service container to the host - 5432:5432 - name: 'TypeScript Migration Test: pg-${{ matrix.postgres_version }}, node-${{ matrix.node_version }}, ubuntu-latest' + name: 'TypeScript Migration Test with ts-node: pg-${{ matrix.postgres_version }}, node-${{ matrix.node_version }}, ubuntu-latest' steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -620,7 +620,58 @@ jobs: run: pnpm run build - name: Integration Test - run: pnpm run migrate up --tsconfig tsconfig.json -m test/ts/migrations && pnpm run migrate down 0 --tsconfig tsconfig.json -m test/ts/migrations --timestamps + run: pnpm run migrate up --tsconfig tsconfig.json --ts-node -m test/ts/migrations && pnpm run migrate down 0 --tsconfig tsconfig.json --ts-node -m test/ts/migrations --timestamps + env: + DATABASE_URL: postgres://ubuntu:ubuntu@localhost:5432/integration_test + + typescript-migration-via-tsx-test: + runs-on: ubuntu-latest + strategy: + matrix: + node_version: [20] + postgres_version: [16.2] + fail-fast: false + timeout-minutes: 10 + + services: + postgres: + image: postgres:${{ matrix.postgres_version }}-alpine + env: + POSTGRES_USER: ubuntu + POSTGRES_PASSWORD: ubuntu + POSTGRES_DB: integration_test + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 5432 on service container to the host + - 5432:5432 + + name: 'TypeScript Migration Test with tsx: pg-${{ matrix.postgres_version }}, node-${{ matrix.node_version }}, ubuntu-latest' + steps: + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Install pnpm + uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 + + - name: Set node version to ${{ matrix.node_version }} + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: ${{ matrix.node_version }} + cache: 'pnpm' + + - name: Install deps + run: pnpm install + + - name: Build + run: pnpm run build + + - name: Integration Test + run: pnpm run migrate up --tsconfig tsconfig.json --tsx -m test/ts/migrations && pnpm run migrate down 0 --tsconfig tsconfig.json --tsx -m test/ts/migrations --timestamps env: DATABASE_URL: postgres://ubuntu:ubuntu@localhost:5432/integration_test diff --git a/bin/node-pg-migrate.ts b/bin/node-pg-migrate.ts index 30008b61..11c243d3 100755 --- a/bin/node-pg-migrate.ts +++ b/bin/node-pg-migrate.ts @@ -24,6 +24,11 @@ process.on('uncaughtException', (err) => { const crossRequire = createRequire(resolve('_')); +/** + * Try to require a module and return null if it doesn't exist. + * + * @param moduleName The name of the module to require. + */ function tryRequire(moduleName: string): TModule | null { try { return crossRequire(moduleName); @@ -60,6 +65,8 @@ const dryRunArg = 'dry-run'; const fakeArg = 'fake'; const decamelizeArg = 'decamelize'; const tsconfigArg = 'tsconfig'; +const tsNodeArg = 'ts-node'; +const tsxArg = 'tsx'; const verboseArg = 'verbose'; const rejectUnauthorizedArg = 'reject-unauthorized'; const envPathArg = 'envPath'; @@ -162,6 +169,16 @@ const parser = yargs(process.argv.slice(2)) describe: 'Path to tsconfig.json file', type: 'string', }, + [tsNodeArg]: { + default: true, + describe: 'Use ts-node for typescript files', + type: 'boolean', + }, + [tsxArg]: { + default: false, + describe: 'Use tsx for typescript files', + type: 'boolean', + }, [envPathArg]: { describe: 'Path to the .env file that should be used for configuration', type: 'string', @@ -255,8 +272,10 @@ let CHECK_ORDER = argv[checkOrderArg]; let VERBOSE = argv[verboseArg]; let DECAMELIZE = argv[decamelizeArg]; let tsconfigPath = argv[tsconfigArg]; +let useTsNode = argv[tsNodeArg]; +let useTsx = argv[tsxArg]; -function readTsconfig() { +function readTsconfig(): void { if (tsconfigPath) { let tsconfig; const json5 = tryRequire('json5'); @@ -283,18 +302,24 @@ function readTsconfig() { console.error("Can't load tsconfig.json:", error); } - const tsnode = tryRequire('ts-node'); - if (!tsnode) { - console.error("For TypeScript support, please install 'ts-node' module"); - } + if (useTsx) { + process.env.TSX_TSCONFIG_PATH = tsconfigPath; + } else if (useTsNode) { + const tsnode = tryRequire('ts-node'); + if (!tsnode) { + console.error( + "For TypeScript support, please install 'ts-node' module" + ); + } - if (tsconfig && tsnode) { - tsnode.register(tsconfig); - if (!MIGRATIONS_FILE_LANGUAGE) { - MIGRATIONS_FILE_LANGUAGE = 'ts'; + if (tsconfig && tsnode) { + tsnode.register(tsconfig); + if (!MIGRATIONS_FILE_LANGUAGE) { + MIGRATIONS_FILE_LANGUAGE = 'ts'; + } + } else { + process.exit(1); } - } else { - process.exit(1); } } } @@ -393,6 +418,8 @@ function readJson(json: unknown): void { typeof val === 'string' || typeof val === 'object' ); tsconfigPath = applyIf(tsconfigPath, tsconfigArg, json, isString); + useTsNode = applyIf(useTsNode, tsNodeArg, json, isBoolean); + useTsx = applyIf(useTsx, tsxArg, json, isBoolean); if ('url' in json && json.url) { DB_CONNECTION ??= json.url; @@ -430,6 +457,14 @@ if (configFileName) { readTsconfig(); +if (useTsx) { + const tsx = + tryRequire('tsx/cjs'); + if (!tsx) { + console.error("For TSX support, please install 'tsx' module"); + } +} + const action = argv._.shift(); // defaults diff --git a/package.json b/package.json index 77bdcd9b..230b9327 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "rimraf": "6.0.1", "ts-node": "10.9.2", "tsup": "8.2.4", + "tsx": "4.19.0", "typescript": "5.5.4", "vitepress": "1.3.4", "vitest": "2.0.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d56551a..b17974ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,7 +101,10 @@ importers: version: 10.9.2(@types/node@18.19.47)(typescript@5.5.4) tsup: specifier: 8.2.4 - version: 8.2.4(postcss@8.4.41)(typescript@5.5.4) + version: 8.2.4(postcss@8.4.41)(tsx@4.19.0)(typescript@5.5.4) + tsx: + specifier: 4.19.0 + version: 4.19.0 typescript: specifier: 5.5.4 version: 5.5.4 @@ -1445,6 +1448,9 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} + get-tsconfig@4.7.6: + resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2200,6 +2206,9 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -2491,6 +2500,11 @@ packages: typescript: optional: true + tsx@4.19.0: + resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4129,6 +4143,10 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 + get-tsconfig@4.7.6: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4688,11 +4706,12 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@6.0.1(postcss@8.4.41): + postcss-load-config@6.0.1(postcss@8.4.41)(tsx@4.19.0): dependencies: lilconfig: 3.1.2 optionalDependencies: postcss: 8.4.41 + tsx: 4.19.0 postcss@8.4.41: dependencies: @@ -4782,6 +4801,8 @@ snapshots: resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.1 @@ -5068,7 +5089,7 @@ snapshots: tslib@2.7.0: {} - tsup@8.2.4(postcss@8.4.41)(typescript@5.5.4): + tsup@8.2.4(postcss@8.4.41)(tsx@4.19.0)(typescript@5.5.4): dependencies: bundle-require: 5.0.0(esbuild@0.23.1) cac: 6.7.14 @@ -5080,7 +5101,7 @@ snapshots: globby: 11.1.0 joycon: 3.1.1 picocolors: 1.0.1 - postcss-load-config: 6.0.1(postcss@8.4.41) + postcss-load-config: 6.0.1(postcss@8.4.41)(tsx@4.19.0) resolve-from: 5.0.0 rollup: 4.21.1 source-map: 0.8.0-beta.0 @@ -5095,6 +5116,13 @@ snapshots: - tsx - yaml + tsx@4.19.0: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.7.6 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1