@sanity/plugin-kit 6.0.3 → 7.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.
@@ -1,210 +1,210 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import util from "util";
4
- import githubUrlToObject from "github-url-to-object";
5
- import validateNpmPackageName from "validate-npm-package-name";
1
+ import { a as urls, i as requiredNodeEngine, r as incompatiblePluginPackage, t as cliName } from "./constants.js";
2
+ import { t as log_default } from "./log.js";
3
+ import { t as binname } from "./package2.js";
6
4
  import { createRequire } from "node:module";
7
5
  import chalk from "chalk";
6
+ import path from "path";
8
7
  import outdent from "outdent";
9
- import { log, urls, minPkgUtilsMajor, requiredNodeEngine, incompatiblePluginPackage, cliName } from "./index.js";
8
+ import fs from "fs";
9
+ import util from "util";
10
+ import githubUrlToObject from "github-url-to-object";
11
+ import validNpmName from "validate-npm-package-name";
10
12
  import crypto from "crypto";
11
13
  import json5 from "json5";
12
14
  import pAny from "p-any";
13
15
  import { URL } from "url";
14
16
  import inquirer from "inquirer";
15
- import { pkg } from "./package2.js";
16
17
  import { getLatestVersion } from "get-latest-version";
17
18
  import pProps from "p-props";
18
19
  const mergedPackages = [
19
- "@sanity/base",
20
- "@sanity/core",
21
- "@sanity/types",
22
- "@sanity/data-aspects",
23
- "@sanity/default-layout",
24
- "@sanity/default-login",
25
- "@sanity/desk-tool",
26
- "@sanity/field",
27
- "@sanity/form-builder",
28
- "@sanity/initial-value-templates",
29
- "@sanity/language-filter",
30
- "@sanity/production-preview",
31
- "@sanity/react-hooks",
32
- "@sanity/resolver",
33
- "@sanity/state-router",
34
- "@sanity/structure",
35
- "@sanity/studio-hints"
20
+ "@sanity/base",
21
+ "@sanity/core",
22
+ "@sanity/types",
23
+ "@sanity/data-aspects",
24
+ "@sanity/default-layout",
25
+ "@sanity/default-login",
26
+ "@sanity/desk-tool",
27
+ "@sanity/field",
28
+ "@sanity/form-builder",
29
+ "@sanity/initial-value-templates",
30
+ "@sanity/language-filter",
31
+ "@sanity/production-preview",
32
+ "@sanity/react-hooks",
33
+ "@sanity/resolver",
34
+ "@sanity/state-router",
35
+ "@sanity/structure",
36
+ "@sanity/studio-hints"
36
37
  ].sort(), deprecatedDevDeps = [
37
- "tsdx",
38
- "sanipack",
39
- "parcel",
40
- "@parcel/packager-ts",
41
- "@parcel/transformer-typescript-types"
42
- ], buildExtensions = [".js", ".jsx", ".es6", ".es", ".mjs", ".ts", ".tsx"];
38
+ "tsdx",
39
+ "sanipack",
40
+ "parcel",
41
+ "@parcel/packager-ts",
42
+ "@parcel/transformer-typescript-types"
43
+ ], buildExtensions = [
44
+ ".js",
45
+ ".jsx",
46
+ ".es6",
47
+ ".es",
48
+ ".mjs",
49
+ ".ts",
50
+ ".tsx"
51
+ ];
43
52
  async function prompt(message, options) {
44
- const type = options.choices ? "list" : options.type, result = await inquirer.prompt([{ ...options, type, message, name: "single" }]);
45
- return result && result.single;
53
+ let type = options.choices ? "list" : options.type, result = await inquirer.prompt([{
54
+ ...options,
55
+ type,
56
+ message,
57
+ name: "single"
58
+ }]);
59
+ return result && result.single;
46
60
  }
47
61
  prompt.separator = () => new inquirer.Separator();
48
62
  function promptForPackageName({ basePath }, defaultVal) {
49
- return prompt("Plugin name (sanity-plugin-...)", {
50
- default: defaultVal || path.basename(basePath),
51
- filter: (name) => {
52
- const prefixless = name.trim().replace(/^sanity-plugin-/, "");
53
- return name[0] === "@" ? name : `sanity-plugin-${prefixless}`;
54
- },
55
- validate: (name) => {
56
- const valid = validateNpmPackageName(name);
57
- return valid.errors ? valid.errors[0] : name[0] !== "@" && name.endsWith("plugin") ? `Name shouldn't include "plugin" multiple times (${name})` : !0;
58
- }
59
- });
63
+ return prompt("Plugin name (sanity-plugin-...)", {
64
+ default: defaultVal || path.basename(basePath),
65
+ filter: (name) => {
66
+ let prefixless = name.trim().replace(/^sanity-plugin-/, "");
67
+ return name[0] === "@" ? name : `sanity-plugin-${prefixless}`;
68
+ },
69
+ validate: (name) => {
70
+ let valid = validNpmName(name);
71
+ return valid.errors ? valid.errors[0] : name[0] !== "@" && name.endsWith("plugin") ? `Name shouldn't include "plugin" multiple times (${name})` : !0;
72
+ }
73
+ });
60
74
  }
61
75
  function promptForRepoOrigin(_options, defaultVal) {
62
- return prompt("Git repository URL", {
63
- default: defaultVal,
64
- filter: (raw) => {
65
- const url = (raw || "").trim(), gh = githubUrlToObject(url);
66
- return gh ? `git+ssh://git@github.com/${gh.user}/${gh.repo}.git` : url;
67
- },
68
- validate: (url) => {
69
- if (!url)
70
- return !0;
71
- try {
72
- return new URL(url) ? !0 : "Invalid URL";
73
- } catch {
74
- return "Invalid URL";
75
- }
76
- }
77
- });
76
+ return prompt("Git repository URL", {
77
+ default: defaultVal,
78
+ filter: (raw) => {
79
+ let url = (raw || "").trim(), gh = githubUrlToObject(url);
80
+ return gh ? `git+ssh://git@github.com/${gh.user}/${gh.repo}.git` : url;
81
+ },
82
+ validate: (url) => {
83
+ if (!url) return !0;
84
+ try {
85
+ return new URL(url), !0;
86
+ } catch {
87
+ return "Invalid URL";
88
+ }
89
+ }
90
+ });
78
91
  }
79
92
  const stat$1 = util.promisify(fs.stat), mkdir = util.promisify(fs.mkdir), readdir = util.promisify(fs.readdir), copyFile = util.promisify(fs.copyFile), readFile$2 = util.promisify(fs.readFile), writeFile = util.promisify(fs.writeFile);
80
93
  function hasSourceEquivalent(compiledFile, paths) {
81
- if (!paths.source)
82
- return fileExists(
83
- path.isAbsolute(compiledFile) ? compiledFile : path.resolve(paths.basePath, compiledFile)
84
- );
85
- const baseDir = path.dirname(compiledFile.replace(paths.compiled, paths.source)), baseName = path.basename(compiledFile, path.extname(compiledFile)), pathStub = path.join(baseDir, baseName);
86
- return buildCandidateExists(pathStub);
94
+ if (!paths.source) return fileExists(path.isAbsolute(compiledFile) ? compiledFile : path.resolve(paths.basePath, compiledFile));
95
+ let baseDir = path.dirname(compiledFile.replace(paths.compiled, paths.source)), baseName = path.basename(compiledFile, path.extname(compiledFile));
96
+ return buildCandidateExists(path.join(baseDir, baseName));
87
97
  }
88
98
  async function hasSourceFile(filePath, paths) {
89
- if (!paths?.source)
90
- return fileExists(
91
- path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? "", filePath)
92
- );
93
- const pathStub = path.isAbsolute(filePath) ? filePath : path.resolve(paths.source, filePath);
94
- return await fileExists(pathStub) ? !0 : buildCandidateExists(pathStub);
99
+ if (!paths?.source) return fileExists(path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? "", filePath));
100
+ let pathStub = path.isAbsolute(filePath) ? filePath : path.resolve(paths.source, filePath);
101
+ return await fileExists(pathStub) ? !0 : buildCandidateExists(pathStub);
95
102
  }
96
103
  function hasCompiledFile(filePath, paths) {
97
- if (!paths?.compiled)
98
- return fileExists(
99
- path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? "", filePath)
100
- );
101
- const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(paths.compiled, filePath), withExt = path.extname(absPath) === "" ? `${absPath}.js` : absPath;
102
- return fileExists(withExt);
104
+ if (!paths?.compiled) return fileExists(path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? "", filePath));
105
+ let absPath = path.isAbsolute(filePath) ? filePath : path.resolve(paths.compiled, filePath);
106
+ return fileExists(path.extname(absPath) === "" ? `${absPath}.js` : absPath);
103
107
  }
104
108
  function buildCandidateExists(pathStub) {
105
- const candidates = buildExtensions.map((extCandidate) => `${pathStub}${extCandidate}`);
106
- return pAny(candidates.map((candidate) => stat$1(candidate))).then(() => !0).catch(() => !1);
109
+ return pAny(buildExtensions.map((extCandidate) => `${pathStub}${extCandidate}`).map((candidate) => stat$1(candidate))).then(() => !0).catch(() => !1);
107
110
  }
108
111
  function fileExists(filePath) {
109
- return stat$1(filePath).then(() => !0).catch(() => !1);
112
+ return stat$1(filePath).then(() => !0).catch(() => !1);
110
113
  }
111
114
  async function readJsonFile(filePath) {
112
- const content = await readFile$2(filePath, "utf8");
113
- return JSON.parse(content);
115
+ let content = await readFile$2(filePath, "utf8");
116
+ return JSON.parse(content);
114
117
  }
115
118
  function writeJsonFile(filePath, content) {
116
- const data = JSON.stringify(content, null, 2) + `
117
- `;
118
- return writeFile(filePath, data, { encoding: "utf8" });
119
+ let data = JSON.stringify(content, null, 2) + "\n";
120
+ return writeFile(filePath, data, { encoding: "utf8" });
119
121
  }
120
122
  async function writeFileWithOverwritePrompt(filePath, content, options) {
121
- const { default: defaultVal, force = !1, ...writeOptions } = options, printablePath = filePath.startsWith(process.cwd()) ? path.relative(process.cwd(), filePath) : filePath;
122
- return await fileEqualsData(filePath, content) || !force && await fileExists(filePath) && !await prompt(`File "${printablePath}" already exists. Overwrite?`, {
123
- type: "confirm",
124
- default: defaultVal
125
- }) ? !1 : (await writeFile(filePath, content, writeOptions), !0);
123
+ let { default: defaultVal, force = !1, ...writeOptions } = options, printablePath = filePath.startsWith(process.cwd()) ? path.relative(process.cwd(), filePath) : filePath;
124
+ return await fileEqualsData(filePath, content) || !force && await fileExists(filePath) && !await prompt(`File "${printablePath}" already exists. Overwrite?`, {
125
+ type: "confirm",
126
+ default: defaultVal
127
+ }) ? !1 : (await writeFile(filePath, content, writeOptions), !0);
126
128
  }
