@sanity/pkg-utils 11.0.17 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/MIGRATE.md +152 -0
  2. package/README.md +110 -55
  3. package/dist/buildAction-DFrmHzYY.js +146 -0
  4. package/dist/buildAction-DFrmHzYY.js.map +1 -0
  5. package/dist/checkAction-BMxszLZS.js +140 -0
  6. package/dist/checkAction-BMxszLZS.js.map +1 -0
  7. package/dist/cli.js +22 -28
  8. package/dist/cli.js.map +1 -1
  9. package/dist/createApiExtractorConfig-CJoZqw8e.js +30 -0
  10. package/dist/createApiExtractorConfig-CJoZqw8e.js.map +1 -0
  11. package/dist/createTSDocConfig-CwaWneTR.js +25 -0
  12. package/dist/createTSDocConfig-CwaWneTR.js.map +1 -0
  13. package/dist/getExtractMessagesConfig-CXljwFbQ.js +75 -0
  14. package/dist/getExtractMessagesConfig-CXljwFbQ.js.map +1 -0
  15. package/dist/handleError-83GwKIFM.js +40 -0
  16. package/dist/handleError-83GwKIFM.js.map +1 -0
  17. package/dist/index.d.ts +141 -195
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +203 -11
  20. package/dist/index.js.map +1 -1
  21. package/dist/initAction-Cv0oRwWP.js +618 -0
  22. package/dist/initAction-Cv0oRwWP.js.map +1 -0
  23. package/dist/printExtractMessages-DyaYtByp.js +33 -0
  24. package/dist/printExtractMessages-DyaYtByp.js.map +1 -0
  25. package/dist/resolveBuildContext-CwqbTV6p.js +713 -0
  26. package/dist/resolveBuildContext-CwqbTV6p.js.map +1 -0
  27. package/dist/resolveTsdownConfig-2OdGF-dM.js +258 -0
  28. package/dist/resolveTsdownConfig-2OdGF-dM.js.map +1 -0
  29. package/dist/spinner-DAHe7SuT.js +15 -0
  30. package/dist/spinner-DAHe7SuT.js.map +1 -0
  31. package/dist/watchAction-uRPAvgLE.js +179 -0
  32. package/dist/watchAction-uRPAvgLE.js.map +1 -0
  33. package/dist/watchConfigFiles-AGBDblwf.js +43 -0
  34. package/dist/watchConfigFiles-AGBDblwf.js.map +1 -0
  35. package/package.json +10 -24
  36. package/dist/_chunks-es/buildAction.js +0 -195
  37. package/dist/_chunks-es/buildAction.js.map +0 -1
  38. package/dist/_chunks-es/checkAction.js +0 -198
  39. package/dist/_chunks-es/checkAction.js.map +0 -1
  40. package/dist/_chunks-es/createApiExtractorConfig.js +0 -52
  41. package/dist/_chunks-es/createApiExtractorConfig.js.map +0 -1
  42. package/dist/_chunks-es/createTSDocConfig.js +0 -31
  43. package/dist/_chunks-es/createTSDocConfig.js.map +0 -1
  44. package/dist/_chunks-es/defaults.js +0 -36
  45. package/dist/_chunks-es/defaults.js.map +0 -1
  46. package/dist/_chunks-es/define.js +0 -7
  47. package/dist/_chunks-es/define.js.map +0 -1
  48. package/dist/_chunks-es/extractModuleBlocks.js +0 -48
  49. package/dist/_chunks-es/extractModuleBlocks.js.map +0 -1
  50. package/dist/_chunks-es/fileExists.js +0 -12
  51. package/dist/_chunks-es/fileExists.js.map +0 -1
  52. package/dist/_chunks-es/getExtractMessagesConfig.js +0 -83
  53. package/dist/_chunks-es/getExtractMessagesConfig.js.map +0 -1
  54. package/dist/_chunks-es/handleError.js +0 -32
  55. package/dist/_chunks-es/handleError.js.map +0 -1
  56. package/dist/_chunks-es/index.js +0 -825
  57. package/dist/_chunks-es/index.js.map +0 -1
  58. package/dist/_chunks-es/initAction.js +0 -654
  59. package/dist/_chunks-es/initAction.js.map +0 -1
  60. package/dist/_chunks-es/printExtractMessages.js +0 -44
  61. package/dist/_chunks-es/printExtractMessages.js.map +0 -1
  62. package/dist/_chunks-es/resolveBuildContext.js +0 -717
  63. package/dist/_chunks-es/resolveBuildContext.js.map +0 -1
  64. package/dist/_chunks-es/resolveRolldownConfig.js +0 -117
  65. package/dist/_chunks-es/resolveRolldownConfig.js.map +0 -1
  66. package/dist/_chunks-es/spinner.js +0 -16
  67. package/dist/_chunks-es/spinner.js.map +0 -1
  68. package/dist/_chunks-es/watchAction.js +0 -160
  69. package/dist/_chunks-es/watchAction.js.map +0 -1
  70. package/dist/_chunks-es/watchConfigFiles.js +0 -49
  71. package/dist/_chunks-es/watchConfigFiles.js.map +0 -1
