@sanity/plugin-kit 0.0.1-studio-v3.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.
Files changed (194) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +398 -0
  3. package/assets/splat/LICENSE +21 -0
  4. package/assets/splat/editorconfig +13 -0
  5. package/assets/splat/eslint.config.js +5 -0
  6. package/assets/splat/gitignore +55 -0
  7. package/assets/splat/npmignore +9 -0
  8. package/assets/splat/prettierrc.js +6 -0
  9. package/assets/splat/sanity.json +8 -0
  10. package/assets/splat/template-tsconfig.json +23 -0
  11. package/assets/splat/v2-incompatible.js.template +11 -0
  12. package/lib/package.json +127 -0
  13. package/lib/src/actions/init.d.ts +65 -0
  14. package/lib/src/actions/init.js +83 -0
  15. package/lib/src/actions/init.js.map +1 -0
  16. package/lib/src/actions/link-watch.d.ts +3 -0
  17. package/lib/src/actions/link-watch.js +69 -0
  18. package/lib/src/actions/link-watch.js.map +1 -0
  19. package/lib/src/actions/splat.d.ts +26 -0
  20. package/lib/src/actions/splat.js +296 -0
  21. package/lib/src/actions/splat.js.map +1 -0
  22. package/lib/src/actions/verify/types.d.ts +77 -0
  23. package/lib/src/actions/verify/types.js +3 -0
  24. package/lib/src/actions/verify/types.js.map +1 -0
  25. package/lib/src/actions/verify/validations.d.ts +28 -0
  26. package/lib/src/actions/verify/validations.js +379 -0
  27. package/lib/src/actions/verify/validations.js.map +1 -0
  28. package/lib/src/actions/verify/verify-common.d.ts +43 -0
  29. package/lib/src/actions/verify/verify-common.js +88 -0
  30. package/lib/src/actions/verify/verify-common.js.map +1 -0
  31. package/lib/src/actions/verify-package.d.ts +5 -0
  32. package/lib/src/actions/verify-package.js +72 -0
  33. package/lib/src/actions/verify-package.js.map +1 -0
  34. package/lib/src/actions/verify-studio.d.ts +5 -0
  35. package/lib/src/actions/verify-studio.js +55 -0
  36. package/lib/src/actions/verify-studio.js.map +1 -0
  37. package/lib/src/actions/verify.d.ts +0 -0
  38. package/lib/src/actions/verify.js +330 -0
  39. package/lib/src/actions/verify.js.map +1 -0
  40. package/lib/src/cli.d.ts +2 -0
  41. package/lib/src/cli.js +86 -0
  42. package/lib/src/cli.js.map +1 -0
  43. package/lib/src/cmds/index.d.ts +8 -0
  44. package/lib/src/cmds/index.js +12 -0
  45. package/lib/src/cmds/index.js.map +1 -0
  46. package/lib/src/cmds/init.d.ts +4 -0
  47. package/lib/src/cmds/init.js +90 -0
  48. package/lib/src/cmds/init.js.map +1 -0
  49. package/lib/src/cmds/link-watch.d.ts +4 -0
  50. package/lib/src/cmds/link-watch.js +49 -0
  51. package/lib/src/cmds/link-watch.js.map +1 -0
  52. package/lib/src/cmds/splat.d.ts +4 -0
  53. package/lib/src/cmds/splat.js +63 -0
  54. package/lib/src/cmds/splat.js.map +1 -0
  55. package/lib/src/cmds/verify-package.d.ts +4 -0
  56. package/lib/src/cmds/verify-package.js +38 -0
  57. package/lib/src/cmds/verify-package.js.map +1 -0
  58. package/lib/src/cmds/verify-studio.d.ts +4 -0
  59. package/lib/src/cmds/verify-studio.js +38 -0
  60. package/lib/src/cmds/verify-studio.js.map +1 -0
  61. package/lib/src/cmds/verify.d.ts +0 -0
  62. package/lib/src/cmds/verify.js +42 -0
  63. package/lib/src/cmds/verify.js.map +1 -0
  64. package/lib/src/cmds/version.d.ts +4 -0
  65. package/lib/src/cmds/version.js +55 -0
  66. package/lib/src/cmds/version.js.map +1 -0
  67. package/lib/src/configs/buildExtensions.d.ts +1 -0
  68. package/lib/src/configs/buildExtensions.js +5 -0
  69. package/lib/src/configs/buildExtensions.js.map +1 -0
  70. package/lib/src/configs/default-source.d.ts +3 -0
  71. package/lib/src/configs/default-source.js +70 -0
  72. package/lib/src/configs/default-source.js.map +1 -0
  73. package/lib/src/configs/merged-packages.d.ts +1 -0
  74. package/lib/src/configs/merged-packages.js +24 -0
  75. package/lib/src/configs/merged-packages.js.map +1 -0
  76. package/lib/src/configs/uselessFiles.d.ts +1 -0
  77. package/lib/src/configs/uselessFiles.js +33 -0
  78. package/lib/src/configs/uselessFiles.js.map +1 -0
  79. package/lib/src/constants.d.ts +11 -0
  80. package/lib/src/constants.js +15 -0
  81. package/lib/src/constants.js.map +1 -0
  82. package/lib/src/dependencies/find.d.ts +0 -0
  83. package/lib/src/dependencies/find.js +195 -0
  84. package/lib/src/dependencies/find.js.map +1 -0
  85. package/lib/src/dependencies/import-linter.d.ts +3 -0
  86. package/lib/src/dependencies/import-linter.js +112 -0
  87. package/lib/src/dependencies/import-linter.js.map +1 -0
  88. package/lib/src/index.d.ts +2 -0
  89. package/lib/src/index.js +6 -0
  90. package/lib/src/index.js.map +1 -0
  91. package/lib/src/npm/manager.d.ts +7 -0
  92. package/lib/src/npm/manager.js +62 -0
  93. package/lib/src/npm/manager.js.map +1 -0
  94. package/lib/src/npm/package.d.ts +8 -0
  95. package/lib/src/npm/package.js +288 -0
  96. package/lib/src/npm/package.js.map +1 -0
  97. package/lib/src/npm/publish.d.ts +1 -0
  98. package/lib/src/npm/publish.js +14 -0
  99. package/lib/src/npm/publish.js.map +1 -0
  100. package/lib/src/npm/resolveLatestVersions.d.ts +3 -0
  101. package/lib/src/npm/resolveLatestVersions.js +35 -0
  102. package/lib/src/npm/resolveLatestVersions.js.map +1 -0
  103. package/lib/src/sanity/manifest.d.ts +48 -0
  104. package/lib/src/sanity/manifest.js +263 -0
  105. package/lib/src/sanity/manifest.js.map +1 -0
  106. package/lib/src/sharedFlags.d.ts +15 -0
  107. package/lib/src/sharedFlags.js +17 -0
  108. package/lib/src/sharedFlags.js.map +1 -0
  109. package/lib/src/util/command-parser.d.ts +9 -0
  110. package/lib/src/util/command-parser.js +41 -0
  111. package/lib/src/util/command-parser.js.map +1 -0
  112. package/lib/src/util/errorToUndefined.d.ts +1 -0
  113. package/lib/src/util/errorToUndefined.js +11 -0
  114. package/lib/src/util/errorToUndefined.js.map +1 -0
  115. package/lib/src/util/files.d.ts +36 -0
  116. package/lib/src/util/files.js +253 -0
  117. package/lib/src/util/files.js.map +1 -0
  118. package/lib/src/util/log.d.ts +14 -0
  119. package/lib/src/util/log.js +36 -0
  120. package/lib/src/util/log.js.map +1 -0
  121. package/lib/src/util/prompt.d.ts +13 -0
  122. package/lib/src/util/prompt.js +75 -0
  123. package/lib/src/util/prompt.js.map +1 -0
  124. package/lib/src/util/readme.d.ts +5 -0
  125. package/lib/src/util/readme.js +73 -0
  126. package/lib/src/util/readme.js.map +1 -0
  127. package/lib/src/util/request.d.ts +1 -0
  128. package/lib/src/util/request.js +19 -0
  129. package/lib/src/util/request.js.map +1 -0
  130. package/lib/src/util/user.d.ts +10 -0
  131. package/lib/src/util/user.js +106 -0
  132. package/lib/src/util/user.js.map +1 -0
  133. package/lib/test/cli.test.d.ts +1 -0
  134. package/lib/test/cli.test.js +64 -0
  135. package/lib/test/cli.test.js.map +1 -0
  136. package/lib/test/fixture-utils.d.ts +25 -0
  137. package/lib/test/fixture-utils.js +67 -0
  138. package/lib/test/fixture-utils.js.map +1 -0
  139. package/lib/test/init-verify-build.test.d.ts +1 -0
  140. package/lib/test/init-verify-build.test.js +75 -0
  141. package/lib/test/init-verify-build.test.js.map +1 -0
  142. package/lib/test/init.test.d.ts +1 -0
  143. package/lib/test/init.test.js +137 -0
  144. package/lib/test/init.test.js.map +1 -0
  145. package/lib/test/run-test-command.d.ts +1 -0
  146. package/lib/test/run-test-command.js +6 -0
  147. package/lib/test/run-test-command.js.map +1 -0
  148. package/lib/test/verify-package.test.d.ts +1 -0
  149. package/lib/test/verify-package.test.js +81 -0
  150. package/lib/test/verify-package.test.js.map +1 -0
  151. package/lib/test/version.test.d.ts +1 -0
  152. package/lib/test/version.test.js +48 -0
  153. package/lib/test/version.test.js.map +1 -0
  154. package/package.json +127 -0
  155. package/src/actions/init.ts +104 -0
  156. package/src/actions/link-watch.ts +74 -0
  157. package/src/actions/splat.ts +366 -0
  158. package/src/actions/verify/types.ts +84 -0
  159. package/src/actions/verify/validations.ts +401 -0
  160. package/src/actions/verify/verify-common.ts +92 -0
  161. package/src/actions/verify-package.ts +87 -0
  162. package/src/actions/verify-studio.ts +55 -0
  163. package/src/actions/verify.ts +328 -0
  164. package/src/cli.ts +77 -0
  165. package/src/cmds/index.ts +9 -0
  166. package/src/cmds/init.ts +85 -0
  167. package/src/cmds/link-watch.ts +51 -0
  168. package/src/cmds/splat.ts +59 -0
  169. package/src/cmds/verify-package.ts +36 -0
  170. package/src/cmds/verify-studio.ts +36 -0
  171. package/src/cmds/verify.ts +40 -0
  172. package/src/cmds/version.ts +67 -0
  173. package/src/configs/buildExtensions.ts +1 -0
  174. package/src/configs/default-source.ts +68 -0
  175. package/src/configs/merged-packages.ts +20 -0
  176. package/src/configs/uselessFiles.ts +29 -0
  177. package/src/constants.ts +13 -0
  178. package/src/dependencies/find.ts +193 -0
  179. package/src/dependencies/import-linter.ts +103 -0
  180. package/src/index.ts +4 -0
  181. package/src/npm/manager.ts +44 -0
  182. package/src/npm/package.ts +370 -0
  183. package/src/npm/publish.ts +9 -0
  184. package/src/npm/resolveLatestVersions.ts +26 -0
  185. package/src/sanity/manifest.ts +340 -0
  186. package/src/sharedFlags.ts +14 -0
  187. package/src/util/command-parser.ts +31 -0
  188. package/src/util/errorToUndefined.ts +7 -0
  189. package/src/util/files.ts +249 -0
  190. package/src/util/log.ts +44 -0
  191. package/src/util/prompt.ts +70 -0
  192. package/src/util/readme.ts +72 -0
  193. package/src/util/request.ts +13 -0
  194. package/src/util/user.ts +110 -0