127
129
  async function copyFileWithOverwritePrompt(from, to, flags) {
128
- const printablePath = to.startsWith(process.cwd()) ? path.relative(process.cwd(), to) : to;
129
- return await filesAreEqual(from, to) || (await ensureDirectoryExists(to), !flags.force && await fileExists(to) && !await prompt(`File "${printablePath}" already exists. Overwrite?`, {
130
- type: "confirm",
131
- default: !1
132
- })) ? !1 : (await copyFile(from, to), !0);
130
+ let printablePath = to.startsWith(process.cwd()) ? path.relative(process.cwd(), to) : to;
131
+ return await filesAreEqual(from, to) || (await ensureDirectoryExists(to), !flags.force && await fileExists(to) && !await prompt(`File "${printablePath}" already exists. Overwrite?`, {
132
+ type: "confirm",
133
+ default: !1
134
+ })) ? !1 : (await copyFile(from, to), !0);
133
135
  }
134
136
  async function ensureDirectoryExists(filePath) {
135
- const dirname = path.dirname(filePath);
136
- await fileExists(dirname) || (await ensureDirectoryExists(dirname), await mkdir(dirname));
137
+ let dirname = path.dirname(filePath);
138
+ await fileExists(dirname) || (await ensureDirectoryExists(dirname), await mkdir(dirname));
137
139
  }
138
140
  async function fileEqualsData(filePath, content) {
139
- const contentHash = crypto.createHash("sha1").update(content).digest("hex"), remoteHash = await getFileHash(filePath);
140
- return contentHash === remoteHash;
141
+ return crypto.createHash("sha1").update(content).digest("hex") === await getFileHash(filePath);
141
142
  }
142
143
  async function filesAreEqual(file1, file2) {
143
- const [hash1, hash2] = await Promise.all([getFileHash(file1, !1), getFileHash(file2)]);
144
- return hash1 === hash2;
144
+ let [hash1, hash2] = await Promise.all([getFileHash(file1, !1), getFileHash(file2)]);
145
+ return hash1 === hash2;
145
146
  }
146
147
  function getFileHash(filePath, allowMissing = !0) {
147
- return new Promise((resolve, reject) => {
148
- const hash = crypto.createHash("sha1"), stream = fs.createReadStream(filePath);
149
- stream.on("error", (err) => {
150
- err.code === "ENOENT" && allowMissing ? resolve(null) : reject(err);
151
- }), stream.on("end", () => resolve(hash.digest("hex"))), stream.on("data", (chunk) => hash.update(chunk));
152
- });
148
+ return new Promise((resolve, reject) => {
149
+ let hash = crypto.createHash("sha1"), stream = fs.createReadStream(filePath);
150
+ stream.on("error", (err) => {
151
+ err.code === "ENOENT" && allowMissing ? resolve(null) : reject(err);
152
+ }), stream.on("end", () => resolve(hash.digest("hex"))), stream.on("data", (chunk) => hash.update(chunk));
153
+ });
153
154
  }
154
155
  async function ensureDir(dirPath) {
155
- try {
156
- await mkdir(dirPath);
157
- } catch (err) {
158
- if (err.code !== "EEXIST")
159
- throw err;
160
- }
156
+ try {
157
+ await mkdir(dirPath);
158
+ } catch (err) {
159
+ if (err.code !== "EEXIST") throw err;
160
+ }
161
161
  }
162
162
  async function isEmptyish(dirPath) {
163
- const ignoredFiles = [".git", ".gitignore", "license", "readme.md"];
164
- return (await readdir(dirPath).catch(() => [])).filter((file) => !ignoredFiles.includes(file.toLowerCase())).length === 0;
165
- }
166
- async function readFileContent({
167
- filename,
168
- basePath
169
- }) {
170
- const filepath = path.normalize(path.join(basePath, filename));
171
- try {
172
- return await readFile$2(filepath, "utf8");
173
- } catch (err) {
174
- if (err.code === "ENOENT") {
175
- log.debug(`No ${filename} file found.`);
176
- return;
177
- }
178
- throw new Error(`Failed to read "${filepath}": ${err.message}`);
179
- }
180
- }
181
- async function readJson5File({
182
- filename,
183
- basePath
184
- }) {
185
- const content = await readFileContent({ filename, basePath });
186
- if (content)
187
- return parseJson5(content, filename);
163
+ let ignoredFiles = [
164
+ ".git",
165
+ ".gitignore",
166
+ "license",
167
+ "readme.md"
168
+ ];
169
+ return (await readdir(dirPath).catch(() => [])).filter((file) => !ignoredFiles.includes(file.toLowerCase())).length === 0;
170
+ }
171
+ async function readFileContent({ filename, basePath }) {
172
+ let filepath = path.normalize(path.join(basePath, filename));
173
+ try {
174
+ return await readFile$2(filepath, "utf8");
175
+ } catch (err) {
176
+ if (err.code === "ENOENT") {
177
+ log_default.debug(`No ${filename} file found.`);
178
+ return;
179
+ }
180
+ throw Error(`Failed to read "${filepath}": ${err.message}`);
181
+ }
182
+ }
183
+ async function readJson5File({ filename, basePath }) {
184
+ let content = await readFileContent({
185
+ filename,
186
+ basePath
187
+ });
188
+ if (content) return parseJson5(content, filename);
188
189
  }
189
190
  function parseJson5(content, errorKey) {
190
- try {
191
- return json5.parse(content);
192
- } catch (err) {
193
- throw new Error(`Error parsing "${errorKey}": ${err.message}`);
194
- }
191
+ try {
192
+ return json5.parse(content);
193
+ } catch (err) {
194
+ throw Error(`Error parsing "${errorKey}": ${err.message}`);
195
+ }
195
196
  }
196
197
  const expectedScripts = {
197
- build: "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
198
- watch: "pkg-utils watch --strict",
199
- "link-watch": "plugin-kit link-watch",
200
- prepublishOnly: "npm run build"
198
+ build: "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
199
+ watch: "pkg-utils watch --strict",
200
+ "link-watch": "plugin-kit link-watch",
201
+ prepublishOnly: "npm run build"
201
202
  };
202
203
  function filesWithSuffixes(fileBases, suffixes) {
203
- return fileBases.flatMap((file) => suffixes.map((suffix) => `${file}.${suffix}`));
204
+ return fileBases.flatMap((file) => suffixes.map((suffix) => `${file}.${suffix}`));
204
205
  }
