@sanity/plugin-kit 5.0.2 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks-es/init.js +2 -2
- package/dist/_chunks-es/init2.js +779 -14
- package/dist/_chunks-es/init2.js.map +1 -1
- package/dist/_chunks-es/inject.js +2 -2
- package/dist/_chunks-es/package.js +321 -1064
- package/dist/_chunks-es/package.js.map +1 -1
- package/dist/_chunks-es/package2.js +1 -1
- package/dist/_chunks-es/{ts.js → verify-common.js} +75 -75
- package/dist/_chunks-es/verify-common.js.map +1 -0
- package/dist/_chunks-es/verify-package.js +1 -1
- package/dist/_chunks-es/verify-package.js.map +1 -1
- package/dist/_chunks-es/verify-studio.js +1 -1
- package/dist/_chunks-es/verify-studio.js.map +1 -1
- package/package.json +1 -1
- package/dist/_chunks-es/ts.js.map +0 -1
|
@@ -3,444 +3,43 @@ import path from "path";
|
|
|
3
3
|
import util from "util";
|
|
4
4
|
import githubUrlToObject from "github-url-to-object";
|
|
5
5
|
import validateNpmPackageName from "validate-npm-package-name";
|
|
6
|
-
import { URL, fileURLToPath } from "url";
|
|
7
|
-
import licenses from "@rexxars/choosealicense-list";
|
|
8
|
-
import gitRemoteOriginUrl from "git-remote-origin-url";
|
|
9
|
-
import { log, urls, minPkgUtilsMajor, requiredNodeEngine, incompatiblePluginPackage, cliName } from "./index.js";
|
|
10
6
|
import { createRequire } from "node:module";
|
|
11
7
|
import chalk from "chalk";
|
|
12
|
-
import outdent
|
|
8
|
+
import outdent from "outdent";
|
|
9
|
+
import { log, urls, minPkgUtilsMajor, requiredNodeEngine, incompatiblePluginPackage, cliName } from "./index.js";
|
|
13
10
|
import crypto from "crypto";
|
|
14
11
|
import json5 from "json5";
|
|
15
12
|
import pAny from "p-any";
|
|
16
|
-
import {
|
|
13
|
+
import { URL } from "url";
|
|
17
14
|
import inquirer from "inquirer";
|
|
15
|
+
import { pkg } from "./package2.js";
|
|
18
16
|
import getLatestVersion from "get-latest-version";
|
|
19
17
|
import pProps from "p-props";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
value: JSON.stringify(eslintConfig, null, 2)
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function eslintignoreTemplate(options) {
|
|
49
|
-
const { flags, outDir } = options, patterns = [
|
|
50
|
-
".eslintrc.js",
|
|
51
|
-
"commitlint.config.js",
|
|
52
|
-
outDir,
|
|
53
|
-
"lint-staged.config.js",
|
|
54
|
-
"package.config.ts",
|
|
55
|
-
flags.typescript ? "*.js" : ""
|
|
56
|
-
].filter(Boolean);
|
|
57
|
-
return patterns.sort(), {
|
|
58
|
-
type: "template",
|
|
59
|
-
force: flags.force,
|
|
60
|
-
to: ".eslintignore",
|
|
61
|
-
value: patterns.join(`
|
|
62
|
-
`)
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
function gitignoreTemplate() {
|
|
66
|
-
return {
|
|
67
|
-
type: "template",
|
|
68
|
-
to: ".gitignore",
|
|
69
|
-
value: outdent`
|
|
70
|
-
# Logs
|
|
71
|
-
logs
|
|
72
|
-
*.log
|
|
73
|
-
npm-debug.log*
|
|
74
|
-
|
|
75
|
-
# Runtime data
|
|
76
|
-
pids
|
|
77
|
-
*.pid
|
|
78
|
-
*.seed
|
|
79
|
-
|
|
80
|
-
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
81
|
-
lib-cov
|
|
82
|
-
|
|
83
|
-
# Coverage directory used by tools like istanbul
|
|
84
|
-
coverage
|
|
85
|
-
|
|
86
|
-
# nyc test coverage
|
|
87
|
-
.nyc_output
|
|
88
|
-
|
|
89
|
-
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
90
|
-
.grunt
|
|
91
|
-
|
|
92
|
-
# node-waf configuration
|
|
93
|
-
.lock-wscript
|
|
94
|
-
|
|
95
|
-
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
96
|
-
build/Release
|
|
97
|
-
|
|
98
|
-
# Dependency directories
|
|
99
|
-
node_modules
|
|
100
|
-
jspm_packages
|
|
101
|
-
|
|
102
|
-
# Optional npm cache directory
|
|
103
|
-
.npm
|
|
104
|
-
|
|
105
|
-
# Optional REPL history
|
|
106
|
-
.node_repl_history
|
|
107
|
-
|
|
108
|
-
# macOS finder cache file
|
|
109
|
-
.DS_Store
|
|
110
|
-
|
|
111
|
-
# VS Code settings
|
|
112
|
-
.vscode
|
|
113
|
-
|
|
114
|
-
# IntelliJ
|
|
115
|
-
.idea
|
|
116
|
-
*.iml
|
|
117
|
-
|
|
118
|
-
# Cache
|
|
119
|
-
.cache
|
|
120
|
-
|
|
121
|
-
# Yalc
|
|
122
|
-
.yalc
|
|
123
|
-
yalc.lock
|
|
124
|
-
|
|
125
|
-
# npm package zips
|
|
126
|
-
*.tgz
|
|
127
|
-
`
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
function pkgConfigTemplate(options) {
|
|
131
|
-
const { flags, outDir } = options;
|
|
132
|
-
return {
|
|
133
|
-
type: "template",
|
|
134
|
-
force: flags.force,
|
|
135
|
-
// Always a `.ts` config: plugins are ESM (`"type": "module"`), so `@sanity/pkg-utils`
|
|
136
|
-
// loads it without needing a `.mts`/`.mjs` extension to force ESM interpretation.
|
|
137
|
-
to: "package.config.ts",
|
|
138
|
-
value: outdent`
|
|
139
|
-
import {defineConfig} from '@sanity/pkg-utils'
|
|
140
|
-
|
|
141
|
-
export default defineConfig({
|
|
142
|
-
dist: '${outDir}',
|
|
143
|
-
tsconfig: 'tsconfig.${outDir}.json',
|
|
144
|
-
|
|
145
|
-
// Remove this block to enable strict export validation
|
|
146
|
-
extract: {
|
|
147
|
-
rules: {
|
|
148
|
-
'ae-incompatible-release-tags': 'off',
|
|
149
|
-
'ae-internal-missing-underscore': 'off',
|
|
150
|
-
'ae-missing-release-tag': 'off',
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
})
|
|
154
|
-
`
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function prettierignoreTemplate(options) {
|
|
158
|
-
const { outDir } = options;
|
|
159
|
-
return {
|
|
160
|
-
type: "template",
|
|
161
|
-
to: ".prettierignore",
|
|
162
|
-
value: [outDir, "pnpm-lock.yaml", "yarn.lock", "package-lock.json"].join(`
|
|
163
|
-
`)
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function tsconfigTemplate(options) {
|
|
167
|
-
const { flags } = options;
|
|
168
|
-
return {
|
|
169
|
-
type: "template",
|
|
170
|
-
force: flags.force,
|
|
171
|
-
to: "tsconfig.json",
|
|
172
|
-
value: outdent`
|
|
173
|
-
{
|
|
174
|
-
"extends": "./tsconfig.settings",
|
|
175
|
-
"include": ["./src", "./package.config.ts"]
|
|
176
|
-
}
|
|
177
|
-
`
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
function tsconfigTemplateDist(options) {
|
|
181
|
-
const { flags, outDir } = options;
|
|
182
|
-
return {
|
|
183
|
-
type: "template",
|
|
184
|
-
force: flags.force,
|
|
185
|
-
to: `tsconfig.${outDir}.json`,
|
|
186
|
-
value: outdent`
|
|
187
|
-
{
|
|
188
|
-
"extends": "./tsconfig.settings",
|
|
189
|
-
"include": ["./src"],
|
|
190
|
-
"exclude": [
|
|
191
|
-
"./src/**/__fixtures__",
|
|
192
|
-
"./src/**/__mocks__",
|
|
193
|
-
"./src/**/*.test.ts",
|
|
194
|
-
"./src/**/*.test.tsx"
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
`
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function tsconfigTemplateSettings(options) {
|
|
201
|
-
const { flags, outDir } = options;
|
|
202
|
-
return {
|
|
203
|
-
type: "template",
|
|
204
|
-
force: flags.force,
|
|
205
|
-
to: "tsconfig.settings.json",
|
|
206
|
-
value: outdent`
|
|
207
|
-
{
|
|
208
|
-
"compilerOptions": {
|
|
209
|
-
"rootDir": ".",
|
|
210
|
-
"outDir": "./${outDir}",
|
|
211
|
-
|
|
212
|
-
"target": "esnext",
|
|
213
|
-
"jsx": "preserve",
|
|
214
|
-
"module": "preserve",
|
|
215
|
-
"moduleResolution": "bundler",
|
|
216
|
-
"esModuleInterop": true,
|
|
217
|
-
"resolveJsonModule": true,
|
|
218
|
-
"moduleDetection": "force",
|
|
219
|
-
"strict": true,
|
|
220
|
-
"allowSyntheticDefaultImports": true,
|
|
221
|
-
"skipLibCheck": true,
|
|
222
|
-
"forceConsistentCasingInFileNames": true,
|
|
223
|
-
"isolatedModules": true,
|
|
224
|
-
|
|
225
|
-
// Don't emit by default, pkg-utils will ignore this when generating .d.ts files
|
|
226
|
-
"noEmit": true
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
`
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
const renovatePreset = {
|
|
233
|
-
name: "renovatebot",
|
|
234
|
-
description: "Files to enable renovatebot.",
|
|
235
|
-
apply: applyPreset$3
|
|
236
|
-
};
|
|
237
|
-
async function applyPreset$3(options) {
|
|
238
|
-
await writeAssets(
|
|
239
|
-
[
|
|
240
|
-
{
|
|
241
|
-
type: "copy",
|
|
242
|
-
from: ["renovatebot", "renovate.json"],
|
|
243
|
-
to: "renovate.json"
|
|
244
|
-
}
|
|
245
|
-
],
|
|
246
|
-
options
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
const lockedDependencies = {
|
|
250
|
-
"styled-components": "^6.1",
|
|
251
|
-
eslint: "^8.57.0"
|
|
252
|
-
};
|
|
253
|
-
function resolveLatestVersions(packages) {
|
|
254
|
-
const versions = {};
|
|
255
|
-
for (const pkgName of packages)
|
|
256
|
-
versions[pkgName] = pkgName in lockedDependencies ? lockedDependencies[pkgName] : "latest";
|
|
257
|
-
return pProps(
|
|
258
|
-
versions,
|
|
259
|
-
async (range, pkgName) => {
|
|
260
|
-
const version = await getLatestVersion(pkgName, { range });
|
|
261
|
-
if (!version)
|
|
262
|
-
throw new Error(`Found no version for ${pkgName}`);
|
|
263
|
-
return rangeify(version);
|
|
264
|
-
},
|
|
265
|
-
{ concurrency: 8 }
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
function rangeify(version) {
|
|
269
|
-
return `^${version}`;
|
|
270
|
-
}
|
|
271
|
-
function errorToUndefined(err) {
|
|
272
|
-
if (err instanceof TypeError)
|
|
273
|
-
throw err;
|
|
274
|
-
}
|
|
275
|
-
const buildExtensions = [".js", ".jsx", ".es6", ".es", ".mjs", ".ts", ".tsx"], stat$1 = util.promisify(fs.stat), readFile$2 = util.promisify(fs.readFile), allowedPartProps = ["name", "implements", "path", "description"], disallowedPluginProps = ["api", "project", "plugins", "env"];
|
|
276
|
-
async function getPaths(options) {
|
|
277
|
-
const { basePath } = options, manifest = await readManifest(options);
|
|
278
|
-
return manifest.paths ? absolutifyPaths(manifest.paths, basePath) : null;
|
|
279
|
-
}
|
|
280
|
-
function absolutifyPaths(paths, basePath) {
|
|
281
|
-
const getPath = (relative) => relative ? path.resolve(path.join(basePath, relative)) : void 0;
|
|
282
|
-
return paths ? {
|
|
283
|
-
basePath,
|
|
284
|
-
compiled: getPath(paths.compiled),
|
|
285
|
-
source: getPath(paths.source)
|
|
286
|
-
} : { basePath };
|
|
287
|
-
}
|
|
288
|
-
async function readManifest(options) {
|
|
289
|
-
const { basePath, validate: validate2 = !0 } = options, manifestPath = path.normalize(path.join(basePath, "sanity.json"));
|
|
290
|
-
let content;
|
|
291
|
-
try {
|
|
292
|
-
content = await readFile$2(manifestPath, "utf8");
|
|
293
|
-
} catch (err) {
|
|
294
|
-
throw err.code === "ENOENT" ? new Error(
|
|
295
|
-
`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.`
|
|
296
|
-
) : new Error(`Failed to read "${manifestPath}": ${err.message}`);
|
|
297
|
-
}
|
|
298
|
-
let parsed;
|
|
299
|
-
try {
|
|
300
|
-
parsed = JSON.parse(content);
|
|
301
|
-
} catch (err) {
|
|
302
|
-
throw new Error(`Error parsing "${manifestPath}": ${err.message}`);
|
|
303
|
-
}
|
|
304
|
-
return validate2 && await validateManifest(parsed, options), parsed;
|
|
305
|
-
}
|
|
306
|
-
async function validateManifest(manifest, opts) {
|
|
307
|
-
const options = { isPlugin: !0, ...opts };
|
|
308
|
-
if (!isObject$1(manifest))
|
|
309
|
-
throw new Error("Invalid sanity.json: Root must be an object");
|
|
310
|
-
if (options.isPlugin ? await validatePluginManifest(manifest, options) : validateProjectManifest(manifest), "root" in manifest && typeof manifest.root != "boolean")
|
|
311
|
-
throw new Error('Invalid sanity.json: "root" property must be a boolean if declared');
|
|
312
|
-
await validateParts(manifest, {
|
|
313
|
-
...options,
|
|
314
|
-
paths: absolutifyPaths(manifest.paths, options.basePath)
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
function validateProjectManifest(manifest) {
|
|
318
|
-
if ("paths" in manifest)
|
|
319
|
-
throw new Error('Invalid sanity.json: "paths" property has no meaning in a project manifest');
|
|
320
|
-
}
|
|
321
|
-
async function validatePluginManifest(manifest, options) {
|
|
322
|
-
const disallowed = Object.keys(manifest).filter((key) => disallowedPluginProps.includes(key)).map((key) => `"${key}"`);
|
|
323
|
-
if (disallowed.length > 0) {
|
|
324
|
-
const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
|
|
325
|
-
throw new Error(
|
|
326
|
-
`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a plugin manifest`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
if (manifest.root)
|
|
330
|
-
throw new Error('Invalid sanity.json: "root" cannot be truthy in a plugin manifest');
|
|
331
|
-
await validatePaths$1(manifest, options);
|
|
332
|
-
}
|
|
333
|
-
async function validatePaths$1(manifest, options) {
|
|
334
|
-
if (!("paths" in manifest))
|
|
335
|
-
return;
|
|
336
|
-
if (!isObject$1(manifest.paths))
|
|
337
|
-
throw new Error('Invalid sanity.json: "paths" must be an object if declared');
|
|
338
|
-
if (typeof manifest.paths.compiled != "string")
|
|
339
|
-
throw new Error(
|
|
340
|
-
'Invalid sanity.json: "paths" must have a (string) "compiled" property if declared'
|
|
341
|
-
);
|
|
342
|
-
if (typeof manifest.paths.source != "string")
|
|
343
|
-
throw new Error(
|
|
344
|
-
'Invalid sanity.json: "paths" must have a (string) "source" property if declared'
|
|
345
|
-
);
|
|
346
|
-
const sourcePath = path.resolve(options.basePath, manifest.paths.source);
|
|
347
|
-
let srcStats;
|
|
348
|
-
try {
|
|
349
|
-
srcStats = await stat$1(sourcePath);
|
|
350
|
-
} catch (err) {
|
|
351
|
-
if (err.code === "ENOENT")
|
|
352
|
-
throw new Error(`sanity.json references "source" path which does not exist: "${sourcePath}"`);
|
|
353
|
-
}
|
|
354
|
-
if (!srcStats?.isDirectory())
|
|
355
|
-
throw new Error(
|
|
356
|
-
`sanity.json references "source" path which is not a directory: "${sourcePath}"`
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
async function validateParts(manifest, options) {
|
|
360
|
-
if (!("parts" in manifest))
|
|
361
|
-
return;
|
|
362
|
-
if (!Array.isArray(manifest.parts))
|
|
363
|
-
throw new Error('Invalid sanity.json: "parts" must be an array if declared');
|
|
364
|
-
let i = 0;
|
|
365
|
-
for (const part of manifest.parts)
|
|
366
|
-
await validatePart(part, i, options), i++;
|
|
367
|
-
}
|
|
368
|
-
async function validatePart(part, index, options) {
|
|
369
|
-
if (!isObject$1(part))
|
|
370
|
-
throw new Error(`Invalid sanity.json: "parts[${index}]" must be an object`);
|
|
371
|
-
validateAllowedPartKeys(part, index), validatePartStringValues(part, index), validatePartNames(part, index, options), await validatePartFiles(part, index, options);
|
|
372
|
-
}
|
|
373
|
-
async function validatePartFiles(part, index, options) {
|
|
374
|
-
const { verifyCompiledParts, verifySourceParts, paths } = options;
|
|
375
|
-
if (!part?.path)
|
|
376
|
-
return;
|
|
377
|
-
const ext = path.extname(part.path);
|
|
378
|
-
if (paths?.source && ext && ext !== ".js" && buildExtensions.includes(ext))
|
|
379
|
-
throw new Error(
|
|
380
|
-
`Invalid sanity.json: Part path has extension which is not applicable after compiling. ${ext} becomes .js after compiling. Specify filename without extension (${path.basename(
|
|
381
|
-
part.path
|
|
382
|
-
)}) (parts[${index}])`
|
|
383
|
-
);
|
|
384
|
-
if (!verifySourceParts && !verifyCompiledParts)
|
|
385
|
-
return;
|
|
386
|
-
const [srcExists, outDirExists] = await Promise.all([
|
|
387
|
-
hasSourceFile(part.path, paths),
|
|
388
|
-
verifyCompiledParts && hasCompiledFile(part.path, paths)
|
|
389
|
-
]);
|
|
390
|
-
if (!srcExists)
|
|
391
|
-
throw new Error(
|
|
392
|
-
`Invalid sanity.json: Part path references file that does not exist in source directory (${paths?.source || paths?.basePath}) (parts[${index}])`
|
|
393
|
-
);
|
|
394
|
-
if (verifyCompiledParts && !outDirExists)
|
|
395
|
-
throw new Error(
|
|
396
|
-
`Invalid sanity.json: Part path references file ("${part.path}") that does not exist in compiled directory (${paths?.compiled}) (parts[${index}])`
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
function validatePartNames(part, index, options) {
|
|
400
|
-
const pluginName = options.pluginName ? options.pluginName.replace(/^sanity-plugin-/, "") : "";
|
|
401
|
-
if (!part?.name || !part?.name?.startsWith(`part:${pluginName}/`))
|
|
402
|
-
throw new Error(
|
|
403
|
-
`Invalid sanity.json: "name" must be prefixed with "part:${pluginName}/" - got "${part?.name}" (parts[${index}])`
|
|
404
|
-
);
|
|
405
|
-
if (!part?.implements?.startsWith("part:"))
|
|
406
|
-
throw new Error(
|
|
407
|
-
`Invalid sanity.json: "implements" must be prefixed with "part:" - got "${part?.implements}" (parts[${index}])`
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
function validateAllowedPartKeys(part, index) {
|
|
411
|
-
const disallowed = Object.keys(part).filter((key) => !allowedPartProps.includes(key)).map((key) => `"${key}"`);
|
|
412
|
-
if (disallowed.length > 0) {
|
|
413
|
-
const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
|
|
414
|
-
throw new Error(
|
|
415
|
-
`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a part declaration (parts[${index}])`
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
function validatePartStringValues(part, index) {
|
|
420
|
-
const nonStrings = Object.keys(part).filter((key) => typeof part[key] != "string").map((key) => `"${key}"`);
|
|
421
|
-
if (nonStrings.length > 0) {
|
|
422
|
-
const plural = nonStrings.length > 1 ? "s" : "", joined = nonStrings.join(", ");
|
|
423
|
-
throw new Error(
|
|
424
|
-
`Invalid sanity.json: Key${plural} ${joined} should be of type string (parts[${index}])`
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
function isObject$1(obj) {
|
|
429
|
-
return !Array.isArray(obj) && obj !== null && typeof obj == "object";
|
|
430
|
-
}
|
|
431
|
-
async function hasSanityJson(basePath) {
|
|
432
|
-
const file = await readJsonFile(path.join(basePath, "sanity.json")).catch(
|
|
433
|
-
errorToUndefined
|
|
434
|
-
);
|
|
435
|
-
return { exists: !!file, isRoot: !!(file && file.root) };
|
|
436
|
-
}
|
|
437
|
-
async function findStudioV3Config(basePath) {
|
|
438
|
-
const jsFile = "sanity.config.js";
|
|
439
|
-
if (await fileExists(path.join(basePath, jsFile)))
|
|
440
|
-
return { v3ConfigFile: jsFile };
|
|
441
|
-
const tsFile = "sanity.config.ts";
|
|
442
|
-
return { v3ConfigFile: await fileExists(path.join(basePath, tsFile)) ? tsFile : void 0 };
|
|
443
|
-
}
|
|
18
|
+
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"
|
|
36
|
+
].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"];
|
|
444
43
|
async function prompt(message, options) {
|
|
445
44
|
const type = options.choices ? "list" : options.type, result = await inquirer.prompt([{ ...options, type, message, name: "single" }]);
|
|
446
45
|
return result && result.single;
|
|
@@ -477,7 +76,7 @@ function promptForRepoOrigin(_options, defaultVal) {
|
|
|
477
76
|
}
|
|
478
77
|
});
|
|
479
78
|
}
|
|
480
|
-
const stat = util.promisify(fs.stat), mkdir = util.promisify(fs.mkdir), readdir = util.promisify(fs.readdir), copyFile = util.promisify(fs.copyFile), readFile$
|
|
79
|
+
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);
|
|
481
80
|
function hasSourceEquivalent(compiledFile, paths) {
|
|
482
81
|
if (!paths.source)
|
|
483
82
|
return fileExists(
|
|
@@ -504,13 +103,13 @@ function hasCompiledFile(filePath, paths) {
|
|
|
504
103
|
}
|
|
505
104
|
function buildCandidateExists(pathStub) {
|
|
506
105
|
const candidates = buildExtensions.map((extCandidate) => `${pathStub}${extCandidate}`);
|
|
507
|
-
return pAny(candidates.map((candidate) => stat(candidate))).then(() => !0).catch(() => !1);
|
|
106
|
+
return pAny(candidates.map((candidate) => stat$1(candidate))).then(() => !0).catch(() => !1);
|
|
508
107
|
}
|
|
509
108
|
function fileExists(filePath) {
|
|
510
|
-
return stat(filePath).then(() => !0).catch(() => !1);
|
|
109
|
+
return stat$1(filePath).then(() => !0).catch(() => !1);
|
|
511
110
|
}
|
|
512
111
|
async function readJsonFile(filePath) {
|
|
513
|
-
const content = await readFile$
|
|
112
|
+
const content = await readFile$2(filePath, "utf8");
|
|
514
113
|
return JSON.parse(content);
|
|
515
114
|
}
|
|
516
115
|
function writeJsonFile(filePath, content) {
|
|
@@ -560,601 +159,41 @@ async function ensureDir(dirPath) {
|
|
|
560
159
|
throw err;
|
|
561
160
|
}
|
|
562
161
|
}
|
|
563
|
-
async function isEmptyish(dirPath) {
|
|
564
|
-
const ignoredFiles = [".git", ".gitignore", "license", "readme.md"];
|
|
565
|
-
return (await readdir(dirPath).catch(() => [])).filter((file) => !ignoredFiles.includes(file.toLowerCase())).length === 0;
|
|
566
|
-
}
|
|
567
|
-
async function readFileContent({
|
|
568
|
-
filename,
|
|
569
|
-
basePath
|
|
570
|
-
}) {
|
|
571
|
-
const filepath = path.normalize(path.join(basePath, filename));
|
|
572
|
-
try {
|
|
573
|
-
return await readFile$1(filepath, "utf8");
|
|
574
|
-
} catch (err) {
|
|
575
|
-
if (err.code === "ENOENT") {
|
|
576
|
-
log.debug(`No ${filename} file found.`);
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
throw new Error(`Failed to read "${filepath}": ${err.message}`);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
async function readJson5File({
|
|
583
|
-
filename,
|
|
584
|
-
basePath
|
|
585
|
-
}) {
|
|
586
|
-
const content = await readFileContent({ filename, basePath });
|
|
587
|
-
if (content)
|
|
588
|
-
return parseJson5(content, filename);
|
|
589
|
-
}
|
|
590
|
-
function parseJson5(content, errorKey) {
|
|
591
|
-
try {
|
|
592
|
-
return json5.parse(content);
|
|
593
|
-
} catch (err) {
|
|
594
|
-
throw new Error(`Error parsing "${errorKey}": ${err.message}`);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
const request = getIt([
|
|
598
|
-
promise({ onlyBody: !0 }),
|
|
599
|
-
jsonRequest(),
|
|
600
|
-
jsonResponse(),
|
|
601
|
-
httpErrors(),
|
|
602
|
-
headers({ "User-Agent": `${pkg.name}@${pkg.version}` })
|
|
603
|
-
]);
|
|
604
|
-
async function getUserInfo({ requireUserConfirmation, flags }, pkg2) {
|
|
605
|
-
const userInfo = getPackageUserInfo({ author: flags.author ?? pkg2?.author }) || await getSanityUserInfo() || await getGitUserInfo();
|
|
606
|
-
return requireUserConfirmation ? promptForInfo(userInfo) : userInfo;
|
|
607
|
-
}
|
|
608
|
-
function getPackageUserInfo(pkg2) {
|
|
609
|
-
let author = pkg2?.author;
|
|
610
|
-
if (!author)
|
|
611
|
-
return;
|
|
612
|
-
if (author && typeof author != "string")
|
|
613
|
-
return author;
|
|
614
|
-
if (!author.includes("@"))
|
|
615
|
-
return { name: author };
|
|
616
|
-
const [pre, ...post] = author.replace(/[<>[\]]/g, "").split(/@/), nameParts = pre.split(/\s+/), email = [nameParts[nameParts.length - 1], ...post].join("@");
|
|
617
|
-
return { name: nameParts.slice(0, -1).join(" "), email };
|
|
618
|
-
}
|
|
619
|
-
async function promptForInfo(defValue) {
|
|
620
|
-
const name = await prompt("Author name", {
|
|
621
|
-
filter: filterString,
|
|
622
|
-
default: defValue && defValue.name,
|
|
623
|
-
validate: requiredString
|
|
624
|
-
}), email = await prompt("Author email", {
|
|
625
|
-
filter: filterString,
|
|
626
|
-
default: defValue && defValue.email,
|
|
627
|
-
validate: validOrEmptyEmail
|
|
628
|
-
});
|
|
629
|
-
return { name, email };
|
|
630
|
-
}
|
|
631
|
-
async function getSanityUserInfo() {
|
|
632
|
-
try {
|
|
633
|
-
const token = (await readJsonFile(
|
|
634
|
-
path.join(xdgBasedir.config ?? "", "sanity", "config.json")
|
|
635
|
-
))?.authToken;
|
|
636
|
-
if (!token)
|
|
637
|
-
return;
|
|
638
|
-
const user = await request({
|
|
639
|
-
url: "https://api.sanity.io/v1/users/me",
|
|
640
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
641
|
-
});
|
|
642
|
-
if (!user)
|
|
643
|
-
return;
|
|
644
|
-
const { name, email } = user;
|
|
645
|
-
return { name, email };
|
|
646
|
-
} catch {
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
async function getGitUserInfo() {
|
|
651
|
-
try {
|
|
652
|
-
const name = execSync("git config user.name", { encoding: "utf8" }).trim(), email = execSync("git config user.email", { encoding: "utf8" }).trim();
|
|
653
|
-
return name ? { name, email: email || void 0 } : void 0;
|
|
654
|
-
} catch {
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
function filterString(val) {
|
|
659
|
-
return (val || "").trim();
|
|
660
|
-
}
|
|
661
|
-
function requiredString(value) {
|
|
662
|
-
return value.length > 1 ? !0 : "Required";
|
|
663
|
-
}
|
|
664
|
-
function validOrEmptyEmail(value) {
|
|
665
|
-
return value ? validate(value) ? !0 : "Must either be a valid email or empty" : !0;
|
|
666
|
-
}
|
|
667
|
-
function generateReadme(data) {
|
|
668
|
-
const { user, pluginName, license } = data;
|
|
669
|
-
return outdent$1`
|
|
670
|
-
# ${pluginName}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
${installationSnippet(pluginName ?? "unknown")}
|
|
674
|
-
|
|
675
|
-
## Usage
|
|
676
|
-
|
|
677
|
-
Add it as a plugin in \`sanity.config.ts\` (or .js):
|
|
678
|
-
|
|
679
|
-
\`\`\`ts
|
|
680
|
-
import {defineConfig} from 'sanity'
|
|
681
|
-
import {myPlugin} from '${pluginName}'
|
|
682
|
-
|
|
683
|
-
export default defineConfig({
|
|
684
|
-
//...
|
|
685
|
-
plugins: [myPlugin({})],
|
|
686
|
-
})
|
|
687
|
-
\`\`\`
|
|
688
|
-
|
|
689
|
-
${getLicenseText(license?.id, user?.name ? user : void 0)}
|
|
690
|
-
${developTestSnippet()}
|
|
691
|
-
` + `
|
|
692
|
-
`;
|
|
693
|
-
}
|
|
694
|
-
function installationSnippet(packageName) {
|
|
695
|
-
return outdent$1`
|
|
696
|
-
## Installation
|
|
697
|
-
|
|
698
|
-
\`\`\`sh
|
|
699
|
-
npm install ${packageName}
|
|
700
|
-
\`\`\`
|
|
701
|
-
`;
|
|
702
|
-
}
|
|
703
|
-
function developTestSnippet() {
|
|
704
|
-
return outdent$1`
|
|
705
|
-
## Develop & test
|
|
706
|
-
|
|
707
|
-
This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
|
|
708
|
-
with default configuration for build & watch scripts.
|
|
709
|
-
|
|
710
|
-
See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
|
|
711
|
-
on how to run this plugin with hotreload in the studio.
|
|
712
|
-
`;
|
|
713
|
-
}
|
|
714
|
-
function getLicenseText(licenseId, user) {
|
|
715
|
-
if (!licenseId)
|
|
716
|
-
return "";
|
|
717
|
-
let licenseName = licenses.find(licenseId).title;
|
|
718
|
-
licenseName = licenseName?.replace(/\s+license$/i, "");
|
|
719
|
-
let licenseText = `## License
|
|
720
|
-
`;
|
|
721
|
-
return licenseName && user?.name ? licenseText = `${licenseText}
|
|
722
|
-
[${licenseName}](LICENSE) \xA9 ${user?.name}
|
|
723
|
-
` : licenseName ? licenseText = `${licenseText}
|
|
724
|
-
[${licenseName}](LICENSE)
|
|
725
|
-
` : licenseText = `${licenseText}
|
|
726
|
-
See [LICENSE](LICENSE)`, licenseText;
|
|
727
|
-
}
|
|
728
|
-
function isDefaultGitHubReadme(readme) {
|
|
729
|
-
if (!readme)
|
|
730
|
-
return !1;
|
|
731
|
-
const lines = readme.split(`
|
|
732
|
-
`, 20).filter(Boolean);
|
|
733
|
-
return lines.length <= 2 && lines[0].startsWith("#");
|
|
734
|
-
}
|
|
735
|
-
const semverWorkflowPreset = {
|
|
736
|
-
name: "semver-workflow",
|
|
737
|
-
description: "Files and dependencies for conventional-commits, github workflow and semantic-release.",
|
|
738
|
-
apply: applyPreset$2
|
|
739
|
-
}, info = (write, msg, ...args) => write && log.info(msg, ...args);
|
|
740
|
-
async function applyPreset$2(options) {
|
|
741
|
-
await writeAssets(semverWorkflowFiles(), options), await addPrepareScript(options), await addDevDependencies$2(options), await updateReadme(options);
|
|
742
|
-
}
|
|
743
|
-
async function addPrepareScript(options) {
|
|
744
|
-
const pkg2 = await getPackage(options), didWrite = await addPackageJsonScripts(pkg2, options, (scripts) => (scripts.prepare = addScript("husky", scripts.prepare), scripts));
|
|
745
|
-
info(didWrite, "Added prepare script to package.json");
|
|
746
|
-
}
|
|
747
|
-
async function addDevDependencies$2(options) {
|
|
748
|
-
const pkg2 = await getPackage(options), devDeps = sortKeys({
|
|
749
|
-
...pkg2.devDependencies,
|
|
750
|
-
...await semverWorkflowDependencies()
|
|
751
|
-
}), newPkg = { ...pkg2 };
|
|
752
|
-
newPkg.devDependencies = devDeps, await writePackageJsonDirect(newPkg, options), log.info("Updated devDependencies."), log.info(
|
|
753
|
-
chalk.green(
|
|
754
|
-
outdent$1`
|
|
755
|
-
semantic-release preset injected.
|
|
756
|
-
|
|
757
|
-
Please confer
|
|
758
|
-
https://github.com/sanity-io/plugin-kit/blob/main/docs/semver-workflow.md#manual-steps-after-inject
|
|
759
|
-
to finalize configuration for this preset.
|
|
760
|
-
`.trim()
|
|
761
|
-
)
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
async function updateReadme(options) {
|
|
765
|
-
const { basePath } = options, readmePath = path.join(basePath, "README.md"), readme = await readFile$1(readmePath, "utf8").catch(errorToUndefined) ?? "", { install, usage, developTest, license, releaseSnippet } = await readmeSnippets(options), prependSections = missingSections(readme, [install, usage]), appendSections = missingSections(readme, [license, developTest, releaseSnippet]);
|
|
766
|
-
if (prependSections.length || appendSections.length) {
|
|
767
|
-
const updatedReadme = [...prependSections, readme, ...appendSections].filter(Boolean).join(`
|
|
768
|
-
|
|
769
|
-
`);
|
|
770
|
-
await writeFile(readmePath, updatedReadme, { encoding: "utf8" }), log.info("Updated README. Please review the changes.");
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
async function readmeSnippets(options) {
|
|
774
|
-
const pkg2 = await getPackage(options), user = await getUserInfo(options, pkg2), bestEffortUrl = readmeBaseurl(pkg2), install = installationSnippet(pkg2.name ?? "unknown"), usage = outdent$1`
|
|
775
|
-
## Usage
|
|
776
|
-
`, license = getLicenseText(typeof pkg2.license == "string" ? pkg2.license : void 0, user), releaseSnippet = outdent$1`
|
|
777
|
-
### Release new version
|
|
778
|
-
|
|
779
|
-
Run ["CI & Release" workflow](${bestEffortUrl}/actions/workflows/main.yml).
|
|
780
|
-
Make sure to select the main branch and check "Release new version".
|
|
781
|
-
|
|
782
|
-
Semantic release will only release on configured branches, so it is safe to run release on any branch.
|
|
783
|
-
`;
|
|
784
|
-
return {
|
|
785
|
-
install,
|
|
786
|
-
usage,
|
|
787
|
-
license,
|
|
788
|
-
developTest: developTestSnippet(),
|
|
789
|
-
releaseSnippet
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
function missingSections(readme, sections) {
|
|
793
|
-
return sections.filter((section) => !closeEnough(section, readme));
|
|
794
|
-
}
|
|
795
|
-
function closeEnough(a, b) {
|
|
796
|
-
const aLines = a.split(`
|
|
797
|
-
`), bLines = b.split(`
|
|
798
|
-
`);
|
|
799
|
-
return aLines.filter((line) => bLines.find((bLine) => bLine === line)).length >= aLines.length * 0.5;
|
|
800
|
-
}
|
|
801
|
-
function semverWorkflowFiles() {
|
|
802
|
-
return [
|
|
803
|
-
{
|
|
804
|
-
type: "copy",
|
|
805
|
-
from: [".github", "workflows", "main.yml"],
|
|
806
|
-
to: [".github", "workflows", "main.yml"]
|
|
807
|
-
},
|
|
808
|
-
{ type: "copy", from: [".husky", "commit-msg"], to: [".husky", "commit-msg"] },
|
|
809
|
-
{ type: "copy", from: [".husky", "pre-commit"], to: [".husky", "pre-commit"] },
|
|
810
|
-
{ type: "copy", from: [".releaserc.json"], to: ".releaserc.json" },
|
|
811
|
-
{ type: "copy", from: ["commitlint.template.js"], to: "commitlint.config.js" },
|
|
812
|
-
{ type: "copy", from: ["lint-staged.template.js"], to: "lint-staged.config.js" }
|
|
813
|
-
].map((fromTo) => fromTo.type === "copy" ? {
|
|
814
|
-
...fromTo,
|
|
815
|
-
from: ["semver-workflow", ...fromTo.from]
|
|
816
|
-
} : fromTo);
|
|
817
|
-
}
|
|
818
|
-
async function semverWorkflowDependencies() {
|
|
819
|
-
return resolveLatestVersions([
|
|
820
|
-
"@commitlint/cli",
|
|
821
|
-
"@commitlint/config-conventional",
|
|
822
|
-
"@sanity/semantic-release-preset",
|
|
823
|
-
"husky",
|
|
824
|
-
"lint-staged"
|
|
825
|
-
]);
|
|
826
|
-
}
|
|
827
|
-
function readmeBaseurl(pkg2) {
|
|
828
|
-
return (pkg2.repository?.url ?? pkg2.homepage ?? "TODO").replace(/.+:\/\//g, "https://").replace(/\.git/g, "").replace(/git@github.com\//g, "github.com/").replace(/git@github.com:/g, "https://github.com/").replace(/#.+/g, "");
|
|
829
|
-
}
|
|
830
|
-
const forcedPackageVersions = {}, forcedDevPackageVersions = {}, forcedPeerPackageVersions = {
|
|
831
|
-
react: "^18",
|
|
832
|
-
"react-dom": "^18",
|
|
833
|
-
"@types/react": "^18",
|
|
834
|
-
"@types/react-dom": "^18",
|
|
835
|
-
sanity: "^3",
|
|
836
|
-
"styled-components": "^5.2"
|
|
837
|
-
}, ui = {
|
|
838
|
-
name: "ui",
|
|
839
|
-
description: "`@sanity/ui` and dependencies",
|
|
840
|
-
apply: applyPreset$1
|
|
841
|
-
};
|
|
842
|
-
async function applyPreset$1(options) {
|
|
843
|
-
await addDependencies(options), await addDevDependencies$1(options), log.info(chalk.green("ui preset injected"));
|
|
844
|
-
}
|
|
845
|
-
async function addDependencies(options) {
|
|
846
|
-
const pkg2 = await getPackage(options), newDeps = sortKeys(
|
|
847
|
-
forceDependencyVersions(
|
|
848
|
-
{
|
|
849
|
-
...pkg2.dependencies,
|
|
850
|
-
...await resolveDependencyList()
|
|
851
|
-
},
|
|
852
|
-
forcedPackageVersions
|
|
853
|
-
)
|
|
854
|
-
), newPkg = { ...pkg2 };
|
|
855
|
-
newPkg.dependencies = newDeps, await writePackageJsonDirect(newPkg, options), log.info("Updated dependencies.");
|
|
856
|
-
}
|
|
857
|
-
async function addDevDependencies$1(options) {
|
|
858
|
-
const pkg2 = await getPackage(options), newDeps = sortKeys(
|
|
859
|
-
forceDependencyVersions(
|
|
860
|
-
{
|
|
861
|
-
...pkg2.devDependencies,
|
|
862
|
-
...await resolveDevDependencyList()
|
|
863
|
-
},
|
|
864
|
-
forcedDevPackageVersions
|
|
865
|
-
)
|
|
866
|
-
), newPkg = { ...pkg2 };
|
|
867
|
-
newPkg.devDependencies = newDeps, await writePackageJsonDirect(newPkg, options), log.info("Updated devDependencies.");
|
|
868
|
-
}
|
|
869
|
-
async function resolveDependencyList() {
|
|
870
|
-
return resolveLatestVersions(["@sanity/icons", "@sanity/ui"]);
|
|
871
|
-
}
|
|
872
|
-
async function resolveDevDependencyList() {
|
|
873
|
-
return resolveLatestVersions([
|
|
874
|
-
// install the peer dependencies of `@sanity/ui` as dev dependencies
|
|
875
|
-
"react",
|
|
876
|
-
"react-dom",
|
|
877
|
-
"styled-components"
|
|
878
|
-
]);
|
|
879
|
-
}
|
|
880
|
-
const uiWorkshop = {
|
|
881
|
-
name: "ui-workshop",
|
|
882
|
-
description: "Files for testing custom components with @sanity/ui-workshop",
|
|
883
|
-
apply: applyPreset
|
|
884
|
-
};
|
|
885
|
-
async function applyPreset(options) {
|
|
886
|
-
await writeAssets(files(), options), await addDevDependencies(options), await updateGitIgnore(options), log.info(
|
|
887
|
-
chalk.green(
|
|
888
|
-
outdent$1`
|
|
889
|
-
ui-workshop preset injected.
|
|
890
|
-
|
|
891
|
-
Please confer
|
|
892
|
-
https://github.com/sanity-io/plugin-kit/blob/main/docs/ui-workshop.md#manual-steps-after-inject
|
|
893
|
-
to finalize configuration for this preset.
|
|
894
|
-
`.trim()
|
|
895
|
-
)
|
|
896
|
-
);
|
|
897
|
-
}
|
|
898
|
-
function files() {
|
|
899
|
-
return [
|
|
900
|
-
{ type: "copy", from: ["workshop.config.ts"], to: ["workshop.config.ts"] },
|
|
901
|
-
{ type: "copy", from: ["src", "CustomField.tsx"], to: ["src", "CustomField.tsx"] },
|
|
902
|
-
{
|
|
903
|
-
type: "copy",
|
|
904
|
-
from: ["src", "__workshop__", "index.tsx"],
|
|
905
|
-
to: ["src", "__workshop__", "index.tsx"]
|
|
906
|
-
},
|
|
907
|
-
{
|
|
908
|
-
type: "copy",
|
|
909
|
-
from: ["src", "__workshop__", "props.tsx"],
|
|
910
|
-
to: ["src", "__workshop__", "props.tsx"]
|
|
911
|
-
}
|
|
912
|
-
].map((fromTo) => fromTo.type === "copy" ? {
|
|
913
|
-
...fromTo,
|
|
914
|
-
from: ["ui-workshop", ...fromTo.from]
|
|
915
|
-
} : fromTo);
|
|
916
|
-
}
|
|
917
|
-
async function updateGitIgnore(options) {
|
|
918
|
-
const { basePath } = options, gitignorePath = path.join(basePath, ".gitignore");
|
|
919
|
-
let gitignore = await readFile$1(gitignorePath, "utf8").catch(errorToUndefined) ?? "";
|
|
920
|
-
const value = ".workshop";
|
|
921
|
-
gitignore.includes(value) || (gitignore += `
|
|
922
|
-
|
|
923
|
-
${value}`, await writeFile(gitignorePath, gitignore, { encoding: "utf8" }));
|
|
924
|
-
}
|
|
925
|
-
async function addDevDependencies(options) {
|
|
926
|
-
const pkg2 = await getPackage(options), devDeps = sortKeys({
|
|
927
|
-
...pkg2.devDependencies,
|
|
928
|
-
...await devDependencies()
|
|
929
|
-
}), newPkg = { ...pkg2 };
|
|
930
|
-
newPkg.devDependencies = devDeps, await writePackageJsonDirect(newPkg, options), log.info("Updated devDependencies.");
|
|
931
|
-
}
|
|
932
|
-
async function devDependencies() {
|
|
933
|
-
return resolveLatestVersions([
|
|
934
|
-
"@sanity/ui-workshop",
|
|
935
|
-
"@sanity/icons",
|
|
936
|
-
"@sanity/ui",
|
|
937
|
-
"react",
|
|
938
|
-
"react-dom",
|
|
939
|
-
"styled-components"
|
|
940
|
-
]);
|
|
941
|
-
}
|
|
942
|
-
const presets = [semverWorkflowPreset, renovatePreset, ui, uiWorkshop], presetNames = presets.map((p) => p?.name);
|
|
943
|
-
function presetHelpList(padStart) {
|
|
944
|
-
return presets.map((p) => `${"".padStart(padStart)}${p.name.padEnd(20)}${p.description}`).join(`
|
|
945
|
-
`);
|
|
946
|
-
}
|
|
947
|
-
async function injectPresets(options) {
|
|
948
|
-
if (options.flags.presetOnly && !options.flags.preset?.length)
|
|
949
|
-
throw new Error("--preset-only, but no --preset [preset-name] was provided.");
|
|
950
|
-
const applyPresets = presetsFromInput(options.flags.preset);
|
|
951
|
-
for (const preset of applyPresets)
|
|
952
|
-
await preset.apply(options);
|
|
953
|
-
}
|
|
954
|
-
function presetsFromInput(inputPresets) {
|
|
955
|
-
if (!inputPresets)
|
|
956
|
-
return [];
|
|
957
|
-
const unknownPresets = inputPresets.filter((p) => !presetNames.includes(p));
|
|
958
|
-
if (unknownPresets.length)
|
|
959
|
-
throw new Error(
|
|
960
|
-
`Unknown --preset(s): [${unknownPresets.join(", ")}]. Must be one of: [${presetNames.join(
|
|
961
|
-
", "
|
|
962
|
-
)}]`
|
|
963
|
-
);
|
|
964
|
-
return inputPresets.filter(onlyUnique).map((presetName) => presets.find((p) => p.name === presetName)).filter((p) => !!p);
|
|
965
|
-
}
|
|
966
|
-
function onlyUnique(value, index, arr) {
|
|
967
|
-
return arr.indexOf(value) === index;
|
|
968
|
-
}
|
|
969
|
-
const bannedFields = ["login", "description", "projecturl", "email"], preferredLicenses = ["MIT", "ISC", "BSD-3-Clause"], otherLicenses = Object.keys(licenses.list).filter((id) => {
|
|
970
|
-
const license = licenses.list[id];
|
|
971
|
-
return !preferredLicenses.includes(id) && !bannedFields.some((field) => license.body.includes(`[${field}]`));
|
|
972
|
-
});
|
|
973
|
-
async function inject(options) {
|
|
974
|
-
options.flags.presetOnly ? log.info("Only apply presets, skipping default inject.") : await injectBase(options), await injectPresets(options);
|
|
975
|
-
}
|
|
976
|
-
async function injectBase(options) {
|
|
977
|
-
const { basePath, flags, requireUserConfirmation } = options, info2 = (write, msg, ...args) => write && log.info(msg, ...args), pkg2 = await getPackage(options).catch(errorToUndefined);
|
|
978
|
-
log.debug("Plugin has package.json: %s", pkg2 ? "yes" : "no");
|
|
979
|
-
const user = await getUserInfo(options, pkg2);
|
|
980
|
-
log.debug("User information: %o", user);
|
|
981
|
-
const pkgName = flags.name ?? pkg2?.name, pluginName = requireUserConfirmation || !pkgName ? await promptForPackageName(options, pkgName) : pkgName;
|
|
982
|
-
log.debug("Plugin name: %s", pluginName);
|
|
983
|
-
const license = await getLicense(flags, { user, pluginName, pkg: pkg2, requireUserConfirmation }), licenseChanged = (pkg2 && pkg2.license) !== (license && license.id);
|
|
984
|
-
log.debug("License: %s", license ? license.id : "<none>");
|
|
985
|
-
const description = await getProjectDescription(basePath, pkg2, requireUserConfirmation);
|
|
986
|
-
log.debug("Description: %s", description || "<none>");
|
|
987
|
-
const repoUrl = flags.repo ?? (await gitRemoteOriginUrl(basePath).catch(errorToUndefined) || pkg2?.repository?.url), gitOrigin = requireUserConfirmation ? await promptForRepoOrigin(options, repoUrl) : repoUrl;
|
|
988
|
-
log.debug("Remote origin: %s", gitOrigin || "<none>");
|
|
989
|
-
const data = { user, pluginName, license, description, pkg: pkg2, gitOrigin };
|
|
990
|
-
let didWrite;
|
|
991
|
-
const newPkg = await writePackageJson(data, options);
|
|
992
|
-
info2(newPkg !== pkg2, "Wrote package.json"), data.pkg = newPkg, didWrite = await writeLicense(data, options, licenseChanged), info2(didWrite, "Wrote license file (LICENSE)"), didWrite = await writeReadme(data, options), info2(didWrite, "Wrote readme file (README.md)"), didWrite = await writeStaticAssets(options), info2(didWrite.length > 0, "Wrote static asset files: %s", didWrite.join(", ")), didWrite = await addBuildScripts(newPkg, options), info2(didWrite, "Added build scripts to package.json"), didWrite = await addCompileDirToGitIgnore(options), info2(didWrite, "Added compilation output directory to .gitignore");
|
|
993
|
-
}
|
|
994
|
-
async function writeReadme(data, options) {
|
|
995
|
-
const { basePath } = options, readmePath = path.join(basePath, "README.md"), readme = await readFile$1(readmePath, "utf8").catch(errorToUndefined);
|
|
996
|
-
return readme && !isDefaultGitHubReadme(readme) ? !1 : (await writeFileWithOverwritePrompt(readmePath, generateReadme(data), {
|
|
997
|
-
encoding: "utf8",
|
|
998
|
-
force: options.flags.force
|
|
999
|
-
}), !0);
|
|
1000
|
-
}
|
|
1001
|
-
async function writeLicense({ license }, options, licenseChanged) {
|
|
1002
|
-
const { basePath, flags } = options;
|
|
1003
|
-
if (flags.license === !1 || !license)
|
|
1004
|
-
return !1;
|
|
1005
|
-
const hasLicenseMdFile = await fileExists(path.join(basePath, "LICENSE.md")), licensePath = path.join(basePath, hasLicenseMdFile ? "LICENSE.md" : "LICENSE");
|
|
1006
|
-
return await writeFileWithOverwritePrompt(licensePath, license.text, {
|
|
1007
|
-
encoding: "utf8",
|
|
1008
|
-
default: licenseChanged,
|
|
1009
|
-
force: flags.force
|
|
1010
|
-
}), !0;
|
|
1011
|
-
}
|
|
1012
|
-
async function getLicense(flags, {
|
|
1013
|
-
user,
|
|
1014
|
-
pluginName,
|
|
1015
|
-
pkg: pkg2,
|
|
1016
|
-
requireUserConfirmation
|
|
1017
|
-
}) {
|
|
1018
|
-
const license = await getLicenseIdentifier(flags, pkg2, requireUserConfirmation);
|
|
1019
|
-
if (!license)
|
|
1020
|
-
return;
|
|
1021
|
-
const text = license.body.replace(/\[fullname\]/g, user?.name).replace(/\[project\]/g, pluginName).replace(/\[year\]/g, (/* @__PURE__ */ new Date()).getFullYear());
|
|
1022
|
-
return { id: license.id, text };
|
|
1023
|
-
}
|
|
1024
|
-
async function getLicenseIdentifier(flags, pkg2, requireUserConfirmation = !1) {
|
|
1025
|
-
if (flags.license === !1)
|
|
1026
|
-
return null;
|
|
1027
|
-
if (typeof flags.license == "string") {
|
|
1028
|
-
const license = licenses.find(`${flags.license}`);
|
|
1029
|
-
if (!license)
|
|
1030
|
-
throw new Error(`License "${flags.license}" not found`);
|
|
1031
|
-
return license;
|
|
1032
|
-
}
|
|
1033
|
-
if (pkg2 && pkg2.license && !requireUserConfirmation) {
|
|
1034
|
-
const license = licenses.find(`${pkg2.license}`);
|
|
1035
|
-
if (license)
|
|
1036
|
-
return license;
|
|
1037
|
-
log.warn(`package.json contains license "${pkg2.license}", which is not recognized`);
|
|
1038
|
-
}
|
|
1039
|
-
const licenseId = await prompt("Which license do you want to use?", {
|
|
1040
|
-
default: pkg2 && pkg2.license && licenses.find(pkg2.license) ? pkg2.license : preferredLicenses[0],
|
|
1041
|
-
choices: [
|
|
1042
|
-
prompt.separator(),
|
|
1043
|
-
...preferredLicenses.map((value) => ({ value, name: licenses.list[value].title })),
|
|
1044
|
-
prompt.separator(),
|
|
1045
|
-
...otherLicenses.map((value) => ({ value, name: licenses.list[value].title }))
|
|
1046
|
-
]
|
|
1047
|
-
});
|
|
1048
|
-
return licenses.find(licenseId);
|
|
1049
|
-
}
|
|
1050
|
-
async function getProjectDescription(basePath, pkg2, requireUserConfirmation = !1) {
|
|
1051
|
-
let description = await resolveProjectDescription(basePath, pkg2);
|
|
1052
|
-
return requireUserConfirmation && (description = await prompt("Plugin description", { default: description || "" })), description ?? "";
|
|
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;
|
|
1053
165
|
}
|
|
1054
|
-
async function
|
|
1055
|
-
|
|
1056
|
-
|
|
166
|
+
async function readFileContent({
|
|
167
|
+
filename,
|
|
168
|
+
basePath
|
|
169
|
+
}) {
|
|
170
|
+
const filepath = path.normalize(path.join(basePath, filename));
|
|
1057
171
|
try {
|
|
1058
|
-
|
|
1059
|
-
`).filter(Boolean);
|
|
1060
|
-
if (!title || !description || !title.match(/^#\s+\w+/))
|
|
1061
|
-
return null;
|
|
1062
|
-
const unlinked = description.replace(/\[(.*?)\]\(.*?\)/g, "$1");
|
|
1063
|
-
return /^[^#]/.test(unlinked) ? unlinked : null;
|
|
172
|
+
return await readFile$2(filepath, "utf8");
|
|
1064
173
|
} catch (err) {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
async function writeAssets(injectables, { basePath, flags }) {
|
|
1069
|
-
const assetsDir = await findAssetsDir(), from = (...segments) => path.join(assetsDir, "inject", ...segments), to = (...segments) => path.join(basePath, ...segments), writes = [];
|
|
1070
|
-
for (const injectable of injectables) {
|
|
1071
|
-
if (injectable.type === "copy") {
|
|
1072
|
-
const fromPath = asArray(injectable.from), toPath = asArray(injectable.to);
|
|
1073
|
-
await copyFileWithOverwritePrompt(from(...fromPath), to(...toPath), flags) && writes.push(path.join(...toPath));
|
|
1074
|
-
continue;
|
|
1075
|
-
}
|
|
1076
|
-
if (injectable.type === "template") {
|
|
1077
|
-
const toPath = asArray(injectable.to);
|
|
1078
|
-
await writeFileWithOverwritePrompt(to(...toPath), `${injectable.value.trim()}
|
|
1079
|
-
`, {
|
|
1080
|
-
default: "n",
|
|
1081
|
-
force: injectable.force || flags.force
|
|
1082
|
-
}), writes.push(path.join(...toPath));
|
|
1083
|
-
continue;
|
|
174
|
+
if (err.code === "ENOENT") {
|
|
175
|
+
log.debug(`No ${filename} file found.`);
|
|
176
|
+
return;
|
|
1084
177
|
}
|
|
1085
|
-
throw new Error(`
|
|
178
|
+
throw new Error(`Failed to read "${filepath}": ${err.message}`);
|
|
1086
179
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
flags.prettier && prettierignoreTemplate({ outDir }),
|
|
1102
|
-
flags.prettier && { type: "copy", from: "prettierrc.json", to: ".prettierrc" }
|
|
1103
|
-
].map((f) => f || void 0).filter((f) => !!f);
|
|
1104
|
-
return writeAssets(files2, options);
|
|
1105
|
-
}
|
|
1106
|
-
function asArray(input) {
|
|
1107
|
-
return typeof input == "string" ? [input] : input;
|
|
1108
|
-
}
|
|
1109
|
-
async function findAssetsDir() {
|
|
1110
|
-
let maxBackpaddle = 3, currDir = path.dirname(fileURLToPath(import.meta.url)), assetsDir = "";
|
|
1111
|
-
for (; !assetsDir && maxBackpaddle; ) {
|
|
1112
|
-
currDir = path.join(currDir, "..");
|
|
1113
|
-
const assets = path.join(currDir, "assets");
|
|
1114
|
-
await fileExists(assets) ? assetsDir = assets : maxBackpaddle--;
|
|
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);
|
|
188
|
+
}
|
|
189
|
+
function parseJson5(content, errorKey) {
|
|
190
|
+
try {
|
|
191
|
+
return json5.parse(content);
|
|
192
|
+
} catch (err) {
|
|
193
|
+
throw new Error(`Error parsing "${errorKey}": ${err.message}`);
|
|
1115
194
|
}
|
|
1116
|
-
if (!assetsDir)
|
|
1117
|
-
throw new Error("Could not find assets directory!");
|
|
1118
|
-
return assetsDir;
|
|
1119
|
-
}
|
|
1120
|
-
async function addCompileDirToGitIgnore(options) {
|
|
1121
|
-
const gitIgnorePath = path.join(options.basePath, ".gitignore"), gitignore = await readFile$1(gitIgnorePath, "utf8").catch(errorToUndefined);
|
|
1122
|
-
if (!gitignore)
|
|
1123
|
-
return !1;
|
|
1124
|
-
const ignore = options.outDir.replace(/^[./]+/, "").split("/")[0];
|
|
1125
|
-
if (!ignore)
|
|
1126
|
-
return !1;
|
|
1127
|
-
const lines = gitignore.trim().split(`
|
|
1128
|
-
`);
|
|
1129
|
-
return lines.includes(ignore) ? !1 : (lines.push("", "# Compiled plugin", ignore), await writeFile(gitIgnorePath, lines.join(`
|
|
1130
|
-
`) + `
|
|
1131
|
-
`, { encoding: "utf8" }), !0);
|
|
1132
195
|
}
|
|
1133
|
-
const
|
|
1134
|
-
"@sanity/base",
|
|
1135
|
-
"@sanity/core",
|
|
1136
|
-
"@sanity/types",
|
|
1137
|
-
"@sanity/data-aspects",
|
|
1138
|
-
"@sanity/default-layout",
|
|
1139
|
-
"@sanity/default-login",
|
|
1140
|
-
"@sanity/desk-tool",
|
|
1141
|
-
"@sanity/field",
|
|
1142
|
-
"@sanity/form-builder",
|
|
1143
|
-
"@sanity/initial-value-templates",
|
|
1144
|
-
"@sanity/language-filter",
|
|
1145
|
-
"@sanity/production-preview",
|
|
1146
|
-
"@sanity/react-hooks",
|
|
1147
|
-
"@sanity/resolver",
|
|
1148
|
-
"@sanity/state-router",
|
|
1149
|
-
"@sanity/structure",
|
|
1150
|
-
"@sanity/studio-hints"
|
|
1151
|
-
].sort(), deprecatedDevDeps = [
|
|
1152
|
-
"tsdx",
|
|
1153
|
-
"sanipack",
|
|
1154
|
-
"parcel",
|
|
1155
|
-
"@parcel/packager-ts",
|
|
1156
|
-
"@parcel/transformer-typescript-types"
|
|
1157
|
-
], expectedScripts = {
|
|
196
|
+
const expectedScripts = {
|
|
1158
197
|
build: "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
|
|
1159
198
|
watch: "pkg-utils watch --strict",
|
|
1160
199
|
"link-watch": "plugin-kit link-watch",
|
|
@@ -1165,7 +204,7 @@ function filesWithSuffixes(fileBases, suffixes) {
|
|
|
1165
204
|
}
|
|
1166
205
|
function validateNodeEngine(packageJson) {
|
|
1167
206
|
return packageJson.engines?.node !== requiredNodeEngine ? [
|
|
1168
|
-
outdent
|
|
207
|
+
outdent`
|
|
1169
208
|
Expected package.json to contain engines.node: "${requiredNodeEngine}" to match @sanity/pkg-utils,
|
|
1170
209
|
but it was: ${packageJson.engines?.node}
|
|
1171
210
|
|
|
@@ -1182,7 +221,7 @@ function validateScripts(packageJson) {
|
|
|
1182
221
|
return !command || !command.includes(expectedCommand);
|
|
1183
222
|
});
|
|
1184
223
|
return divergentScripts.length && errors.push(
|
|
1185
|
-
outdent
|
|
224
|
+
outdent`
|
|
1186
225
|
The following script commands did not contain expected defaults: ${divergentScripts.map(([key]) => key).join(", ")}
|
|
1187
226
|
|
|
1188
227
|
This checks for that the commands-strings includes these terms.
|
|
@@ -1210,7 +249,7 @@ async function validateTsConfig(ts, options) {
|
|
|
1210
249
|
const expectedOutput = wrongEntries.map(([key, value]) => `"${key}": ${typeof value == "string" ? `"${value}"` : value},`).join(`
|
|
1211
250
|
`);
|
|
1212
251
|
errors.push(
|
|
1213
|
-
outdent
|
|
252
|
+
outdent`
|
|
1214
253
|
Recommended ${tsconfig} compilerOptions missing:
|
|
1215
254
|
|
|
1216
255
|
The following fields had unexpected values: [${wrongEntries.map(([key]) => key).join(", ")}]
|
|
@@ -1225,7 +264,7 @@ async function validateTsConfig(ts, options) {
|
|
|
1225
264
|
}
|
|
1226
265
|
function validatePackageType({ type }) {
|
|
1227
266
|
return type === "module" ? [] : [
|
|
1228
|
-
outdent
|
|
267
|
+
outdent`
|
|
1229
268
|
package.json must set "type": "module" — plugins built with @sanity/plugin-kit are ESM-only.
|
|
1230
269
|
Found: ${type ? `"type": "${type}"` : 'no "type" field (defaults to "commonjs")'}
|
|
1231
270
|
|
|
@@ -1235,9 +274,9 @@ function validatePackageType({ type }) {
|
|
|
1235
274
|
`.trimStart()
|
|
1236
275
|
];
|
|
1237
276
|
}
|
|
1238
|
-
function validatePkgUtilsDependency({ devDependencies
|
|
1239
|
-
return
|
|
1240
|
-
outdent
|
|
277
|
+
function validatePkgUtilsDependency({ devDependencies }) {
|
|
278
|
+
return devDependencies?.["@sanity/pkg-utils"] ? [] : [
|
|
279
|
+
outdent`
|
|
1241
280
|
package.json does not list @sanity/pkg-utils as a devDependency.
|
|
1242
281
|
@sanity/pkg-utils replaced parcel as the recommended build tool in @sanity/plugin-kit 2.0.0
|
|
1243
282
|
|
|
@@ -1252,7 +291,7 @@ function validatePkgUtilsVersion({ basePath }) {
|
|
|
1252
291
|
installedVersion = require2("@sanity/pkg-utils/package.json").version;
|
|
1253
292
|
} catch {
|
|
1254
293
|
return [
|
|
1255
|
-
outdent
|
|
294
|
+
outdent`
|
|
1256
295
|
@sanity/pkg-utils is not installed.
|
|
1257
296
|
plugin-kit loads package.config.ts through @sanity/pkg-utils (a peer dependency).
|
|
1258
297
|
|
|
@@ -1262,7 +301,7 @@ function validatePkgUtilsVersion({ basePath }) {
|
|
|
1262
301
|
}
|
|
1263
302
|
const major = Number.parseInt(installedVersion?.split(".")[0] ?? "", 10);
|
|
1264
303
|
return !Number.isFinite(major) || major < minPkgUtilsMajor ? [
|
|
1265
|
-
outdent
|
|
304
|
+
outdent`
|
|
1266
305
|
@sanity/pkg-utils ${installedVersion} is too old.
|
|
1267
306
|
plugin-kit requires @sanity/pkg-utils >=${minPkgUtilsMajor} to load package.config.ts.
|
|
1268
307
|
|
|
@@ -1271,9 +310,9 @@ function validatePkgUtilsVersion({ basePath }) {
|
|
|
1271
310
|
] : [];
|
|
1272
311
|
}
|
|
1273
312
|
function validateSanityDependencies(packageJson) {
|
|
1274
|
-
const { dependencies, devDependencies
|
|
313
|
+
const { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies }, illegalDeps = Object.keys(allDependencies).filter((dep) => mergedPackages.includes(dep)), unique = [...new Set(illegalDeps).values()];
|
|
1275
314
|
return unique.length ? [
|
|
1276
|
-
outdent
|
|
315
|
+
outdent`
|
|
1277
316
|
package.json depends on "@sanity/*" packages that have moved into "sanity" package.
|
|
1278
317
|
|
|
1279
318
|
The following dependencies should be replaced with "sanity":
|
|
@@ -1286,9 +325,9 @@ function validateSanityDependencies(packageJson) {
|
|
|
1286
325
|
] : [];
|
|
1287
326
|
}
|
|
1288
327
|
function validateDeprecatedDependencies(packageJson) {
|
|
1289
|
-
const { dependencies, devDependencies
|
|
328
|
+
const { dependencies, devDependencies, peerDependencies } = packageJson, allDependencies = { ...dependencies, ...devDependencies, ...peerDependencies }, illegalDeps = Object.keys(allDependencies).filter((dep) => deprecatedDevDeps.includes(dep)), unique = [...new Set(illegalDeps).values()];
|
|
1290
329
|
return unique.length ? [
|
|
1291
|
-
outdent
|
|
330
|
+
outdent`
|
|
1292
331
|
package.json contains deprecated dependencies that should be removed:
|
|
1293
332
|
- ${unique.join(`
|
|
1294
333
|
- `)}
|
|
@@ -1302,7 +341,7 @@ async function validateBabelConfig({ basePath }) {
|
|
|
1302
341
|
await fileExists(filepath) && babelFiles.push(filename);
|
|
1303
342
|
}
|
|
1304
343
|
return babelFiles.length ? [
|
|
1305
|
-
outdent
|
|
344
|
+
outdent`
|
|
1306
345
|
Found babel-config file: [${babelFiles.join(
|
|
1307
346
|
", "
|
|
1308
347
|
)}]. When using default @sanity/plugin-kit build command,
|
|
@@ -1313,38 +352,38 @@ async function validateBabelConfig({ basePath }) {
|
|
|
1313
352
|
] : [];
|
|
1314
353
|
}
|
|
1315
354
|
async function validateStudioConfig({ basePath }) {
|
|
1316
|
-
const suffixes = ["ts", "js", "tsx", "jsx"], filenames = filesWithSuffixes(["sanity.config", "sanity.cli"], suffixes),
|
|
355
|
+
const suffixes = ["ts", "js", "tsx", "jsx"], filenames = filesWithSuffixes(["sanity.config", "sanity.cli"], suffixes), files = {};
|
|
1317
356
|
for (const filename of filenames) {
|
|
1318
357
|
const filepath = path.normalize(path.join(basePath, filename));
|
|
1319
|
-
|
|
358
|
+
files[filename] = await fileExists(filepath);
|
|
1320
359
|
}
|
|
1321
|
-
const sanityJson = await readJson5File({ basePath, filename: "sanity.json" }), hasConfigFile = (fileBase) => filesWithSuffixes([fileBase], suffixes).some((filename) =>
|
|
360
|
+
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 = [];
|
|
1322
361
|
if (sanityJson) {
|
|
1323
|
-
const
|
|
1324
|
-
outdent
|
|
362
|
+
const info = [
|
|
363
|
+
outdent`
|
|
1325
364
|
Found sanity.json. This file is not used by Sanity Studio V3.
|
|
1326
365
|
|
|
1327
366
|
Please consult the Studio V3 migration guide:
|
|
1328
367
|
${urls.migrationGuideStudio}
|
|
1329
368
|
It will detail how to convert sanity.json to sanity.config.ts (or .js) and sanity.cli.ts (or .js) equivalents.
|
|
1330
369
|
`.trimStart(),
|
|
1331
|
-
sanityJson.plugins?.length && outdent
|
|
370
|
+
sanityJson.plugins?.length && outdent`
|
|
1332
371
|
For V3 versions and alternatives to V2 plugins, please refer to the Sanity Exchange:
|
|
1333
372
|
${urls.sanityExchange}
|
|
1334
373
|
`.trimStart()
|
|
1335
374
|
].filter((s) => !!s);
|
|
1336
|
-
errors.push(
|
|
375
|
+
errors.push(info.join(`
|
|
1337
376
|
|
|
1338
377
|
`));
|
|
1339
378
|
}
|
|
1340
379
|
return hasCliConfig || errors.push(
|
|
1341
|
-
outdent
|
|
380
|
+
outdent`
|
|
1342
381
|
sanity.cli.(${suffixes.join(
|
|
1343
382
|
" | "
|
|
1344
383
|
)}) missing. Please create a file named sanity.cli.ts with the following content:
|
|
1345
384
|
|
|
1346
385
|
${chalk.green(
|
|
1347
|
-
outdent
|
|
386
|
+
outdent`
|
|
1348
387
|
import {createCliConfig} from 'sanity/cli'
|
|
1349
388
|
|
|
1350
389
|
export default createCliConfig({
|
|
@@ -1360,13 +399,13 @@ async function validateStudioConfig({ basePath }) {
|
|
|
1360
399
|
For more, see ${urls.migrationGuideStudio}
|
|
1361
400
|
`.trimStart()
|
|
1362
401
|
), hasStudioConfig || errors.push(
|
|
1363
|
-
outdent
|
|
402
|
+
outdent`
|
|
1364
403
|
sanity.config.(${suffixes.join(
|
|
1365
404
|
" | "
|
|
1366
405
|
)}) missing. At a minimum sanity.config.ts should contain:
|
|
1367
406
|
|
|
1368
407
|
${chalk.green(
|
|
1369
|
-
outdent
|
|
408
|
+
outdent`
|
|
1370
409
|
import { defineConfig } from "sanity"
|
|
1371
410
|
import { deskTool } from "sanity/desk"
|
|
1372
411
|
|
|
@@ -1416,13 +455,13 @@ async function validatePluginSanityJson({
|
|
|
1416
455
|
hasSinglePart ? null : 'sanity.json should have exactly one entry in "parts", but did not.',
|
|
1417
456
|
correctImplements ? null : `The part should implement ${expectedDefaults.parts[0].implements}, but did not.`,
|
|
1418
457
|
firstPart?.path && !pathExists ? `The file in "path", ${firstPart?.path}, does not exist.` : null,
|
|
1419
|
-
hasDependency ? null : outdent
|
|
458
|
+
hasDependency ? null : outdent`
|
|
1420
459
|
package.json should have ${incompatiblePluginPackage} as a dependency, but did not.
|
|
1421
460
|
Install it with: npm install --save ${incompatiblePluginPackage}
|
|
1422
461
|
`.trimStart()
|
|
1423
462
|
].filter((e) => !!e);
|
|
1424
463
|
return [
|
|
1425
|
-
outdent
|
|
464
|
+
outdent`
|
|
1426
465
|
Invalid sanity.json. It is used for compatibility checking in V2 studios:
|
|
1427
466
|
|
|
1428
467
|
- ${errors.join(`
|
|
@@ -1451,7 +490,7 @@ async function validateSrcIndexFile(basePath) {
|
|
|
1451
490
|
for (const indexFile of allowedIndexFiles)
|
|
1452
491
|
hasIndex = hasIndex || await fileExists(indexFile);
|
|
1453
492
|
return hasIndex ? [] : [
|
|
1454
|
-
outdent
|
|
493
|
+
outdent`
|
|
1455
494
|
Expected one of [${paths.join(", ")}] to exist.
|
|
1456
495
|
|
|
1457
496
|
@sanity/pkg-utils expects a non-jsx file to be the source entry-point for the plugin.
|
|
@@ -1463,21 +502,21 @@ async function disallowDuplicateConfig({
|
|
|
1463
502
|
basePath,
|
|
1464
503
|
pkgJson,
|
|
1465
504
|
configKey,
|
|
1466
|
-
files
|
|
505
|
+
files
|
|
1467
506
|
}) {
|
|
1468
507
|
const found = [];
|
|
1469
|
-
for (const file of
|
|
508
|
+
for (const file of files) {
|
|
1470
509
|
const filePath = path.join(basePath, file);
|
|
1471
510
|
await fileExists(filePath) && found.push(file);
|
|
1472
511
|
}
|
|
1473
512
|
return found.length > 1 ? [
|
|
1474
|
-
outdent
|
|
513
|
+
outdent`
|
|
1475
514
|
Found multiple config files that serve the same purpose: [${found.join(", ")}].
|
|
1476
515
|
|
|
1477
516
|
There should be at most one of these files. Delete the rest.
|
|
1478
517
|
`
|
|
1479
518
|
] : found.length && pkgJson[configKey] ? [
|
|
1480
|
-
outdent
|
|
519
|
+
outdent`
|
|
1481
520
|
package.json contains ${configKey}, but there also exists a config file that serves the same purpose.
|
|
1482
521
|
Config file: ${found.join("")}]
|
|
1483
522
|
|
|
@@ -1519,6 +558,209 @@ async function disallowDuplicatePrettierConfig(basePath, pkgJson) {
|
|
|
1519
558
|
]
|
|
1520
559
|
});
|
|
1521
560
|
}
|
|
561
|
+
const forcedPackageVersions = {}, forcedDevPackageVersions = {}, forcedPeerPackageVersions = {
|
|
562
|
+
react: "^18",
|
|
563
|
+
"react-dom": "^18",
|
|
564
|
+
"@types/react": "^18",
|
|
565
|
+
"@types/react-dom": "^18",
|
|
566
|
+
sanity: "^3",
|
|
567
|
+
"styled-components": "^5.2"
|
|
568
|
+
};
|
|
569
|
+
function errorToUndefined(err) {
|
|
570
|
+
if (err instanceof TypeError)
|
|
571
|
+
throw err;
|
|
572
|
+
}
|
|
573
|
+
const stat = util.promisify(fs.stat), readFile$1 = util.promisify(fs.readFile), allowedPartProps = ["name", "implements", "path", "description"], disallowedPluginProps = ["api", "project", "plugins", "env"];
|
|
574
|
+
async function getPaths(options) {
|
|
575
|
+
const { basePath } = options, manifest = await readManifest(options);
|
|
576
|
+
return manifest.paths ? absolutifyPaths(manifest.paths, basePath) : null;
|
|
577
|
+
}
|
|
578
|
+
function absolutifyPaths(paths, basePath) {
|
|
579
|
+
const getPath = (relative) => relative ? path.resolve(path.join(basePath, relative)) : void 0;
|
|
580
|
+
return paths ? {
|
|
581
|
+
basePath,
|
|
582
|
+
compiled: getPath(paths.compiled),
|
|
583
|
+
source: getPath(paths.source)
|
|
584
|
+
} : { basePath };
|
|
585
|
+
}
|
|
586
|
+
async function readManifest(options) {
|
|
587
|
+
const { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "sanity.json"));
|
|
588
|
+
let content;
|
|
589
|
+
try {
|
|
590
|
+
content = await readFile$1(manifestPath, "utf8");
|
|
591
|
+
} catch (err) {
|
|
592
|
+
throw err.code === "ENOENT" ? new Error(
|
|
593
|
+
`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.`
|
|
594
|
+
) : new Error(`Failed to read "${manifestPath}": ${err.message}`);
|
|
595
|
+
}
|
|
596
|
+
let parsed;
|
|
597
|
+
try {
|
|
598
|
+
parsed = JSON.parse(content);
|
|
599
|
+
} catch (err) {
|
|
600
|
+
throw new Error(`Error parsing "${manifestPath}": ${err.message}`);
|
|
601
|
+
}
|
|
602
|
+
return validate && await validateManifest(parsed, options), parsed;
|
|
603
|
+
}
|
|
604
|
+
async function validateManifest(manifest, opts) {
|
|
605
|
+
const options = { isPlugin: !0, ...opts };
|
|
606
|
+
if (!isObject$1(manifest))
|
|
607
|
+
throw new Error("Invalid sanity.json: Root must be an object");
|
|
608
|
+
if (options.isPlugin ? await validatePluginManifest(manifest, options) : validateProjectManifest(manifest), "root" in manifest && typeof manifest.root != "boolean")
|
|
609
|
+
throw new Error('Invalid sanity.json: "root" property must be a boolean if declared');
|
|
610
|
+
await validateParts(manifest, {
|
|
611
|
+
...options,
|
|
612
|
+
paths: absolutifyPaths(manifest.paths, options.basePath)
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
function validateProjectManifest(manifest) {
|
|
616
|
+
if ("paths" in manifest)
|
|
617
|
+
throw new Error('Invalid sanity.json: "paths" property has no meaning in a project manifest');
|
|
618
|
+
}
|
|
619
|
+
async function validatePluginManifest(manifest, options) {
|
|
620
|
+
const disallowed = Object.keys(manifest).filter((key) => disallowedPluginProps.includes(key)).map((key) => `"${key}"`);
|
|
621
|
+
if (disallowed.length > 0) {
|
|
622
|
+
const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
|
|
623
|
+
throw new Error(
|
|
624
|
+
`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a plugin manifest`
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
if (manifest.root)
|
|
628
|
+
throw new Error('Invalid sanity.json: "root" cannot be truthy in a plugin manifest');
|
|
629
|
+
await validatePaths$1(manifest, options);
|
|
630
|
+
}
|
|
631
|
+
async function validatePaths$1(manifest, options) {
|
|
632
|
+
if (!("paths" in manifest))
|
|
633
|
+
return;
|
|
634
|
+
if (!isObject$1(manifest.paths))
|
|
635
|
+
throw new Error('Invalid sanity.json: "paths" must be an object if declared');
|
|
636
|
+
if (typeof manifest.paths.compiled != "string")
|
|
637
|
+
throw new Error(
|
|
638
|
+
'Invalid sanity.json: "paths" must have a (string) "compiled" property if declared'
|
|
639
|
+
);
|
|
640
|
+
if (typeof manifest.paths.source != "string")
|
|
641
|
+
throw new Error(
|
|
642
|
+
'Invalid sanity.json: "paths" must have a (string) "source" property if declared'
|
|
643
|
+
);
|
|
644
|
+
const sourcePath = path.resolve(options.basePath, manifest.paths.source);
|
|
645
|
+
let srcStats;
|
|
646
|
+
try {
|
|
647
|
+
srcStats = await stat(sourcePath);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
if (err.code === "ENOENT")
|
|
650
|
+
throw new Error(`sanity.json references "source" path which does not exist: "${sourcePath}"`);
|
|
651
|
+
}
|
|
652
|
+
if (!srcStats?.isDirectory())
|
|
653
|
+
throw new Error(
|
|
654
|
+
`sanity.json references "source" path which is not a directory: "${sourcePath}"`
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
async function validateParts(manifest, options) {
|
|
658
|
+
if (!("parts" in manifest))
|
|
659
|
+
return;
|
|
660
|
+
if (!Array.isArray(manifest.parts))
|
|
661
|
+
throw new Error('Invalid sanity.json: "parts" must be an array if declared');
|
|
662
|
+
let i = 0;
|
|
663
|
+
for (const part of manifest.parts)
|
|
664
|
+
await validatePart(part, i, options), i++;
|
|
665
|
+
}
|
|
666
|
+
async function validatePart(part, index, options) {
|
|
667
|
+
if (!isObject$1(part))
|
|
668
|
+
throw new Error(`Invalid sanity.json: "parts[${index}]" must be an object`);
|
|
669
|
+
validateAllowedPartKeys(part, index), validatePartStringValues(part, index), validatePartNames(part, index, options), await validatePartFiles(part, index, options);
|
|
670
|
+
}
|
|
671
|
+
async function validatePartFiles(part, index, options) {
|
|
672
|
+
const { verifyCompiledParts, verifySourceParts, paths } = options;
|
|
673
|
+
if (!part?.path)
|
|
674
|
+
return;
|
|
675
|
+
const ext = path.extname(part.path);
|
|
676
|
+
if (paths?.source && ext && ext !== ".js" && buildExtensions.includes(ext))
|
|
677
|
+
throw new Error(
|
|
678
|
+
`Invalid sanity.json: Part path has extension which is not applicable after compiling. ${ext} becomes .js after compiling. Specify filename without extension (${path.basename(
|
|
679
|
+
part.path
|
|
680
|
+
)}) (parts[${index}])`
|
|
681
|
+
);
|
|
682
|
+
if (!verifySourceParts && !verifyCompiledParts)
|
|
683
|
+
return;
|
|
684
|
+
const [srcExists, outDirExists] = await Promise.all([
|
|
685
|
+
hasSourceFile(part.path, paths),
|
|
686
|
+
verifyCompiledParts && hasCompiledFile(part.path, paths)
|
|
687
|
+
]);
|
|
688
|
+
if (!srcExists)
|
|
689
|
+
throw new Error(
|
|
690
|
+
`Invalid sanity.json: Part path references file that does not exist in source directory (${paths?.source || paths?.basePath}) (parts[${index}])`
|
|
691
|
+
);
|
|
692
|
+
if (verifyCompiledParts && !outDirExists)
|
|
693
|
+
throw new Error(
|
|
694
|
+
`Invalid sanity.json: Part path references file ("${part.path}") that does not exist in compiled directory (${paths?.compiled}) (parts[${index}])`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
function validatePartNames(part, index, options) {
|
|
698
|
+
const pluginName = options.pluginName ? options.pluginName.replace(/^sanity-plugin-/, "") : "";
|
|
699
|
+
if (!part?.name || !part?.name?.startsWith(`part:${pluginName}/`))
|
|
700
|
+
throw new Error(
|
|
701
|
+
`Invalid sanity.json: "name" must be prefixed with "part:${pluginName}/" - got "${part?.name}" (parts[${index}])`
|
|
702
|
+
);
|
|
703
|
+
if (!part?.implements?.startsWith("part:"))
|
|
704
|
+
throw new Error(
|
|
705
|
+
`Invalid sanity.json: "implements" must be prefixed with "part:" - got "${part?.implements}" (parts[${index}])`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function validateAllowedPartKeys(part, index) {
|
|
709
|
+
const disallowed = Object.keys(part).filter((key) => !allowedPartProps.includes(key)).map((key) => `"${key}"`);
|
|
710
|
+
if (disallowed.length > 0) {
|
|
711
|
+
const plural = disallowed.length > 1 ? "s" : "", joined = disallowed.join(", ");
|
|
712
|
+
throw new Error(
|
|
713
|
+
`Invalid sanity.json: Key${plural} ${joined} ${plural ? "are" : "is"} not allowed in a part declaration (parts[${index}])`
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function validatePartStringValues(part, index) {
|
|
718
|
+
const nonStrings = Object.keys(part).filter((key) => typeof part[key] != "string").map((key) => `"${key}"`);
|
|
719
|
+
if (nonStrings.length > 0) {
|
|
720
|
+
const plural = nonStrings.length > 1 ? "s" : "", joined = nonStrings.join(", ");
|
|
721
|
+
throw new Error(
|
|
722
|
+
`Invalid sanity.json: Key${plural} ${joined} should be of type string (parts[${index}])`
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
function isObject$1(obj) {
|
|
727
|
+
return !Array.isArray(obj) && obj !== null && typeof obj == "object";
|
|
728
|
+
}
|
|
729
|
+
async function hasSanityJson(basePath) {
|
|
730
|
+
const file = await readJsonFile(path.join(basePath, "sanity.json")).catch(
|
|
731
|
+
errorToUndefined
|
|
732
|
+
);
|
|
733
|
+
return { exists: !!file, isRoot: !!(file && file.root) };
|
|
734
|
+
}
|
|
735
|
+
async function findStudioV3Config(basePath) {
|
|
736
|
+
const jsFile = "sanity.config.js";
|
|
737
|
+
if (await fileExists(path.join(basePath, jsFile)))
|
|
738
|
+
return { v3ConfigFile: jsFile };
|
|
739
|
+
const tsFile = "sanity.config.ts";
|
|
740
|
+
return { v3ConfigFile: await fileExists(path.join(basePath, tsFile)) ? tsFile : void 0 };
|
|
741
|
+
}
|
|
742
|
+
const lockedDependencies = {
|
|
743
|
+
"styled-components": "^6.1",
|
|
744
|
+
eslint: "^8.57.0"
|
|
745
|
+
};
|
|
746
|
+
function resolveLatestVersions(packages) {
|
|
747
|
+
const versions = {};
|
|
748
|
+
for (const pkgName of packages)
|
|
749
|
+
versions[pkgName] = pkgName in lockedDependencies ? lockedDependencies[pkgName] : "latest";
|
|
750
|
+
return pProps(
|
|
751
|
+
versions,
|
|
752
|
+
async (range, pkgName) => {
|
|
753
|
+
const version = await getLatestVersion(pkgName, { range });
|
|
754
|
+
if (!version)
|
|
755
|
+
throw new Error(`Found no version for ${pkgName}`);
|
|
756
|
+
return rangeify(version);
|
|
757
|
+
},
|
|
758
|
+
{ concurrency: 8 }
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
function rangeify(version) {
|
|
762
|
+
return `^${version}`;
|
|
763
|
+
}
|
|
1522
764
|
const defaultDependencies = [incompatiblePluginPackage], defaultDevDependencies = [
|
|
1523
765
|
"sanity",
|
|
1524
766
|
// peer dependencies of `sanity`
|
|
@@ -1529,7 +771,7 @@ const defaultDependencies = [incompatiblePluginPackage], defaultDevDependencies
|
|
|
1529
771
|
async function getPackage(opts) {
|
|
1530
772
|
const options = { flags: {}, ...opts };
|
|
1531
773
|
validateOptions(options);
|
|
1532
|
-
const { basePath, validate
|
|
774
|
+
const { basePath, validate = !0 } = options, manifestPath = path.normalize(path.join(basePath, "package.json"));
|
|
1533
775
|
let content;
|
|
1534
776
|
try {
|
|
1535
777
|
content = await readFile(manifestPath, "utf8");
|
|
@@ -1546,7 +788,7 @@ async function getPackage(opts) {
|
|
|
1546
788
|
}
|
|
1547
789
|
if (!isObject(parsed))
|
|
1548
790
|
throw new Error("Invalid package.json: Root must be an object");
|
|
1549
|
-
return
|
|
791
|
+
return validate && await validatePackage(parsed, options), parsed;
|
|
1550
792
|
}
|
|
1551
793
|
async function validatePackage(manifest, opts) {
|
|
1552
794
|
validateOptions(opts);
|
|
@@ -1635,7 +877,7 @@ async function writePackageJson(data, options) {
|
|
|
1635
877
|
...await resolveLatestVersions(defaultDependencies)
|
|
1636
878
|
},
|
|
1637
879
|
forcedPackageVersions
|
|
1638
|
-
),
|
|
880
|
+
), devDependencies = forceDependencyVersions(
|
|
1639
881
|
{
|
|
1640
882
|
...addDevDeps || {},
|
|
1641
883
|
...prev.devDependencies || {},
|
|
@@ -1649,8 +891,8 @@ async function writePackageJson(data, options) {
|
|
|
1649
891
|
...await resolveLatestVersions(defaultPeerDependencies)
|
|
1650
892
|
},
|
|
1651
893
|
forcedPeerPackageVersions
|
|
1652
|
-
), source = flags.typescript ? "./src/index.ts" : "./src/index.js",
|
|
1653
|
-
|
|
894
|
+
), source = flags.typescript ? "./src/index.ts" : "./src/index.js", files = [outDir, "sanity.json", "src", "v2-incompatible.js"];
|
|
895
|
+
files.sort();
|
|
1654
896
|
const forcedOrder = {
|
|
1655
897
|
name: pluginName,
|
|
1656
898
|
version: prev.version ?? "1.0.0",
|
|
@@ -1670,10 +912,10 @@ async function writePackageJson(data, options) {
|
|
|
1670
912
|
"./package.json": "./package.json"
|
|
1671
913
|
},
|
|
1672
914
|
...flags.typescript ? { types: `./${outDir}/index.d.ts` } : {},
|
|
1673
|
-
files
|
|
915
|
+
files,
|
|
1674
916
|
scripts: { ...prev.scripts },
|
|
1675
917
|
dependencies: sortKeys(dependencies),
|
|
1676
|
-
devDependencies: sortKeys(
|
|
918
|
+
devDependencies: sortKeys(devDependencies),
|
|
1677
919
|
peerDependencies: sortKeys(peerDependencies),
|
|
1678
920
|
engines: {
|
|
1679
921
|
node: requiredNodeEngine
|
|
@@ -1728,19 +970,31 @@ function forceDependencyVersions(deps, versions = forcedPackageVersions) {
|
|
|
1728
970
|
return Object.fromEntries(entries);
|
|
1729
971
|
}
|
|
1730
972
|
export {
|
|
973
|
+
addBuildScripts,
|
|
974
|
+
addPackageJsonScripts,
|
|
975
|
+
addScript,
|
|
976
|
+
copyFileWithOverwritePrompt,
|
|
1731
977
|
disallowDuplicateEslintConfig,
|
|
1732
978
|
disallowDuplicatePrettierConfig,
|
|
1733
979
|
ensureDir,
|
|
980
|
+
errorToUndefined,
|
|
1734
981
|
fileExists,
|
|
1735
982
|
findStudioV3Config,
|
|
983
|
+
forceDependencyVersions,
|
|
984
|
+
forcedDevPackageVersions,
|
|
985
|
+
forcedPackageVersions,
|
|
1736
986
|
getPackage,
|
|
1737
987
|
hasSanityJson,
|
|
1738
|
-
inject,
|
|
1739
988
|
isEmptyish,
|
|
1740
989
|
mergedPackages,
|
|
1741
990
|
mkdir,
|
|
1742
|
-
presetHelpList,
|
|
1743
991
|
prompt,
|
|
992
|
+
promptForPackageName,
|
|
993
|
+
promptForRepoOrigin,
|
|
994
|
+
readFile$2 as readFile,
|
|
995
|
+
readJsonFile,
|
|
996
|
+
resolveLatestVersions,
|
|
997
|
+
sortKeys,
|
|
1744
998
|
validateBabelConfig,
|
|
1745
999
|
validateDeprecatedDependencies,
|
|
1746
1000
|
validateNodeEngine,
|
|
@@ -1754,6 +1008,9 @@ export {
|
|
|
1754
1008
|
validateSrcIndexFile,
|
|
1755
1009
|
validateStudioConfig,
|
|
1756
1010
|
validateTsConfig,
|
|
1757
|
-
writeFile
|
|
1011
|
+
writeFile,
|
|
1012
|
+
writeFileWithOverwritePrompt,
|
|
1013
|
+
writePackageJson,
|
|
1014
|
+
writePackageJsonDirect
|
|
1758
1015
|
};
|
|
1759
1016
|
//# sourceMappingURL=package.js.map
|