Skip to content

Commit dcc9323

Browse files
mttdntclaude
authored andcommitted
feat(create-sanity): bundle init logic into single file (#759)
Reapply PR #759 changes onto current main. Replaces the old create-sanity shim with a Rollup-bundled standalone entry point, extracts shared flag definitions, and decouples init from oclif. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 09a30e2 commit dcc9323

44 files changed

Lines changed: 2115 additions & 544 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/pr-759.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- auto-generated -->
2+
---
3+
'@sanity/cli-core': minor
4+
'@sanity/cli': minor
5+
'create-sanity': minor
6+
---
7+
8+
bundle `init` logic into single file

knip.config.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import {type KnipConfig} from 'knip'
33
const project = ['src/**/*.{js,jsx,ts,tsx}', '!**/docs/**']
44

55
const baseConfig = {
6-
// For now only care about cli package
7-
// Disabled: the changeset plugin can't resolve local file paths in the changelog config
8-
changesets: false,
96
ignore: [
7+
'packages/@sanity/cli-test/fixtures/**',
8+
109
// See `helpClass` in `oclif.config.js`
1110
'packages/@sanity/cli/src/SanityHelp.ts',
1211
// Loaded dynamically by @changesets/cli at version time
@@ -80,7 +79,9 @@ const baseConfig = {
8079
project,
8180
},
8281
'packages/create-sanity': {
83-
ignoreDependencies: ['@sanity/cli'],
82+
// @sanity/cli is imported via relative source paths (../../@sanity/cli/src/...)
83+
// for bundling, but the workspace link is still needed for resolution
84+
ignoreDependencies: ['@sanity/cli', 'rxjs'],
8485
},
8586
},
8687
} satisfies KnipConfig

packages/@sanity/cli-core/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
"source": "./src/_exports/index.ts",
3434
"default": "./dist/_exports/index.js"
3535
},
36+
"./errors": {
37+
"source": "./src/_exports/errors.ts",
38+
"default": "./dist/_exports/errors.js"
39+
},
3640
"./ux": {
3741
"source": "./src/_exports/ux.ts",
3842
"default": "./dist/_exports/ux.js"
@@ -69,6 +73,7 @@
6973
"@sanity/client": "catalog:",
7074
"babel-plugin-react-compiler": "^1.0.0",
7175
"boxen": "^8.0.1",
76+
"clean-stack": "^6.0.0",
7277
"debug": "catalog:",
7378
"get-it": "^8.7.0",
7479
"get-tsconfig": "catalog:",
@@ -82,6 +87,7 @@
8287
"tsx": "catalog:",
8388
"vite": "catalog:",
8489
"vite-node": "^5.3.0",
90+
"wrap-ansi": "^10.0.0",
8591
"zod": "catalog:"
8692
},
8793
"devDependencies": {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from '../errors/CLIError.js'
2+
export * from '../errors/CLIWarning.js'
3+
export * from '../errors/NonInteractiveError.js'
4+
export * from '../errors/NotFoundError.js'
5+
export * from '../errors/ProjectRootNotFoundError.js'

packages/@sanity/cli-core/src/_exports/index.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import {deprecate} from 'node:util'
2+
3+
import {NonInteractiveError as _NonInteractiveError} from '../errors/NonInteractiveError.js'
4+
import {NotFoundError as _NotFoundError} from '../errors/NotFoundError.js'
5+
import {ProjectRootNotFoundError as _ProjectRootNotFoundError} from '../errors/ProjectRootNotFoundError.js'
6+
17
export * from '../config/cli/getCliConfig.js'
28
export * from '../config/cli/getCliConfigSync.js'
39
export {type CliConfig} from '../config/cli/types/cliConfig.js'
@@ -11,9 +17,6 @@ export * from '../config/util/findConfigsPaths.js'
1117
export * from '../config/util/findStudioConfigPath.js'
1218
export {type ProjectRootResult} from '../config/util/recursivelyResolveProjectRoot.js'
1319
export * from '../debug.js'
14-
export * from '../errors/NonInteractiveError.js'
15-
export * from '../errors/NotFoundError.js'
16-
export * from '../errors/ProjectRootNotFoundError.js'
1720
export * from '../exitCodes.js'
1821
export * from '../loaders/studio/studioWorkerTask.js'
1922
export * from '../loaders/tsx/tsxWorkerTask.js'
@@ -50,3 +53,16 @@ export * from '../util/resolveLocalPackage.js'
5053
export * from '../util/safeStructuredClone.js'
5154
export * from '../ux/colorizeJson.js'
5255
export * from '../ux/timer.js'
56+
57+
export const NonInteractiveError = deprecate(
58+
_NonInteractiveError,
59+
'Import `NonInteractiveError` from `@sanity/cli-core/errors`',
60+
)
61+
export const NotFoundError = deprecate(
62+
_NotFoundError,
63+
'Import `NotFoundError` from `@sanity/cli-core/errors`',
64+
)
65+
export const ProjectRootNotFoundError = deprecate(
66+
_ProjectRootNotFoundError,
67+
'Import `ProjectRootNotFoundError` from `@sanity/cli-core/errors`',
68+
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export {NonInteractiveError} from '../errors/NonInteractiveError.js'
22
export * from '../ux/boxen.js'
3+
export * from '../ux/errors.js'
34
export * from '../ux/logSymbols.js'
5+
export * from '../ux/output.js'
46
export * from '../ux/prompts.js'
57
export * from '../ux/spinner.js'
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {styleText} from 'node:util'
2+
3+
import {type PrettyPrintableError} from '@oclif/core/interfaces'
4+
import cleanStack from 'clean-stack'
5+
6+
/**
7+
* A formatted CLI error that pretty-prints to stderr.
8+
*
9+
* This is a lightweight reimplementation of `@oclif/core`'s `CLIError`.
10+
* We can't import the original because `@oclif/core` is a CJS barrel that
11+
* pulls in the entire oclif runtime (~10MB) when bundled - defeating
12+
* tree-shaking in the standalone `create-sanity` bundle. By owning the
13+
* error class here, code in `@sanity/cli-core` and the init action tree
14+
* can throw formatted errors without depending on oclif at all.
15+
*
16+
* The `oclif` property is shaped so oclif's error handler still recognises
17+
* these errors when thrown inside an oclif command, preserving the correct
18+
* exit code and suppressing redundant stack traces.
19+
*/
20+
export class CLIError extends Error {
21+
code?: string
22+
oclif: {exit?: number} = {exit: 2}
23+
ref?: string
24+
skipOclifErrorHandling?: boolean
25+
suggestions?: string[]
26+
27+
constructor(error: Error | string, options: PrettyPrintableError & {exit?: false | number} = {}) {
28+
super(error instanceof Error ? error.message : error)
29+
if (error instanceof Error && error.stack) {
30+
this.stack = error.stack
31+
}
32+
if (options.exit !== undefined)
33+
this.oclif.exit = options.exit === false ? undefined : options.exit
34+
this.code = options.code
35+
this.suggestions = options.suggestions
36+
this.ref = options.ref
37+
}
38+
39+
get bang(): string | undefined {
40+
return styleText('red', process.platform === 'win32' ? '»' : '›')
41+
}
42+
43+
get prettyStack(): string {
44+
return cleanStack(super.stack!, {pretty: true})
45+
}
46+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {styleText} from 'node:util'
2+
3+
import {CLIError} from './CLIError.js'
4+
5+
/**
6+
* A warning-level CLI error. Identical to {@link CLIError} except the
7+
* bang prefix is yellow instead of red.
8+
*/
9+
export class CLIWarning extends CLIError {
10+
constructor(input: Error | string) {
11+
super(input instanceof Error ? input.message : input)
12+
this.name = 'Warning'
13+
}
14+
15+
override get bang(): string | undefined {
16+
return styleText('yellow', process.platform === 'win32' ? '»' : '›')
17+
}
18+
}

packages/@sanity/cli-core/src/errors/NonInteractiveError.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {CLIError} from '@oclif/core/errors'
1+
import {CLIError} from './CLIError.js'
22

33
/**
44
* Error thrown when a prompt is attempted in a non-interactive environment

packages/@sanity/cli-core/src/errors/ProjectRootNotFoundError.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import {CLIError} from '@oclif/core/errors'
2-
31
import {isRecord} from '../util/isRecord.js'
2+
import {CLIError} from './CLIError.js'
43

54
/**
65
* Error thrown when a project root directory cannot be found.

0 commit comments

Comments
 (0)