205
206
  function validateNodeEngine(packageJson) {
206
- return packageJson.engines?.node !== requiredNodeEngine ? [
207
- outdent`
207
+ return packageJson.engines?.node === ">=20.19 <22 || >=22.12" ? [] : [outdent`
208
208
  Expected package.json to contain engines.node: "${requiredNodeEngine}" to match @sanity/pkg-utils,
209
209
  but it was: ${packageJson.engines?.node}
210
210
 
@@ -212,44 +212,38 @@ function validateNodeEngine(packageJson) {
212
212
 
213
213
  "engines": {
214
214
  "node": "${requiredNodeEngine}"
215
- }`.trimStart()
216
- ] : [];
215
+ }`.trimStart()];
217
216
  }
218
217
  function validateScripts(packageJson) {
219
- const errors = [], divergentScripts = Object.entries(expectedScripts).filter(([key, expectedCommand]) => {
220
- const command = packageJson.scripts?.[key];
221
- return !command || !command.includes(expectedCommand);
222
- });
223
- return divergentScripts.length && errors.push(
224
- outdent`
218
+ let errors = [], divergentScripts = Object.entries(expectedScripts).filter(([key, expectedCommand]) => {
219
+ let command = packageJson.scripts?.[key];
220
+ return !command || !command.includes(expectedCommand);
221
+ });
222
+ return divergentScripts.length && errors.push(outdent`
225
223
  The following script commands did not contain expected defaults: ${divergentScripts.map(([key]) => key).join(", ")}
226
224
 
227
225
  This checks for that the commands-strings includes these terms.
228
226
 
229
227
  Please add the following to your package.json "scripts":
230
228
 
231
- ${divergentScripts.map(([key, value]) => `"${key}": "${value}"`).join(`,
232
- `)}
233
- `.trimStart()
234
- ), errors;
229
+ ${divergentScripts.map(([key, value]) => `"${key}": "${value}"`).join(",\n")}
230
+ `.trimStart()), errors;
235
231
  }
236
232
  async function validateTsConfig(ts, options) {
237
- const { basePath, outDir, tsconfig } = options, errors = [], wrongEntries = Object.entries({
238
- target: "esnext",
239
- jsx: "preserve",
240
- module: "preserve",
241
- rootDir: ".",
242
- outDir,
243
- noEmit: !0
244
- }).filter(([key, value]) => {
245
- let option = ts.options[key];
246
- return key === "rootDir" && typeof option == "string" && (option = path.relative(basePath, option) || "."), key === "outDir" && typeof option == "string" && (option = path.relative(basePath, option) || "."), key === "target" && option === 99 && (option = "esnext"), key === "module" && option === 200 && (option = "preserve"), key === "jsx" && option === 1 && (option = "preserve"), typeof value == "string" && typeof option == "string" ? value.toLowerCase() !== option?.toLowerCase() : value !== option;
247
- });
248
- if (wrongEntries.length) {
249
- const expectedOutput = wrongEntries.map(([key, value]) => `"${key}": ${typeof value == "string" ? `"${value}"` : value},`).join(`
250
- `);
251
- errors.push(
252
- outdent`
233
+ let { basePath, outDir, tsconfig } = options, errors = [], wrongEntries = Object.entries({
234
+ target: "esnext",
235
+ jsx: "preserve",
236
+ module: "preserve",
237
+ rootDir: ".",
238
+ outDir,
239
+ noEmit: !0
240
+ }).filter(([key, value]) => {
241
+ let option = ts.options[key];
242
+ return key === "rootDir" && typeof option == "string" && (option = path.relative(basePath, option) || "."), key === "outDir" && typeof option == "string" && (option = path.relative(basePath, option) || "."), key === "target" && option === 99 && (option = "esnext"), key === "module" && option === 200 && (option = "preserve"), key === "jsx" && option === 1 && (option = "preserve"), typeof value == "string" && typeof option == "string" ? value.toLowerCase() !== option?.toLowerCase() : value !== option;
243
+ });
244
+ if (wrongEntries.length) {
245
+ let expectedOutput = wrongEntries.map(([key, value]) => `"${key}": ${typeof value == "string" ? `"${value}"` : value},`).join("\n");
246
+ errors.push(outdent`
253
247
  Recommended ${tsconfig} compilerOptions missing:
254
248
 
255
249
  The following fields had unexpected values: [${wrongEntries.map(([key]) => key).join(", ")}]
@@ -257,51 +251,63 @@ async function validateTsConfig(ts, options) {
257
251
  ${expectedOutput}
258
252
 
259
253
  Please update your ${tsconfig} accordingly.
260
- `.trimStart()
261
- );
262
- }
263
- return errors;
264
- }
254
+ `.trimStart());
255
+ }
256
+ return errors;
257
+ }
258
+ /**
259
+ * Hard requirement: plugins must be ESM (`"type": "module"`).
260
+ *
261
+ * plugin-kit loads `package.config.ts` through `@sanity/pkg-utils`, which can only load ESM
262
+ * TypeScript configs reliably when the plugin itself is ESM. CommonJS (or an omitted `type`)
263
+ * is not supported and cannot be opted out of.
264
+ */
265
265
  function validatePackageType({ type }) {
266
- return type === "module" ? [] : [
267
- outdent`
266
+ return type === "module" ? [] : [outdent`
268
267
  package.json must set "type": "module" — plugins built with @sanity/plugin-kit are ESM-only.
269
- Found: ${type ? `"type": "${type}"` : 'no "type" field (defaults to "commonjs")'}
268
+ Found: ${type ? `"type": "${type}"` : "no \"type\" field (defaults to \"commonjs\")"}
270
269
 
271
270
  Please add the following to package.json:
272
271
 
273
272
  "type": "module"
274
- `.trimStart()
275
- ];
276
- }
273
+ `.trimStart()];
274
+ }
275
+ /**
276
+ * Recursively collects the locations of any `require` condition within a package.json `exports`
277
+ * field. Conditions can be nested arbitrarily deep (and inside fallback arrays), so we walk the
278
+ * whole tree rather than only inspecting the first level.
279
+ *
280
+ * Subpath keys always start with `.` (e.g. `"./feature"`), while condition keys never do, so an
281
+ * exact `require` key is unambiguously a CommonJS export condition.
282
+ */
277
283
  function findRequireConditions(node, pathSegments) {
278
- if (Array.isArray(node))
279
- return node.flatMap(
280
- (entry, index) => findRequireConditions(entry, [...pathSegments, String(index)])
281
- );
282
- if (!node || typeof node != "object")
283
- return [];
284
- const found = [];
285
- for (const [key, value] of Object.entries(node))
286
- key === "require" && found.push(formatExportsPath(pathSegments)), found.push(...findRequireConditions(value, [...pathSegments, key]));
287
- return found;
284
+ if (Array.isArray(node)) return node.flatMap((entry, index) => findRequireConditions(entry, [...pathSegments, String(index)]));
285
+ if (!node || typeof node != "object") return [];
286
+ let found = [];
287
+ for (let [key, value] of Object.entries(node)) key === "require" && found.push(formatExportsPath(pathSegments)), found.push(...findRequireConditions(value, [...pathSegments, key]));
288
+ return found;
288
289
  }
289
290
  function formatExportsPath(segments) {
290
- return `exports${segments.map((segment) => `[${JSON.stringify(segment)}]`).join("")}`;
291
- }
291
+ return `exports${segments.map((segment) => `[${JSON.stringify(segment)}]`).join("")}`;
292
+ }
293
+ /**
294
+ * Bans CommonJS interop in package.json. The plugin baseline is Sanity Studio v5 or later, which is
295
+ * pure ESM, so there is no reason to publish a parallel CJS build anymore. This flags:
296
+ *
297
+ * - `require` export conditions
298
+ * - the top-level `main` field
299
+ * - the top-level `module` field
300
+ */
292
301
  function validateEsmOnly(packageJson) {
293
- const offenders = [];
294
- typeof packageJson.main < "u" && offenders.push(`- the top-level "main" field (${JSON.stringify(packageJson.main)})`), typeof packageJson.module < "u" && offenders.push(`- the top-level "module" field (${JSON.stringify(packageJson.module)})`);
295
- const requireConditions = [...new Set(findRequireConditions(packageJson.exports, []))];
296
- for (const conditionPath of requireConditions)
297
- offenders.push(`- a "require" export condition at ${conditionPath}`);
298
- return offenders.length ? [
299
- outdent`
302
+ let offenders = [];
303
+ packageJson.main !== void 0 && offenders.push(`- the top-level "main" field (${JSON.stringify(packageJson.main)})`), packageJson.module !== void 0 && offenders.push(`- the top-level "module" field (${JSON.stringify(packageJson.module)})`);
304
+ let requireConditions = [...new Set(findRequireConditions(packageJson.exports, []))];
305
+ for (let conditionPath of requireConditions) offenders.push(`- a "require" export condition at ${conditionPath}`);
306
+ return offenders.length ? [outdent`
300
307
  package.json ships CommonJS (CJS) output, but Sanity plugins target Sanity Studio v5+, which is pure ESM.
301
308
 
302
309
  Remove the following so the package stays ESM-only:
303
- ${offenders.join(`
304
- `)}
310
+ ${offenders.join("\n")}
305
311
 
306
312
  Supporting CJS is not worth it:
307
313
  - It can have unintended side-effects.
@@ -311,119 +317,111 @@ function validateEsmOnly(packageJson) {
311
317
  in the module tree, bloating bundles and slowing down builds.
312
318
 
313
319
  Rely on "exports" together with "type": "module", and drop "main", "module" and any "require" conditions.
314
- `.trimStart()
315
- ] : [];
320
+ `.trimStart()] : [];
316
321
  }
317
322
  function validatePkgUtilsDependency({ devDependencies }) {
318
- return devDependencies?.["@sanity/pkg-utils"] ? [] : [
319
- outdent`
323
+ return devDependencies?.["@sanity/pkg-utils"] ? [] : [outdent`
320
324
  package.json does not list @sanity/pkg-utils as a devDependency.
321
325
  @sanity/pkg-utils replaced parcel as the recommended build tool in @sanity/plugin-kit 2.0.0
322
326
 
323
327
  Please add it by running 'npm install --save-dev @sanity/pkg-utils'.
324
- `.trimStart()
325
- ];
328
+ `.trimStart()];
326
329
  }
330
+ /**
331
+ * Verifies that the installed `@sanity/pkg-utils` (the peer dependency plugin-kit loads
332
+ * `package.config.ts` with) is recent enough to expose the `loadConfig({cwd, pkgPath})` API.
333
+ */
327
334
  function validatePkgUtilsVersion({ basePath }) {
328
- const require2 = createRequire(path.join(basePath, "package.json"));
329
- let installedVersion;
330
- try {
331
- installedVersion = require2("@sanity/pkg-utils/package.json").version;
332
- } catch {
333
- return [
334
- outdent`
335
+ let require = createRequire(path.join(basePath, "package.json")), installedVersion;
336
+ try {
337
+ installedVersion = require("@sanity/pkg-utils/package.json").version;
338
+ } catch {
339
+ return [outdent`
335
340
  @sanity/pkg-utils is not installed.
336
341
  plugin-kit loads package.config.ts through @sanity/pkg-utils (a peer dependency).
337
342
 
338
343
  Please install it by running 'npm install --save-dev @sanity/pkg-utils'.
339
- `.trimStart()
340
- ];
341
- }
342
- const major = Number.parseInt(installedVersion?.split(".")[0] ?? "", 10);
343
- return !Number.isFinite(major) || major < minPkgUtilsMajor ? [
344
- outdent`
344
+ `.trimStart()];
345
+ }
346
+ let major = Number.parseInt(installedVersion?.split(".")[0] ?? "", 10);
347
+ return !Number.isFinite(major) || major < 10 ? [outdent`
345
348
  @sanity/pkg-utils ${installedVersion} is too old.
346
- plugin-kit requires @sanity/pkg-utils >=${minPkgUtilsMajor} to load package.config.ts.
349
+ plugin-kit requires @sanity/pkg-utils >=${10} to load package.config.ts.
347
350
 
348
351
  Please upgrade it by running 'npm install --save-dev @sanity/pkg-utils@latest'.
349
- `.trimStart()
350
- ] : [];
352
+ `.trimStart()] : [];
351
353
  }
352
354
  function validateSanityDependencies(packageJson) {
353
- const { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies }, illegalDeps = Object.keys(allDependencies).filter((dep) => mergedPackages.includes(dep)), unique = [...new Set(illegalDeps).values()];
354
- return unique.length ? [
355
- outdent`
355
+ let { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = {
356
+ ...dependencies,
357
+ ...devDependencies,
358
+ ...peerDependencies
359
+ }, illegalDeps = Object.keys(allDependencies).filter((dep) => mergedPackages.includes(dep)), unique = [...new Set(illegalDeps).values()];
360
+ return unique.length ? [outdent`
356
361
  package.json depends on "@sanity/*" packages that have moved into "sanity" package.
357
362
 
358
363
  The following dependencies should be replaced with "sanity":
359
- - ${unique.join(`
360
- - `)}
364
+ - ${unique.join("\n- ")}
361
365
 
362
366
  Refer to the reference docs to find replacement imports:
363
367
  ${urls.refDocs}
364
- `.trimStart()
365
- ] : [];
368
+ `.trimStart()] : [];
366
369
  }
367
370
  function validateDeprecatedDependencies(packageJson) {
368
- const { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies }, illegalDeps = Object.keys(allDependencies).filter((dep) => deprecatedDevDeps.includes(dep)), unique = [...new Set(illegalDeps).values()];
369
- return unique.length ? [
370
- outdent`
371
+ let { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = {
372
+ ...dependencies,
373
+ ...devDependencies,
374
+ ...peerDependencies
375
+ }, illegalDeps = Object.keys(allDependencies).filter((dep) => deprecatedDevDeps.includes(dep)), unique = [...new Set(illegalDeps).values()];
376
+ return unique.length ? [outdent`
371
377
  package.json contains deprecated dependencies that should be removed:
372
- - ${unique.join(`
373
- - `)}
374
- `.trimStart()
375
- ] : [];
378
+ - ${unique.join("\n- ")}
379
+ `.trimStart()] : [];
376
380
  }
377
381
  async function validateBabelConfig({ basePath }) {
378
- const filenames = [".babelrc", ...filesWithSuffixes([".babelrc", "babel.config"], ["json", "js", "cjs", "mjs"])], babelFiles = [];
379
- for (const filename of filenames) {
380
- const filepath = path.normalize(path.join(basePath, filename));
381
- await fileExists(filepath) && babelFiles.push(filename);
382
- }
383
- return babelFiles.length ? [
384
- outdent`
385
- Found babel-config file: [${babelFiles.join(
386
- ", "
387
- )}]. When using default @sanity/plugin-kit build command,
382
+ let filenames = [".babelrc", ...filesWithSuffixes([".babelrc", "babel.config"], [
383
+ "json",
384
+ "js",
385
+ "cjs",
386
+ "mjs"
387
+ ])], babelFiles = [];
388
+ for (let filename of filenames) await fileExists(path.normalize(path.join(basePath, filename))) && babelFiles.push(filename);
389
+ return babelFiles.length ? [outdent`
390
+ Found babel-config file: [${babelFiles.join(", ")}]. When using default @sanity/plugin-kit build command,
388
391
  this is probably not needed.
389
392
 
390
393
  Delete the file, or disable this check.
391
- `.trimStart()
392
- ] : [];
394
+ `.trimStart()] : [];
393
395
  }
394
396
  async function validateStudioConfig({ basePath }) {
395
- const suffixes = ["ts", "js", "tsx", "jsx"], filenames = filesWithSuffixes(["sanity.config", "sanity.cli"], suffixes), files = {};
396
- for (const filename of filenames) {
397
- const filepath = path.normalize(path.join(basePath, filename));
398
- files[filename] = await fileExists(filepath);
399
- }
400
- const sanityJson = await readJson5File({ basePath, filename: "sanity.json" }), hasConfigFile = (fileBase) => filesWithSuffixes([fileBase], suffixes).some((filename) => files[filename]), hasCliConfig = hasConfigFile("sanity.cli"), hasStudioConfig = hasConfigFile("sanity.config"), errors = [];
401
- if (sanityJson) {
402
- const info = [
403
- outdent`
397
+ let suffixes = [
398
+ "ts",
399
+ "js",
400
+ "tsx",
401
+ "jsx"
402
+ ], filenames = filesWithSuffixes(["sanity.config", "sanity.cli"], suffixes), files = {};
403
+ for (let filename of filenames) files[filename] = await fileExists(path.normalize(path.join(basePath, filename)));
404
+ let sanityJson = await readJson5File({
405
+ basePath,
406
+ filename: "sanity.json"
407
+ }), hasConfigFile = (fileBase) => filesWithSuffixes([fileBase], suffixes).some((filename) => files[filename]), hasCliConfig = hasConfigFile("sanity.cli"), hasStudioConfig = hasConfigFile("sanity.config"), errors = [];
408
+ if (sanityJson) {
409
+ let info = [outdent`
404
410
  Found sanity.json. This file is not used by Sanity Studio V3.
405
411
 
406
412
  Please consult the Studio V3 migration guide:
407
413
  ${urls.migrationGuideStudio}
408
414
  It will detail how to convert sanity.json to sanity.config.ts (or .js) and sanity.cli.ts (or .js) equivalents.
409
- `.trimStart(),
410
- sanityJson.plugins?.length && outdent`
415
+ `.trimStart(), sanityJson.plugins?.length && outdent`
411
416
  For V3 versions and alternatives to V2 plugins, please refer to the Sanity Exchange:
412
417
  ${urls.sanityExchange}
413
- `.trimStart()
414
- ].filter((s) => !!s);
415
- errors.push(info.join(`
416
-
417
- `));
418
- }
419
- return hasCliConfig || errors.push(
420
- outdent`
421
- sanity.cli.(${suffixes.join(
422
- " | "
423
- )}) missing. Please create a file named sanity.cli.ts with the following content:
418
+ `.trimStart()].filter((s) => !!s);
419
+ errors.push(info.join("\n\n"));
420
+ }
421
+ return hasCliConfig || errors.push(outdent`
422
+ sanity.cli.(${suffixes.join(" | ")}) missing. Please create a file named sanity.cli.ts with the following content:
424
423
 
425
- ${chalk.green(
426
- outdent`
424
+ ${chalk.green(outdent`
427
425
  import {createCliConfig} from 'sanity/cli'
428
426
 
429
427
  export default createCliConfig({
@@ -431,21 +429,15 @@ async function validateStudioConfig({ basePath }) {
431
429
  projectId: '${sanityJson?.api?.projectId ?? "project-id"}',
432
430
  dataset: '${sanityJson?.api?.dataset ?? "dataset"}',
433
431
  }
434
- })`
435
- )}
432
+ })`)}
436
433
 
437
434
  Make sure to replace the projectId and dataset fields with your own.
438
435
 
439
436
  For more, see ${urls.migrationGuideStudio}
440
- `.trimStart()
441
- ), hasStudioConfig || errors.push(
442
- outdent`
443
- sanity.config.(${suffixes.join(
444
- " | "
445
- )}) missing. At a minimum sanity.config.ts should contain:
437
+ `.trimStart()), hasStudioConfig || errors.push(outdent`
438
+ sanity.config.(${suffixes.join(" | ")}) missing. At a minimum sanity.config.ts should contain:
446
439
 
447
- ${chalk.green(
448
- outdent`
440
+ ${chalk.green(outdent`
449
441
  import { defineConfig } from "sanity"
450
442
  import { deskTool } from "sanity/desk"
451
443
 
@@ -464,43 +456,37 @@ async function validateStudioConfig({ basePath }) {
464
456
  /* put your v2 schema-types here */
465
457
  ],
466
458
  },
467
- })`
468
- ).trimStart()}
459
+ })`).trimStart()}
469
460
 
470
461
  Make sure to replace the projectId and dataset fields with your own.
471
462
 
472
463
  For more, see ${urls.migrationGuideStudio}
473
- `.trimStart()
474
- ), errors.length ? [errors.join(`
475
-
476
- ---
477
-
478
- `)] : [];
479
- }
480
- async function validateIncompatiblePlugin({
481
- basePath,
482
- packageJson
483
- }) {
484
- const { dependencies, devDependencies, peerDependencies } = packageJson, inDependencies = !!(dependencies?.[incompatiblePluginPackage] || devDependencies?.[incompatiblePluginPackage] || peerDependencies?.[incompatiblePluginPackage]), hasShimFile = await fileExists(path.normalize(path.join(basePath, "v2-incompatible.js"))), sanityJsonReferencesShim = !!(await readJson5File({ basePath, filename: "sanity.json" }))?.parts?.some(
485
- (part) => part?.path?.includes("v2-incompatible")
486
- );
487
- if (!inDependencies && !hasShimFile && !sanityJsonReferencesShim)
488
- return [];
489
- const found = [
490
- inDependencies ? `- "${incompatiblePluginPackage}" listed in package.json` : null,
491
- hasShimFile ? "- the v2-incompatible.js file" : null,
492
- sanityJsonReferencesShim ? "- a sanity.json referencing v2-incompatible.js" : null
493
- ].filter((e) => !!e);
494
- return [
495
- outdent`
464
+ `.trimStart()), errors.length ? [errors.join("\n\n---\n\n")] : [];
465
+ }
466
+ /**
467
+ * Detects leftover usage of the legacy `@sanity/incompatible-plugin` shim and asks for its removal.
468
+ *
469
+ * The shim (a `sanity.json` + `v2-incompatible.js` entry point, plus the `@sanity/incompatible-plugin`
470
+ * dependency) only rendered an error dialog in the long end-of-life Sanity Studio v2 when a v3 plugin
471
+ * was installed there. plugin-kit no longer scaffolds it, so a plugin should not ship it anymore.
472
+ */
473
+ async function validateIncompatiblePlugin({ basePath, packageJson }) {
474
+ let { dependencies, devDependencies, peerDependencies } = packageJson, inDependencies = !!(dependencies?.["@sanity/incompatible-plugin"] || devDependencies?.["@sanity/incompatible-plugin"] || peerDependencies?.["@sanity/incompatible-plugin"]), hasShimFile = await fileExists(path.normalize(path.join(basePath, "v2-incompatible.js"))), sanityJsonReferencesShim = !!(await readJson5File({
475
+ basePath,
476
+ filename: "sanity.json"
477
+ }))?.parts?.some((part) => part?.path?.includes("v2-incompatible"));
478
+ return !inDependencies && !hasShimFile && !sanityJsonReferencesShim ? [] : [outdent`
496
479
  ${incompatiblePluginPackage} is no longer used and should be removed.
497
480
 
498
481
  It only rendered an error dialog in the long end-of-life Sanity Studio v2 when a v3 plugin was
499
482
  installed there. That compatibility shim is now obsolete, so plugin-kit no longer adds it.
500
483
 
501
484
  Found:
502
- ${found.join(`
503
- `)}
485
+ ${[
486
+ inDependencies ? `- "${incompatiblePluginPackage}" listed in package.json` : null,
487
+ hasShimFile ? "- the v2-incompatible.js file" : null,
488
+ sanityJsonReferencesShim ? "- a sanity.json referencing v2-incompatible.js" : null
489
+ ].filter((e) => !!e).join("\n")}
504
490
 
505
491
  To fix this:
506
492
  - Remove "${incompatiblePluginPackage}" from package.json (dependencies/devDependencies/peerDependencies)
@@ -509,19 +495,20 @@ async function validateIncompatiblePlugin({
509
495
  - Remove "sanity.json" and "v2-incompatible.js" from the package.json "files" array
510
496
 
511
497
  For more, see ${urls.incompatiblePlugin}
512
- `.trimStart()
513
- ];
498
+ `.trimStart()];
514
499
  }
515
500
  function validatePackageName$1(packageJson) {
516
- const valid = validateNpmPackageName(packageJson.name ?? "");
517
- return valid.validForNewPackages ? !packageJson.name?.startsWith("@") && !packageJson.name?.startsWith("sanity-plugin-") ? [
518
- 'Invalid package.json: "name" should be prefixed with "sanity-plugin-" (or scoped - @your-company/plugin-name)'
519
- ] : [] : [`Invalid package.json: "name" is invalid: ${(valid.errors ?? valid.warnings ?? []).join(", ")}`];
520
- }
501
+ let valid = validNpmName(packageJson.name ?? "");
502
+ return valid.validForNewPackages ? !packageJson.name?.startsWith("@") && !packageJson.name?.startsWith("sanity-plugin-") ? ["Invalid package.json: \"name\" should be prefixed with \"sanity-plugin-\" (or scoped - @your-company/plugin-name)"] : [] : [`Invalid package.json: "name" is invalid: ${(valid.errors ?? valid.warnings ?? []).join(", ")}`];
503
+ }
504
+ /**
505
+ * Plugins built with @sanity/plugin-kit publish the compiled output (the `dist` directory) plus any
506
+ * v2-compatibility files. The `src` directory should not be published: it bloats the package and can
507
+ * cause bundlers that resolve the `source` export condition to pull in raw, uncompiled TypeScript.
508
+ */
521
509
  function validateBannedFiles(packageJson) {
522
- const { files } = packageJson;
523
- return Array.isArray(files) ? files.some((entry) => typeof entry != "string" ? !1 : entry.trim().replace(/^\.?\/+/, "").replace(/\/+$/, "") === "src") ? [
524
- outdent`
510
+ let { files } = packageJson;
511
+ return !Array.isArray(files) || !files.some((entry) => typeof entry == "string" && entry.trim().replace(/^\.?\/+/, "").replace(/\/+$/, "") === "src") ? [] : [outdent`
525
512
  package.json "files" must not include "src".
526
513
 
527
514
  Plugins built with @sanity/plugin-kit publish the compiled output in "dist" (and any v2-compatibility files).
@@ -529,538 +516,395 @@ function validateBannedFiles(packageJson) {
529
516
  "source" export condition to import raw, uncompiled TypeScript.
530
517
 
531
518
  Please remove "src" from the "files" array in package.json.
532
- `.trimStart()
533
- ] : [] : [];
519
+ `.trimStart()];
534
520
  }
535
521
  async function validateSrcIndexFile(basePath) {
536
- const paths = ["index.js", "index.ts"].map((p) => path.join("src", p)), allowedIndexFiles = paths.map((file) => path.join(basePath, file));
537
- let hasIndex = !1;
538
- for (const indexFile of allowedIndexFiles)
539
- hasIndex = hasIndex || await fileExists(indexFile);
540
- return hasIndex ? [] : [
541
- outdent`
522
+ let paths = ["index.js", "index.ts"].map((p) => path.join("src", p)), allowedIndexFiles = paths.map((file) => path.join(basePath, file)), hasIndex = !1;
523
+ for (let indexFile of allowedIndexFiles) hasIndex ||= await fileExists(indexFile);
524
+ return hasIndex ? [] : [outdent`
542
525
  Expected one of [${paths.join(", ")}] to exist.
543
526
 
544
527
  @sanity/pkg-utils expects a non-jsx file to be the source entry-point for the plugin.
545
528
  If you currently have JSX in your index file, extract it into a separate file and import it.
546
- `
547
- ];
548
- }
549
- async function disallowDuplicateConfig({
550
- basePath,
551
- pkgJson,
552
- configKey,
553
- files
554
- }) {
555
- const found = [];
556
- for (const file of files) {
557
- const filePath = path.join(basePath, file);
558
- await fileExists(filePath) && found.push(file);
559
- }
560
- return found.length > 1 ? [
561
- outdent`
529
+ `];
530
+ }
531
+ async function disallowDuplicateConfig({ basePath, pkgJson, configKey, files }) {
532
+ let found = [];
533
+ for (let file of files) await fileExists(path.join(basePath, file)) && found.push(file);
534
+ return found.length > 1 ? [outdent`
562
535
  Found multiple config files that serve the same purpose: [${found.join(", ")}].
563
536
 
564
537
  There should be at most one of these files. Delete the rest.
565
- `
566
- ] : found.length && pkgJson[configKey] ? [
567
- outdent`
538
+ `] : found.length && pkgJson[configKey] ? [outdent`
568
539
  package.json contains ${configKey}, but there also exists a config file that serves the same purpose.
569
540
  Config file: ${found.join("")}]
570
541
 
571
542
  Either delete the file or remove ${configKey} entry from package.json.
572
- `
573
- ] : [];
543
+ `] : [];
574
544
  }
575
545
  async function disallowDuplicateEslintConfig(basePath, pkgJson) {
576
- return disallowDuplicateConfig({
577
- basePath,
578
- pkgJson,
579
- configKey: "eslint",
580
- files: [
581
- ".eslintrc",
582
- ".eslintrc.js",
583
- ".eslintrc.cjs",
584
- ".eslintrc.yaml",
585
- ".eslintrc.yml",
586
- ".eslintrc.json"
587
- ]
588
- });
546
+ return disallowDuplicateConfig({
547
+ basePath,
548
+ pkgJson,
549
+ configKey: "eslint",
550
+ files: [
551
+ ".eslintrc",
552
+ ".eslintrc.js",
553
+ ".eslintrc.cjs",
554
+ ".eslintrc.yaml",
555
+ ".eslintrc.yml",
556
+ ".eslintrc.json"
557
+ ]
558
+ });
589
559
  }
590
560
  async function disallowDuplicatePrettierConfig(basePath, pkgJson) {
591
- return disallowDuplicateConfig({
592
- basePath,
593
- pkgJson,
594
- configKey: "prettier",
595
- files: [
596
- ".prettierrc",
597
- ".prettierrc.json5",
598
- ".prettierrc.json",
599
- ".prettierrc.yaml",
600
- ".prettierrc.yml",
601
- ".prettierrc.js",
602
- ".prettierrc.cjs",
603
- ".prettier.config,js",
604
- ".prettier.config.cjs",
605
- ".prettierrc.toml"
606
- ]
607
- });
561
+ return disallowDuplicateConfig({
562
+ basePath,
563
+ pkgJson,
564
+ configKey: "prettier",
565
+ files: [
566
+ ".prettierrc",
567
+ ".prettierrc.json5",
568
+ ".prettierrc.json",
569
+ ".prettierrc.yaml",
570
+ ".prettierrc.yml",
571
+ ".prettierrc.js",
572
+ ".prettierrc.cjs",
573
+ ".prettier.config,js",
574
+ ".prettier.config.cjs",
575
+ ".prettierrc.toml"
576
+ ]
577
+ });
608
578
  }
609
579
  const forcedPackageVersions = {}, forcedDevPackageVersions = {}, forcedPeerPackageVersions = {
610
- react: "^18",
611
- "react-dom": "^18",
612
- "@types/react": "^18",
613
- "@types/react-dom": "^18",
614
- sanity: "^5 || ^6.0.0-0",
615
- "styled-components": "^5.2"
580
+ react: "^18",
581
+ "react-dom": "^18",
582
+ "@types/react": "^18",
583
+ "@types/react-dom": "^18",
584
+ sanity: "^5 || ^6.0.0-0",
585
+ "styled-components": "^5.2"
616
586
  };
617
587
  function errorToUndefined(err) {
618
- if (err instanceof TypeError)
619
- throw err;
620
- }
621
- const stat = util.promisify(fs.stat), readFile$1 = util.promisify(fs.readFile), allowedPartProps = ["name", "implements", "path", "description"], disallowedPluginProps = ["api", "project", "plugins", "env"];
588
+ if (err instanceof TypeError) throw err;
589
+ }
590
+ const stat = util.promisify(fs.stat), readFile$1 = util.promisify(fs.readFile), allowedPartProps = [
591
+ "name",
592
+ "implements",
593
+ "path",
594
+ "description"
595
+ ], disallowedPluginProps = [
596
+ "api",
597
+ "project",
598
+ "plugins",
599
+ "env"
600
+ ];
622
601
  async function getPaths(options) {
623
- const { basePath } = options, manifest = await readManifest(options);
624
- return manifest.paths ? absolutifyPaths(manifest.paths, basePath) : null;
602
+ let { basePath } = options, manifest = await readManifest(options);
603
+ return manifest.paths ? absolutifyPaths(manifest.paths, basePath) : null;
625
604
  }
626
605
  function absolutifyPaths(paths, basePath) {
627
- const getPath = (relative) => relative ? path.resolve(path.join(basePath, relative)) : void 0;
628
- return paths ? {
629
- basePath,
630
- compiled: getPath(paths.compiled),
631
- source: getPath(paths.source)
632
- } : { basePath };
606
+ let getPath = (relative) => relative ? path.resolve(path.join(basePath, relative)) : void 0;
607
+ return paths ? {
608
+ basePath,
609
+ compiled: getPath(paths.compiled),
610
+ source: getPath(paths.source)
611
+ } : { basePath };
633
612
  }
634
613
  async function readManifest(options) {
635
- const { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "sanity.json"));
636
- let content;
637
- try {
638
- content = await readFile$1(manifestPath, "utf8");
639
- } catch (err) {
640
- throw err.code === "ENOENT" ? new Error(
641
- `No sanity.json found. sanity.json is required for plugins to function. Use \`${pkg.binname} init\` for a new plugin, or create an empty \`sanity.json\` with an empty object (\`{}\`) for existing ones.`
642
- ) : new Error(`Failed to read "${manifestPath}": ${err.message}`);
643
- }
644
- let parsed;
645
- try {
646
- parsed = JSON.parse(content);
647
- } catch (err) {
648
- throw new Error(`Error parsing "${manifestPath}": ${err.message}`);
649
- }
650
- return validate && await validateManifest(parsed, options), parsed;
614
+ let { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "sanity.json")), content;
615
+ try {
616
+ content = await readFile$1(manifestPath, "utf8");
617
+ } catch (err) {
618
+ throw err.code === "ENOENT" ? Error(`No sanity.json found. sanity.json is required for plugins to function. Use \`${binname} init\` for a new plugin, or create an empty \`sanity.json\` with an empty object (\`{}\`) for existing ones.`) : Error(`Failed to read "${manifestPath}": ${err.message}`);
619
+ }
620
+ let parsed;
621
+ try {
622
+ parsed = JSON.parse(content);
623
+ } catch (err) {
624
+ throw Error(`Error parsing "${manifestPath}": ${err.message}`);
625
+ }
626
+ return validate && await validateManifest(parsed, options), parsed;
651
627
  }
