chore: migrate package to ESM (chalk 5 / plist 5 / citty 0.2)#30
Merged
Conversation
Convert the CLI from CommonJS to ESM ("type": "module", tsconfig
module/moduleResolution nodenext), which unblocks the three ESM-only
deps held back in #28: chalk 5, plist 5, citty 0.2.
- Add explicit .js extensions to all relative import/export/dynamic-import
specifiers (required under NodeNext), preserving file-over-directory
resolution (./types -> ./types.js, the file, not the barrel).
- Rewrite CJS interop sites: chalk/StreamZip default imports; read
package.json version via fs + import.meta.url instead of require().
- node-stream-zip is a single-function CJS export, so its three import
sites must use a default import — a namespace import yields no .async.
- Drop @types/plist (plist 5 bundles its own types).
- Rename eslint.config.js -> eslint.config.cjs (flat config stays CJS).
Validated: build, typecheck (src+test), lint (0 errors), 147 tests,
and CLI/MCP smoke runs all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts: # src/commands/cloud.ts # src/commands/list.ts # src/commands/live.ts # src/commands/login.ts # src/commands/logout.ts # src/commands/status.ts # src/commands/switch-org.ts # src/commands/upgrade.ts # src/commands/upload.ts # src/commands/whoami.ts # src/services/results-polling.service.ts
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
CI (Node 22) failed with "node-apk does not provide an export named 'Apk'". Both node-apk and bplist-parser are CJS with no exports map, so named imports rely on cjs-module-lexer's named-export detection — which is Node-version-dependent (Node 25 detects them, Node 22 does not). Switch to default-import + destructure, which relies only on the guaranteed `default = module.exports` interop and works on every Node version. plist stays a named import (it's genuine ESM). Verified under Node 22: unit suite (incl. APK metadata extraction) loads and passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Converts the CLI from CommonJS to ESM, which unblocks the three ESM-only major deps that were held back in #28.
package.json:"type": "module"tsconfig.json:module/moduleResolution→nodenext,esModuleInterop: true.jsextensions on all relative import/export/dynamic-import specifiers (required under NodeNext), preserving file-over-directory resolution —./types→./types.js(the filesrc/types.ts), not thesrc/types/index.tsbarrelchalk5 is ESM)getCliVersion()readspackage.jsonviaJSON.parse(readFileSync(new URL('../../package.json', import.meta.url)))instead ofrequire()(keeps it out of the tscrootDir)@types/plist(plist 5 bundles its own types)eslint.config.js→eslint.config.cjs(flat config stays CJS)This branch also merges in
origin/dev(PR #29, unified CLI output).Gotcha worth flagging
node-stream-zip'smodule.exportsis a single function with.asynchanging off it. A namespace import (import * as StreamZip) yields{ default, 'module.exports' }with no.async, sonew StreamZip.async(...)throwsis not a constructorat runtime. Must be a default import. Typecheck does not catch this — only the test suite did. Other bare-package namespace imports (js-yaml, yazl, tar, tus-js-client, @clack/prompts, bplist-parser, plist) are fine: cjs-module-lexer detects their named exports.Validation
build ✓ · typecheck (src + test) ✓ · lint 0 errors ✓ · 147 tests passing ✓ · CLI
--version/--help+ MCPtools/listsmoke ✓🤖 Generated with Claude Code