@sanity/plugin-kit 5.0.3 → 6.0.1

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.
@@ -13,7 +13,7 @@ import pAny from "p-any";
13
13
  import { URL } from "url";
14
14
  import inquirer from "inquirer";
15
15
  import { pkg } from "./package2.js";
16
- import getLatestVersion from "get-latest-version";
16
+ import { getLatestVersion } from "get-latest-version";
17
17
  import pProps from "p-props";
18
18
  const mergedPackages = [
19
19
  "@sanity/base",
@@ -274,6 +274,46 @@ function validatePackageType({ type }) {
274
274
  `.trimStart()
275
275
  ];
276
276
  }
277
+ 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;
288
+ }
289
+ function formatExportsPath(segments) {
290
+ return `exports${segments.map((segment) => `[${JSON.stringify(segment)}]`).join("")}`;
291
+ }
292
+ 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`
300
+ package.json ships CommonJS (CJS) output, but Sanity plugins target Sanity Studio v5+, which is pure ESM.
301
+
302
+ Remove the following so the package stays ESM-only:
303
+ ${offenders.join(`
304
+ `)}
305
+
306
+ Supporting CJS is not worth it:
307
+ - It can have unintended side-effects.
308
+ - The Node.js versions plugin-kit supports (${requiredNodeEngine}) fully support require(esm), so a
309
+ consumer that still uses require() loads the ESM build directly — which is far more predictable.
310
+ - Publishing a single format guarantees two copies of the plugin's code (ESM + CJS) can't both end up
311
+ in the module tree, bloating bundles and slowing down builds.
312
+
313
+ Rely on "exports" together with "type": "module", and drop "main", "module" and any "require" conditions.
314
+ `.trimStart()
315
+ ] : [];
316
+ }
277
317
  function validatePkgUtilsDependency({ devDependencies }) {
278
318
  return devDependencies?.["@sanity/pkg-utils"] ? [] : [
279
319
  outdent`
@@ -437,52 +477,60 @@ async function validateStudioConfig({ basePath }) {
437
477
 
438
478
  `)] : [];
439
479
  }
440
- async function validatePluginSanityJson({
480
+ async function validateIncompatiblePlugin({
441
481
  basePath,
442
482
  packageJson
443
483
  }) {
444
- const sanityJson = await readJson5File({ basePath, filename: "sanity.json" }), expectedDefaults = {
445
- parts: [
446
- {
447
- implements: "part:@sanity/base/sanity-root",
448
- path: "./v2-incompatible.js"
449
- }
450
- ]
451
- }, hasSinglePart = sanityJson && Object.keys(sanityJson).length === 1 && sanityJson?.parts && sanityJson.parts.length === 1, firstPart = hasSinglePart ? sanityJson?.parts?.[0] : void 0, correctImplements = firstPart?.implements === expectedDefaults.parts[0].implements, pathExists = firstPart?.path && await fileExists(path.normalize(path.join(basePath, firstPart.path))), hasDependency = !!packageJson.dependencies?.[incompatiblePluginPackage];
452
- if (!(sanityJson && hasSinglePart && correctImplements && pathExists && hasDependency)) {
453
- const errors = [
454
- sanityJson ? null : "sanity.json does not exist",
455
- hasSinglePart ? null : 'sanity.json should have exactly one entry in "parts", but did not.',
456
- correctImplements ? null : `The part should implement ${expectedDefaults.parts[0].implements}, but did not.`,
457
- firstPart?.path && !pathExists ? `The file in "path", ${firstPart?.path}, does not exist.` : null,
458
- hasDependency ? null : outdent`
459
- package.json should have ${incompatiblePluginPackage} as a dependency, but did not.
460
- Install it with: npm install --save ${incompatiblePluginPackage}
461
- `.trimStart()
462
- ].filter((e) => !!e);
463
- return [
464
- outdent`
465
- Invalid sanity.json. It is used for compatibility checking in V2 studios:
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`
496
+ ${incompatiblePluginPackage} is no longer used and should be removed.
466
497
 
467
- - ${errors.join(`
468
- - `)}
498
+ It only rendered an error dialog in the long end-of-life Sanity Studio v2 when a v3 plugin was
499
+ installed there. That compatibility shim is now obsolete, so plugin-kit no longer adds it.
500
+
501
+ Found:
502
+ ${found.join(`
503
+ `)}
469
504
 
470
- sanity.json will only be used when incorrectly installing a v3 plugin in a v2 Studio.
505
+ To fix this:
506
+ - Remove "${incompatiblePluginPackage}" from package.json (dependencies/devDependencies/peerDependencies)
507
+ - Delete the v2-incompatible.js file
508
+ - Delete sanity.json (if it only contains the v2-incompatible "part")
509
+ - Remove "sanity.json" and "v2-incompatible.js" from the package.json "files" array
471
510
 
472
- This check ensures that sanity.json conforms with the usage section of
473
- ${urls.incompatiblePlugin}
511
+ For more, see ${urls.incompatiblePlugin}
474
512
  `.trimStart()
475
- ];
476
- }
477
- return [];
513
+ ];
478
514
  }