652
628
  async function validateManifest(manifest, opts) {
653
- const options = { isPlugin: !0, ...opts };
654
- if (!isObject$1(manifest))
655
- throw new Error("Invalid sanity.json: Root must be an object");
656
- if (options.isPlugin ? await validatePluginManifest(manifest, options) : validateProjectManifest(manifest), "root" in manifest && typeof manifest.root != "boolean")
657
- throw new Error('Invalid sanity.json: "root" property must be a boolean if declared');
658
- await validateParts(manifest, {
659
- ...options,
660
- paths: absolutifyPaths(manifest.paths, options.basePath)
661
- });
629
+ let options = {
630
+ isPlugin: !0,
631
+ ...opts
632
+ };
633
+ if (!isObject$1(manifest)) throw Error("Invalid sanity.json: Root must be an object");
634
+ if (options.isPlugin ? await validatePluginManifest(manifest, options) : validateProjectManifest(manifest), "root" in manifest && typeof manifest.root != "boolean") throw Error("Invalid sanity.json: \"root\" property must be a boolean if declared");
635
+ await validateParts(manifest, {
636
+ ...options,
637
+ paths: absolutifyPaths(manifest.paths, options.basePath)
638
+ });
662
639
  }
663
640
  function validateProjectManifest(manifest) {
664
- if ("paths" in manifest)
665
- throw new Error('Invalid sanity.json: "paths" property has no meaning in a project manifest');
641
+ if ("paths" in manifest) throw Error("Invalid sanity.json: \"paths\" property has no meaning in a project manifest");
666
642
  }
667
643
  async function validatePluginManifest(manifest, options) {
668
- const disallowed = Object.keys(manifest).filter((key) => disallowedPluginProps.includes(key)).map((key) => `"${key}"`);
669
- if (disallowed.length > 0) {
670
- const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
671
- throw new Error(
672
- `Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a plugin manifest`
673
- );
674
- }
675
- if (manifest.root)
676
- throw new Error('Invalid sanity.json: "root" cannot be truthy in a plugin manifest');
677
- await validatePaths$1(manifest, options);
644
+ let disallowed = Object.keys(manifest).filter((key) => disallowedPluginProps.includes(key)).map((key) => `"${key}"`);
645
+ if (disallowed.length > 0) {
646
+ let plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
647
+ throw Error(`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a plugin manifest`);
648
+ }
649
+ if (manifest.root) throw Error("Invalid sanity.json: \"root\" cannot be truthy in a plugin manifest");
650
+ await validatePaths$1(manifest, options);
678
651
  }
679
652
  async function validatePaths$1(manifest, options) {
680
- if (!("paths" in manifest))
681
- return;
682
- if (!isObject$1(manifest.paths))
683
- throw new Error('Invalid sanity.json: "paths" must be an object if declared');
684
- if (typeof manifest.paths.compiled != "string")
685
- throw new Error(
686
- 'Invalid sanity.json: "paths" must have a (string) "compiled" property if declared'
687
- );
688
- if (typeof manifest.paths.source != "string")
689
- throw new Error(
690
- 'Invalid sanity.json: "paths" must have a (string) "source" property if declared'
691
- );
692
- const sourcePath = path.resolve(options.basePath, manifest.paths.source);
693
- let srcStats;
694
- try {
695
- srcStats = await stat(sourcePath);
696
- } catch (err) {
697
- if (err.code === "ENOENT")
698
- throw new Error(`sanity.json references "source" path which does not exist: "${sourcePath}"`);
699
- }
700
- if (!srcStats?.isDirectory())
701
- throw new Error(
702
- `sanity.json references "source" path which is not a directory: "${sourcePath}"`
703
- );
653
+ if (!("paths" in manifest)) return;
654
+ if (!isObject$1(manifest.paths)) throw Error("Invalid sanity.json: \"paths\" must be an object if declared");
655
+ if (typeof manifest.paths.compiled != "string") throw Error("Invalid sanity.json: \"paths\" must have a (string) \"compiled\" property if declared");
656
+ if (typeof manifest.paths.source != "string") throw Error("Invalid sanity.json: \"paths\" must have a (string) \"source\" property if declared");
657
+ let sourcePath = path.resolve(options.basePath, manifest.paths.source), srcStats;
658
+ try {
659
+ srcStats = await stat(sourcePath);
660
+ } catch (err) {
661
+ if (err.code === "ENOENT") throw Error(`sanity.json references "source" path which does not exist: "${sourcePath}"`);
662
+ }
663
+ if (!srcStats?.isDirectory()) throw Error(`sanity.json references "source" path which is not a directory: "${sourcePath}"`);
704
664
  }
705
665
  async function validateParts(manifest, options) {
706
- if (!("parts" in manifest))
707
- return;
708
- if (!Array.isArray(manifest.parts))
709
- throw new Error('Invalid sanity.json: "parts" must be an array if declared');
710
- let i = 0;
711
- for (const part of manifest.parts)
712
- await validatePart(part, i, options), i++;
666
+ if (!("parts" in manifest)) return;
667
+ if (!Array.isArray(manifest.parts)) throw Error("Invalid sanity.json: \"parts\" must be an array if declared");
668
+ let i = 0;
669
+ for (let part of manifest.parts) await validatePart(part, i, options), i++;
713
670
  }
714
671
  async function validatePart(part, index, options) {
715
- if (!isObject$1(part))
716
- throw new Error(`Invalid sanity.json: "parts[${index}]" must be an object`);
717
- validateAllowedPartKeys(part, index), validatePartStringValues(part, index), validatePartNames(part, index, options), await validatePartFiles(part, index, options);
672
+ if (!isObject$1(part)) throw Error(`Invalid sanity.json: "parts[${index}]" must be an object`);
673
+ validateAllowedPartKeys(part, index), validatePartStringValues(part, index), validatePartNames(part, index, options), await validatePartFiles(part, index, options);
718
674
  }
719
675
  async function validatePartFiles(part, index, options) {
720
- const { verifyCompiledParts, verifySourceParts, paths } = options;
721
- if (!part?.path)
722
- return;
723
- const ext = path.extname(part.path);
724
- if (paths?.source && ext && ext !== ".js" && buildExtensions.includes(ext))
725
- throw new Error(
726
- `Invalid sanity.json: Part path has extension which is not applicable after compiling. ${ext} becomes .js after compiling. Specify filename without extension (${path.basename(
727
- part.path
728
- )}) (parts[${index}])`
729
- );
730
- if (!verifySourceParts && !verifyCompiledParts)
731
- return;
732
- const [srcExists, outDirExists] = await Promise.all([
733
- hasSourceFile(part.path, paths),
734
- verifyCompiledParts && hasCompiledFile(part.path, paths)
735
- ]);
736
- if (!srcExists)
737
- throw new Error(
738
- `Invalid sanity.json: Part path references file that does not exist in source directory (${paths?.source || paths?.basePath}) (parts[${index}])`
739
- );
740
- if (verifyCompiledParts && !outDirExists)
741
- throw new Error(
742
- `Invalid sanity.json: Part path references file ("${part.path}") that does not exist in compiled directory (${paths?.compiled}) (parts[${index}])`
743
- );
676
+ let { verifyCompiledParts, verifySourceParts, paths } = options;
677
+ if (!part?.path) return;
678
+ let ext = path.extname(part.path);
679
+ if (paths?.source && ext && ext !== ".js" && buildExtensions.includes(ext)) throw Error(`Invalid sanity.json: Part path has extension which is not applicable after compiling. ${ext} becomes .js after compiling. Specify filename without extension (${path.basename(part.path)}) (parts[${index}])`);
680
+ if (!verifySourceParts && !verifyCompiledParts) return;
681
+ let [srcExists, outDirExists] = await Promise.all([hasSourceFile(part.path, paths), verifyCompiledParts && hasCompiledFile(part.path, paths)]);
682
+ if (!srcExists) throw Error(`Invalid sanity.json: Part path references file that does not exist in source directory (${paths?.source || paths?.basePath}) (parts[${index}])`);
683
+ if (verifyCompiledParts && !outDirExists) throw Error(`Invalid sanity.json: Part path references file ("${part.path}") that does not exist in compiled directory (${paths?.compiled}) (parts[${index}])`);
744
684
  }
745
685
  function validatePartNames(part, index, options) {
746
- const pluginName = options.pluginName ? options.pluginName.replace(/^sanity-plugin-/, "") : "";
747
- if (!part?.name || !part?.name?.startsWith(`part:${pluginName}/`))
748
- throw new Error(
749
- `Invalid sanity.json: "name" must be prefixed with "part:${pluginName}/" - got "${part?.name}" (parts[${index}])`
750
- );
751
- if (!part?.implements?.startsWith("part:"))
752
- throw new Error(
753
- `Invalid sanity.json: "implements" must be prefixed with "part:" - got "${part?.implements}" (parts[${index}])`
754
- );
686
+ let pluginName = options.pluginName ? options.pluginName.replace(/^sanity-plugin-/, "") : "";
687
+ if (!part?.name || !part?.name?.startsWith(`part:${pluginName}/`)) throw Error(`Invalid sanity.json: "name" must be prefixed with "part:${pluginName}/" - got "${part?.name}" (parts[${index}])`);
688
+ if (!part?.implements?.startsWith("part:")) throw Error(`Invalid sanity.json: "implements" must be prefixed with "part:" - got "${part?.implements}" (parts[${index}])`);
755
689
  }
756
690
  function validateAllowedPartKeys(part, index) {
757
- const disallowed = Object.keys(part).filter((key) => !allowedPartProps.includes(key)).map((key) => `"${key}"`);
758
- if (disallowed.length > 0) {
759
- const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
760
- throw new Error(
761
- `Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a part declaration (parts[${index}])`
762
- );
763
- }
691
+ let disallowed = Object.keys(part).filter((key) => !allowedPartProps.includes(key)).map((key) => `"${key}"`);
692
+ if (disallowed.length > 0) {
693
+ let plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
694
+ throw Error(`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a part declaration (parts[${index}])`);
695
+ }
764
696
  }
765
697
  function validatePartStringValues(part, index) {
766
- const nonStrings = Object.keys(part).filter((key) => typeof part[key] != "string").map((key) => `"${key}"`);
767
- if (nonStrings.length > 0) {
768
- const plural = nonStrings.length > 1 ? "s" : "", joined = nonStrings.join(", ");
769
- throw new Error(
770
- `Invalid sanity.json: Key${plural} ${joined} should be of type string (parts[${index}])`
771
- );
772
- }
698
+ let nonStrings = Object.keys(part).filter((key) => typeof part[key] != "string").map((key) => `"${key}"`);
699
+ if (nonStrings.length > 0) {
700
+ let plural = nonStrings.length > 1 ? "s" : "", joined = nonStrings.join(", ");
701
+ throw Error(`Invalid sanity.json: Key${plural} ${joined} should be of type string (parts[${index}])`);
702
+ }
773
703
  }
774
704
  function isObject$1(obj) {
775
- return !Array.isArray(obj) && obj !== null && typeof obj == "object";
705
+ return !Array.isArray(obj) && typeof obj == "object" && !!obj;
776
706
  }
777
707
  async function hasSanityJson(basePath) {
778
- const file = await readJsonFile(path.join(basePath, "sanity.json")).catch(
779
- errorToUndefined
780
- );
781
- return { exists: !!file, isRoot: !!(file && file.root) };
708
+ let file = await readJsonFile(path.join(basePath, "sanity.json")).catch(errorToUndefined);
709
+ return {
710
+ exists: !!file,
711
+ isRoot: !!(file && file.root)
712
+ };
782
713
  }
783
714
  async function findStudioV3Config(basePath) {
784
- const jsFile = "sanity.config.js";
785
- if (await fileExists(path.join(basePath, jsFile)))
786
- return { v3ConfigFile: jsFile };
787
- const tsFile = "sanity.config.ts";
788
- return { v3ConfigFile: await fileExists(path.join(basePath, tsFile)) ? tsFile : void 0 };
715
+ let jsFile = "sanity.config.js";
716
+ if (await fileExists(path.join(basePath, jsFile))) return { v3ConfigFile: jsFile };
717
+ let tsFile = "sanity.config.ts";
718
+ return { v3ConfigFile: await fileExists(path.join(basePath, tsFile)) ? tsFile : void 0 };
789
719
  }
790
720
  const lockedDependencies = {
791
- "styled-components": "^6.1",
792
- eslint: "^8.57.0"
721
+ "styled-components": "^6.1",
722
+ eslint: "^8.57.0",
723
+ typescript: "^6"
793
724
  };
794
725
  function resolveLatestVersions(packages) {
795
- const versions = {};
796
- for (const pkgName of packages)
797
- versions[pkgName] = pkgName in lockedDependencies ? lockedDependencies[pkgName] : "latest";
798
- return pProps(
799
- versions,
800
- async (range, pkgName) => {
801
- const version = await getLatestVersion(pkgName, { range });
802
- if (!version)
803
- throw new Error(`Found no version for ${pkgName}`);
804
- return rangeify(version);
805
- },
806
- { concurrency: 8 }
807
- );
726
+ let versions = {};
727
+ for (let pkgName of packages) versions[pkgName] = pkgName in lockedDependencies ? lockedDependencies[pkgName] : "latest";
728
+ return pProps(versions, async (range, pkgName) => {
729
+ let version = await getLatestVersion(pkgName, { range });
730
+ if (!version) throw Error(`Found no version for ${pkgName}`);
731
+ return rangeify(version);
732
+ }, { concurrency: 8 });
808
733
  }
809
734
  function rangeify(version) {
810
- return `^${version}`;
735
+ return `^${version}`;
811
736
  }
812
737
  const defaultDependencies = [], defaultDevDependencies = [
813
- "sanity",
814
- // peer dependencies of `sanity`
815
- "react",
816
- "react-dom",
817
- "styled-components"
818
- ], defaultPeerDependencies = ["react", "sanity"], readFile = util.promisify(fs.readFile), pathKeys = ["main", "module", "browser", "types"];
738
+ "sanity",
739
+ "react",
740
+ "react-dom",
741
+ "styled-components"
742
+ ], defaultPeerDependencies = ["react", "sanity"], readFile = util.promisify(fs.readFile), pathKeys = [
743
+ "main",
744
+ "module",
745
+ "browser",
746
+ "types"
747
+ ];
819
748
  async function getPackage(opts) {
820
- const options = { flags: {}, ...opts };
821
- validateOptions(options);
822
- const { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "package.json"));
823
- let content;
824
- try {
825
- content = await readFile(manifestPath, "utf8");
826
- } catch (err) {
827
- throw err.code === "ENOENT" ? new Error(
828
- `No package.json found. package.json is required to publish to npm. Use \`${cliName} init\` for a new plugin, or \`npm init\` for an existing one`
829
- ) : new Error(`Failed to read "${manifestPath}": ${err.message}`);
830
- }
831
- let parsed;
832
- try {
833
- parsed = JSON.parse(content);
834
- } catch (err) {
835
- throw new Error(`Error parsing "${manifestPath}": ${err.message}`);
836
- }
837
- if (!isObject(parsed))
838
- throw new Error("Invalid package.json: Root must be an object");
839
- return validate && await validatePackage(parsed, options), parsed;
749
+ let options = {
750
+ flags: {},
751
+ ...opts
752
+ };
753
+ validateOptions(options);
754
+ let { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "package.json")), content;
755
+ try {
756
+ content = await readFile(manifestPath, "utf8");
757
+ } catch (err) {
758
+ throw err.code === "ENOENT" ? Error(`No package.json found. package.json is required to publish to npm. Use \`${cliName} init\` for a new plugin, or \`npm init\` for an existing one`) : Error(`Failed to read "${manifestPath}": ${err.message}`);
759
+ }
760
+ let parsed;
761
+ try {
762
+ parsed = JSON.parse(content);
763
+ } catch (err) {
764
+ throw Error(`Error parsing "${manifestPath}": ${err.message}`);
765
+ }
766
+ if (!isObject(parsed)) throw Error("Invalid package.json: Root must be an object");
767
+ return validate && await validatePackage(parsed, options), parsed;
840
768
  }
