Skip to content

feat(http-client-python): migrate eng scripts from tsx to native Node.js TypeScript - #11425

Open
Timothee Guerin (timotheeguerin) with Copilot wants to merge 11 commits into
mainfrom
copilot/migrate-to-native-node-typescript
Open

feat(http-client-python): migrate eng scripts from tsx to native Node.js TypeScript#11425
Timothee Guerin (timotheeguerin) with Copilot wants to merge 11 commits into
mainfrom
copilot/migrate-to-native-node-typescript

Conversation

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Mirrors the change from Azure/typespec-azure#5068: replace tsx as the TypeScript script runner with Node.js native TypeScript support (Node 22+ strips types natively).

Changes

  • package.json: Replace all tsx ./eng/scripts/... invocations with node ./eng/scripts/...; remove tsx from dependencies
  • eng/scripts/setup/*.ts and eng/scripts/ci/regenerate.ts: Change relative imports from .js.ts extensions (required for native Node TS resolution)
  • Help text / comments: Update tsx <script>.ts usage examples to node <script>.ts

…js TypeScript

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Comment thread packages/http-client-python/package.json
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Python emitter diff

Baseline gh:13845fedc83a14fc3441f435f59246e0e4d41116 vs this PR.

No changes to generated output.

Rendered diff: inline on the run summary, or the emitter-diff-html artifact.

Informational check (eng/emitter-diff); does not block the PR.

@timotheeguerin

Copy link
Copy Markdown
Member

Copilot the build is failing did you check it was passing?

Installing npm dependencies...
> npm ci

> @typespec/http-client-python@0.35.0 install
> node ./eng/scripts/setup/install.ts

file:///mnt/vss/_work/1/s/packages/http-client-python/eng/scripts/setup/system-requirements.ts:1
import { ChildProcess, spawn, SpawnOptions } from "child_process";
                              ^^^^^^^^^^^^
SyntaxError: The requested module 'child_process' does not provide an export named 'SpawnOptions'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:226:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:335:5)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:681:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5)

Node.js v22.23.1
npm error code 1
npm error path /mnt/vss/_work/1/s/packages/http-client-python
npm error command failed
npm error command sh -c node ./eng/scripts/setup/install.ts
npm error A complete log of this run can be found in: /home/cloudtest/.npm/_logs/2026-07-28T17_42_30_653Z-debug-0.log
Invoke-LoggedCommand: /mnt/vss/_work/1/s/packages/http-client-python/eng/scripts/Initialize-Repository.ps1:42

…atibility

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Copilot the build is failing did you check it was passing?

Installing npm dependencies...

...

Fixed in the latest commit. The root cause: Node.js native type stripping doesn't do import elision — it strips type annotations but leaves import statements untouched. SpawnOptions (an interface in child_process) and RegenerateContext/RegenerateFlags (interfaces in regenerate-common.ts) were imported as values, which fails at runtime since they have no runtime representation. Added the type keyword inline on those imports:

  • system-requirements.ts: import { ChildProcess, spawn, type SpawnOptions }
  • regenerate.ts: type RegenerateContext, type RegenerateFlags

@timotheeguerin

Copy link
Copy Markdown
Member

Copilot still failing

pm install typespec-http-client-python-0.35.0.tgz
npm error code 1
npm error path /mnt/vss/_work/1/s/packages/http-client-python/node_modules/@typespec/http-client-python
npm error command failed
npm error command sh -c node ./eng/scripts/setup/install.ts
npm error node:internal/modules/typescript:183
npm error throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(filename);
npm error ^
npm error
npm error Error [ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING]: Stripping types is currently unsupported for files under node_modules, for "file:///mnt/vss/_work/1/s/packages/http-client-python/node_modules/@typespec/http-client-python/eng/scripts/setup/install.ts"
npm error at stripTypeScriptModuleTypes (node:internal/modules/typescript:183:11)
npm error at ModuleLoader. (node:internal/modules/esm/translators:680:29)
npm error at #translate (node:internal/modules/esm/loader:434:20)
npm error at afterLoad (node:internal/modules/esm/loader:502:29)
npm error at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:507:12)
npm error at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:560:36)
npm error at afterResolve (node:internal/modules/esm/loader:607:52)
npm error at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:613:12)
npm error at node:internal/modules/esm/loader:632:32
npm error at TracingChannel.tracePromise (node:diagnostics_channel:362:14) {
npm error code: 'ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING'
npm error }
npm error
npm error Node.js v24.18.0
npm error A complete log of this run can be found in: /home

…modules type stripping

- Create eng/scripts/setup/install-runner.js and prepare-runner.js as plain
  JavaScript bootstrappers that work in any Node.js context (including under
  node_modules where type stripping is not allowed)
- Create eng/scripts/setup/tsconfig.build.json to compile setup scripts to
  dist/scripts/setup/ using rewriteRelativeImportExtensions so .ts imports
  become .js in the compiled output
- Update package.json: install/prepare lifecycle scripts use the .js runners;
  build step now also compiles setup scripts to dist/

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Copilot still failing

pm install typespec-http-client-python-0.35.0.tgz
...

Fixed in the latest commit.

Root cause: Node.js 22+ native TypeScript type stripping is explicitly disabled for files under node_modules — even though the .ts source and .ts-extension imports work fine in the repo's own dev context, they fail when the package is installed as a dependency.

Fix:

  1. eng/scripts/setup/tsconfig.build.json — new TypeScript config that compiles all eng/scripts/setup/*.tsdist/scripts/setup/*.js, using rewriteRelativeImportExtensions: true (TS 5.7+) so .ts import specifiers become .js in the compiled output.

  2. install-runner.js / prepare-runner.js — small plain-JavaScript bootstrappers (no TypeScript syntax) that:

    • Use the pre-compiled dist/scripts/setup/install.js when available (i.e., when installed from npm/tgz — the dist/** is already in files)
    • Fall back to native TS stripping on ./install.ts in the dev/repo context (not under node_modules)
  3. package.json:

    • install: now node ./eng/scripts/setup/install-runner.js
    • prepare: now node ./eng/scripts/setup/prepare-runner.js
    • build: appends && tsc -p ./eng/scripts/setup/tsconfig.build.json so the compiled JS is always present in the tgz

@timotheeguerin

Copy link
Copy Markdown
Member

Copilot still failing the build

29:5 warning Unexpected console statement no-console

/mnt/vss/_work/1/s/packages/http-client-python/eng/scripts/setup/prepare-runner.js
29:5 warning Unexpected console statement no-console

✖ 2 problems (0 errors, 2 warnings)

ESLint found too many warnings (maximum: 0).
[FAIL] eslint emitter/ eng/scripts/ --max-warnings=0 failed with code 1

=== Linting Python Generator (pygen) ===

[RUN] /mnt/vss/_work/1/s/packages/http-client-python/venv/bin/python -m pylint generator/pygen --rcfile=eng/scripts/ci/config/pylintrc --recursive=y --py-version=3.10


Your code has been rated at 10.00/10

[PASS] /mnt/vss/_work/1/s/packages/http-client-python/venv/bin/python completed successfully
Invoke-LoggedCommand: /mnt/vss/_work/1/s/packages/http-client-python/eng/scripts/Build-Packages.ps1:87
Line |
87 | Invoke-LoggedCommand "npm run lint" -GroupOutput
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ##[error]Command completed with exit code 1 (00:00:15.6450394): npm run
| lint

##[error]PowerShell e

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Copilot still failing the build

29:5 warning Unexpected console statement no-console
...

Fixed — added // eslint-disable-line no-console to the console.log statements in both install-runner.js and prepare-runner.js, matching the convention used throughout the other scripts in the package.

@pkg-pr-new

pkg-pr-new Bot commented Jul 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@11425

commit: cf7a56f

@timotheeguerin

Copy link
Copy Markdown
Member

Copilot still failing


=== Creating npm package ===
> npm pack

> @typespec/http-client-python@0.35.0 prepare
> node ./eng/scripts/setup/prepare-runner.js

node:internal/modules/esm/load:199
    throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed, schemes);
          ^

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'd:'
    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:199:11)
    at defaultLoadSync (node:internal/modules/esm/load:146:3)
    at ModuleLoader.load (node:internal/modules/esm/loader:831:12)
    at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:609:31)
    at #createModuleJob (node:internal/modules/esm/loader:640:36)
    at #getJobFromResolveResult (node:internal/modules/esm/loader:353:34)
    at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:321:41)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:680:25) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}

Node.js v22.23.1
npm error code 1
npm error path D:\a\_work\1\s\packages\http-client-python
npm error command failed
npm error command C:\Windows\system32\cmd.exe /d /s /c node ./eng/scripts/setup/prepare-runner.js
npm error A complete log of this run can be found in: C:\npm\cache\_logs\2026-07-28T20_38_06_518Z-debug-0.log
Invoke-LoggedCommand : ##[error]Command completed with exit code 1 (00:00:00.9767322): npm pack


DO test the FULL build locally and make sure it passes

also pull main and merge conflicts

…tive-node-typescript

# Conflicts:
#	packages/http-client-python/package.json

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuchao Yan (@msyyc) I was not super sure about the way it was done in the packaged instance

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot could we change what file gets called with publishConfig overrides?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into it — publishConfig can't do this with npm.

  • npm's publishConfig only holds npm config values (registry/tag/access/provenance/etc.), not package.json field overrides: lib/commands/publish.js just does flatten(manifest.publishConfig, opts) into the npm config. Arbitrary field overrides (main, exports, scripts, …) are a pnpm/yarn feature, and even pnpm's allowlist doesn't include scripts.
  • I also confirmed empirically that npm pack does not rewrite package.json from publishConfig — the tarball's manifest keeps the original scripts. Since Build-Packages.ps1 packs with npm pack and then npm install <tgz>, the packed install/prepare scripts are exactly what's in the repo's package.json. This package is also excluded from the pnpm workspace, so pnpm's publish rewriting doesn't apply either.

So the entry file has to be one that works in both contexts, which is why the *-runner.js bootstraps exist (.ts can't be type-stripped under node_modules).

If the runners feel too magic, the alternative I'd suggest is dropping TypeScript for the lifecycle chain entirely — convert eng/scripts/setup/{install,prepare,run-python3,system-requirements}.ts to plain .js. That removes both runners plus the extra tsconfig.build.json/tsc build step, at the cost of losing types in those ~340 lines. Happy to do that if you prefer it — just let me know.

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - internal ✏️

Migrate eng scripts from tsx to native Node.js TypeScript support

"./dist/emitter/pyodide-loader.js": "./dist/emitter/pyodide-loader.browser.js"
},
"engines": {
"node": ">=22.0.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"node": ">=22.6.0"
Image

@microsoft-github-policy-service microsoft-github-policy-service Bot added the stale Mark a PR that hasn't been recently updated and will be closed. label Aug 24, 2026
@msyyc Yuchao Yan (msyyc) removed the stale Mark a PR that hasn't been recently updated and will be closed. label Aug 26, 2026
@msyyc

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

@timotheeguerin

Copy link
Copy Markdown
Member

Copilot resolve the merge conflicts in this pull request

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 28, 2026 12:49

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Copilot resolve the merge conflicts in this pull request

Merged main and resolved the conflicts in ecd9b2f.

Two conflicting files, both from main splitting type imports onto their own lines:

  • eng/scripts/ci/regenerate.ts — kept main's import type { RegenerateContext, RegenerateFlags } line, with the .ts extension.
  • eng/scripts/setup/system-requirements.ts — kept main's import type { ChildProcess, SpawnOptions } + import { spawn } split.

Verified both files parse/execute under Node's native type stripping.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • packages/http-client-python/package-lock.json: Generated file

Copilot AI review requested due to automatic review settings September 4, 2026 14:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The migration is internally consistent and preserves installed-package lifecycle behavior through compiled fallbacks.

Review details

Files not reviewed (1)

  • packages/http-client-python/package-lock.json: Generated file
  • Files reviewed: 14/15 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants