From a32205b012e031a644311d3fdf00e3f6a28559ef Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 6 Jun 2024 19:12:46 -0700 Subject: [PATCH] define "source" export condition Thanks to @colinhacks for the idea. Fix: https://github.com/isaacs/tshy/issues/69 --- README.md | 86 +++++++++++++++++++ src/exports.ts | 27 +++++- tap-snapshots/test/exports.ts.test.cjs | 112 ++++++++++++++++++++++--- 3 files changed, 209 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index aaa46b6..4e3e019 100644 --- a/README.md +++ b/README.md @@ -276,10 +276,12 @@ appropriate build target locations, like: "./foo": { "import": { "types": "./dist/esm/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/esm/foo.js" }, "require": { "types": "./dist/commonjs/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/commonjs/foo.js" } } @@ -345,20 +347,24 @@ be: ".": { "require": { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js" }, "import": { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js" } }, "./component/foo": { "require": { "types": "./dist/commonjs/component/foo.d.ts", + "source": "./src/component/foo.ts", "default": "./dist/commonjs/component/foo.js" }, "import": { "types": "./dist/esm/component/foo.d.ts", + "source": "./src/component/foo.ts", "default": "./dist/esm/component/foo.js" } }, @@ -404,6 +410,8 @@ your code. For this reason: - Because it links files into place, a rebuild _is_ required when a file is added or removed. +See also: "Loading from Source", below. + ### Package `#imports` You can use `"imports"` in your package.json, and it will be @@ -597,10 +605,12 @@ will produce: ".": { "require": { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.js", "default": "./dist/commonjs/index.js" }, "import": { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js" } } @@ -705,22 +715,27 @@ Will result in: ".": { "deno": { "types": "./dist/deno/index.d.ts", + "source": "./src/index.ts", "default": "./dist/deno/index.js" }, "browser": { "types": "./dist/browser/index.d.ts", + "default": "./src/index.ts", "default": "./dist/browser/index.js" }, "webpack": { "types": "./dist/webpack/index.d.ts", + "source": "./src/index.ts", "default": "./dist/webpack/index.js" }, "require": { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js" }, "import": { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js" } } @@ -745,6 +760,44 @@ src/index-deno.mts # esm variant for deno src/index-webpack.cts # cjs variant for webpack ``` +If dialect overrides are used, then the `"source"` export +condition will refer to the original source for the override. For +example: + +```json +{ + "exports": { + ".": { + "deno": { + "types": "./dist/deno/index.d.ts", + "source": "./src/index-deno.mts", + "default": "./dist/deno/index.js" + }, + "browser": { + "types": "./dist/browser/index.d.ts", + "default": "./src/index-browser.mts", + "default": "./dist/browser/index.js" + }, + "webpack": { + "types": "./dist/webpack/index.d.ts", + "source": "./src/index-webpack.cts", + "default": "./dist/webpack/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "source": "./src/index-cjs.cts", + "default": "./dist/commonjs/index.js" + }, + "import": { + "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", + "default": "./dist/esm/index.js" + } + } + } +} +``` + Note that the `commonjs` override uses the abbreviated `cjs` name (historical reasons, it was originally the only override supported), and that the file extension must be `cts` or `mts` @@ -801,6 +854,39 @@ provided for you. Then the `tsconfig.json` file will be used as the default project for code hints in VSCode, neovim, tests, etc. +### Loading from Source + +If you are using tshy in a monorepo environment, you can +configure TypeScript (and other tools) to resolve to the _source_ +files rather than built artifacts by telling them to use the +`"source"` export condition. + +For example, in editors such as VS Code and neovim/CoC that use +the TypeScript language services, you can give them a `tsconfig` +that contains this: + +```json +{ + "compilerOptions": { + "customConditions": ["source"] + } +} +``` + +If you are loading your program with a custom Node.js importer +like [`tsx`](https://npm.im/tsx) that can load TypeScript +directly, you can specify it like this: + +```bash +node --import=tsx --conditions=source ./script.ts +``` + +Other TypeScript-aware tools may have other mechanisms for +specifying export conditions. Refer to their documentation for +more information. + +See also: "Live Dev", above. + ### Custom `project` Configure `tshy.project` if you want tshy to extend from a custom diff --git a/src/exports.ts b/src/exports.ts index 1ab7ada..7bd0230 100644 --- a/src/exports.ts +++ b/src/exports.ts @@ -107,6 +107,8 @@ const getExports = ( const exp: ConditionalValueObject = (e[sub] = {}) if (impTarget) { for (const d of esmDialects) { + const source = s && (polyfills.get(d)?.map.get(s) ?? s) + const target = getTargetForDialectCondition( s, d, @@ -116,9 +118,13 @@ const getExports = ( ) if (target) { exp[d] = liveDev - ? target + ? { + source, + default: target, + } : { types: target.replace(/\.js$/, '.d.ts'), + source, default: target, } } @@ -127,6 +133,7 @@ const getExports = ( if (reqTarget) { for (const d of commonjsDialects) { + const source = s && (polyfills.get(d)?.map.get(s) ?? s) const target = getTargetForDialectCondition( s, d, @@ -136,9 +143,13 @@ const getExports = ( ) if (target) { exp[d] = liveDev - ? target + ? { + source, + default: target, + } : { types: target.replace(/\.js$/, '.d.ts'), + source, default: target, } } @@ -147,17 +158,25 @@ const getExports = ( // put the default import/require after all the other special ones. if (impTarget) { exp.import = liveDev - ? impTarget + ? { + source: s, + default: impTarget, + } : { types: impTarget.replace(/\.(m?)js$/, '.d.$1ts'), + source: s, default: impTarget, } } if (reqTarget) { exp.require = liveDev - ? reqTarget + ? { + source: s, + default: reqTarget, + } : { types: reqTarget.replace(/\.(c?)js$/, '.d.$1ts'), + source: s, default: reqTarget, } } diff --git a/tap-snapshots/test/exports.ts.test.cjs b/tap-snapshots/test/exports.ts.test.cjs index d691133..ce145a7 100644 --- a/tap-snapshots/test/exports.ts.test.cjs +++ b/tap-snapshots/test/exports.ts.test.cjs @@ -10,12 +10,14 @@ Object { ".": Object { "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, "./foo": Object { "require": Object { "types": "./dist/commonjs/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/commonjs/foo.js", }, }, @@ -27,20 +29,24 @@ Object { ".": Object { "blah": Object { "types": "./dist/blah/index.d.ts", + "source": "./src/index.ts", "default": "./dist/blah/index.js", }, "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, "./foo": Object { "blah": Object { "types": "./dist/blah/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/blah/foo.js", }, "require": Object { "types": "./dist/commonjs/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/commonjs/foo.js", }, }, @@ -52,12 +58,14 @@ Object { ".": Object { "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, }, "./foo": Object { "import": Object { "types": "./dist/esm/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/esm/foo.js", }, }, @@ -69,28 +77,34 @@ Object { ".": Object { "deno": Object { "types": "./dist/deno/index.d.ts", + "source": "./src/index.ts", "default": "./dist/deno/index.js", }, "no-overrides": Object { "types": "./dist/no-overrides/index.d.ts", + "source": "./src/index.ts", "default": "./dist/no-overrides/index.js", }, "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, }, "./foo": Object { "deno": Object { "types": "./dist/deno/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/deno/foo.js", }, "no-overrides": Object { "types": "./dist/no-overrides/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/no-overrides/foo.js", }, "import": Object { "types": "./dist/esm/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/esm/foo.js", }, }, @@ -102,20 +116,24 @@ Object { ".": Object { "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, "./foo": Object { "import": Object { "types": "./dist/esm/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/esm/foo.js", }, "require": Object { "types": "./dist/commonjs/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/commonjs/foo.js", }, }, @@ -127,44 +145,54 @@ Object { ".": Object { "deno": Object { "types": "./dist/deno/index.d.ts", + "source": "./src/index.ts", "default": "./dist/deno/index.js", }, "no-overrides": Object { "types": "./dist/no-overrides/index.d.ts", + "source": "./src/index.ts", "default": "./dist/no-overrides/index.js", }, "blah": Object { "types": "./dist/blah/index.d.ts", + "source": "./src/index.ts", "default": "./dist/blah/index.js", }, "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, "./foo": Object { "deno": Object { "types": "./dist/deno/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/deno/foo.js", }, "no-overrides": Object { "types": "./dist/no-overrides/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/no-overrides/foo.js", }, "blah": Object { "types": "./dist/blah/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/blah/foo.js", }, "import": Object { "types": "./dist/esm/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/esm/foo.js", }, "require": Object { "types": "./dist/commonjs/foo.d.ts", + "source": "./src/foo.ts", "default": "./dist/commonjs/foo.js", }, }, @@ -174,25 +202,61 @@ Object { exports[`test/exports.ts > TAP > liveDev > no envs > must match snapshot 1`] = ` Object { ".": Object { - "deno": "./dist/deno/index.ts", - "blah": "./dist/blah/index.ts", - "import": "./dist/esm/index.ts", - "require": "./dist/commonjs/index.ts", + "deno": Object { + "source": "./src/index.ts", + "default": "./dist/deno/index.ts", + }, + "blah": Object { + "source": "./src/index.ts", + "default": "./dist/blah/index.ts", + }, + "import": Object { + "source": "./src/index.ts", + "default": "./dist/esm/index.ts", + }, + "require": Object { + "source": "./src/index.ts", + "default": "./dist/commonjs/index.ts", + }, }, "./package.json": "./package.json", "./foo": Object { - "deno": "./dist/deno/foo.mts", - "import": "./dist/esm/foo.mts", + "deno": Object { + "source": "./src/foo.mts", + "default": "./dist/deno/foo.mts", + }, + "import": Object { + "source": "./src/foo.mts", + "default": "./dist/esm/foo.mts", + }, }, "./foo-cjs": Object { - "blah": "./dist/blah/foo.cts", - "require": "./dist/commonjs/foo.cts", + "blah": Object { + "source": "./src/foo.cts", + "default": "./dist/blah/foo.cts", + }, + "require": Object { + "source": "./src/foo.cts", + "default": "./dist/commonjs/foo.cts", + }, }, "./fill": Object { - "deno": "./dist/deno/fill.ts", - "blah": "./dist/blah/fill.ts", - "import": "./dist/esm/fill.ts", - "require": "./dist/commonjs/fill.ts", + "deno": Object { + "source": "./src/fill.ts", + "default": "./dist/deno/fill.ts", + }, + "blah": Object { + "source": "./src/fill.ts", + "default": "./dist/blah/fill.ts", + }, + "import": Object { + "source": "./src/fill.ts", + "default": "./dist/esm/fill.ts", + }, + "require": Object { + "source": "./src/fill.ts", + "default": "./dist/commonjs/fill.ts", + }, }, } ` @@ -202,18 +266,22 @@ Object { ".": Object { "deno": Object { "types": "./dist/deno/index.d.ts", + "source": "./src/index.ts", "default": "./dist/deno/index.js", }, "blah": Object { "types": "./dist/blah/index.d.ts", + "source": "./src/index.ts", "default": "./dist/blah/index.js", }, "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, @@ -221,38 +289,46 @@ Object { "./foo": Object { "deno": Object { "types": "./dist/deno/foo.mjs", + "source": "./src/foo.mts", "default": "./dist/deno/foo.mjs", }, "import": Object { "types": "./dist/esm/foo.d.mts", + "source": "./src/foo.mts", "default": "./dist/esm/foo.mjs", }, }, "./foo-cjs": Object { "blah": Object { "types": "./dist/blah/foo.cjs", + "source": "./src/foo.cts", "default": "./dist/blah/foo.cjs", }, "require": Object { "types": "./dist/commonjs/foo.d.cts", + "source": "./src/foo.cts", "default": "./dist/commonjs/foo.cjs", }, }, "./fill": Object { "deno": Object { "types": "./dist/deno/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/deno/fill.js", }, "blah": Object { "types": "./dist/blah/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/blah/fill.js", }, "import": Object { "types": "./dist/esm/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/esm/fill.js", }, "require": Object { "types": "./dist/commonjs/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/commonjs/fill.js", }, }, @@ -264,18 +340,22 @@ Object { ".": Object { "deno": Object { "types": "./dist/deno/index.d.ts", + "source": "./src/index.ts", "default": "./dist/deno/index.js", }, "blah": Object { "types": "./dist/blah/index.d.ts", + "source": "./src/index.ts", "default": "./dist/blah/index.js", }, "import": Object { "types": "./dist/esm/index.d.ts", + "source": "./src/index.ts", "default": "./dist/esm/index.js", }, "require": Object { "types": "./dist/commonjs/index.d.ts", + "source": "./src/index.ts", "default": "./dist/commonjs/index.js", }, }, @@ -283,38 +363,46 @@ Object { "./foo": Object { "deno": Object { "types": "./dist/deno/foo.mjs", + "source": "./src/foo.mts", "default": "./dist/deno/foo.mjs", }, "import": Object { "types": "./dist/esm/foo.d.mts", + "source": "./src/foo.mts", "default": "./dist/esm/foo.mjs", }, }, "./foo-cjs": Object { "blah": Object { "types": "./dist/blah/foo.cjs", + "source": "./src/foo.cts", "default": "./dist/blah/foo.cjs", }, "require": Object { "types": "./dist/commonjs/foo.d.cts", + "source": "./src/foo.cts", "default": "./dist/commonjs/foo.cjs", }, }, "./fill": Object { "deno": Object { "types": "./dist/deno/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/deno/fill.js", }, "blah": Object { "types": "./dist/blah/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/blah/fill.js", }, "import": Object { "types": "./dist/esm/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/esm/fill.js", }, "require": Object { "types": "./dist/commonjs/fill.d.ts", + "source": "./src/fill.ts", "default": "./dist/commonjs/fill.js", }, },