841
769
  async function validatePackage(manifest, opts) {
842
- validateOptions(opts);
843
- const options = { isPlugin: !0, ...opts };
844
- options.isPlugin && await validatePluginPackage(manifest, options), validateLockFiles(options);
770
+ validateOptions(opts);
771
+ let options = {
772
+ isPlugin: !0,
773
+ ...opts
774
+ };
775
+ options.isPlugin && await validatePluginPackage(manifest, options), validateLockFiles(options);
845
776
  }
846
777
  function validateOptions(opts) {
847
- const options = opts || {};
848
- if (!isObject(options))
849
- throw new Error("Options must be an object");
850
- if (typeof options.basePath != "string")
851
- throw new Error('"options.basePath" must be a string (path to plugin base path)');
778
+ let options = opts || {};
779
+ if (!isObject(options)) throw Error("Options must be an object");
780
+ if (typeof options.basePath != "string") throw Error("\"options.basePath\" must be a string (path to plugin base path)");
852
781
  }
853
782
  async function validatePluginPackage(manifest, options) {
854
- validatePackageName(manifest), await validatePaths(manifest, options);
783
+ validatePackageName(manifest), await validatePaths(manifest, options);
855
784
  }
856
785
  function validatePackageName(manifest) {
857
- if (typeof manifest.name != "string")
858
- throw new Error('Invalid package.json: "name" must be a string');
859
- const valid = validateNpmPackageName(manifest.name);
860
- if (!valid.validForNewPackages)
861
- throw new Error(`Invalid package.json: "name" is invalid: ${(valid.errors ?? []).join(", ")}`);
862
- if (manifest.name[0] !== "@" && !manifest.name.startsWith("sanity-plugin-"))
863
- throw new Error(
864
- 'Invalid package.json: "name" should be prefixed with "sanity-plugin-" (or scoped - @your-company/plugin-name)'
865
- );
786
+ if (typeof manifest.name != "string") throw Error("Invalid package.json: \"name\" must be a string");
787
+ let valid = validNpmName(manifest.name);
788
+ if (!valid.validForNewPackages) throw Error(`Invalid package.json: "name" is invalid: ${(valid.errors ?? []).join(", ")}`);
789
+ if (manifest.name[0] !== "@" && !manifest.name.startsWith("sanity-plugin-")) throw Error("Invalid package.json: \"name\" should be prefixed with \"sanity-plugin-\" (or scoped - @your-company/plugin-name)");
866
790
  }
867
791
  async function validatePaths(manifest, options) {
868
- const paths = await getPaths({
869
- ...options,
870
- pluginName: manifest.name ?? "unknown",
871
- verifySourceParts: !1,
872
- verifyCompiledParts: !1
873
- }), abs = (file) => path.isAbsolute(file) ? file : path.resolve(path.join(options.basePath, file)), exists = (file) => fs.existsSync(abs(file)), willExist = (file) => paths && hasSourceEquivalent(abs(file), paths), withinSourceDir = (file) => paths?.source && abs(file).startsWith(paths.source), withinTargetDir = (file) => paths?.compiled && abs(file).startsWith(paths.compiled);
874
- for (const key of pathKeys) {
875
- if (!(key in manifest))
876
- continue;
877
- const manifestValue = manifest[key];
878
- if (typeof manifestValue != "string")
879
- throw new Error(`Invalid package.json: "${key}" must be a string if defined`);
880
- if (!options?.flags?.allowSourceTarget && paths && withinSourceDir(manifestValue))
881
- throw new Error(
882
- `Invalid package.json: "${key}" points to file within source (uncompiled) directory. Use --allow-source-target if you really want to do this.`
883
- );
884
- if (exists(manifestValue) && paths && withinTargetDir(manifestValue) && !await willExist(manifestValue))
885
- throw new Error(
886
- `Invalid package.json: "${key}" points to file that will not exist after compiling`
887
- );
888
- if (!exists(manifestValue) && !await willExist(manifestValue)) {
889
- if (!paths)
890
- throw new Error(`Invalid package.json: "${key}" points to file that does not exist`);
891
- const inOutDir = paths.compiled && !abs(manifestValue).startsWith(paths.compiled);
892
- throw new Error(
893
- inOutDir ? `Invalid package.json: "${key}" points to file that does not exist, and "paths" is not configured to compile to this location` : `Invalid package.json: "${key}" points to file that does not exist, and no equivalent is found in source directory`
894
- );
895
- }
896
- }
792
+ let paths = await getPaths({
793
+ ...options,
794
+ pluginName: manifest.name ?? "unknown",
795
+ verifySourceParts: !1,
796
+ verifyCompiledParts: !1
797
+ }), abs = (file) => path.isAbsolute(file) ? file : path.resolve(path.join(options.basePath, file)), exists = (file) => fs.existsSync(abs(file)), willExist = (file) => paths && hasSourceEquivalent(abs(file), paths), withinSourceDir = (file) => paths?.source && abs(file).startsWith(paths.source), withinTargetDir = (file) => paths?.compiled && abs(file).startsWith(paths.compiled);
798
+ for (let key of pathKeys) {
799
+ if (!(key in manifest)) continue;
800
+ let manifestValue = manifest[key];
801
+ if (typeof manifestValue != "string") throw Error(`Invalid package.json: "${key}" must be a string if defined`);
802
+ if (!options?.flags?.allowSourceTarget && paths && withinSourceDir(manifestValue)) throw Error(`Invalid package.json: "${key}" points to file within source (uncompiled) directory. Use --allow-source-target if you really want to do this.`);
803
+ if (exists(manifestValue) && paths && withinTargetDir(manifestValue) && !await willExist(manifestValue)) throw Error(`Invalid package.json: "${key}" points to file that will not exist after compiling`);
804
+ if (!exists(manifestValue) && !await willExist(manifestValue)) {
805
+ if (!paths) throw Error(`Invalid package.json: "${key}" points to file that does not exist`);
806
+ let inOutDir = paths.compiled && !abs(manifestValue).startsWith(paths.compiled);
807
+ throw Error(inOutDir ? `Invalid package.json: "${key}" points to file that does not exist, and "paths" is not configured to compile to this location` : `Invalid package.json: "${key}" points to file that does not exist, and no equivalent is found in source directory`);
808
+ }
809
+ }
897
810
  }
898
811
  function isObject(obj) {
899
- return !Array.isArray(obj) && obj !== null && typeof obj == "object";
812
+ return !Array.isArray(obj) && typeof obj == "object" && !!obj;
900
813
  }
901
814
  function validateLockFiles(options) {
902
- const npm = fs.existsSync(path.join(options.basePath, "package-lock.json")), yarn = fs.existsSync(path.join(options.basePath, "yarn.lock"));
903
- if (npm && yarn)
904
- throw new Error("Invalid plugin: contains both package-lock.json and yarn.lock");
815
+ let npm = fs.existsSync(path.join(options.basePath, "package-lock.json")), yarn = fs.existsSync(path.join(options.basePath, "yarn.lock"));
816
+ if (npm && yarn) throw Error("Invalid plugin: contains both package-lock.json and yarn.lock");
905
817
  }