package/MIGRATE.md ADDED
@@ -0,0 +1,152 @@
1
+ # Migrating to `@sanity/pkg-utils` v12
2
+
3
+ v12 replaced the rollup/rolldown build stack with [`tsdown`](https://tsdown.dev) +
4
+ [`@sanity/tsdown-config`](https://github.com/sanity-io/pkg-utils/tree/main/packages/@sanity/tsdown-config#readme).
5
+
6
+ Most packages need **no changes**. If your `package.config.ts` uses a removed option, the build
7
+ stops with an error that contains these same migration instructions (skipped when
8
+ `NODE_ENV=production`, or with `legacyChecks: false`).
9
+
10
+ ## TL;DR
11
+
12
+ | v11 | v12 |
13
+ | ----------------------------------- | ------------------------------------------------------------------- |
14
+ | `dts: 'rolldown'` | delete it (it's the default now) |
15
+ | `dts: 'api-extractor'` | delete it (types come from tsdown) |
16
+ | `tsgo: true` | `dts: {tsgo: true}` |
17
+ | `babel: {reactCompiler: true}` | `reactCompiler: true` |
18
+ | `reactCompilerOptions: {...}` | `reactCompiler: {...}` |
19
+ | `babel: {styledComponents: true}` | `styledComponents: true` |
20
+ | `babel: {plugins: [...]}` | `plugins` + [`@rolldown/plugin-babel`](#custom-babel-plugins) |
21
+ | `rollup: {vanillaExtract: true}` | `vanillaExtract: true` |
22
+ | `rollup: {plugins: [...]}` | `plugins: [...]` |
23
+ | `rollup: {optimizeLodash: ...}` | removed — see [lodash](#lodash) |
24
+ | `extract: {enabled: false}` | `tsdoc: false` |
25
+ | `extract: {rules, customTags}` | `tsdoc: {rules, customTags}` |
26
+ | `extract: {bundledPackages: [...]}` | `deps: {alwaysBundle: [...]}` — see [type inlining](#type-inlining) |
27
+ | `external: [...]` | `deps: {neverBundle: [...]}` (deprecated, still works) |
28
+ | `external: (prev) => prev.filter()` | `deps: {alwaysBundle: [...]}` (deprecated, still works) |
29
+ | `jsx`, `jsxFactory`, … | `tsconfig.json` `compilerOptions.jsx` and friends |
30
+ | `process.env.PKG_FORMAT` | [`package.json#imports` conditions](#pkg_format-and-pkg_runtime) |
31
+ | `process.env.PKG_RUNTIME` | [`package.json#imports` conditions](#pkg_format-and-pkg_runtime) |
32
+ | `process.env.PKG_FILE_PATH` | [`import.meta.url`](#pkg_file_path) |
33
+ | `pkg build --clean` | delete it (cleaning is on by default; `--no-clean` skips it) |
34
+
35
+ Other behavior changes:
36
+
37
+ - **Node 20 is no longer supported for running builds**: `engines.node` is
38
+ `^22.18.0 || >=24.11.0` (tsdown's requirement). The published output is unaffected.
39
+ - **Shared chunks are content-hashed** (`_chunks-[format]` folders are gone), so a chunk can
40
+ never take an entry's filename ([sanity-io/ui#2262](https://github.com/sanity-io/ui/issues/2262)).
41
+ - **`pkg check` runs [publint](https://publint.dev)** on the packed package (with
42
+ `publishConfig` applied) instead of the esbuild resolution checks. Fix what it reports — it
43
+ lints what consumers actually install.
44
+ - **Local builds keep `exports` in sync**: the map is regenerated from the build (with the
45
+ `source`-condition development pattern and a `source`-less `publishConfig.exports`); CI uses
46
+ the committed `package.json` as-is.
47
+ - `tsdown.config.*` files are **never** loaded by `pkg build` — `package.config.ts` is the only
48
+ config source. For customization beyond the config surface, use `tsdown` +
49
+ `@sanity/tsdown-config` directly.
50
+
51
+ ## `PKG_FORMAT` and `PKG_RUNTIME`
52
+
53
+ The `process.env.PKG_FORMAT` and `process.env.PKG_RUNTIME` build-time constants are gone
54
+ (`process.env.PKG_VERSION` remains). Use
55
+ [conditional `package.json#imports`](https://nodejs.org/api/packages.html#imports) instead —
56
+ they express the same thing with more precision, and conditions compose (`require` vs `import`,
57
+ `node`/`browser`/`worker`, `deno`/`bun`, `react-server`, …).
58
+
59
+ ### Per-platform code, resolved at build time (replaces `PKG_RUNTIME`)
60
+
61
+ Give each platform its own file; every build of the waterfall inlines the matching condition
62
+ (the `browser`/`node` variant builds pick their files, everything else gets `default`):
63
+
64
+ ```json
65
+ {
66
+ "imports": {
67
+ "#env": {
68
+ "browser": "./src/env.browser.ts",
69
+ "node": "./src/env.node.ts",
70
+ "default": "./src/env.default.ts"
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ```ts
77
+ // src/index.ts
78
+ export {env} from '#env'
79
+ ```
80
+
81
+ ### Per-format (or per-runtime) code, resolved at load time (replaces `PKG_FORMAT`)
82
+
83
+ Bundled code can't branch per output format at build time — one module graph feeds both
84
+ formats. Point the import map at two small **shipped** files and keep the specifier external,
85
+ so Node (and consumers' bundlers) resolve it when the package loads:
86
+
87
+ ```json
88
+ {
89
+ "imports": {
90
+ "#format": {
91
+ "require": "./format.cjs",
92
+ "default": "./format.mjs"
93
+ }
94
+ },
95
+ "files": ["dist", "format.cjs", "format.mjs"]
96
+ }
97
+ ```
98
+
99
+ ```ts
100
+ // package.config.ts — keep `#…` specifiers external
101
+ export default defineConfig({
102
+ deps: {neverBundle: [/^#/]},
103
+ })
104
+ ```
105
+
106
+ ## `PKG_FILE_PATH`
107
+
108
+ Use `import.meta.url` — it works in both output formats (the CJS output rewrites it to
109
+ `require("url").pathToFileURL(__filename).href`):
110
+
111
+ ```ts
112
+ import {fileURLToPath} from 'node:url'
113
+
114
+ const filePath = fileURLToPath(import.meta.url)
115
+ ```
116
+
117
+ ## Custom Babel plugins
118
+
119
+ Install [`@rolldown/plugin-babel`](https://www.npmjs.com/package/@rolldown/plugin-babel) in
120
+ your package and pass it through `plugins`:
121
+
122
+ ```ts
123
+ import pluginBabel from '@rolldown/plugin-babel'
124
+ import {defineConfig} from '@sanity/pkg-utils'
125
+
126
+ export default defineConfig({
127
+ plugins: [await pluginBabel({plugins: ['babel-plugin-example']})],
128
+ })
129
+ ```
130
+
131
+ (`styledComponents` no longer needs Babel at all — it uses oxc's native port, so
132
+ `babel-plugin-styled-components` can be uninstalled.)
133
+
134
+ ## Type inlining
135
+
136
+ Type inlining follows the bundling decisions now:
137
+
138
+ - imported `devDependencies` are inlined automatically (JS **and** types),
139
+ - `deps: {alwaysBundle: [...]}` force-inlines a `dependency`/`peerDependency` (JS **and** types).
140
+
141
+ Inlining only the _types_ of an external dependency (the v11 `extract.bundledPackages` pattern)
142
+ has no successor.
143
+
144
+ Note tsdown's matching semantics: strings match exactly (or as globs), so covering subpath
145
+ imports takes a pattern like `/^@scope\/name(\/|$)/`.
146
+
147
+ ## lodash
148
+
149
+ The lodash import optimization is gone, including the implicit auto-enable when `lodash` was a
150
+ dependency. Preferably drop lodash altogether (see [e18e.dev](https://e18e.dev) for
151
+ replacements like [`es-toolkit`](https://es-toolkit.dev)), or import from `lodash-es`, which
152
+ tree-shakes in consumers without build-time rewriting.
package/README.md CHANGED
@@ -28,6 +28,24 @@ pkg-utils watch
28
28
 
29
29
  Run `pkg-utils -h` for more information on CLI usage.
30
30
 
31
+ ## How it works
32
+
33
+ Since v12, `@sanity/pkg-utils` composes [`tsdown`](https://tsdown.dev) and
34
+ [`@sanity/tsdown-config`](https://github.com/sanity-io/pkg-utils/tree/main/packages/@sanity/tsdown-config#readme):
35
+ the hand-written `exports` map in `package.json` stays the input that decides what gets built, and
36
+ for every platform (the default build, plus one extra build per `browser`/`node` exports condition)
37
+ pkg-utils resolves a config from `@sanity/tsdown-config`, layers its own opinions over it
38
+ (browserslist-driven syntax targets, build-time constants, exports reconciliation), and runs
39
+ tsdown's programmatic `build()`.
40
+
41
+ `tsdown.config.*` files are never loaded — `package.config.ts` is the only configuration source of
42
+ `pkg build`. For customizations beyond the options below, use `tsdown` +
43
+ `@sanity/tsdown-config` directly instead.
44
+
45
+ During local builds the `exports` map is regenerated from the build (with `source` conditions for
46
+ development, and a `source`-less `publishConfig.exports` for publishing) and kept in sync; in CI
47
+ the committed `package.json` is used as-is.
48
+
31
49
  ## Configuration
32
50
 
33
51
  `@sanity/pkg-utils` reads most of its configuration from `package.json`. But sometimes you need more
@@ -40,7 +58,7 @@ control. You may then add a configuration file named `package.config.ts` (or `.m
40
58
  import {defineConfig} from '@sanity/pkg-utils'
41
59
 
42
60
  export default defineConfig({
43
- extract: {
61
+ tsdoc: {
44
62
  rules: {
45
63
  // do not require internal members to be prefixed with `_`
46
64
  'ae-internal-missing-underscore': 'off',
@@ -62,12 +80,35 @@ export default defineConfig({
62
80
  An array of entry points to bundle. This is useful if you want to bundle something that should not
63
81
  be exported by the package, e.g. CLI scripts or Node.js workers.
64
82
 
83
+ #### `clean`
84
+
85
+ - Type: `boolean | string[]`
86
+ - Default: `true`
87
+
88
+ tsdown's [`clean` option](https://tsdown.dev/options/cleaning), passed through as-is. Cleaning is
89
+ on by default: `true` cleans the `dist` folder before the build, `false` skips cleaning, and a
90
+ `string[]` replaces the default with the listed paths/globs — include `dist` when you still want it
91
+ cleaned alongside other folders (e.g. `clean: ['dist', 'coverage']` replaces a
92
+ `"clean": "rimraf dist coverage"` script). `pkg build --no-clean` skips cleaning for a single run.
93
+
65
94
  #### `define`
66
95
 
67
96
  - Type: `Record<string, string | number | boolean | null | undefined>`
68
97
  - Default: `{}`
69
98
 
70
- An object defining globals within the package.
99
+ An object defining globals within the package. `process.env.PKG_VERSION` is always defined,
100
+ replaced with the package's `version` (overridable with a `PKG_VERSION` environment variable).
101
+
102
+ #### `deps`
103
+
104
+ - Type: `UserConfig['deps']`
105
+ - Default: `undefined`
106
+
107
+ tsdown's [`deps` option](https://tsdown.dev/options/dependencies), passed through as-is:
108
+ `neverBundle` marks dependencies as external, `alwaysBundle` forces a dependency to be inlined
109
+ (types included — type inlining follows the bundling decisions). Note tsdown's matching semantics:
110
+ strings match exactly (or as globs), so covering subpath imports takes a pattern like
111
+ `/^@scope\/name(\/|$)/`.
71
112
 
72
113
  #### `dist`
73
114
 
@@ -76,78 +117,56 @@ An object defining globals within the package.
76
117
 
77
118
  The path to the directory to which bundle and chunk files should be written.
78
119
 
79
- #### `exports`
120
+ #### `dts`
80
121
 
81
- - Type: `PkgConfigProperty<PkgExports>`
82
- - Default: the value of `"exports"` in `package.json`
83
-
84
- Override or modify the value of the `exports` before it’s parsed internally.
85
-
86
- #### `extract`
87
-
88
- - Type:
89
- ```ts
90
- {
91
- rules?: {
92
- 'ae-incompatible-release-tags'?: PkgRuleLevel
93
- 'ae-internal-missing-underscore'?: PkgRuleLevel
94
- 'ae-missing-release-tag'?: PkgRuleLevel
95
- }
96
- }
97
- ```
122
+ - Type: `false | DtsOptions`
98
123
  - Default: `undefined`
99
124
 
100
- Configure the level of reporting of [API Extractor](https://api-extractor.com/) (which is used to bundle the
101
- type definitions, as well as lint the TSDoc of the package).
102
-
103
- #### `external`
104
-
105
- - Type: `string[]`
106
- - Default: `[]`
107
-
108
- Packages to exclude from bundles.
109
-
110
- #### `jsx`
111
-
112
- - Type: `'transform' | 'preserve' | 'automatic'`
113
- - Default: `'automatic'`
114
-
115
- Strategy for bundling JSX.
116
-
117
- #### `jsxFactory`
118
-
119
- - Type: `string`
120
- - Default: `'createElement'`
121
-
122
- The name of the function that creates JSX elements.
125
+ tsdown's [`dts` options](https://tsdown.dev/options/dts), passed through as-is (an object, or
126
+ `false` to skip generating `.d.ts` files entirely). For example `dts: {tsgo: true}` selects the
127
+ Go-native TypeScript compiler for type generation.
123
128
 
124
- #### `jsxFragment`
129
+ #### `exports`
125
130
 
126
- - Type: `string`
127
- - Default: `'Fragment'`
131
+ - Type: `PkgConfigProperty<PkgExports>`
132
+ - Default: the value of `"exports"` in `package.json`
128
133
 
129
- The name of JSX fragment elements.
134
+ Override or modify the value of the `exports` before it’s parsed internally.
130
135
 
131
- #### `jsxImportSource`
136
+ #### `legacyChecks`
132
137
 
133
- - Type: `string`
134
- - Default: `'react'`
138
+ - Type: `boolean`
139
+ - Default: `process.env.NODE_ENV !== 'production'`
135
140
 
136
- The name of the library from which to import JSX factory and fragment names.
141
+ Gates the migration checks for options that were removed or deprecated in v12 (they throw helpful
142
+ errors with migration instructions). On by default outside production builds, where migration
143
+ mistakes surface during development; skipped when `NODE_ENV=production`.
137
144
 
138
145
  #### `minify`
139
146
 
140
147
  - Type: `boolean`
141
148
  - Default: `false`
142
149
 
143
- Whether to minify the bundled JavaScript.
150
+ Whether to fully minify the bundled JavaScript (identifier mangling and whitespace removal
151
+ included). The output is always compressed (constant folding, dead code elimination) with
152
+ function/class names preserved.
144
153
 
145
- #### `rollup.plugins`
154
+ #### `plugins`
146
155
 
147
- - Type: `PkgConfigProperty<RollupPlugin[]>`
156
+ - Type: `UserConfig['plugins']`
148
157
  - Default: `[]`
149
158
 
150
- Rollup plugins to load when bundling.
159
+ Extra [rolldown plugins](https://tsdown.dev/advanced/plugins), appended after the plugins
160
+ pkg-utils sets up. Most Rollup plugins are also compatible.
161
+
162
+ #### `reactCompiler`
163
+
164
+ - Type: `boolean | ReactCompilerOptions`
165
+ - Default: `false`
166
+
167
+ Runs `babel-plugin-react-compiler` (which must be installed) on the source files before they are
168
+ bundled, so published components are memoized automatically. Pass `true` for the defaults, or an
169
+ options object to configure the compiler (e.g. `{target: '18'}`).
151
170
 
152
171
  #### `runtime`
153
172
 
@@ -170,6 +189,14 @@ Whether to include source map files.
170
189
 
171
190
  The path to the directory in which source code is located.
172
191
 
192
+ #### `styledComponents`
193
+
194
+ - Type: `boolean | StyledComponentsOptions`
195
+ - Default: `false`
196
+
197
+ Applies the `styled-components` transform (`displayName`, `componentId`, CSS minification, etc)
198
+ using oxc's native port of `babel-plugin-styled-components` — no Babel dependencies required.
199
+
173
200
  #### `tsconfig`
174
201
 
175
202
  - Type: `string`
@@ -177,6 +204,34 @@ The path to the directory in which source code is located.
177
204
 
178
205
  The path to the TypeScript configuration file.
179
206
 
207
+ #### `tsdoc`
208
+
209
+ - Type: `false | {customTags?: TSDocCustomTag[]; rules?: {...}}`
210
+ - Default: `undefined` (enabled)
211
+
212
+ Runs [API Extractor](https://api-extractor.com/) during `pkg check` to check that TSDoc tags are
213
+ valid and release tags are correct. Set `tsdoc: false` to disable it.
214
+
215
+ #### `vanillaExtract`
216
+
217
+ - Type: `boolean | PackageVanillaExtractOptions`
218
+ - Default: `false`
219
+
220
+ Extracts the CSS from [vanilla-extract](https://vanilla-extract.style) `.css.ts` files into
221
+ `dist/bundle.css` (minified and lowered with `lightningcss`), injects the self-referential
222
+ `import "<pkg>/bundle.css"`, emits a no-op `bundle-css.js` shim for runtimes that cannot import
223
+ `.css` files, and writes the conditional `"./bundle.css"` export to `package.json`.
224
+
225
+ ## Migrating to v12
226
+
227
+ v12 replaced the rollup/rolldown build stack with `tsdown` + `@sanity/tsdown-config`. Most
228
+ packages need no changes; removed options throw an error with migration instructions when set
229
+ (gated by [`legacyChecks`](#legacychecks)), and deprecated options keep working with a warning.
230
+
231
+ See [MIGRATE.md](./MIGRATE.md) for the full guide — including how
232
+ [conditional `package.json#imports`](https://nodejs.org/api/packages.html#imports) replace the
233
+ removed `PKG_FORMAT`/`PKG_RUNTIME` constants, and `import.meta.url` replaces `PKG_FILE_PATH`.
234
+
180
235
  ## License
181
236
 
182
237
  MIT
@@ -0,0 +1,146 @@
1
+ import { n as createLogger, r as isRecord, t as handleError } from "./handleError-83GwKIFM.js";
2
+ import { a as loadPkgWithReporting, o as loadConfig, t as resolveBuildContext } from "./resolveBuildContext-CwqbTV6p.js";
3
+ import { t as createSpinner } from "./spinner-DAHe7SuT.js";
4
+ import { n as resolveTsdownBuilds, t as resolveTsdownConfig } from "./resolveTsdownConfig-2OdGF-dM.js";
5
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
6
+ import path from "node:path";
7
+ import { up } from "empathic/package";
8
+ import { build } from "tsdown";
9
+ const RE_TS_SOURCE = /\.[cm]?tsx?$/;
10
+ /**
11
+ * Build the distribution files of a npm package.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import {build} from '@sanity/pkg-utils'
16
+ *
17
+ * build({
18
+ * cwd: process.cwd(),
19
+ * tsconfig: 'tsconfig.dist.json,
20
+ * }).then(() => {
21
+ * console.log('successfully built')
22
+ * }).catch((err) => {
23
+ * console.log(`build error: ${err.message}`)
24
+ * })
25
+ * ```
26
+ *
27
+ * @public
28
+ */
29
+ async function build$1(options) {
30
+ let { cwd, emitDeclarationOnly, strict = !1, tsconfig: tsconfigOption, clean = !0, quiet = !1 } = options, logger = createLogger(quiet), pkgPath = up({ cwd });
31
+ if (!pkgPath) throw Error("no package.json found", { cause: { cwd } });
32
+ let config = await loadConfig({
33
+ cwd,
34
+ pkgPath
35
+ }), { parseStrictOptions } = await import("./resolveBuildContext-CwqbTV6p.js").then((n) => n.n), ctx = await resolveBuildContext({
36
+ config,
37
+ cwd,
38
+ emitDeclarationOnly,
39
+ logger,
40
+ pkg: await loadPkgWithReporting({
41
+ pkgPath,
42
+ logger,
43
+ strict,
44
+ strictOptions: parseStrictOptions(config?.strictOptions ?? {})
45
+ }),
46
+ strict,
47
+ tsconfig: tsconfigOption || config?.tsconfig || "tsconfig.json"
48
+ });
49
+ warnAboutTsdownConfigFiles(cwd, logger);
50
+ let builds = resolveTsdownBuilds(ctx), first = !0;
51
+ for (let buildDef of builds) {
52
+ if (ctx.emitDeclarationOnly && !buildDef.entries.some((entry) => RE_TS_SOURCE.test(entry.source))) continue;
53
+ let spinner = createSpinner(buildTaskName(buildDef), quiet);
54
+ try {
55
+ let inlineConfig = await resolveTsdownConfig(ctx, buildDef, { clean: first && clean });
56
+ first = !1;
57
+ let bundles = await build(inlineConfig);
58
+ ctx.emitDeclarationOnly && removeNonDeclarationOutputs(bundles), buildDef.canonical && restoreAuthoredTypes(ctx), spinner.complete(), ctx.logger.log(), printBuildOutputs(ctx, bundles), ctx.logger.log();
59
+ } catch (err) {
60
+ if (spinner.error(), err instanceof Error) {
61
+ let RE_CWD = new RegExp(escapeRegExp(cwd), "g");
62
+ ctx.logger.error((err.stack || err.message).replace(RE_CWD, ".")), ctx.logger.log();
63
+ }
64
+ process.exit(1);
65
+ }
66
+ }
67
+ }
68
+ function buildTaskName(buildDef) {
69
+ let formats = Array.from(new Set(buildDef.entries.flatMap((entry) => entry.formats)));
70
+ return `build ${buildDef.key} (${formats.join(", ") || "types"})`;
71
+ }
72
+ const RE_DTS_OUTPUT = /\.d\.[mc]?ts(\.map)?$/;
73
+ /** Removes every emitted file that is not a declaration file (or its sourcemap). */
74
+ function removeNonDeclarationOutputs(bundles) {
75
+ for (let bundle of bundles) for (let chunk of bundle.chunks) RE_DTS_OUTPUT.test(chunk.fileName) || (rmSync(path.join(chunk.outDir, chunk.fileName), { force: !0 }), rmSync(path.join(chunk.outDir, `${chunk.fileName}.map`), { force: !0 }));
76
+ }
77
+ /**
78
+ * Prints `<pkg>: <source> → <output>` for every entry chunk (JS and `.d.ts`) that tsdown
79
+ * emitted, mirroring the per-file output of previous majors.
80
+ */
81
+ function printBuildOutputs(ctx, bundles) {
82
+ let { cwd, logger, pkg } = ctx, lines = /* @__PURE__ */ new Set();
83
+ for (let bundle of bundles) for (let chunk of bundle.chunks) {
84
+ if (chunk.type !== "chunk" || !chunk.isEntry || !chunk.facadeModuleId || ctx.emitDeclarationOnly && !RE_DTS_OUTPUT.test(chunk.fileName)) continue;
85
+ let source = `./${path.relative(cwd, chunk.facadeModuleId).replaceAll("\\", "/").replace(/\.d\.([mc]?)ts$/, ".$1ts")}`, output = `./${path.relative(cwd, path.join(chunk.outDir, chunk.fileName)).replaceAll("\\", "/")}`;
86
+ lines.add(`${pkg.name}: ${source} \u2192 ${output}`);
87
+ }
88
+ for (let line of Array.from(lines).toSorted()) logger.log(line);
89
+ }
90
+ /**
91
+ * tsdown's exports generation rewrites the top-level `types` field alongside `main`/`module`
92
+ * when the `legacy` fields are maintained, preferring the CJS declarations (`.d.cts`) for
93
+ * dual-format packages. The hand-written value is authoritative here (the Sanity convention
94
+ * points `types` at the ESM `.d.ts`), so it is restored after the canonical build.
95
+ */
96
+ function restoreAuthoredTypes(ctx) {
97
+ let authoredTypes = ctx.pkg.types;
98
+ if (!authoredTypes) return;
99
+ let pkgPath = path.resolve(ctx.cwd, "package.json"), text;
100
+ try {
101
+ text = readFileSync(pkgPath, "utf8");
102
+ } catch {
103
+ return;
104
+ }
105
+ let json = JSON.parse(text);
106
+ if (!isRecord(json) || json.types === authoredTypes) return;
107
+ json.types = authoredTypes;
108
+ let indent = /^([ \t]+)\S/m.exec(text)?.[1] ?? 2, output = JSON.stringify(json, null, indent);
109
+ text.endsWith("\n") && (output += "\n"), writeFileSync(pkgPath, output, "utf8");
110
+ }
111
+ /**
112
+ * pkg-utils owns its own experience: `tsdown.config.*` files are never loaded in pkg-utils
113
+ * mode (`package.config.ts` is the sole config source), so their presence is worth a warning.
114
+ */
115
+ function warnAboutTsdownConfigFiles(cwd, logger) {
116
+ let found = [
117
+ "tsdown.config.ts",
118
+ "tsdown.config.mts",
119
+ "tsdown.config.cts",
120
+ "tsdown.config.js",
121
+ "tsdown.config.mjs",
122
+ "tsdown.config.cjs",
123
+ "tsdown.config.json"
124
+ ].find((candidate) => existsSync(path.resolve(cwd, candidate)));
125
+ found && logger.warn(`found \`${found}\`, which @sanity/pkg-utils does not load — \`package.config.ts\` is the only config source of \`pkg build\`. Either migrate the package fully to tsdown (and drop @sanity/pkg-utils), or move the configuration into \`package.config.ts\`.`);
126
+ }
127
+ function escapeRegExp(value) {
128
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
129
+ }
130
+ async function buildAction(options) {
131
+ try {
132
+ await build$1({
133
+ cwd: process.cwd(),
134
+ emitDeclarationOnly: options.emitDeclarationOnly,
135
+ strict: options.strict,
136
+ tsconfig: options.tsconfig,
137
+ clean: options.clean,
138
+ quiet: options.quiet
139
+ });
140
+ } catch (err) {
141
+ handleError(err);
142
+ }
143
+ }
144
+ export { buildAction };
145
+
146
+ //# sourceMappingURL=buildAction-DFrmHzYY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildAction-DFrmHzYY.js","names":["build","findPkgPath","tsdownBuild","build"],"sources":["../src/node/build.ts","../src/cli/buildAction.ts"],"sourcesContent":["import {existsSync, readFileSync, rmSync, writeFileSync} from 'node:fs'\nimport path from 'node:path'\nimport {up as findPkgPath} from 'empathic/package'\nimport {build as tsdownBuild, type TsdownBundle} from 'tsdown'\nimport {loadConfig} from './core/config/loadConfig.ts'\nimport {isRecord} from './core/isRecord.ts'\nimport {loadPkgWithReporting} from './core/pkg/loadPkgWithReporting.ts'\nimport {createLogger, type Logger} from './logger.ts'\nimport {resolveBuildContext} from './resolveBuildContext.ts'\nimport {createSpinner} from './spinner.ts'\nimport {\n resolveTsdownBuilds,\n type TsdownBuild as TsdownBuildDef,\n} from './tasks/tsdown/resolveTsdownBuilds.ts'\nimport {resolveTsdownConfig} from './tasks/tsdown/resolveTsdownConfig.ts'\n\nconst RE_TS_SOURCE = /\\.[cm]?tsx?$/\n\n/**\n * Build the distribution files of a npm package.\n *\n * @example\n * ```ts\n * import {build} from '@sanity/pkg-utils'\n *\n * build({\n * cwd: process.cwd(),\n * tsconfig: 'tsconfig.dist.json,\n * }).then(() => {\n * console.log('successfully built')\n * }).catch((err) => {\n * console.log(`build error: ${err.message}`)\n * })\n * ```\n *\n * @public\n */\nexport async function build(options: {\n cwd: string\n emitDeclarationOnly?: boolean\n strict?: boolean\n tsconfig?: string\n clean?: boolean\n quiet?: boolean\n}): Promise<void> {\n const {\n cwd,\n emitDeclarationOnly,\n strict = false,\n tsconfig: tsconfigOption,\n // `--no-clean` skips cleaning for this run; `true` (the CLI default — `--clean` still\n // parses as a no-op for v11 compatibility) defers to the `clean` config option\n clean = true,\n quiet = false,\n } = options\n const logger = createLogger(quiet)\n\n const pkgPath = findPkgPath({cwd})\n if (!pkgPath) {\n throw new Error('no package.json found', {cause: {cwd}})\n }\n const config = await loadConfig({cwd, pkgPath})\n\n const {parseStrictOptions} = await import('./strict.ts')\n const strictOptions = parseStrictOptions(config?.strictOptions ?? {})\n const pkg = await loadPkgWithReporting({pkgPath, logger, strict, strictOptions})\n\n const tsconfig = tsconfigOption || config?.tsconfig || 'tsconfig.json'\n\n const ctx = await resolveBuildContext({\n config,\n cwd,\n emitDeclarationOnly,\n logger,\n pkg,\n strict,\n tsconfig,\n })\n\n warnAboutTsdownConfigFiles(cwd, logger)\n\n const builds = resolveTsdownBuilds(ctx)\n\n let first = true\n for (const buildDef of builds) {\n // A types-only run skips builds without TypeScript sources entirely\n if (\n ctx.emitDeclarationOnly &&\n !buildDef.entries.some((entry) => RE_TS_SOURCE.test(entry.source))\n ) {\n continue\n }\n\n const taskName = buildTaskName(buildDef)\n const spinner = createSpinner(taskName, quiet)\n\n try {\n const inlineConfig = await resolveTsdownConfig(ctx, buildDef, {clean: first && clean})\n first = false\n\n const bundles = await tsdownBuild(inlineConfig)\n\n if (ctx.emitDeclarationOnly) {\n // `dts.emitDtsOnly` suppresses the JS chunks of the ES pass, but the CJS pass emits\n // its JS regardless (only its extra dts pass runs the dts plugin) — a types-only\n // build removes everything that is not a declaration file\n removeNonDeclarationOutputs(bundles)\n }\n\n if (buildDef.canonical) {\n restoreAuthoredTypes(ctx)\n }\n\n spinner.complete()\n ctx.logger.log()\n\n printBuildOutputs(ctx, bundles)\n ctx.logger.log()\n } catch (err) {\n spinner.error()\n\n if (err instanceof Error) {\n const RE_CWD = new RegExp(escapeRegExp(cwd), 'g')\n\n ctx.logger.error((err.stack || err.message).replace(RE_CWD, '.'))\n ctx.logger.log()\n }\n\n process.exit(1)\n }\n }\n}\n\nfunction buildTaskName(buildDef: TsdownBuildDef): string {\n const formats = Array.from(new Set(buildDef.entries.flatMap((entry) => entry.formats)))\n return `build ${buildDef.key} (${formats.join(', ') || 'types'})`\n}\n\nconst RE_DTS_OUTPUT = /\\.d\\.[mc]?ts(\\.map)?$/\n\n/** Removes every emitted file that is not a declaration file (or its sourcemap). */\nfunction removeNonDeclarationOutputs(bundles: TsdownBundle[]): void {\n for (const bundle of bundles) {\n for (const chunk of bundle.chunks) {\n if (RE_DTS_OUTPUT.test(chunk.fileName)) continue\n rmSync(path.join(chunk.outDir, chunk.fileName), {force: true})\n rmSync(path.join(chunk.outDir, `${chunk.fileName}.map`), {force: true})\n }\n }\n}\n\n/**\n * Prints `<pkg>: <source> → <output>` for every entry chunk (JS and `.d.ts`) that tsdown\n * emitted, mirroring the per-file output of previous majors.\n */\nfunction printBuildOutputs(\n ctx: {cwd: string; emitDeclarationOnly: boolean; logger: Logger; pkg: {name: string}},\n bundles: TsdownBundle[],\n): void {\n const {cwd, logger, pkg} = ctx\n const lines = new Set<string>()\n\n for (const bundle of bundles) {\n for (const chunk of bundle.chunks) {\n if (chunk.type !== 'chunk' || !chunk.isEntry || !chunk.facadeModuleId) continue\n if (ctx.emitDeclarationOnly && !RE_DTS_OUTPUT.test(chunk.fileName)) continue\n const source = `./${path\n .relative(cwd, chunk.facadeModuleId)\n .replaceAll('\\\\', '/')\n // the dts chunks facade the fake `.d.ts` module ids of rolldown-plugin-dts; print the\n // actual `.ts` source instead\n .replace(/\\.d\\.([mc]?)ts$/, '.$1ts')}`\n const output = `./${path\n .relative(cwd, path.join(chunk.outDir, chunk.fileName))\n .replaceAll('\\\\', '/')}`\n lines.add(`${pkg.name}: ${source} \\u2192 ${output}`)\n }\n }\n\n for (const line of Array.from(lines).toSorted()) {\n logger.log(line)\n }\n}\n\n/**\n * tsdown's exports generation rewrites the top-level `types` field alongside `main`/`module`\n * when the `legacy` fields are maintained, preferring the CJS declarations (`.d.cts`) for\n * dual-format packages. The hand-written value is authoritative here (the Sanity convention\n * points `types` at the ESM `.d.ts`), so it is restored after the canonical build.\n */\nfunction restoreAuthoredTypes(ctx: {cwd: string; pkg: {types?: string | undefined}}): void {\n const authoredTypes = ctx.pkg.types\n if (!authoredTypes) return\n\n const pkgPath = path.resolve(ctx.cwd, 'package.json')\n let text: string\n try {\n text = readFileSync(pkgPath, 'utf8')\n } catch {\n return\n }\n const json: unknown = JSON.parse(text)\n if (!isRecord(json) || json['types'] === authoredTypes) return\n json['types'] = authoredTypes\n\n const indent = /^([ \\t]+)\\S/m.exec(text)?.[1] ?? 2\n let output = JSON.stringify(json, null, indent)\n if (text.endsWith('\\n')) output += '\\n'\n writeFileSync(pkgPath, output, 'utf8')\n}\n\n/**\n * pkg-utils owns its own experience: `tsdown.config.*` files are never loaded in pkg-utils\n * mode (`package.config.ts` is the sole config source), so their presence is worth a warning.\n */\nfunction warnAboutTsdownConfigFiles(cwd: string, logger: Logger): void {\n const candidates = [\n 'tsdown.config.ts',\n 'tsdown.config.mts',\n 'tsdown.config.cts',\n 'tsdown.config.js',\n 'tsdown.config.mjs',\n 'tsdown.config.cjs',\n 'tsdown.config.json',\n ]\n const found = candidates.find((candidate) => existsSync(path.resolve(cwd, candidate)))\n if (found) {\n logger.warn(\n `found \\`${found}\\`, which @sanity/pkg-utils does not load — \\`package.config.ts\\` is the only config source of \\`pkg build\\`. Either migrate the package fully to tsdown (and drop @sanity/pkg-utils), or move the configuration into \\`package.config.ts\\`.`,\n )\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import {build} from '../node/build.ts'\nimport {handleError} from './handleError.ts'\n\nexport async function buildAction(options: {\n emitDeclarationOnly?: boolean\n strict?: boolean\n tsconfig?: string\n clean?: boolean\n quiet?: boolean\n}): Promise<void> {\n try {\n await build({\n cwd: process.cwd(),\n emitDeclarationOnly: options.emitDeclarationOnly,\n strict: options.strict,\n tsconfig: options.tsconfig,\n clean: options.clean,\n quiet: options.quiet,\n })\n } catch (err) {\n handleError(err)\n }\n}\n"],"mappings":"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"}