@sanity/cli 8.23.0 → 8.24.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.
- package/README.md +313 -0
- package/dist/actions/codemods/dashboard.js +136 -8
- package/dist/actions/codemods/dashboard.js.map +1 -1
- package/dist/actions/codemods/types.js.map +1 -1
- package/dist/actions/init/project/getOrCreateDataset.js +8 -5
- package/dist/actions/init/project/getOrCreateDataset.js.map +1 -1
- package/dist/actions/init/project/getOrCreateProject.js +7 -5
- package/dist/actions/init/project/getOrCreateProject.js.map +1 -1
- package/dist/actions/init/project/promptUserForOrganization.js +6 -4
- package/dist/actions/init/project/promptUserForOrganization.js.map +1 -1
- package/dist/commands/codemod.js +1 -0
- package/dist/commands/codemod.js.map +1 -1
- package/dist/util/searchChoices.js +52 -0
- package/dist/util/searchChoices.js.map +1 -0
- package/oclif.manifest.json +1673 -1673
- package/package.json +6 -6
- package/templates/shopify/.gitignore +0 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/init/project/getOrCreateDataset.ts"],"sourcesContent":["import {subdebug} from '@sanity/cli-core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/init/project/getOrCreateDataset.ts"],"sourcesContent":["import {subdebug} from '@sanity/cli-core'\nimport {search, Separator} from '@sanity/cli-core/ux'\n\nimport {promptForDatasetName} from '../../../prompts/promptForDatasetName.js'\nimport {promptForDefaultConfig} from '../../../prompts/promptForDefaultConfig.js'\nimport {listDatasets} from '../../../services/datasets.js'\nimport {getProjectFeatures} from '../../../services/getProjectFeatures.js'\nimport {searchChoices, searchTheme} from '../../../util/searchChoices.js'\nimport {createDataset} from '../../dataset/create.js'\nimport {type InitContext} from '../types.js'\n\nconst debug = subdebug('init')\n\nexport async function getOrCreateDataset(opts: {\n dataset?: string\n defaultConfig: boolean | undefined\n displayName: string\n output: InitContext['output']\n projectId: string\n showDefaultConfigPrompt: boolean\n unattended: boolean\n visibility?: string\n}): Promise<{\n datasetName: string\n userAction: 'create' | 'none' | 'select'\n}> {\n const {dataset, visibility} = opts\n let {defaultConfig} = opts\n\n if (dataset && opts.unattended) {\n return {datasetName: dataset, userAction: 'none'}\n }\n\n const [datasets, projectFeatures] = await Promise.all([\n listDatasets(opts.projectId),\n getProjectFeatures(opts.projectId),\n ])\n\n if (dataset) {\n debug('User has specified dataset through a flag (%s)', dataset)\n const existing = datasets.find((ds) => ds.name === dataset)\n if (!existing) {\n debug('Specified dataset not found, creating it')\n await createDataset({\n datasetName: dataset,\n forcePublic: defaultConfig,\n output: opts.output,\n projectFeatures,\n projectId: opts.projectId,\n visibility,\n })\n }\n\n return {datasetName: dataset, userAction: 'none'}\n }\n\n if (opts.unattended) {\n debug('Unattended mode without --dataset, defaulting to \"production\" dataset')\n const datasetName = 'production'\n const existing = datasets.find((ds) => ds.name === datasetName)\n if (!existing) {\n await createDataset({\n datasetName,\n forcePublic: visibility === undefined,\n isUnattended: true,\n output: opts.output,\n projectFeatures,\n projectId: opts.projectId,\n visibility,\n })\n }\n return {datasetName, userAction: existing ? 'none' : 'create'}\n }\n\n if (datasets.length === 0) {\n debug('No datasets found for project, prompting for name')\n if (opts.showDefaultConfigPrompt) {\n defaultConfig = await promptForDefaultConfig()\n }\n const name = defaultConfig\n ? 'production'\n : await promptForDatasetName({\n message: 'Name of your first dataset:',\n })\n await createDataset({\n datasetName: name,\n forcePublic: defaultConfig,\n output: opts.output,\n projectFeatures,\n projectId: opts.projectId,\n visibility,\n })\n return {datasetName: name, userAction: 'create'}\n }\n\n debug(`User has ${datasets.length} dataset(s) already, showing list of choices`)\n const datasetChoices = datasets.map((dataset) => ({name: dataset.name, value: dataset.name}))\n\n const selected = await search({\n message: 'Select dataset to use',\n source: searchChoices([\n {name: 'Create new dataset', value: 'new'},\n new Separator(),\n ...datasetChoices,\n ]),\n theme: searchTheme,\n })\n\n if (selected === 'new') {\n const existingDatasetNames = datasets.map((ds) => ds.name)\n debug('User wants to create a new dataset, prompting for name')\n if (opts.showDefaultConfigPrompt && !existingDatasetNames.includes('production')) {\n defaultConfig = await promptForDefaultConfig()\n }\n\n const newDatasetName = defaultConfig\n ? 'production'\n : await promptForDatasetName(\n {\n message: 'Dataset name:',\n },\n existingDatasetNames,\n )\n await createDataset({\n datasetName: newDatasetName,\n forcePublic: defaultConfig,\n output: opts.output,\n projectFeatures,\n projectId: opts.projectId,\n visibility,\n })\n return {datasetName: newDatasetName, userAction: 'create'}\n }\n\n debug(`Returning selected dataset (${selected})`)\n return {datasetName: selected, userAction: 'select'}\n}\n"],"names":["subdebug","search","Separator","promptForDatasetName","promptForDefaultConfig","listDatasets","getProjectFeatures","searchChoices","searchTheme","createDataset","debug","getOrCreateDataset","opts","dataset","visibility","defaultConfig","unattended","datasetName","userAction","datasets","projectFeatures","Promise","all","projectId","existing","find","ds","name","forcePublic","output","undefined","isUnattended","length","showDefaultConfigPrompt","message","datasetChoices","map","value","selected","source","theme","existingDatasetNames","includes","newDatasetName"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { subdebug } from '@sanity/cli-core';
|
|
2
|
-
import {
|
|
2
|
+
import { search, Separator } from '@sanity/cli-core/ux';
|
|
3
3
|
import { listOrganizations } from '../../../services/organizations.js';
|
|
4
4
|
import { listProjects } from '../../../services/projects.js';
|
|
5
|
+
import { searchChoices, searchTheme } from '../../../util/searchChoices.js';
|
|
5
6
|
import { hasProjectAttachGrant } from '../../organizations/hasProjectAttachGrant.js';
|
|
6
7
|
import { InitError } from '../initError.js';
|
|
7
8
|
import { promptForProjectCreation } from './promptForProjectCreation.js';
|
|
@@ -87,16 +88,17 @@ export async function getOrCreateProject({ coupon, newProject, organization, pla
|
|
|
87
88
|
name: `${project.displayName} (${project.id})`,
|
|
88
89
|
value: project.id
|
|
89
90
|
}));
|
|
90
|
-
const selected = await
|
|
91
|
-
|
|
91
|
+
const selected = await search({
|
|
92
|
+
message: 'Create a new project or select an existing one',
|
|
93
|
+
source: searchChoices([
|
|
92
94
|
{
|
|
93
95
|
name: 'Create new project',
|
|
94
96
|
value: 'new'
|
|
95
97
|
},
|
|
96
98
|
new Separator(),
|
|
97
99
|
...projectChoices
|
|
98
|
-
],
|
|
99
|
-
|
|
100
|
+
]),
|
|
101
|
+
theme: searchTheme
|
|
100
102
|
});
|
|
101
103
|
if (selected === 'new') {
|
|
102
104
|
debug('User wants to create a new project, prompting for name');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/init/project/getOrCreateProject.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug} from '@sanity/cli-core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/init/project/getOrCreateProject.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug} from '@sanity/cli-core'\nimport {search, Separator} from '@sanity/cli-core/ux'\n\nimport {listOrganizations, type ProjectOrganization} from '../../../services/organizations.js'\nimport {listProjects} from '../../../services/projects.js'\nimport {searchChoices, searchTheme} from '../../../util/searchChoices.js'\nimport {hasProjectAttachGrant} from '../../organizations/hasProjectAttachGrant.js'\nimport {InitError} from '../initError.js'\nimport {promptForProjectCreation} from './promptForProjectCreation.js'\n\nconst debug = subdebug('init')\n\nexport async function getOrCreateProject({\n coupon,\n newProject,\n organization,\n planId,\n project,\n unattended,\n user,\n}: {\n coupon?: string\n newProject: string | undefined\n organization: string | undefined\n planId: string | undefined\n project: string | undefined\n unattended: boolean\n user: SanityOrgUser\n}): Promise<{\n displayName: string\n isFirstProject: boolean\n organizationId?: string\n projectId: string\n userAction: 'create' | 'select'\n}> {\n const projectId = project || newProject\n let projects\n let organizations: ProjectOrganization[]\n\n // When a projectId is provided, organizations aren't needed for the fast path, so\n // skip that request entirely. Only fetch both in parallel when prompting is required.\n try {\n if (projectId) {\n projects = (await listProjects()).toSorted((a, b) => b.createdAt.localeCompare(a.createdAt))\n organizations = []\n } else {\n const [allProjects, allOrgs] = await Promise.all([listProjects(), listOrganizations()])\n projects = allProjects.toSorted((a, b) => b.createdAt.localeCompare(a.createdAt))\n organizations = allOrgs\n }\n } catch (err: unknown) {\n if (unattended && projectId) {\n return {\n displayName: 'Unknown project',\n isFirstProject: false,\n organizationId: organization,\n projectId,\n userAction: 'select',\n }\n }\n const message = err instanceof Error ? err.message : String(err)\n throw new InitError(`Failed to communicate with the Sanity API:\\n${message}`, 1)\n }\n\n if (projects.length === 0 && unattended) {\n throw new InitError('No projects found for current user', 1)\n }\n\n if (projectId) {\n // When called after createProjectFromName (--project-name flow), the new project\n // is expected to appear here since listProjects reads the same user's own projects.\n // If it doesn't, fail loudly rather than continuing with an \"Unknown project\" placeholder.\n const proj = projects.find((p) => p.id === projectId)\n if (!proj) {\n throw new InitError(\n `Given project ID (${projectId}) not found, or you do not have access to it`,\n 1,\n )\n }\n\n return {\n displayName: proj.displayName,\n isFirstProject: false,\n organizationId: proj.organizationId ?? undefined,\n projectId,\n userAction: 'select',\n }\n }\n\n if (organization) {\n const org =\n organizations.find((o) => o.id === organization) ||\n organizations.find((o) => o.slug === organization)\n\n if (!org) {\n throw new InitError(\n `Given organization ID (${organization}) not found, or you do not have access to it`,\n 1,\n )\n }\n\n if (!(await hasProjectAttachGrant(organization))) {\n throw new InitError(\n 'You lack the necessary permissions to attach a project to this organization',\n 1,\n )\n }\n }\n\n const isUsersFirstProject = projects.length === 0\n if (isUsersFirstProject || coupon) {\n debug(\n isUsersFirstProject\n ? 'No projects found for user, prompting for name'\n : 'Using a coupon - skipping project selection',\n )\n\n const created = await promptForProjectCreation({\n coupon,\n isUsersFirstProject,\n organizationId: organization,\n organizations,\n planId,\n user,\n })\n\n return {\n ...created,\n isFirstProject: isUsersFirstProject,\n userAction: 'create',\n }\n }\n\n debug(`User has ${projects.length} project(s) already, showing list of choices`)\n\n const projectChoices = projects.map((project) => ({\n name: `${project.displayName} (${project.id})`,\n value: project.id,\n }))\n\n const selected = await search({\n message: 'Create a new project or select an existing one',\n source: searchChoices([\n {name: 'Create new project', value: 'new'},\n new Separator(),\n ...projectChoices,\n ]),\n theme: searchTheme,\n })\n\n if (selected === 'new') {\n debug('User wants to create a new project, prompting for name')\n\n const created = await promptForProjectCreation({\n coupon,\n isUsersFirstProject,\n organizationId: organization,\n organizations,\n planId,\n user,\n })\n\n return {\n ...created,\n isFirstProject: isUsersFirstProject,\n userAction: 'create',\n }\n }\n\n debug(`Returning selected project (${selected})`)\n const selectedProject = projects.find((proj) => proj.id === selected)\n return {\n displayName: selectedProject?.displayName || '',\n isFirstProject: isUsersFirstProject,\n organizationId: selectedProject?.organizationId ?? undefined,\n projectId: selected,\n userAction: 'select',\n }\n}\n"],"names":["subdebug","search","Separator","listOrganizations","listProjects","searchChoices","searchTheme","hasProjectAttachGrant","InitError","promptForProjectCreation","debug","getOrCreateProject","coupon","newProject","organization","planId","project","unattended","user","projectId","projects","organizations","toSorted","a","b","createdAt","localeCompare","allProjects","allOrgs","Promise","all","err","displayName","isFirstProject","organizationId","userAction","message","Error","String","length","proj","find","p","id","undefined","org","o","slug","isUsersFirstProject","created","projectChoices","map","name","value","selected","source","theme","selectedProject"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { subdebug } from '@sanity/cli-core';
|
|
2
|
-
import {
|
|
2
|
+
import { search } from '@sanity/cli-core/ux';
|
|
3
|
+
import { searchChoices, searchTheme } from '../../../util/searchChoices.js';
|
|
3
4
|
import { findOrganizationByUserName } from '../../organizations/findOrganizationByUserName.js';
|
|
4
5
|
import { getOrganizationChoices } from '../../organizations/getOrganizationChoices.js';
|
|
5
6
|
import { getOrganizationsWithAttachGrantInfo } from '../../organizations/getOrganizationsWithAttachGrantInfo.js';
|
|
@@ -23,10 +24,11 @@ export async function promptUserForOrganization({ isAppTemplate = false, organiz
|
|
|
23
24
|
organizationChoices = getOrganizationChoices(withGrantInfo);
|
|
24
25
|
defaultOrganizationId = withAttach.length === 1 ? withAttach[0].organization.id : findOrganizationByUserName(organizations, user);
|
|
25
26
|
}
|
|
26
|
-
const chosenOrg = await
|
|
27
|
-
choices: organizationChoices,
|
|
27
|
+
const chosenOrg = await search({
|
|
28
28
|
default: defaultOrganizationId || undefined,
|
|
29
|
-
message: 'Select organization:'
|
|
29
|
+
message: 'Select organization:',
|
|
30
|
+
source: searchChoices(organizationChoices),
|
|
31
|
+
theme: searchTheme
|
|
30
32
|
});
|
|
31
33
|
if (chosenOrg === '-new-') {
|
|
32
34
|
const newOrganization = await promptUserForNewOrganization(user);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/init/project/promptUserForOrganization.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug} from '@sanity/cli-core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/init/project/promptUserForOrganization.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug} from '@sanity/cli-core'\nimport {search} from '@sanity/cli-core/ux'\n\nimport {type ProjectOrganization} from '../../../services/organizations.js'\nimport {searchChoices, searchTheme} from '../../../util/searchChoices.js'\nimport {findOrganizationByUserName} from '../../organizations/findOrganizationByUserName.js'\nimport {getOrganizationChoices} from '../../organizations/getOrganizationChoices.js'\nimport {getOrganizationsWithAttachGrantInfo} from '../../organizations/getOrganizationsWithAttachGrantInfo.js'\nimport {type OrganizationChoices} from '../../organizations/types.js'\nimport {promptUserForNewOrganization} from './promptUserForNewOrganization.js'\n\nconst debug = subdebug('init')\n\nexport async function promptUserForOrganization({\n isAppTemplate = false,\n organizations,\n user,\n}: {\n isAppTemplate?: boolean\n organizations: ProjectOrganization[]\n user: SanityOrgUser\n}) {\n if (organizations.length === 0) {\n const newOrganization = await promptUserForNewOrganization(user)\n return newOrganization.id\n }\n\n let organizationChoices: OrganizationChoices\n let defaultOrganizationId: string | undefined\n\n if (isAppTemplate) {\n organizationChoices = getOrganizationChoices(organizations)\n defaultOrganizationId =\n organizations.length === 1\n ? organizations[0].id\n : findOrganizationByUserName(organizations, user)\n } else {\n debug(`User has ${organizations.length} organization(s), checking attach access`)\n const withGrantInfo = await getOrganizationsWithAttachGrantInfo(organizations)\n const withAttach = withGrantInfo.filter(({hasAttachGrant}) => hasAttachGrant)\n\n debug('User has attach access to %d organizations.', withAttach.length)\n organizationChoices = getOrganizationChoices(withGrantInfo)\n defaultOrganizationId =\n withAttach.length === 1\n ? withAttach[0].organization.id\n : findOrganizationByUserName(organizations, user)\n }\n\n const chosenOrg = await search({\n default: defaultOrganizationId || undefined,\n message: 'Select organization:',\n source: searchChoices(organizationChoices),\n theme: searchTheme,\n })\n\n if (chosenOrg === '-new-') {\n const newOrganization = await promptUserForNewOrganization(user)\n return newOrganization.id\n }\n\n return chosenOrg || undefined\n}\n"],"names":["subdebug","search","searchChoices","searchTheme","findOrganizationByUserName","getOrganizationChoices","getOrganizationsWithAttachGrantInfo","promptUserForNewOrganization","debug","promptUserForOrganization","isAppTemplate","organizations","user","length","newOrganization","id","organizationChoices","defaultOrganizationId","withGrantInfo","withAttach","filter","hasAttachGrant","organization","chosenOrg","default","undefined","message","source","theme"],"mappings":"AAAA,SAA4BA,QAAQ,QAAO,mBAAkB;AAC7D,SAAQC,MAAM,QAAO,sBAAqB;AAG1C,SAAQC,aAAa,EAAEC,WAAW,QAAO,iCAAgC;AACzE,SAAQC,0BAA0B,QAAO,oDAAmD;AAC5F,SAAQC,sBAAsB,QAAO,gDAA+C;AACpF,SAAQC,mCAAmC,QAAO,6DAA4D;AAE9G,SAAQC,4BAA4B,QAAO,oCAAmC;AAE9E,MAAMC,QAAQR,SAAS;AAEvB,OAAO,eAAeS,0BAA0B,EAC9CC,gBAAgB,KAAK,EACrBC,aAAa,EACbC,IAAI,EAKL;IACC,IAAID,cAAcE,MAAM,KAAK,GAAG;QAC9B,MAAMC,kBAAkB,MAAMP,6BAA6BK;QAC3D,OAAOE,gBAAgBC,EAAE;IAC3B;IAEA,IAAIC;IACJ,IAAIC;IAEJ,IAAIP,eAAe;QACjBM,sBAAsBX,uBAAuBM;QAC7CM,wBACEN,cAAcE,MAAM,KAAK,IACrBF,aAAa,CAAC,EAAE,CAACI,EAAE,GACnBX,2BAA2BO,eAAeC;IAClD,OAAO;QACLJ,MAAM,CAAC,SAAS,EAAEG,cAAcE,MAAM,CAAC,wCAAwC,CAAC;QAChF,MAAMK,gBAAgB,MAAMZ,oCAAoCK;QAChE,MAAMQ,aAAaD,cAAcE,MAAM,CAAC,CAAC,EAACC,cAAc,EAAC,GAAKA;QAE9Db,MAAM,+CAA+CW,WAAWN,MAAM;QACtEG,sBAAsBX,uBAAuBa;QAC7CD,wBACEE,WAAWN,MAAM,KAAK,IAClBM,UAAU,CAAC,EAAE,CAACG,YAAY,CAACP,EAAE,GAC7BX,2BAA2BO,eAAeC;IAClD;IAEA,MAAMW,YAAY,MAAMtB,OAAO;QAC7BuB,SAASP,yBAAyBQ;QAClCC,SAAS;QACTC,QAAQzB,cAAcc;QACtBY,OAAOzB;IACT;IAEA,IAAIoB,cAAc,SAAS;QACzB,MAAMT,kBAAkB,MAAMP,6BAA6BK;QAC3D,OAAOE,gBAAgBC,EAAE;IAC3B;IAEA,OAAOQ,aAAaE;AACtB"}
|
package/dist/commands/codemod.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/codemod.ts"],"sourcesContent":["import {execSync, spawn} from 'node:child_process'\nimport {existsSync} from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {codemods} from '../actions/codemods/index.js'\nimport {type CodeMod} from '../actions/codemods/types.js'\n\nconst codemodeDebug = subdebug('codemod')\n\nexport class CodemodCommand extends SanityCommand<typeof CodemodCommand> {\n static override args = {\n codemodName: Args.string({\n description: 'Name of the codemod to run',\n required: false,\n }),\n }\n\n static override description = 'Updates Sanity Studio codebase with a code modification script'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Show available code mods',\n },\n {\n command: '<%= config.bin %> <%= command.id %> reactIconsV3 --dry',\n description: 'Run codemod to transform react-icons imports (dry run)',\n },\n ]\n\n static override flags = {\n dry: Flags.boolean({\n default: false,\n description: 'Dry run (no changes are made to files)',\n }),\n extensions: Flags.string({\n default: 'js,ts,tsx',\n description: 'Transform files with these file extensions (comma separated)',\n }),\n 'no-verify': Flags.boolean({\n default: false,\n description: 'Skip verification steps before running codemod',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CodemodCommand)\n const {codemodName} = args\n const workDir = process.cwd()\n\n if (!codemodName) {\n this.printMods()\n return\n }\n\n // Make a record where all the keys of the available codemods are lowercased,\n // eg `reactIconsV3` turns into `{reacticonsv3: CodeMod}`\n const normalizedMods: Map<string, CodeMod> = new Map()\n for (const [originalName, mod] of Object.entries(codemods)) {\n normalizedMods.set(originalName.toLowerCase(), mod)\n }\n\n // Verify that mod exists\n const mod = normalizedMods.get(codemodName.toLowerCase())\n if (!mod) {\n this.error(`Codemod with name \"${codemodName}\" not found`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n // Verify if there is any verification defined, and user has not opted out of it\n if (typeof mod.verify === 'function' && !flags['no-verify']) {\n try {\n await mod.verify({workDir})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n codemodeDebug('Verification failed: %s', err.message)\n this.error(`Verification failed: ${err.message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n\n // If extensions are defined, they come in as CSV, so split and normalize them\n const exts = flags.extensions\n ? flags.extensions.split(',').map((ext) => ext.trim().replace(/^\\./, ''))\n : ['js', 'ts', 'tsx']\n\n const dryRun = flags.dry\n\n // We use npx to run jscodeshift, so verify that it exists and works before using it\n this.ensureNpx()\n\n const prepared = await mod.prepare?.({output: this.output, workDir})\n // jscodeshift JSON-parses option values, so encode them to keep strings like \"2024\" as strings\n const transformOptions = Object.entries(prepared?.options ?? {}).map(\n ([key, value]) => `--${key}=${JSON.stringify(value)}`,\n )\n\n // If there is a gitignore in the target folder, we want to use that to know\n // which folders to ignore - eg `dist`, `coverage` or whatever\n const hasGitIgnore = existsSync(path.join(workDir, '.gitignore'))\n\n // Build the CLI command arguments\n const cliRoot = path.resolve(import.meta.dirname, '../..')\n const modPath = path.resolve(path.join(cliRoot, 'codemods', mod.filename))\n const cmdArgs = [\n 'jscodeshift',\n '--ignore-pattern',\n 'node_modules',\n '--ignore-pattern',\n 'dist',\n hasGitIgnore && '--ignore-config',\n hasGitIgnore && '.gitignore',\n '-t',\n modPath,\n '--extensions',\n exts.join(','),\n dryRun && '--dry',\n ...transformOptions,\n ...(prepared?.paths ?? [workDir]),\n ].filter((item): item is string => typeof item === 'string')\n\n const child = spawn('npx', cmdArgs, {\n stdio: 'inherit',\n })\n\n const handleSigint = () => {\n child.kill(2)\n }\n\n process.on('SIGINT', handleSigint)\n\n // Wait inside run() so oclif handles the exit, rather than throwing from an event callback\n const code = await new Promise<number | null>((resolve) => {\n child.on('close', resolve)\n })\n process.removeListener('SIGINT', handleSigint)\n this.exit(code || undefined)\n }\n\n private ensureNpx(): void {\n try {\n const npxHelp = execSync('npx --help', {encoding: 'utf8'})\n if (!npxHelp.includes('npm')) {\n this.error('Not the npx we expected', {exit: exitCodes.RUNTIME_ERROR})\n }\n } catch {\n this.error(\n `Failed to run \"npx\" - required to run codemods. Do you have a recent version of npm installed?`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n }\n\n private printMods(): void {\n this.log('Available code modifications:\\n')\n\n for (const [modName, mod] of Object.entries(codemods)) {\n this.log(`${modName} - ${mod.purpose}`)\n }\n }\n}\n"],"names":["execSync","spawn","existsSync","path","Args","Flags","exitCodes","SanityCommand","subdebug","codemods","codemodeDebug","CodemodCommand","args","codemodName","string","description","required","examples","command","flags","dry","boolean","default","extensions","run","parse","workDir","process","cwd","printMods","normalizedMods","Map","originalName","mod","Object","entries","set","toLowerCase","get","error","exit","RUNTIME_ERROR","verify","err","Error","String","message","exts","split","map","ext","trim","replace","dryRun","ensureNpx","prepared","prepare","output","transformOptions","options","key","value","JSON","stringify","hasGitIgnore","join","cliRoot","resolve","dirname","modPath","filename","cmdArgs","paths","filter","item","child","stdio","handleSigint","kill","on","code","Promise","removeListener","undefined","npxHelp","encoding","includes","log","modName","purpose"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,KAAK,QAAO,qBAAoB;AAClD,SAAQC,UAAU,QAAO,UAAS;AAClC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AAEnE,SAAQC,QAAQ,QAAO,+BAA8B;AAGrD,MAAMC,gBAAgBF,SAAS;AAE/B,OAAO,MAAMG,uBAAuBJ;IAClC,OAAgBK,OAAO;QACrBC,aAAaT,KAAKU,MAAM,CAAC;YACvBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,iEAAgE;IAE9F,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtBC,KAAKf,MAAMgB,OAAO,CAAC;YACjBC,SAAS;YACTP,aAAa;QACf;QACAQ,YAAYlB,MAAMS,MAAM,CAAC;YACvBQ,SAAS;YACTP,aAAa;QACf;QACA,aAAaV,MAAMgB,OAAO,CAAC;YACzBC,SAAS;YACTP,aAAa;QACf;IACF,EAAC;IAED,MAAaS,MAAqB;QAChC,MAAM,EAACZ,IAAI,EAAEO,KAAK,EAAC,GAAG,MAAM,IAAI,CAACM,KAAK,CAACd;QACvC,MAAM,EAACE,WAAW,EAAC,GAAGD;QACtB,MAAMc,UAAUC,QAAQC,GAAG;QAE3B,IAAI,CAACf,aAAa;YAChB,IAAI,CAACgB,SAAS;YACd;QACF;QAEA,6EAA6E;QAC7E,yDAAyD;QACzD,MAAMC,iBAAuC,IAAIC;QACjD,KAAK,MAAM,CAACC,cAAcC,IAAI,IAAIC,OAAOC,OAAO,CAAC1B,UAAW;YAC1DqB,eAAeM,GAAG,CAACJ,aAAaK,WAAW,IAAIJ;QACjD;QAEA,yBAAyB;QACzB,MAAMA,MAAMH,eAAeQ,GAAG,CAACzB,YAAYwB,WAAW;QACtD,IAAI,CAACJ,KAAK;YACR,IAAI,CAACM,KAAK,CAAC,CAAC,mBAAmB,EAAE1B,YAAY,WAAW,CAAC,EAAE;gBAAC2B,MAAMlC,UAAUmC,aAAa;YAAA;QAC3F;QAEA,gFAAgF;QAChF,IAAI,OAAOR,IAAIS,MAAM,KAAK,cAAc,CAACvB,KAAK,CAAC,YAAY,EAAE;YAC3D,IAAI;gBACF,MAAMc,IAAIS,MAAM,CAAC;oBAAChB;gBAAO;YAC3B,EAAE,OAAOa,OAAO;gBACd,MAAMI,MAAMJ,iBAAiBK,QAAQL,QAAQ,IAAIK,MAAMC,OAAON;gBAC9D7B,cAAc,2BAA2BiC,IAAIG,OAAO;gBACpD,IAAI,CAACP,KAAK,CAAC,CAAC,qBAAqB,EAAEI,IAAIG,OAAO,EAAE,EAAE;oBAACN,MAAMlC,UAAUmC,aAAa;gBAAA;YAClF;QACF;QAEA,8EAA8E;QAC9E,MAAMM,OAAO5B,MAAMI,UAAU,GACzBJ,MAAMI,UAAU,CAACyB,KAAK,CAAC,KAAKC,GAAG,CAAC,CAACC,MAAQA,IAAIC,IAAI,GAAGC,OAAO,CAAC,OAAO,OACnE;YAAC;YAAM;YAAM;SAAM;QAEvB,MAAMC,SAASlC,MAAMC,GAAG;QAExB,oFAAoF;QACpF,IAAI,CAACkC,SAAS;QAEd,MAAMC,WAAW,MAAMtB,IAAIuB,OAAO,GAAG;
|
|
1
|
+
{"version":3,"sources":["../../src/commands/codemod.ts"],"sourcesContent":["import {execSync, spawn} from 'node:child_process'\nimport {existsSync} from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {codemods} from '../actions/codemods/index.js'\nimport {type CodeMod} from '../actions/codemods/types.js'\n\nconst codemodeDebug = subdebug('codemod')\n\nexport class CodemodCommand extends SanityCommand<typeof CodemodCommand> {\n static override args = {\n codemodName: Args.string({\n description: 'Name of the codemod to run',\n required: false,\n }),\n }\n\n static override description = 'Updates Sanity Studio codebase with a code modification script'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Show available code mods',\n },\n {\n command: '<%= config.bin %> <%= command.id %> reactIconsV3 --dry',\n description: 'Run codemod to transform react-icons imports (dry run)',\n },\n ]\n\n static override flags = {\n dry: Flags.boolean({\n default: false,\n description: 'Dry run (no changes are made to files)',\n }),\n extensions: Flags.string({\n default: 'js,ts,tsx',\n description: 'Transform files with these file extensions (comma separated)',\n }),\n 'no-verify': Flags.boolean({\n default: false,\n description: 'Skip verification steps before running codemod',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CodemodCommand)\n const {codemodName} = args\n const workDir = process.cwd()\n\n if (!codemodName) {\n this.printMods()\n return\n }\n\n // Make a record where all the keys of the available codemods are lowercased,\n // eg `reactIconsV3` turns into `{reacticonsv3: CodeMod}`\n const normalizedMods: Map<string, CodeMod> = new Map()\n for (const [originalName, mod] of Object.entries(codemods)) {\n normalizedMods.set(originalName.toLowerCase(), mod)\n }\n\n // Verify that mod exists\n const mod = normalizedMods.get(codemodName.toLowerCase())\n if (!mod) {\n this.error(`Codemod with name \"${codemodName}\" not found`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n // Verify if there is any verification defined, and user has not opted out of it\n if (typeof mod.verify === 'function' && !flags['no-verify']) {\n try {\n await mod.verify({workDir})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n codemodeDebug('Verification failed: %s', err.message)\n this.error(`Verification failed: ${err.message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n\n // If extensions are defined, they come in as CSV, so split and normalize them\n const exts = flags.extensions\n ? flags.extensions.split(',').map((ext) => ext.trim().replace(/^\\./, ''))\n : ['js', 'ts', 'tsx']\n\n const dryRun = flags.dry\n\n // We use npx to run jscodeshift, so verify that it exists and works before using it\n this.ensureNpx()\n\n const prepared = await mod.prepare?.({dry: dryRun, output: this.output, workDir})\n // jscodeshift JSON-parses option values, so encode them to keep strings like \"2024\" as strings\n const transformOptions = Object.entries(prepared?.options ?? {}).map(\n ([key, value]) => `--${key}=${JSON.stringify(value)}`,\n )\n\n // If there is a gitignore in the target folder, we want to use that to know\n // which folders to ignore - eg `dist`, `coverage` or whatever\n const hasGitIgnore = existsSync(path.join(workDir, '.gitignore'))\n\n // Build the CLI command arguments\n const cliRoot = path.resolve(import.meta.dirname, '../..')\n const modPath = path.resolve(path.join(cliRoot, 'codemods', mod.filename))\n const cmdArgs = [\n 'jscodeshift',\n '--ignore-pattern',\n 'node_modules',\n '--ignore-pattern',\n 'dist',\n hasGitIgnore && '--ignore-config',\n hasGitIgnore && '.gitignore',\n '-t',\n modPath,\n '--extensions',\n exts.join(','),\n dryRun && '--dry',\n ...transformOptions,\n ...(prepared?.paths ?? [workDir]),\n ].filter((item): item is string => typeof item === 'string')\n\n const child = spawn('npx', cmdArgs, {\n stdio: 'inherit',\n })\n\n const handleSigint = () => {\n child.kill(2)\n }\n\n process.on('SIGINT', handleSigint)\n\n // Wait inside run() so oclif handles the exit, rather than throwing from an event callback\n const code = await new Promise<number | null>((resolve) => {\n child.on('close', resolve)\n })\n process.removeListener('SIGINT', handleSigint)\n this.exit(code || undefined)\n }\n\n private ensureNpx(): void {\n try {\n const npxHelp = execSync('npx --help', {encoding: 'utf8'})\n if (!npxHelp.includes('npm')) {\n this.error('Not the npx we expected', {exit: exitCodes.RUNTIME_ERROR})\n }\n } catch {\n this.error(\n `Failed to run \"npx\" - required to run codemods. Do you have a recent version of npm installed?`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n }\n\n private printMods(): void {\n this.log('Available code modifications:\\n')\n\n for (const [modName, mod] of Object.entries(codemods)) {\n this.log(`${modName} - ${mod.purpose}`)\n }\n }\n}\n"],"names":["execSync","spawn","existsSync","path","Args","Flags","exitCodes","SanityCommand","subdebug","codemods","codemodeDebug","CodemodCommand","args","codemodName","string","description","required","examples","command","flags","dry","boolean","default","extensions","run","parse","workDir","process","cwd","printMods","normalizedMods","Map","originalName","mod","Object","entries","set","toLowerCase","get","error","exit","RUNTIME_ERROR","verify","err","Error","String","message","exts","split","map","ext","trim","replace","dryRun","ensureNpx","prepared","prepare","output","transformOptions","options","key","value","JSON","stringify","hasGitIgnore","join","cliRoot","resolve","dirname","modPath","filename","cmdArgs","paths","filter","item","child","stdio","handleSigint","kill","on","code","Promise","removeListener","undefined","npxHelp","encoding","includes","log","modName","purpose"],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
|
+
import { Separator } from '@sanity/cli-core/ux';
|
|
3
|
+
/** `search` prompt theme that adds a "type to search" hint to the key help line. */ export const searchTheme = {
|
|
4
|
+
style: {
|
|
5
|
+
keysHelpTip: (keys)=>[
|
|
6
|
+
[
|
|
7
|
+
'type',
|
|
8
|
+
'to search'
|
|
9
|
+
],
|
|
10
|
+
...keys
|
|
11
|
+
].map(([key, action])=>`${styleText('bold', key)} ${styleText('dim', action)}`).join(styleText('dim', ' • '))
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const isChoice = (choice)=>!Separator.isSeparator(choice);
|
|
15
|
+
/**
|
|
16
|
+
* Builds a `search` prompt source that keeps choices whose `name` contains every search word.
|
|
17
|
+
* Actions above the first separator (e.g. "Create new ...") stay visible, below the matches while
|
|
18
|
+
* searching so that Enter picks the top match. Without a selectable match the actions are
|
|
19
|
+
* disabled, so Enter does nothing.
|
|
20
|
+
*/ export function searchChoices(choices) {
|
|
21
|
+
const separatorIndex = choices.findIndex((choice)=>Separator.isSeparator(choice));
|
|
22
|
+
const actions = choices.slice(0, Math.max(separatorIndex, 0)).filter((choice)=>isChoice(choice));
|
|
23
|
+
const searchable = choices.slice(separatorIndex + 1).filter((choice)=>isChoice(choice));
|
|
24
|
+
return (term)=>{
|
|
25
|
+
const trimmed = term?.trim() ?? '';
|
|
26
|
+
if (!trimmed) {
|
|
27
|
+
return choices;
|
|
28
|
+
}
|
|
29
|
+
const words = trimmed.toLowerCase().split(/\s+/);
|
|
30
|
+
const matches = searchable.filter((choice)=>words.every((word)=>choice.name.toLowerCase().includes(word)));
|
|
31
|
+
if (actions.length === 0) {
|
|
32
|
+
return matches;
|
|
33
|
+
}
|
|
34
|
+
if (matches.some((choice)=>!choice.disabled)) {
|
|
35
|
+
return [
|
|
36
|
+
...matches,
|
|
37
|
+
new Separator(),
|
|
38
|
+
...actions
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [
|
|
42
|
+
...matches,
|
|
43
|
+
new Separator(matches.length > 0 ? undefined : `No matches for "${trimmed}"`),
|
|
44
|
+
...actions.map((action)=>({
|
|
45
|
+
...action,
|
|
46
|
+
disabled: '(clear search to select)'
|
|
47
|
+
}))
|
|
48
|
+
];
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=searchChoices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/util/searchChoices.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Separator} from '@sanity/cli-core/ux'\n\ntype Choice = {disabled?: boolean | string; name: string; value: string}\n\n/** `search` prompt theme that adds a \"type to search\" hint to the key help line. */\nexport const searchTheme = {\n style: {\n keysHelpTip: (keys: [key: string, action: string][]) =>\n [['type', 'to search'], ...keys]\n .map(([key, action]) => `${styleText('bold', key)} ${styleText('dim', action)}`)\n .join(styleText('dim', ' • ')),\n },\n}\n\nconst isChoice = (choice: Choice | Separator): choice is Choice => !Separator.isSeparator(choice)\n\n/**\n * Builds a `search` prompt source that keeps choices whose `name` contains every search word.\n * Actions above the first separator (e.g. \"Create new ...\") stay visible, below the matches while\n * searching so that Enter picks the top match. Without a selectable match the actions are\n * disabled, so Enter does nothing.\n */\nexport function searchChoices(choices: Array<Choice | Separator>) {\n const separatorIndex = choices.findIndex((choice) => Separator.isSeparator(choice))\n const actions = choices.slice(0, Math.max(separatorIndex, 0)).filter((choice) => isChoice(choice))\n const searchable = choices.slice(separatorIndex + 1).filter((choice) => isChoice(choice))\n\n return (term: string | undefined) => {\n const trimmed = term?.trim() ?? ''\n\n if (!trimmed) {\n return choices\n }\n\n const words = trimmed.toLowerCase().split(/\\s+/)\n const matches = searchable.filter((choice) =>\n words.every((word) => choice.name.toLowerCase().includes(word)),\n )\n\n if (actions.length === 0) {\n return matches\n }\n\n if (matches.some((choice) => !choice.disabled)) {\n return [...matches, new Separator(), ...actions]\n }\n\n return [\n ...matches,\n new Separator(matches.length > 0 ? undefined : `No matches for \"${trimmed}\"`),\n ...actions.map((action) => ({...action, disabled: '(clear search to select)'})),\n ]\n }\n}\n"],"names":["styleText","Separator","searchTheme","style","keysHelpTip","keys","map","key","action","join","isChoice","choice","isSeparator","searchChoices","choices","separatorIndex","findIndex","actions","slice","Math","max","filter","searchable","term","trimmed","trim","words","toLowerCase","split","matches","every","word","name","includes","length","some","disabled","undefined"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,SAAS,QAAO,sBAAqB;AAI7C,kFAAkF,GAClF,OAAO,MAAMC,cAAc;IACzBC,OAAO;QACLC,aAAa,CAACC,OACZ;gBAAC;oBAAC;oBAAQ;iBAAY;mBAAKA;aAAK,CAC7BC,GAAG,CAAC,CAAC,CAACC,KAAKC,OAAO,GAAK,GAAGR,UAAU,QAAQO,KAAK,CAAC,EAAEP,UAAU,OAAOQ,SAAS,EAC9EC,IAAI,CAACT,UAAU,OAAO;IAC7B;AACF,EAAC;AAED,MAAMU,WAAW,CAACC,SAAiD,CAACV,UAAUW,WAAW,CAACD;AAE1F;;;;;CAKC,GACD,OAAO,SAASE,cAAcC,OAAkC;IAC9D,MAAMC,iBAAiBD,QAAQE,SAAS,CAAC,CAACL,SAAWV,UAAUW,WAAW,CAACD;IAC3E,MAAMM,UAAUH,QAAQI,KAAK,CAAC,GAAGC,KAAKC,GAAG,CAACL,gBAAgB,IAAIM,MAAM,CAAC,CAACV,SAAWD,SAASC;IAC1F,MAAMW,aAAaR,QAAQI,KAAK,CAACH,iBAAiB,GAAGM,MAAM,CAAC,CAACV,SAAWD,SAASC;IAEjF,OAAO,CAACY;QACN,MAAMC,UAAUD,MAAME,UAAU;QAEhC,IAAI,CAACD,SAAS;YACZ,OAAOV;QACT;QAEA,MAAMY,QAAQF,QAAQG,WAAW,GAAGC,KAAK,CAAC;QAC1C,MAAMC,UAAUP,WAAWD,MAAM,CAAC,CAACV,SACjCe,MAAMI,KAAK,CAAC,CAACC,OAASpB,OAAOqB,IAAI,CAACL,WAAW,GAAGM,QAAQ,CAACF;QAG3D,IAAId,QAAQiB,MAAM,KAAK,GAAG;YACxB,OAAOL;QACT;QAEA,IAAIA,QAAQM,IAAI,CAAC,CAACxB,SAAW,CAACA,OAAOyB,QAAQ,GAAG;YAC9C,OAAO;mBAAIP;gBAAS,IAAI5B;mBAAgBgB;aAAQ;QAClD;QAEA,OAAO;eACFY;YACH,IAAI5B,UAAU4B,QAAQK,MAAM,GAAG,IAAIG,YAAY,CAAC,gBAAgB,EAAEb,QAAQ,CAAC,CAAC;eACzEP,QAAQX,GAAG,CAAC,CAACE,SAAY,CAAA;oBAAC,GAAGA,MAAM;oBAAE4B,UAAU;gBAA0B,CAAA;SAC7E;IACH;AACF"}
|