906
818
  async function writePackageJson(data, options) {
907
- const { user, pluginName, license, description, pkg: prevPkg, gitOrigin } = data, {
908
- outDir,
909
- peerDependencies: addPeers,
910
- dependencies: addDeps,
911
- devDependencies: addDevDeps
912
- } = options, { flags } = options, prev = prevPkg || {}, usePrettier = flags.prettier !== !1, useEslint = flags.eslint !== !1, useTypescript = flags.eslint !== !1, newDevDependencies = [cliName, "@sanity/pkg-utils"];
913
- useTypescript && (log.debug("Using TypeScript. Adding to dev dependencies."), newDevDependencies.push("@types/react", "typescript")), usePrettier && (log.debug("Using prettier. Adding to dev dependencies."), newDevDependencies.push("prettier", "prettier-plugin-packagejson")), useEslint && (log.debug("Using eslint. Adding to dev dependencies."), newDevDependencies.push(
914
- "eslint",
915
- "eslint-config-sanity",
916
- "eslint-plugin-react",
917
- "eslint-plugin-react-hooks"
918
- ), usePrettier && newDevDependencies.push("eslint-config-prettier", "eslint-plugin-prettier"), useTypescript && newDevDependencies.push("@typescript-eslint/eslint-plugin", "@typescript-eslint/parser")), log.debug("Resolving latest versions for %s", newDevDependencies.join(", "));
919
- const dependencies = forceDependencyVersions(
920
- {
921
- ...prev.dependencies || {},
922
- ...addDeps || {},
923
- ...await resolveLatestVersions(defaultDependencies)
924
- },
925
- forcedPackageVersions
926
- ), devDependencies = forceDependencyVersions(
927
- {
928
- ...addDevDeps || {},
929
- ...prev.devDependencies || {},
930
- ...await resolveLatestVersions([...newDevDependencies, ...defaultDevDependencies])
931
- },
932
- forcedDevPackageVersions
933
- ), peerDependencies = forceDependencyVersions(
934
- {
935
- ...prev.peerDependencies || {},
936
- ...addPeers || {},
937
- ...await resolveLatestVersions(defaultPeerDependencies)
938
- },
939
- forcedPeerPackageVersions
940
- ), source = flags.typescript ? "./src/index.ts" : "./src/index.js", files = [outDir];
941
- files.sort();
942
- const forcedOrder = {
943
- name: pluginName,
944
- version: prev.version ?? "1.0.0",
945
- description: description || "",
946
- keywords: prev.keywords ?? ["sanity", "sanity-plugin"],
947
- ...urlsFromOrigin(gitOrigin),
948
- ...repoFromOrigin(gitOrigin),
949
- license: license ? license.id : "UNLICENSED",
950
- author: user?.email ? `${user.name} <${user.email}>` : user?.name,
951
- sideEffects: !1,
952
- type: "module",
953
- exports: {
954
- ".": {
955
- source,
956
- default: `./${outDir}/index.js`
957
- },
958
- "./package.json": "./package.json"
959
- },
960
- ...flags.typescript ? { types: `./${outDir}/index.d.ts` } : {},
961
- files,
962
- scripts: { ...prev.scripts },
963
- dependencies: sortKeys(dependencies),
964
- devDependencies: sortKeys(devDependencies),
965
- peerDependencies: sortKeys(peerDependencies),
966
- engines: {
967
- node: requiredNodeEngine
968
- }
969
- }, manifest = {
970
- ...forcedOrder,
971
- // Use already configured values by default (if not otherwise specified)
972
- ...prev || {},
973
- // We're de-declaring properties because of key order in package.json
974
- ...forcedOrder
975
- }, differs = JSON.stringify(prev) !== JSON.stringify(manifest);
976
- return log.debug("Does manifest differ? %s", differs ? "yes" : "no"), differs && await writePackageJsonDirect(manifest, options), differs ? manifest : prev;
819
+ let { user, pluginName, license, description, pkg: prevPkg, gitOrigin } = data, { outDir, peerDependencies: addPeers, dependencies: addDeps, devDependencies: addDevDeps } = options, { flags } = options, prev = prevPkg || {}, usePrettier = flags.prettier !== !1, useEslint = flags.eslint !== !1, useTypescript = flags.eslint !== !1, newDevDependencies = [cliName, "@sanity/pkg-utils"];
820
+ useTypescript && (log_default.debug("Using TypeScript. Adding to dev dependencies."), newDevDependencies.push("@types/react", "typescript")), usePrettier && (log_default.debug("Using prettier. Adding to dev dependencies."), newDevDependencies.push("prettier", "prettier-plugin-packagejson")), useEslint && (log_default.debug("Using eslint. Adding to dev dependencies."), newDevDependencies.push("eslint", "eslint-config-sanity", "eslint-plugin-react", "eslint-plugin-react-hooks"), usePrettier && newDevDependencies.push("eslint-config-prettier", "eslint-plugin-prettier"), useTypescript && newDevDependencies.push("@typescript-eslint/eslint-plugin", "@typescript-eslint/parser")), log_default.debug("Resolving latest versions for %s", newDevDependencies.join(", "));
821
+ let dependencies = forceDependencyVersions({
822
+ ...prev.dependencies || {},
823
+ ...addDeps || {},
824
+ ...await resolveLatestVersions(defaultDependencies)
825
+ }, forcedPackageVersions), devDependencies = forceDependencyVersions({
826
+ ...addDevDeps || {},
827
+ ...prev.devDependencies || {},
828
+ ...await resolveLatestVersions([...newDevDependencies, ...defaultDevDependencies])
829
+ }, forcedDevPackageVersions), peerDependencies = forceDependencyVersions({
830
+ ...prev.peerDependencies || {},
831
+ ...addPeers || {},
832
+ ...await resolveLatestVersions(defaultPeerDependencies)
833
+ }, forcedPeerPackageVersions), source = flags.typescript ? "./src/index.ts" : "./src/index.js", files = [outDir];
834
+ files.sort();
835
+ let forcedOrder = {
836
+ name: pluginName,
837
+ version: prev.version ?? "1.0.0",
838
+ description: description || "",
839
+ keywords: prev.keywords ?? ["sanity", "sanity-plugin"],
840
+ ...urlsFromOrigin(gitOrigin),
841
+ ...repoFromOrigin(gitOrigin),
842
+ license: license ? license.id : "UNLICENSED",
843
+ author: user?.email ? `${user.name} <${user.email}>` : user?.name,
844
+ sideEffects: !1,
845
+ type: "module",
846
+ exports: {
847
+ ".": {
848
+ source,
849
+ default: `./${outDir}/index.js`
850
+ },
851
+ "./package.json": "./package.json"
852
+ },
853
+ ...flags.typescript ? { types: `./${outDir}/index.d.ts` } : {},
854
+ files,
855
+ scripts: { ...prev.scripts },
856
+ dependencies: sortKeys(dependencies),
857
+ devDependencies: sortKeys(devDependencies),
858
+ peerDependencies: sortKeys(peerDependencies),
859
+ engines: { node: requiredNodeEngine }
860
+ }, manifest = {
861
+ ...forcedOrder,
862
+ ...prev || {},
863
+ ...forcedOrder
864
+ }, differs = JSON.stringify(prev) !== JSON.stringify(manifest);
865
+ return log_default.debug("Does manifest differ? %s", differs ? "yes" : "no"), differs && await writePackageJsonDirect(manifest, options), differs ? manifest : prev;
977
866
  }
978
867
  function urlsFromOrigin(gitOrigin) {
979
- if (!gitOrigin)
980
- return {};
981
- const details = githubUrlToObject(gitOrigin);
982
- return details ? {
983
- homepage: `https://github.com/${details.user}/${details.repo}#readme`,
984
- bugs: {
985
- url: `https://github.com/${details.user}/${details.repo}/issues`
986
- }
987
- } : {};
868
+ if (!gitOrigin) return {};
869
+ let details = githubUrlToObject(gitOrigin);
870
+ return details ? {
871
+ homepage: `https://github.com/${details.user}/${details.repo}#readme`,
872
+ bugs: { url: `https://github.com/${details.user}/${details.repo}/issues` }
873
+ } : {};
988
874
  }
989
875
  function repoFromOrigin(gitOrigin) {
990
- return gitOrigin ? {
991
- repository: {
992
- type: "git",
993
- url: gitOrigin
994
- }
995
- } : {};
876
+ return gitOrigin ? { repository: {
877
+ type: "git",
878
+ url: gitOrigin
879
+ } } : {};
996
880
  }
997
881
  function addScript(cmd, existing) {
998
- return existing && existing.includes(cmd) ? existing : cmd;
882
+ return existing && existing.includes(cmd) ? existing : cmd;
999
883
  }
1000
884
  async function addPackageJsonScripts(manifest, options, updateScripts) {
1001
- const originalScripts = manifest.scripts || {}, scripts = updateScripts({ ...originalScripts }), differs = Object.keys(scripts).some((key) => scripts[key] !== originalScripts[key]);
1002
- return differs && await writePackageJsonDirect({ ...manifest, scripts }, options), differs;
885
+ let originalScripts = manifest.scripts || {}, scripts = updateScripts({ ...originalScripts }), differs = Object.keys(scripts).some((key) => scripts[key] !== originalScripts[key]);
886
+ return differs && await writePackageJsonDirect({
887
+ ...manifest,
888
+ scripts
889
+ }, options), differs;
1003
890
  }
1004
891
  async function writePackageJsonDirect(manifest, { basePath }) {
1005
- await writeJsonFile(path.join(basePath, "package.json"), manifest);
892
+ await writeJsonFile(path.join(basePath, "package.json"), manifest);
1006
893
  }
1007
894
  async function addBuildScripts(manifest, options) {
1008
- return options.flags.scripts ? addPackageJsonScripts(manifest, options, (scripts) => (scripts.build = addScript(expectedScripts.build, scripts.build), scripts.format = addScript("prettier --write --cache --ignore-unknown .", scripts.format), scripts["link-watch"] = addScript(expectedScripts["link-watch"], scripts["link-watch"]), scripts.lint = addScript("eslint .", scripts.lint), scripts.prepublishOnly = addScript(expectedScripts.prepublishOnly, scripts.prepublishOnly), scripts.watch = addScript(expectedScripts.watch, scripts.watch), scripts)) : !1;
895
+ return options.flags.scripts ? addPackageJsonScripts(manifest, options, (scripts) => (scripts.build = addScript(expectedScripts.build, scripts.build), scripts.format = addScript("prettier --write --cache --ignore-unknown .", scripts.format), scripts["link-watch"] = addScript(expectedScripts["link-watch"], scripts["link-watch"]), scripts.lint = addScript("eslint .", scripts.lint), scripts.prepublishOnly = addScript(expectedScripts.prepublishOnly, scripts.prepublishOnly), scripts.watch = addScript(expectedScripts.watch, scripts.watch), scripts)) : !1;
1009
896
  }
1010
897
  function sortKeys(unordered) {
1011
- return Object.keys(unordered).sort().reduce((obj, key) => (obj[key] = unordered[key], obj), {});
898
+ return Object.keys(unordered).sort().reduce((obj, key) => (obj[key] = unordered[key], obj), {});
1012
899
  }
900
+ /** @internal */
1013
901
  function forceDependencyVersions(deps, versions = forcedPackageVersions) {
1014
- const entries = Object.entries(deps).map((entry) => {
1015
- const [pkg2] = entry, forceVersion = versions[pkg2];
1016
- return forceVersion ? [pkg2, forceVersion] : entry;
1017
- });
1018
- return Object.fromEntries(entries);
1019
- }
1020
- export {
1021
- addBuildScripts,
1022
- addPackageJsonScripts,
1023
- addScript,
1024
- copyFileWithOverwritePrompt,
1025
- disallowDuplicateEslintConfig,
1026
- disallowDuplicatePrettierConfig,
1027
- ensureDir,
1028
- errorToUndefined,
1029
- fileExists,
1030
- findStudioV3Config,
1031
- forceDependencyVersions,
1032
- forcedDevPackageVersions,
1033
- forcedPackageVersions,
1034
- getPackage,
1035
- hasSanityJson,
1036
- isEmptyish,
1037
- mergedPackages,
1038
- mkdir,
1039
- prompt,
1040
- promptForPackageName,
1041
- promptForRepoOrigin,
1042
- readFile$2 as readFile,
1043
- readJsonFile,
1044
- resolveLatestVersions,
1045
- sortKeys,
1046
- validateBabelConfig,
1047
- validateBannedFiles,
1048
- validateDeprecatedDependencies,
1049
- validateEsmOnly,
1050
- validateIncompatiblePlugin,
1051
- validateNodeEngine,
1052
- validatePackageName$1 as validatePackageName,
1053
- validatePackageType,
1054
- validatePkgUtilsDependency,
1055
- validatePkgUtilsVersion,
1056
- validateSanityDependencies,
1057
- validateScripts,
1058
- validateSrcIndexFile,
1059
- validateStudioConfig,
1060
- validateTsConfig,
1061
- writeFile,
1062
- writeFileWithOverwritePrompt,
1063
- writePackageJson,
1064
- writePackageJsonDirect
1065
- };
1066
- //# sourceMappingURL=package.js.map
902
+ let entries = Object.entries(deps).map((entry) => {
903
+ let [pkg] = entry, forceVersion = versions[pkg];
904
+ return forceVersion ? [pkg, forceVersion] : entry;
905
+ });
906
+ return Object.fromEntries(entries);
907
+ }
908
+ export { validateStudioConfig as A, writeFileWithOverwritePrompt as B, validatePackageName$1 as C, validateSanityDependencies as D, validatePkgUtilsVersion as E, isEmptyish as F, promptForPackageName as H, mkdir as I, readFile$2 as L, copyFileWithOverwritePrompt as M, ensureDir as N, validateScripts as O, fileExists as P, readJsonFile as R, validateNodeEngine as S, validatePkgUtilsDependency as T, promptForRepoOrigin as U, prompt as V, mergedPackages as W, validateBabelConfig as _, getPackage as a, validateEsmOnly as b, writePackageJsonDirect as c, hasSanityJson as d, errorToUndefined as f, disallowDuplicatePrettierConfig as g, disallowDuplicateEslintConfig as h, forceDependencyVersions as i, validateTsConfig as j, validateSrcIndexFile as k, resolveLatestVersions as l, forcedPackageVersions as m, addPackageJsonScripts as n, sortKeys as o, forcedDevPackageVersions as p, addScript as r, writePackageJson as s, addBuildScripts as t, findStudioV3Config as u, validateBannedFiles as v, validatePackageType as w, validateIncompatiblePlugin as x, validateDeprecatedDependencies as y, writeFile as z };
909
+
910
+ //# sourceMappingURL=package.js.map