@@ -0,0 +1,84 @@
1
+ import {VerifyPackageConfig} from './verify-common'
2
+
3
+ export interface SanityPlugin {
4
+ verifyPackage?: VerifyPackageConfig
5
+ }
6
+
7
+ export interface PackageJson {
8
+ name?: string
9
+ version?: string
10
+ description?: string
11
+ author?: string
12
+ source?: string
13
+ exports?: {
14
+ [index: string]:
15
+ | {
16
+ require?: string
17
+ default?: string
18
+ }
19
+ | undefined
20
+ }
21
+ main?: string
22
+ module?: string
23
+ types?: string
24
+ typings?: string
25
+ browser?: string
26
+ files?: string[]
27
+ scripts?: Record<string, string>
28
+ dependencies?: Record<string, string>
29
+ peerDependencies?: Record<string, string>
30
+ devDependencies?: Record<string, string>
31
+ sanityPlugin?: SanityPlugin
32
+ engines?: {
33
+ node?: string
34
+ }
35
+ keywords?: string[]
36
+ repository?: {url?: string}
37
+
38
+ [index: string]: unknown
39
+ }
40
+
41
+ export interface CompilerOptions {
42
+ jsx?: string
43
+ moduleResolution?: string
44
+ target?: string
45
+ module?: string
46
+ sourceMap?: boolean
47
+ inlineSourceMap?: boolean
48
+ esModuleInterop?: boolean
49
+ skipLibCheck?: boolean
50
+ isolatedModules?: boolean
51
+ downlevelIteration?: boolean
52
+ declaration?: boolean
53
+ allowSyntheticDefaultImports?: boolean
54
+ outDir?: string
55
+ baseUrl?: string
56
+ checkJs?: false
57
+ }
58
+
59
+ export interface TsConfig {
60
+ compilerOptions?: CompilerOptions
61
+ include?: string[]
62
+ }
63
+
64
+ export interface SanityV2Json {
65
+ parts?: [
66
+ {
67
+ implements?: string
68
+ path?: 'string'
69
+ }
70
+ ]
71
+ }
72
+
73
+ export interface SanityStudioJson {
74
+ root?: boolean
75
+ project?: {
76
+ name?: string
77
+ }
78
+ api?: {
79
+ projectId?: string
80
+ dataset?: string
81
+ }
82
+ plugins?: string[]
83
+ parts?: Record<string, unknown>[]
84
+ }
@@ -0,0 +1,401 @@
1
+ import outdent from 'outdent'
2
+ // @ts-expect-error missing types
3
+ import validateNpmPackageName from 'validate-npm-package-name'
4
+ // @ts-expect-error missing types
5
+ import findBabelConfig from 'find-babel-config'
6
+ import {incompatiblePluginPackage, urls} from '../../constants'
7
+ import {mergedPackages} from '../../configs/merged-packages'
8
+ import path from 'path'
9
+ import {fileExists, readFileContent, readJson5File} from '../../util/files'
10
+ import chalk from 'chalk'
11
+ import {CompilerOptions, PackageJson, SanityStudioJson, SanityV2Json, TsConfig} from './types'
12
+
13
+ export const expectedScripts = {
14
+ prebuild: `plugin-kit verify-package --silent`,
15
+ build: 'parcel build',
16
+ watch: 'parcel watch',
17
+ 'link-watch': 'plugin-kit link-watch',
18
+ prepublishOnly: 'npm run build',
19
+ }
20
+ const expectedModulesFields = ['source', 'exports', 'main', 'module', 'files']
21
+ const expectedCompilerOptions = {
22
+ jsx: 'preserve',
23
+ moduleResolution: 'node',
24
+ target: 'esnext',
25
+ module: 'esnext',
26
+ sourceMap: false,
27
+ inlineSourceMap: false,
28
+ esModuleInterop: true,
29
+ skipLibCheck: true,
30
+ isolatedModules: true,
31
+ downlevelIteration: true,
32
+ declaration: true,
33
+ allowSyntheticDefaultImports: true,
34
+ //outDir: 'lib',
35
+ //baseUrl: '.',
36
+ //checkJs: false,
37
+ }
38
+
39
+ export function validateNodeEngine(packageJson: PackageJson) {
40
+ const nodeVersionRange = '>=14.0.0'
41
+ if (packageJson.engines?.node !== nodeVersionRange) {
42
+ return [
43
+ outdent`
44
+ Expected package.json to contain engines.node: ">=14.0.0" to ensure Studio compatible builds,
45
+ but it was: ${packageJson.engines?.node}
46
+
47
+ Please add the following to package.json:
48
+
49
+ "engines": {
50
+ "node": "${nodeVersionRange}"
51
+ }`.trimStart(),
52
+ ]
53
+ }
54
+ }
55
+
56
+ export function validateModule(packageJson: PackageJson): string[] {
57
+ const errors: string[] = []
58
+
59
+ const missingFields = expectedModulesFields.filter((field) => !packageJson[field])
60
+
61
+ if (missingFields.length) {
62
+ errors.push(
63
+ outdent`
64
+ Expected source, exports, main, module and files entries in package.json, but ${missingFields.join(
65
+ ', '
66
+ )} where missing.
67
+
68
+ Example:
69
+
70
+ Given a plugin with entry-point in src/index.ts, using default parcel build command,
71
+ package.json should contain the following entries to ensure that cjs and esm outputs are built into lib:
72
+
73
+ "source": "./src/index.ts",
74
+ "exports": {
75
+ ".": {
76
+ "require": "./lib/cjs/index.js",
77
+ "default": "./lib/esm/index.js"
78
+ }
79
+ },
80
+ "main": "./lib/cjs/index.js",
81
+ "module": "./lib/esm/index.js",
82
+ "types": "./lib/types/index.d.ts",
83
+ "files": [
84
+ "src",
85
+ "lib"
86
+ ],
87
+
88
+ Refer to Parcel library targets for more: https://parceljs.org/features/targets/#library-targets
89
+ `.trimStart()
90
+ )
91
+ }
92
+ return errors
93
+ }
94
+
95
+ export function validateScripts(packageJson: PackageJson): string[] {
96
+ const errors: string[] = []
97
+
98
+ const divergentScripts = Object.entries(expectedScripts).filter(([key, expectedCommand]) => {
99
+ const command = packageJson.scripts?.[key]
100
+ // check for includes instead of equals to give some leniency in command params and such
101
+ return !command || !command.includes(expectedCommand)
102
+ })
103
+
104
+ if (divergentScripts.length) {
105
+ errors.push(
106
+ outdent`
107
+ The following script commands did not contain expected defaults: ${divergentScripts
108
+ .map(([key]) => key)
109
+ .join(', ')}
110
+
111
+ This checks for that the commands-strings includes these terms.
112
+ For example, this will validate ok:
113
+ "prebuild": "npm run clean && ${expectedScripts.prebuild}",
114
+
115
+ Please add the following to your package.json "scripts":
116
+
117
+ ${divergentScripts.map(([key, value]) => `"${key}": "${value}"`).join(',\n')}
118
+ `.trimStart()
119
+ )
120
+ }
121
+ return errors
122
+ }
123
+
124
+ export async function validateTsConfig(tsConfig: TsConfig) {
125
+ const errors: string[] = []
126
+ const options = tsConfig.compilerOptions ?? {}
127
+ const wrongEntries = Object.entries(expectedCompilerOptions).filter(([key, value]) => {
128
+ const option = options[key as keyof CompilerOptions]
129
+ return typeof value === 'string' && typeof option === 'string'
130
+ ? value.toLowerCase() !== option?.toLowerCase()
131
+ : value !== option
132
+ })
133
+
134
+ if (wrongEntries.length) {
135
+ const expectedOutput = wrongEntries
136
+ .map(([key, value]) => `"${key}": ${typeof value === 'string' ? `"${value}"` : value},`)
137
+ .join('\n')
138
+
139
+ errors.push(
140
+ outdent`
141
+ Recommended tsconfig.json compilerOptions missing:
142
+
143
+ The following fields had unexpected values: [${wrongEntries.map(([key]) => key).join(', ')}]
144
+ Expected to find these values:
145
+ ${expectedOutput}
146
+
147
+ Please update your tsconfig.json accordingly.
148
+ `.trimStart()
149
+ )
150
+ }
151
+
152
+ return errors
153
+ }
154
+
155
+ export function validateParcelDependency({devDependencies}: PackageJson): string[] {
156
+ if (!devDependencies?.parcel) {
157
+ return [
158
+ outdent`
159
+ package.json does not list parcel as a devDependency.
160
+
161
+ Please add it by running 'npm install --save-dev parcel'.
162
+ `.trimStart(),
163
+ ]
164
+ }
165
+ return []
166
+ }
167
+
168
+ export function validateSanityDependencies(packageJson: PackageJson): string[] {
169
+ const {dependencies, devDependencies, peerDependencies} = packageJson
170
+ const allDependencies = {...dependencies, ...devDependencies, ...peerDependencies}
171
+
172
+ const illegalDeps = Object.keys(allDependencies).filter((dep) => mergedPackages.includes(dep))
173
+ const deps = new Set<string>(illegalDeps)
174
+ const unique = [...deps.values()]
175
+ if (unique.length) {
176
+ return [
177
+ outdent`
178
+ package.json depends on "@sanity/*" packages that have moved into "sanity" package.
179
+
180
+ The following dependencies should be replaced with "sanity":
181
+ - ${unique.join('\n- ')}
182
+
183
+ Refer to the reference docs to find replacement imports:
184
+ ${urls.refDocs}
185
+ `.trimStart(),
186
+ ]
187
+ }
188
+ return []
189
+ }
190
+
191
+ export async function validateRollupConfig({basePath}: {basePath: string}) {
192
+ const configpath = path.normalize(path.join(basePath, 'rollup.config.js'))
193
+
194
+ if (await fileExists(configpath)) {
195
+ return [
196
+ outdent`
197
+ Found rollup.config.js file. When using default parcel build command, this will have no effect.
198
+
199
+ Delete the rollup.config.js file, or disable this check.
200
+ `.trimStart(),
201
+ ]
202
+ }
203
+ return []
204
+ }
205
+
206
+ export async function validateBabelConfig({basePath}: {basePath: string}) {
207
+ const babelConfig: {file?: string} = await findBabelConfig(basePath)
208
+
209
+ if (babelConfig.file) {
210
+ return [
211
+ outdent`
212
+ Found babel-config file: ${babelConfig.file}. When using default parcel build command,
213
+ this is probably not needed.
214
+
215
+ Delete the ${babelConfig.file} file, or disable this check.
216
+ `.trimStart(),
217
+ ]
218
+ }
219
+ return []
220
+ }
221
+
222
+ export async function validateStudioConfig({basePath}: {basePath: string}): Promise<string[]> {
223
+ const filenames = ['sanity.config.ts', 'sanity.config.js', 'sanity.cli.ts', 'sanity.cli.js']
224
+
225
+ const files = await filenames.reduce(async (record, filename) => {
226
+ // @ts-expect-error it works though
227
+ record[filename] = await readFileContent({basePath, filename})
228
+ return record
229
+ }, Promise.resolve({} as Record<string, string | undefined>))
230
+
231
+ const sanityJson = await readJson5File<SanityStudioJson>({basePath, filename: 'sanity.json'})
232
+
233
+ const hasCliConfig = files['sanity.cli.ts'] || files['sanity.cli.js']
234
+ const hasStudioConfig = files['sanity.config.ts'] || files['sanity.config.js']
235
+
236
+ const errors: string[] = []
237
+
238
+ if (sanityJson) {
239
+ const info = [
240
+ outdent`
241
+ Found sanity.json. This file is not used by Sanity Studio V3.
242
+
243
+ Please consult the Studio V3 migration guide:
244
+ ${urls.migrationGuideStudio}
245
+ It will detail how to convert sanity.json to sanity.config.ts (or .js) and sanity.cli.ts (or .js) equivalents.
246
+ `.trimStart(),
247
+ sanityJson.plugins?.length &&
248
+ outdent`
249
+ For V3 versions and alternatives to V2 plugins, please refer to the Sanity Exchange:
250
+ ${urls.sanityExchange}
251
+ `.trimStart(),
252
+ ].filter((s): s is string => !!s)
253
+
254
+ errors.push(info.join('\n\n'))
255
+ }
256
+
257
+ if (!hasCliConfig) {
258
+ errors.push(
259
+ outdent`
260
+ sanity.cli.ts (or .js) missing. Please create a file named sanity.cli.ts with the following content:
261
+
262
+ ${chalk.green(
263
+ outdent`
264
+ import {createCliConfig} from 'sanity/cli'
265
+
266
+ export default createCliConfig({
267
+ api: {
268
+ projectId: '${sanityJson?.api?.projectId ?? 'project-id'}',
269
+ dataset: '${sanityJson?.api?.dataset ?? 'dataset'}',
270
+ }
271
+ })`
272
+ )}
273
+
274
+ Make sure to replace the projectId and dataset fields with your own.
275
+
276
+ For more, see ${urls.migrationGuideStudio}
277
+ `.trimStart()
278
+ )
279
+ }
280
+
281
+ if (!hasStudioConfig) {
282
+ errors.push(
283
+ outdent`
284
+ sanity.config.ts (or .js) missing. At a minimum sanity.config.ts should contain:
285
+
286
+ ${chalk
287
+ .green(
288
+ outdent`
289
+ import { createConfig, createPlugin } from "sanity"
290
+ import { deskTool } from "sanity/desk"
291
+
292
+ export default createConfig({
293
+ name: "default",
294
+
295
+ projectId: '${sanityJson?.api?.projectId ?? 'project-id'}',
296
+ dataset: '${sanityJson?.api?.dataset ?? 'dataset'}',
297
+
298
+ plugins: [
299
+ deskTool(),
300
+ ],
301
+
302
+ schema: {
303
+ types: [
304
+ /* put your v2 schema-types here */
305
+ ],
306
+ },
307
+ })`
308
+ )
309
+ .trimStart()}
310
+
311
+ Make sure to replace the projectId and dataset fields with your own.
312
+
313
+ For more, see ${urls.migrationGuideStudio}
314
+ `.trimStart()
315
+ )
316
+ }
317
+
318
+ return [errors.join(`\n\n---\n\n`)]
319
+ }
320
+
321
+ export async function validatePluginSanityJson({
322
+ basePath,
323
+ packageJson,
324
+ }: {
325
+ basePath: string
326
+ packageJson: PackageJson
327
+ }) {
328
+ const sanityJson = await readJson5File<SanityV2Json>({basePath, filename: 'sanity.json'})
329
+
330
+ const expectedDefaults = {
331
+ parts: [
332
+ {
333
+ implements: 'part:@sanity/base/sanity-root',
334
+ path: './v2-incompatible.js',
335
+ },
336
+ ],
337
+ }
338
+
339
+ const hasSinglePart =
340
+ sanityJson &&
341
+ Object.keys(sanityJson).length === 1 &&
342
+ sanityJson?.parts &&
343
+ sanityJson.parts.length === 1
344
+
345
+ const firstPart = hasSinglePart ? sanityJson?.parts?.[0] : undefined
346
+ const correctImplements = firstPart?.implements === expectedDefaults.parts[0].implements
347
+ const pathExists =
348
+ firstPart?.path && (await fileExists(path.normalize(path.join(basePath, firstPart.path))))
349
+ const hasDependency = !!packageJson.dependencies?.[incompatiblePluginPackage]
350
+ const isValid = sanityJson && hasSinglePart && correctImplements && pathExists && hasDependency
351
+
352
+ if (!isValid) {
353
+ const errors = [
354
+ !sanityJson ? 'sanity.json does not exist' : null,
355
+ !hasSinglePart ? 'sanity.json should have exactly one entry in "parts", but did not.' : null,
356
+ !correctImplements
357
+ ? `The part should implement ${expectedDefaults.parts[0].implements}, but did not.`
358
+ : null,
359
+ firstPart?.path && !pathExists
360
+ ? `The file in "path", ${firstPart?.path}, does not exist.`
361
+ : null,
362
+
363
+ !hasDependency
364
+ ? outdent`
365
+ package.json should have ${incompatiblePluginPackage} as a dependency, but did not.
366
+ Install it with: npm install --save ${incompatiblePluginPackage}
367
+ `.trimStart()
368
+ : null,
369
+ ].filter((e): e is string => !!e)
370
+
371
+ return [
372
+ outdent`
373
+ Invalid sanity.json. It is used for compatibility checking in V2 studios:
374
+
375
+ - ${errors.join('\n- ')}
376
+
377
+ sanity.json will only be used when incorrectly installing a v3 plugin in a v2 Studio.
378
+
379
+ This check ensures that sanity.json conforms with the usage section of
380
+ ${urls.incompatiblePlugin}
381
+ `.trimStart(),
382
+ ]
383
+ }
384
+ return []
385
+ }
386
+
387
+ export function validatePackageName(packageJson: PackageJson) {
388
+ const valid: {validForNewPackages?: boolean; errors: string[]} = validateNpmPackageName(
389
+ packageJson.name
390
+ )
391
+ if (!valid.validForNewPackages) {
392
+ return [`Invalid package.json: "name" is invalid: ${valid.errors.join(', ')}`]
393
+ }
394
+
395
+ const isScoped = packageJson.name?.startsWith('@')
396
+ if (!isScoped && !packageJson.name?.startsWith('sanity-plugin-')) {
397
+ return [
398
+ `Invalid package.json: "name" should be prefixed with "sanity-plugin-" (or scoped - @your-company/plugin-name)`,
399
+ ]
400
+ }
401
+ }
@@ -0,0 +1,92 @@
1
+ import log from '../../util/log'
2
+ import {TypedFlags} from 'meow'
3
+ import fs from 'fs'
4
+ import sharedFlags from '../../sharedFlags'
5
+ import {TsConfig} from './types'
6
+ import chalk from 'chalk'
7
+ import outdent from 'outdent'
8
+ import {runCommand} from '../../util/command-parser'
9
+
10
+ export const readFile = fs.promises.readFile
11
+ const splitLine = `\n----------------------------------------------------------`
12
+
13
+ export const verifyPackageConfigDefaults = {
14
+ packageName: true,
15
+ module: true,
16
+ tsconfig: true,
17
+ tsc: true,
18
+ dependencies: true,
19
+ rollupConfig: true,
20
+ babelConfig: true,
21
+ sanityV2Json: true,
22
+ eslintImports: true,
23
+ scripts: true,
24
+ parcel: true,
25
+ nodeEngine: true,
26
+ studioConfig: true,
27
+ } as const
28
+
29
+ export type VerifyPackageConfig = Partial<Record<keyof typeof verifyPackageConfigDefaults, boolean>>
30
+
31
+ export const verifyFlags = {
32
+ ...sharedFlags,
33
+ single: {
34
+ default: false,
35
+ type: 'boolean',
36
+ },
37
+ } as const
38
+
39
+ export type VerifyFlags = TypedFlags<typeof verifyFlags>
40
+
41
+ export function disableCheckText(checkKey: string) {
42
+ return chalk.grey(
43
+ outdent`
44
+ To skip this validation add the following to your package.json:
45
+ "sanityPlugin": {
46
+ "verifyPackage": {
47
+ "${checkKey}": false
48
+ }
49
+ }
50
+ `.trimStart()
51
+ )
52
+ }
53
+
54
+ export function createValidator(
55
+ verifyConfig: VerifyPackageConfig,
56
+ flags: VerifyFlags,
57
+ errors: string[]
58
+ ) {
59
+ return async function validation(
60
+ checkKey: keyof VerifyPackageConfig,
61
+ task: () => Promise<string[] | undefined>
62
+ ) {
63
+ if (verifyConfig[checkKey] !== false) {
64
+ const result = await task()
65
+ if (result?.length) {
66
+ result.push(disableCheckText(checkKey))
67
+ const errorMessage = result.join('\n\n')
68
+ errors.push(errorMessage)
69
+ log.error(`\n` + errorMessage + splitLine)
70
+ }
71
+ }
72
+
73
+ if (flags.single && errors.length) {
74
+ throw new Error(
75
+ outdent`Detected outstanding upgrade issues.
76
+
77
+ Fail-fast (--single) mode enabled, stopping validation here.
78
+ `
79
+ )
80
+ }
81
+ }
82
+ }
83
+
84
+ export async function runTscMaybe(verifyConfig: VerifyPackageConfig, tsConfig?: TsConfig) {
85
+ if (tsConfig && verifyConfig.tsc !== false) {
86
+ log.info('All checks ok, running Typescript compiler.')
87
+ const {code} = await runCommand('tsc --noEmit')
88
+ if (code !== 0) {
89
+ throw new Error('Compilation failed. See output above.\n\n' + disableCheckText('tsc'))
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,87 @@
1
+ import {getPackage} from '../npm/package'
2
+ import log from '../util/log'
3
+ import {cliName, urls} from '../constants'
4
+ import {validateImports} from '../dependencies/import-linter'
5
+ import outdent from 'outdent'
6
+ import {
7
+ createValidator,
8
+ runTscMaybe,
9
+ VerifyFlags,
10
+ VerifyPackageConfig,
11
+ } from './verify/verify-common'
12
+ import {readJson5File} from '../util/files'
13
+ import {
14
+ validateBabelConfig,
15
+ validateModule,
16
+ validateNodeEngine,
17
+ validatePackageName,
18
+ validateParcelDependency,
19
+ validatePluginSanityJson,
20
+ validateRollupConfig,
21
+ validateSanityDependencies,
22
+ validateScripts,
23
+ validateTsConfig,
24
+ } from './verify/validations'
25
+ import {PackageJson, TsConfig} from './verify/types'
26
+ import chalk from 'chalk'
27
+
28
+ export async function verifyPackage({basePath, flags}: {basePath: string; flags: VerifyFlags}) {
29
+ let errors: string[] = []
30
+
31
+ const packageJson: PackageJson = await getPackage({basePath, validate: false})
32
+ const verifyConfig: VerifyPackageConfig = packageJson.sanityPlugin?.verifyPackage || {}
33
+
34
+ const validation = createValidator(verifyConfig, flags, errors)
35
+
36
+ const tsConfig = await readJson5File<TsConfig>({basePath, filename: 'tsconfig.json'})
37
+
38
+ await validation('packageName', async () => validatePackageName(packageJson))
39
+ await validation('parcel', async () => validateParcelDependency(packageJson))
40
+ await validation('scripts', async () => validateScripts(packageJson))
41
+ await validation('module', async () => validateModule(packageJson))
42
+ await validation('nodeEngine', async () => validateNodeEngine(packageJson))
43
+
44
+ tsConfig && (await validation('tsconfig', async () => validateTsConfig(tsConfig)))
45
+
46
+ await validation('sanityV2Json', async () => validatePluginSanityJson({basePath, packageJson}))
47
+
48
+ await validation('rollupConfig', async () => validateRollupConfig({basePath}))
49
+ await validation('babelConfig', async () => validateBabelConfig({basePath}))
50
+
51
+ await validation('dependencies', async () => validateSanityDependencies(packageJson))
52
+ await validation('eslintImports', async () => validateImports({basePath}))
53
+
54
+ if (errors.length) {
55
+ throw new Error(
56
+ outdent`
57
+ Detected validation issues!
58
+ To make this package Sanity v3 compatible, fix the issues starting from the top, or disable any checks you deem unnecessary.
59
+
60
+ These issues assume the package uses @sanity/plugin-kit defaults for development and building.
61
+ Refer to ${urls.pluginReadme} for configuration options.
62
+
63
+ More information is available here:
64
+ - Studio migration guide: ${urls.migrationGuideStudio}
65
+ - Plugin migration guide: ${urls.migrationGuidePlugin}
66
+ - Reference documentation: ${urls.refDocs}
67
+
68
+ ${chalk.grey(
69
+ `To fail-fast on first detected issue run:\nnpx ${cliName} verify-package' --single`
70
+ )}
71
+ `.trimStart()
72
+ )
73
+ }
74
+
75
+ await runTscMaybe(verifyConfig, tsConfig)
76
+
77
+ log.success(
78
+ outdent`
79
+ No outstanding upgrade issues detected.
80
+
81
+ Suggested next steps:
82
+ - Use plugin-kit to build and develop the plugin according to ${urls.pluginReadme}.
83
+ - Build the plugin and fix any compilation errors
84
+ - Test the plugin using the link-watch command
85
+ `.trim()
86
+ )
87
+ }