479
515
  function validatePackageName$1(packageJson) {
480
- const valid = validateNpmPackageName(
481
- packageJson.name
482
- );
516
+ const valid = validateNpmPackageName(packageJson.name ?? "");
483
517
  return valid.validForNewPackages ? !packageJson.name?.startsWith("@") && !packageJson.name?.startsWith("sanity-plugin-") ? [
484
518
  'Invalid package.json: "name" should be prefixed with "sanity-plugin-" (or scoped - @your-company/plugin-name)'
485
- ] : [] : [`Invalid package.json: "name" is invalid: ${valid.errors.join(", ")}`];
519
+ ] : [] : [`Invalid package.json: "name" is invalid: ${(valid.errors ?? valid.warnings ?? []).join(", ")}`];
520
+ }
521
+ 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`
525
+ package.json "files" must not include "src".
526
+
527
+ Plugins built with @sanity/plugin-kit publish the compiled output in "dist" (and any v2-compatibility files).
528
+ Shipping the "src" directory bloats the published package and can cause bundlers that resolve the
529
+ "source" export condition to import raw, uncompiled TypeScript.
530
+
531
+ Please remove "src" from the "files" array in package.json.
532
+ `.trimStart()
533
+ ] : [] : [];
486
534
  }
487
535
  async function validateSrcIndexFile(basePath) {
488
536
  const paths = ["index.js", "index.ts"].map((p) => path.join("src", p)), allowedIndexFiles = paths.map((file) => path.join(basePath, file));
@@ -563,7 +611,7 @@ const forcedPackageVersions = {}, forcedDevPackageVersions = {}, forcedPeerPacka
563
611
  "react-dom": "^18",
564
612
  "@types/react": "^18",
565
613
  "@types/react-dom": "^18",
566
- sanity: "^3",
614
+ sanity: "^5 || ^6.0.0-0",
567
615
  "styled-components": "^5.2"
568
616
  };
569
617
  function errorToUndefined(err) {
@@ -761,7 +809,7 @@ function resolveLatestVersions(packages) {
761
809
  function rangeify(version) {
762
810
  return `^${version}`;
763
811
  }
764
- const defaultDependencies = [incompatiblePluginPackage], defaultDevDependencies = [
812
+ const defaultDependencies = [], defaultDevDependencies = [
765
813
  "sanity",
766
814
  // peer dependencies of `sanity`
767
815
  "react",
@@ -808,11 +856,9 @@ async function validatePluginPackage(manifest, options) {
808
856
  function validatePackageName(manifest) {
809
857
  if (typeof manifest.name != "string")
810
858
  throw new Error('Invalid package.json: "name" must be a string');
811
- const valid = validateNpmPackageName(
812
- manifest.name
813
- );
859
+ const valid = validateNpmPackageName(manifest.name);
814
860
  if (!valid.validForNewPackages)
815
- throw new Error(`Invalid package.json: "name" is invalid: ${valid.errors.join(", ")}`);
861
+ throw new Error(`Invalid package.json: "name" is invalid: ${(valid.errors ?? []).join(", ")}`);
816
862
  if (manifest.name[0] !== "@" && !manifest.name.startsWith("sanity-plugin-"))
817
863
  throw new Error(
818
864
  'Invalid package.json: "name" should be prefixed with "sanity-plugin-" (or scoped - @your-company/plugin-name)'
@@ -891,7 +937,7 @@ async function writePackageJson(data, options) {
891
937
  ...await resolveLatestVersions(defaultPeerDependencies)
892
938
  },
893
939
  forcedPeerPackageVersions
894
- ), source = flags.typescript ? "./src/index.ts" : "./src/index.js", files = [outDir, "sanity.json", "src", "v2-incompatible.js"];
940
+ ), source = flags.typescript ? "./src/index.ts" : "./src/index.js", files = [outDir];
895
941
  files.sort();
896
942
  const forcedOrder = {
897
943
  name: pluginName,
@@ -930,6 +976,8 @@ async function writePackageJson(data, options) {
930
976
  return log.debug("Does manifest differ? %s", differs ? "yes" : "no"), differs && await writePackageJsonDirect(manifest, options), differs ? manifest : prev;
931
977
  }
932
978
  function urlsFromOrigin(gitOrigin) {
979
+ if (!gitOrigin)
980
+ return {};
933
981
  const details = githubUrlToObject(gitOrigin);
934
982
  return details ? {
935
983
  homepage: `https://github.com/${details.user}/${details.repo}#readme`,
@@ -996,13 +1044,15 @@ export {
996
1044
  resolveLatestVersions,
997
1045
  sortKeys,
998
1046
  validateBabelConfig,
1047
+ validateBannedFiles,
999
1048
  validateDeprecatedDependencies,
1049
+ validateEsmOnly,
1050
+ validateIncompatiblePlugin,
1000
1051
  validateNodeEngine,
1001
1052
  validatePackageName$1 as validatePackageName,
1002
1053
  validatePackageType,
1003
1054
  validatePkgUtilsDependency,
1004
1055
  validatePkgUtilsVersion,
1005
- validatePluginSanityJson,
1006
1056
  validateSanityDependencies,
1007
1057
  validateScripts,
1008
1058
  validateSrcIndexFile,