@sanity/plugin-kit 4.0.20 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/inject/semver-workflow/.husky/commit-msg +0 -0
- package/assets/inject/semver-workflow/.husky/pre-commit +0 -0
- package/assets/inject/ui-workshop/src/__workshop__/props.tsx +2 -1
- package/bin/plugin-kit.js +3 -1
- package/dist/{_chunks-cjs/cli.js → _chunks-es/index.js} +53 -63
- package/dist/_chunks-es/index.js.map +1 -0
- package/dist/{_chunks-cjs/init2.js → _chunks-es/init.js} +25 -23
- package/dist/_chunks-es/init.js.map +1 -0
- package/dist/_chunks-es/init2.js +140 -0
- package/dist/_chunks-es/init2.js.map +1 -0
- package/{src/cmds/inject.ts → dist/_chunks-es/inject.js} +18 -32
- package/dist/{_chunks-cjs → _chunks-es}/inject.js.map +1 -1
- package/dist/_chunks-es/link-watch.js +91 -0
- package/dist/_chunks-es/link-watch.js.map +1 -0
- package/dist/_chunks-es/load-package-config.js +22 -0
- package/dist/_chunks-es/load-package-config.js.map +1 -0
- package/dist/_chunks-es/package.js +1759 -0
- package/dist/_chunks-es/package.js.map +1 -0
- package/dist/_chunks-es/package2.js +9 -0
- package/dist/{_chunks-cjs → _chunks-es}/package2.js.map +1 -1
- package/dist/_chunks-es/ts.js +171 -0
- package/dist/_chunks-es/ts.js.map +1 -0
- package/dist/_chunks-es/verify-package.js +92 -0
- package/dist/_chunks-es/verify-package.js.map +1 -0
- package/dist/_chunks-es/verify-studio.js +61 -0
- package/dist/_chunks-es/verify-studio.js.map +1 -0
- package/dist/_chunks-es/version.js +50 -0
- package/dist/_chunks-es/version.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +40 -98
- package/LICENSE +0 -21
- package/dist/_chunks-cjs/cli.js.map +0 -1
- package/dist/_chunks-cjs/init.js +0 -892
- package/dist/_chunks-cjs/init.js.map +0 -1
- package/dist/_chunks-cjs/init2.js.map +0 -1
- package/dist/_chunks-cjs/inject.js +0 -54
- package/dist/_chunks-cjs/link-watch.js +0 -84
- package/dist/_chunks-cjs/link-watch.js.map +0 -1
- package/dist/_chunks-cjs/package.js +0 -1809
- package/dist/_chunks-cjs/package.js.map +0 -1
- package/dist/_chunks-cjs/package2.js +0 -8
- package/dist/_chunks-cjs/ts.js +0 -160732
- package/dist/_chunks-cjs/ts.js.map +0 -1
- package/dist/_chunks-cjs/verify-package.js +0 -75
- package/dist/_chunks-cjs/verify-package.js.map +0 -1
- package/dist/_chunks-cjs/verify-studio.js +0 -57
- package/dist/_chunks-cjs/verify-studio.js.map +0 -1
- package/dist/_chunks-cjs/version.js +0 -51
- package/dist/_chunks-cjs/version.js.map +0 -1
- package/dist/cli.d.ts +0 -4
- package/dist/cli.js +0 -6
- package/dist/cli.js.map +0 -1
- package/src/actions/init.ts +0 -95
- package/src/actions/inject.ts +0 -399
- package/src/actions/link-watch.ts +0 -98
- package/src/actions/verify/types.ts +0 -56
- package/src/actions/verify/validations.ts +0 -505
- package/src/actions/verify/verify-common.ts +0 -93
- package/src/actions/verify-package.ts +0 -103
- package/src/actions/verify-studio.ts +0 -58
- package/src/cli.ts +0 -77
- package/src/cmds/index.ts +0 -20
- package/src/cmds/init.ts +0 -90
- package/src/cmds/link-watch.ts +0 -50
- package/src/cmds/verify-package.ts +0 -36
- package/src/cmds/verify-studio.ts +0 -36
- package/src/cmds/version.ts +0 -67
- package/src/configs/banned-packages.ts +0 -27
- package/src/configs/buildExtensions.ts +0 -1
- package/src/configs/default-source.ts +0 -64
- package/src/configs/eslint.ts +0 -51
- package/src/configs/forced-package-versions.ts +0 -12
- package/src/configs/git.ts +0 -68
- package/src/configs/pkg-config.ts +0 -30
- package/src/configs/prettier.ts +0 -11
- package/src/configs/tsconfig.ts +0 -78
- package/src/configs/uselessFiles.ts +0 -29
- package/src/constants.ts +0 -15
- package/src/dependencies/find.ts +0 -193
- package/src/dependencies/import-linter.ts +0 -95
- package/src/index.ts +0 -1
- package/src/npm/manager.ts +0 -44
- package/src/npm/package.ts +0 -427
- package/src/npm/publish.ts +0 -9
- package/src/npm/resolveLatestVersions.ts +0 -31
- package/src/presets/presets.ts +0 -54
- package/src/presets/renovatebot.ts +0 -21
- package/src/presets/semver-workflow.ts +0 -186
- package/src/presets/ui-workshop.ts +0 -97
- package/src/presets/ui.ts +0 -67
- package/src/sanity/manifest.ts +0 -340
- package/src/sharedFlags.ts +0 -14
- package/src/util/command-parser.ts +0 -36
- package/src/util/errorToUndefined.ts +0 -7
- package/src/util/files.ts +0 -260
- package/src/util/log.ts +0 -44
- package/src/util/prompt.ts +0 -70
- package/src/util/readme.ts +0 -88
- package/src/util/request.ts +0 -11
- package/src/util/ts.ts +0 -19
- package/src/util/user.ts +0 -129
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import childProcess from 'child_process'
|
|
2
|
-
import npmRunPath from 'npm-run-path'
|
|
3
|
-
import log from './log'
|
|
4
|
-
|
|
5
|
-
interface Command {
|
|
6
|
-
command: string
|
|
7
|
-
args: string[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function parseCommand(commandString: string): Command {
|
|
11
|
-
const normalized = commandString.replace(/ +/g, ' ')
|
|
12
|
-
const commandAndArg = normalized.split(' ')
|
|
13
|
-
return {
|
|
14
|
-
command: commandAndArg[0],
|
|
15
|
-
args: commandAndArg.length > 1 ? commandAndArg.slice(1) : [],
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function runCommand(commandString: string): Promise<{code: number}> {
|
|
20
|
-
log.info(`Running command: ${commandString}`)
|
|
21
|
-
const {command, args} = parseCommand(commandString)
|
|
22
|
-
|
|
23
|
-
let options: any = {stdio: 'inherit', env: npmRunPath.env()}
|
|
24
|
-
|
|
25
|
-
// ref: https://stackoverflow.com/questions/37459717/error-spawn-enoent-on-windows/37487465
|
|
26
|
-
options = process.platform === 'win32' ? {...options, shell: true} : options
|
|
27
|
-
|
|
28
|
-
return new Promise((resolve, reject) => {
|
|
29
|
-
childProcess
|
|
30
|
-
.spawn(command, args, options)
|
|
31
|
-
.on('error', reject)
|
|
32
|
-
.on('close', (exitCode) => {
|
|
33
|
-
resolve({code: exitCode ?? 0})
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
}
|
package/src/util/files.ts
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import util from 'util'
|
|
4
|
-
import pAny from 'p-any'
|
|
5
|
-
import crypto from 'crypto'
|
|
6
|
-
import {buildExtensions} from '../configs/buildExtensions'
|
|
7
|
-
import {prompt} from './prompt'
|
|
8
|
-
import {InitFlags} from '../actions/init'
|
|
9
|
-
import log from './log'
|
|
10
|
-
import json5 from 'json5'
|
|
11
|
-
import {ManifestPaths} from '../sanity/manifest'
|
|
12
|
-
|
|
13
|
-
export const stat = util.promisify(fs.stat)
|
|
14
|
-
export const mkdir = util.promisify(fs.mkdir)
|
|
15
|
-
export const readdir = util.promisify(fs.readdir)
|
|
16
|
-
export const copyFile = util.promisify(fs.copyFile)
|
|
17
|
-
export const readFile = util.promisify(fs.readFile)
|
|
18
|
-
export const writeFile = util.promisify(fs.writeFile)
|
|
19
|
-
|
|
20
|
-
export function hasSourceEquivalent(compiledFile: string, paths: ManifestPaths) {
|
|
21
|
-
if (!paths.source) {
|
|
22
|
-
return fileExists(
|
|
23
|
-
path.isAbsolute(compiledFile) ? compiledFile : path.resolve(paths.basePath, compiledFile),
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// /plugin/dist/MyComponent.js => /plugin/src
|
|
28
|
-
const baseDir = path.dirname(compiledFile.replace(paths.compiled as string, paths.source))
|
|
29
|
-
|
|
30
|
-
// /plugin/dist/MyComponent.js => MyComponent
|
|
31
|
-
const baseName = path.basename(compiledFile, path.extname(compiledFile))
|
|
32
|
-
|
|
33
|
-
// MyComponent => /plugin/src/MyComponent
|
|
34
|
-
const pathStub = path.join(baseDir, baseName)
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
* /plugin/src/MyComponent => [
|
|
38
|
-
* /plugin/src/MyComponent.jsx,
|
|
39
|
-
* /plugin/src/MyComponent.mjs,
|
|
40
|
-
* ...
|
|
41
|
-
* ]
|
|
42
|
-
*/
|
|
43
|
-
return buildCandidateExists(pathStub)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Generally used for parts resolving
|
|
47
|
-
export async function hasSourceFile(filePath: string, paths?: ManifestPaths) {
|
|
48
|
-
if (!paths?.source) {
|
|
49
|
-
return fileExists(
|
|
50
|
-
path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? '', filePath),
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// filePath: components/SomeInput
|
|
55
|
-
// paths: {source: '/plugin/src'}
|
|
56
|
-
// MyComponent => /plugin/src/MyComponent
|
|
57
|
-
const pathStub = path.isAbsolute(filePath) ? filePath : path.resolve(paths.source, filePath)
|
|
58
|
-
|
|
59
|
-
if (await fileExists(pathStub)) {
|
|
60
|
-
return true
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return buildCandidateExists(pathStub)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Generally used for parts resolving
|
|
67
|
-
export function hasCompiledFile(filePath: string, paths?: ManifestPaths) {
|
|
68
|
-
if (!paths?.compiled) {
|
|
69
|
-
return fileExists(
|
|
70
|
-
path.isAbsolute(filePath) ? filePath : path.resolve(paths?.basePath ?? '', filePath),
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// filePath: components/SomeInput
|
|
75
|
-
// paths: {compiled: '/plugin/dist'}
|
|
76
|
-
|
|
77
|
-
// components/SomeInput => /plugin/dist/components/SomeInput
|
|
78
|
-
const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(paths.compiled, filePath)
|
|
79
|
-
|
|
80
|
-
// /plugin/dist/components/SomeInput => /plugin/dist/components/SomeInput.js
|
|
81
|
-
// /plugin/dist/components/SomeInput.js => /plugin/dist/components/SomeInput.js
|
|
82
|
-
// /plugin/dist/components/SomeInput.css => /plugin/dist/components/SomeInput.css
|
|
83
|
-
const fileExt = path.extname(absPath)
|
|
84
|
-
const withExt = fileExt === '' ? `${absPath}.js` : absPath
|
|
85
|
-
|
|
86
|
-
return fileExists(withExt)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function buildCandidateExists(pathStub: string) {
|
|
90
|
-
const candidates = buildExtensions.map((extCandidate) => `${pathStub}${extCandidate}`)
|
|
91
|
-
|
|
92
|
-
return pAny(candidates.map((candidate) => stat(candidate)))
|
|
93
|
-
.then(() => true)
|
|
94
|
-
.catch(() => false)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function fileExists(filePath: string) {
|
|
98
|
-
return stat(filePath)
|
|
99
|
-
.then(() => true)
|
|
100
|
-
.catch(() => false)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export async function readJsonFile<T>(filePath: string) {
|
|
104
|
-
const content = await readFile(filePath, 'utf8')
|
|
105
|
-
return JSON.parse(content) as T
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function writeJsonFile(filePath: string, content: Record<string, unknown>) {
|
|
109
|
-
const data = JSON.stringify(content, null, 2) + '\n'
|
|
110
|
-
return writeFile(filePath, data, {encoding: 'utf8'})
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export async function writeFileWithOverwritePrompt(
|
|
114
|
-
filePath: string,
|
|
115
|
-
content: string,
|
|
116
|
-
options: {default?: any; force?: boolean} & fs.ObjectEncodingOptions,
|
|
117
|
-
) {
|
|
118
|
-
const {default: defaultVal, force = false, ...writeOptions} = options
|
|
119
|
-
const withinCwd = filePath.startsWith(process.cwd())
|
|
120
|
-
const printablePath = withinCwd ? path.relative(process.cwd(), filePath) : filePath
|
|
121
|
-
|
|
122
|
-
if (await fileEqualsData(filePath, content)) {
|
|
123
|
-
return false
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (
|
|
127
|
-
!force &&
|
|
128
|
-
(await fileExists(filePath)) &&
|
|
129
|
-
!(await prompt(`File "${printablePath}" already exists. Overwrite?`, {
|
|
130
|
-
type: 'confirm',
|
|
131
|
-
default: defaultVal,
|
|
132
|
-
}))
|
|
133
|
-
) {
|
|
134
|
-
return false
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
await writeFile(filePath, content, writeOptions)
|
|
138
|
-
return true
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export async function copyFileWithOverwritePrompt(from: string, to: string, flags: InitFlags) {
|
|
142
|
-
const withinCwd = to.startsWith(process.cwd())
|
|
143
|
-
const printablePath = withinCwd ? path.relative(process.cwd(), to) : to
|
|
144
|
-
|
|
145
|
-
if (await filesAreEqual(from, to)) {
|
|
146
|
-
return false
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await ensureDirectoryExists(to)
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
!flags.force &&
|
|
153
|
-
(await fileExists(to)) &&
|
|
154
|
-
!(await prompt(`File "${printablePath}" already exists. Overwrite?`, {
|
|
155
|
-
type: 'confirm',
|
|
156
|
-
default: false,
|
|
157
|
-
}))
|
|
158
|
-
) {
|
|
159
|
-
return false
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
await copyFile(from, to)
|
|
163
|
-
return true
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function ensureDirectoryExists(filePath: string) {
|
|
167
|
-
const dirname = path.dirname(filePath)
|
|
168
|
-
if (await fileExists(dirname)) {
|
|
169
|
-
return true
|
|
170
|
-
}
|
|
171
|
-
await ensureDirectoryExists(dirname)
|
|
172
|
-
await mkdir(dirname)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export async function fileEqualsData(filePath: string, content: string) {
|
|
176
|
-
const contentHash = crypto.createHash('sha1').update(content).digest('hex')
|
|
177
|
-
const remoteHash = await getFileHash(filePath)
|
|
178
|
-
return contentHash === remoteHash
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export async function filesAreEqual(file1: string, file2: string) {
|
|
182
|
-
const [hash1, hash2] = await Promise.all([getFileHash(file1, false), getFileHash(file2)])
|
|
183
|
-
return hash1 === hash2
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function getFileHash(filePath: string, allowMissing = true) {
|
|
187
|
-
return new Promise((resolve, reject) => {
|
|
188
|
-
const hash = crypto.createHash('sha1')
|
|
189
|
-
const stream = fs.createReadStream(filePath)
|
|
190
|
-
stream.on('error', (err) => {
|
|
191
|
-
if ((err as unknown as {code?: string}).code === 'ENOENT' && allowMissing) {
|
|
192
|
-
resolve(null)
|
|
193
|
-
} else {
|
|
194
|
-
reject(err)
|
|
195
|
-
}
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
stream.on('end', () => resolve(hash.digest('hex')))
|
|
199
|
-
stream.on('data', (chunk) => hash.update(chunk))
|
|
200
|
-
})
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export async function ensureDir(dirPath: string) {
|
|
204
|
-
try {
|
|
205
|
-
await mkdir(dirPath)
|
|
206
|
-
} catch (err) {
|
|
207
|
-
if ((err as unknown as {code?: string}).code !== 'EEXIST') {
|
|
208
|
-
throw err
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export async function isEmptyish(dirPath: string) {
|
|
214
|
-
const ignoredFiles = ['.git', '.gitignore', 'license', 'readme.md']
|
|
215
|
-
const allFiles = await readdir(dirPath).catch(() => [])
|
|
216
|
-
const files = allFiles.filter((file) => !ignoredFiles.includes(file.toLowerCase()))
|
|
217
|
-
return files.length === 0
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export async function readFileContent({
|
|
221
|
-
filename,
|
|
222
|
-
basePath,
|
|
223
|
-
}: {
|
|
224
|
-
filename: string
|
|
225
|
-
basePath: string
|
|
226
|
-
}): Promise<string | undefined> {
|
|
227
|
-
const filepath = path.normalize(path.join(basePath, filename))
|
|
228
|
-
try {
|
|
229
|
-
return await readFile(filepath, 'utf8')
|
|
230
|
-
} catch (err: any) {
|
|
231
|
-
if (err.code === 'ENOENT') {
|
|
232
|
-
log.debug(`No ${filename} file found.`)
|
|
233
|
-
return undefined
|
|
234
|
-
}
|
|
235
|
-
throw new Error(`Failed to read "${filepath}": ${err.message}`)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export async function readJson5File<T>({
|
|
240
|
-
filename,
|
|
241
|
-
basePath,
|
|
242
|
-
}: {
|
|
243
|
-
filename: string
|
|
244
|
-
basePath: string
|
|
245
|
-
}): Promise<T | undefined> {
|
|
246
|
-
const content = await readFileContent({filename, basePath})
|
|
247
|
-
if (!content) {
|
|
248
|
-
return undefined
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return parseJson5<T>(content, filename)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export function parseJson5<T>(content: string, errorKey: string): T {
|
|
255
|
-
try {
|
|
256
|
-
return json5.parse<T>(content)
|
|
257
|
-
} catch (err: any) {
|
|
258
|
-
throw new Error(`Error parsing "${errorKey}": ${err.message}`)
|
|
259
|
-
}
|
|
260
|
-
}
|
package/src/util/log.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Note: This is _specifically_ meant for CLI usage,
|
|
2
|
-
// I realize that "singletons" are bad.
|
|
3
|
-
|
|
4
|
-
import chalk from 'chalk'
|
|
5
|
-
|
|
6
|
-
let beQuiet = false
|
|
7
|
-
let beVerbose = false
|
|
8
|
-
|
|
9
|
-
function setVerbosity({verbose, silent}: {verbose: boolean; silent: boolean}) {
|
|
10
|
-
if (silent) {
|
|
11
|
-
beVerbose = false
|
|
12
|
-
beQuiet = true
|
|
13
|
-
} else if (verbose) {
|
|
14
|
-
beVerbose = true
|
|
15
|
-
beQuiet = false
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default {
|
|
20
|
-
setVerbosity: setVerbosity,
|
|
21
|
-
|
|
22
|
-
// Bypasses any checks, prints regardless (only use for things like `cli --version`)
|
|
23
|
-
msg: (msg: any, ...args: any[]) => !beQuiet && console.log(msg, ...args),
|
|
24
|
-
|
|
25
|
-
// Debug only printed on --verbose
|
|
26
|
-
debug: (msg: any, ...args: any[]) =>
|
|
27
|
-
!beQuiet && beVerbose && console.debug(`${chalk.bgBlack.white('[debug]')} ${msg}`, ...args),
|
|
28
|
-
|
|
29
|
-
// Success messages only printed if not --silent
|
|
30
|
-
success: (msg: any, ...args: any[]) =>
|
|
31
|
-
!beQuiet && console.info(`${chalk.bgBlack.greenBright('[success]')} ${msg}`, ...args),
|
|
32
|
-
|
|
33
|
-
// Info only printed if not --silent ("standard" level)
|
|
34
|
-
info: (msg: any, ...args: any[]) =>
|
|
35
|
-
!beQuiet && console.info(`${chalk.bgBlack.cyanBright('[info]')} ${msg}`, ...args),
|
|
36
|
-
|
|
37
|
-
// Warning only printed if not --silent
|
|
38
|
-
warn: (msg: any, ...args: any[]) =>
|
|
39
|
-
!beQuiet && console.warn(`${chalk.bgBlack.yellowBright('[warn]')} ${msg}`, ...args),
|
|
40
|
-
|
|
41
|
-
// Errors are always printed
|
|
42
|
-
error: (msg: any, ...args: any[]) =>
|
|
43
|
-
console.error(`${chalk.bgBlack.redBright('[error]')} ${msg}`, ...args),
|
|
44
|
-
}
|
package/src/util/prompt.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {URL} from 'url'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import inquirer from 'inquirer'
|
|
4
|
-
// @ts-expect-error missing types
|
|
5
|
-
import validNpmName from 'validate-npm-package-name'
|
|
6
|
-
// @ts-expect-error missing types
|
|
7
|
-
import githubUrlToObject from 'github-url-to-object'
|
|
8
|
-
import {InjectOptions} from '../actions/inject'
|
|
9
|
-
|
|
10
|
-
export async function prompt(
|
|
11
|
-
message: string,
|
|
12
|
-
options: {
|
|
13
|
-
choices?: any
|
|
14
|
-
type?: string
|
|
15
|
-
default?: any
|
|
16
|
-
filter?: (val: any) => any
|
|
17
|
-
validate?: (val: any) => boolean | string
|
|
18
|
-
},
|
|
19
|
-
) {
|
|
20
|
-
const type = options.choices ? 'list' : options.type
|
|
21
|
-
const result = await inquirer.prompt([{...options, type, message, name: 'single'}])
|
|
22
|
-
return result && result.single
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
prompt.separator = () => new inquirer.Separator()
|
|
26
|
-
|
|
27
|
-
export function promptForPackageName({basePath}: InjectOptions, defaultVal?: string) {
|
|
28
|
-
return prompt('Plugin name (sanity-plugin-...)', {
|
|
29
|
-
default: defaultVal || path.basename(basePath),
|
|
30
|
-
filter: (name) => {
|
|
31
|
-
const prefixless = name.trim().replace(/^sanity-plugin-/, '')
|
|
32
|
-
return name[0] === '@' ? name : `sanity-plugin-${prefixless}`
|
|
33
|
-
},
|
|
34
|
-
validate: (name) => {
|
|
35
|
-
const valid: {errors?: string[]} = validNpmName(name)
|
|
36
|
-
if (valid.errors) {
|
|
37
|
-
return valid.errors[0]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (name[0] !== '@' && name.endsWith('plugin')) {
|
|
41
|
-
return `Name shouldn't include "plugin" multiple times (${name})`
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return true
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function promptForRepoOrigin(options: InjectOptions, defaultVal?: string) {
|
|
50
|
-
return prompt('Git repository URL', {
|
|
51
|
-
default: defaultVal,
|
|
52
|
-
filter: (raw) => {
|
|
53
|
-
const url = (raw || '').trim()
|
|
54
|
-
const gh: {user: string; repo: string} | undefined = githubUrlToObject(url)
|
|
55
|
-
return gh ? `git+ssh://git@github.com/${gh.user}/${gh.repo}.git` : url
|
|
56
|
-
},
|
|
57
|
-
validate: (url) => {
|
|
58
|
-
if (!url) {
|
|
59
|
-
return true
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const parsed = new URL(url)
|
|
64
|
-
return parsed ? true : 'Invalid URL'
|
|
65
|
-
} catch (err) {
|
|
66
|
-
return 'Invalid URL'
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
}
|
package/src/util/readme.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import outdent from 'outdent'
|
|
2
|
-
// @ts-expect-error missing types
|
|
3
|
-
import licenses from '@rexxars/choosealicense-list'
|
|
4
|
-
import {PackageData} from '../actions/inject'
|
|
5
|
-
import {User} from './user'
|
|
6
|
-
|
|
7
|
-
export function generateReadme(data: PackageData) {
|
|
8
|
-
const {user, pluginName, license} = data
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
outdent`
|
|
12
|
-
# ${pluginName}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
${installationSnippet(pluginName ?? 'unknown')}
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
Add it as a plugin in \`sanity.config.ts\` (or .js):
|
|
20
|
-
|
|
21
|
-
\`\`\`ts
|
|
22
|
-
import {defineConfig} from 'sanity'
|
|
23
|
-
import {myPlugin} from '${pluginName}'
|
|
24
|
-
|
|
25
|
-
export default defineConfig({
|
|
26
|
-
//...
|
|
27
|
-
plugins: [myPlugin({})],
|
|
28
|
-
})
|
|
29
|
-
\`\`\`
|
|
30
|
-
|
|
31
|
-
${getLicenseText(license?.id, user?.name ? (user as User) : undefined)}
|
|
32
|
-
${developTestSnippet()}
|
|
33
|
-
` + '\n'
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function installationSnippet(packageName: string) {
|
|
38
|
-
return outdent`
|
|
39
|
-
## Installation
|
|
40
|
-
|
|
41
|
-
\`\`\`sh
|
|
42
|
-
npm install ${packageName}
|
|
43
|
-
\`\`\`
|
|
44
|
-
`
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function developTestSnippet() {
|
|
48
|
-
return outdent`
|
|
49
|
-
## Develop & test
|
|
50
|
-
|
|
51
|
-
This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
|
|
52
|
-
with default configuration for build & watch scripts.
|
|
53
|
-
|
|
54
|
-
See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
|
|
55
|
-
on how to run this plugin with hotreload in the studio.
|
|
56
|
-
`
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function getLicenseText(licenseId?: string, user?: User) {
|
|
60
|
-
if (!licenseId) {
|
|
61
|
-
return ''
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let licenseName: string | undefined = licenses.find(licenseId).title
|
|
65
|
-
licenseName = licenseName?.replace(/\s+license$/i, '')
|
|
66
|
-
|
|
67
|
-
let licenseText = '## License\n'
|
|
68
|
-
if (licenseName && user?.name) {
|
|
69
|
-
licenseText = `${licenseText}\n[${licenseName}](LICENSE) © ${user?.name}\n`
|
|
70
|
-
} else if (licenseName) {
|
|
71
|
-
licenseText = `${licenseText}\n[${licenseName}](LICENSE)\n`
|
|
72
|
-
} else {
|
|
73
|
-
licenseText = `${licenseText}\nSee [LICENSE](LICENSE)`
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return licenseText
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function isDefaultGitHubReadme(readme: string) {
|
|
80
|
-
if (!readme) {
|
|
81
|
-
return false
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const lines = readme.split('\n', 20).filter(Boolean)
|
|
85
|
-
|
|
86
|
-
// title + _optional_ description
|
|
87
|
-
return lines.length <= 2 && lines[0].startsWith('#')
|
|
88
|
-
}
|
package/src/util/request.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import {getIt} from 'get-it'
|
|
2
|
-
import {jsonRequest, jsonResponse, httpErrors, headers, promise} from 'get-it/middleware'
|
|
3
|
-
import pkg from '../../package.json'
|
|
4
|
-
|
|
5
|
-
export const request = getIt([
|
|
6
|
-
promise({onlyBody: true}),
|
|
7
|
-
jsonRequest(),
|
|
8
|
-
jsonResponse(),
|
|
9
|
-
httpErrors(),
|
|
10
|
-
headers({'User-Agent': `${pkg.name}@${pkg.version}`}),
|
|
11
|
-
])
|
package/src/util/ts.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import {fileExists} from './files'
|
|
4
|
-
|
|
5
|
-
export async function readTSConfig(options: {basePath: string; filename: string}) {
|
|
6
|
-
const {basePath, filename} = options
|
|
7
|
-
const filePath = path.resolve(basePath, filename)
|
|
8
|
-
const exists = await fileExists(filePath)
|
|
9
|
-
|
|
10
|
-
if (!exists) return undefined
|
|
11
|
-
|
|
12
|
-
return ts.readConfigFile(filePath, ts.sys.readFile).config
|
|
13
|
-
? ts.parseJsonConfigFileContent(
|
|
14
|
-
ts.readConfigFile(filePath, ts.sys.readFile).config,
|
|
15
|
-
ts.sys,
|
|
16
|
-
basePath,
|
|
17
|
-
)
|
|
18
|
-
: undefined
|
|
19
|
-
}
|
package/src/util/user.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import {execSync} from 'child_process'
|
|
3
|
-
import xdgBasedir from 'xdg-basedir'
|
|
4
|
-
import {validate as isValidEmail} from 'email-validator'
|
|
5
|
-
import {readJsonFile} from './files'
|
|
6
|
-
import {request} from './request'
|
|
7
|
-
import {prompt} from './prompt'
|
|
8
|
-
import {InjectOptions} from '../actions/inject'
|
|
9
|
-
import {PackageJson} from '../actions/verify/types'
|
|
10
|
-
|
|
11
|
-
export interface User {
|
|
12
|
-
name: string
|
|
13
|
-
email?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function getUserInfo(
|
|
17
|
-
{requireUserConfirmation, flags}: InjectOptions,
|
|
18
|
-
pkg?: PackageJson,
|
|
19
|
-
): Promise<User | undefined> {
|
|
20
|
-
const userInfo =
|
|
21
|
-
getPackageUserInfo({author: flags.author ?? pkg?.author}) ||
|
|
22
|
-
(await getSanityUserInfo()) ||
|
|
23
|
-
((await getGitUserInfo()) as User | undefined)
|
|
24
|
-
if (requireUserConfirmation) {
|
|
25
|
-
return promptForInfo(userInfo)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return userInfo
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function getPackageUserInfo(pkg?: {
|
|
32
|
-
author?:
|
|
33
|
-
| string
|
|
34
|
-
| {
|
|
35
|
-
name: string
|
|
36
|
-
email?: string
|
|
37
|
-
}
|
|
38
|
-
}): User | undefined {
|
|
39
|
-
let author = pkg?.author
|
|
40
|
-
if (!author) {
|
|
41
|
-
return undefined
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (author && typeof author !== 'string') {
|
|
45
|
-
return author
|
|
46
|
-
} else if (!author.includes('@')) {
|
|
47
|
-
return {name: author}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const [pre, ...post] = author.replace(/[<>[\]]/g, '').split(/@/)
|
|
51
|
-
const nameParts = pre.split(/\s+/)
|
|
52
|
-
const email = [nameParts[nameParts.length - 1], ...post].join('@')
|
|
53
|
-
const name = nameParts.slice(0, -1).join(' ')
|
|
54
|
-
return {name, email}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function promptForInfo(defValue?: User) {
|
|
58
|
-
const name = await prompt('Author name', {
|
|
59
|
-
filter: filterString,
|
|
60
|
-
default: defValue && defValue.name,
|
|
61
|
-
validate: requiredString,
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const email = await prompt('Author email', {
|
|
65
|
-
filter: filterString,
|
|
66
|
-
default: defValue && defValue.email,
|
|
67
|
-
validate: validOrEmptyEmail,
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
return {name, email}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async function getSanityUserInfo(): Promise<User | undefined> {
|
|
74
|
-
try {
|
|
75
|
-
const data = await readJsonFile<{authToken?: string}>(
|
|
76
|
-
path.join(xdgBasedir.config ?? '', 'sanity', 'config.json'),
|
|
77
|
-
)
|
|
78
|
-
const token = data?.authToken
|
|
79
|
-
|
|
80
|
-
if (!token) {
|
|
81
|
-
return undefined
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const user = await request({
|
|
85
|
-
url: 'https://api.sanity.io/v1/users/me',
|
|
86
|
-
headers: {Authorization: `Bearer ${token}`},
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
if (!user) {
|
|
90
|
-
return undefined
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const {name, email} = user
|
|
94
|
-
return {name, email}
|
|
95
|
-
} catch (err) {
|
|
96
|
-
return undefined
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function getGitUserInfo(): Promise<User | undefined> {
|
|
101
|
-
try {
|
|
102
|
-
const name = execSync('git config user.name', {encoding: 'utf8'}).trim()
|
|
103
|
-
const email = execSync('git config user.email', {encoding: 'utf8'}).trim()
|
|
104
|
-
|
|
105
|
-
if (!name) {
|
|
106
|
-
return undefined
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return {name, email: email || undefined}
|
|
110
|
-
} catch (err) {
|
|
111
|
-
return undefined
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function filterString(val: string) {
|
|
116
|
-
return (val || '').trim()
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function requiredString(value: string) {
|
|
120
|
-
return value.length > 1 ? true : 'Required'
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function validOrEmptyEmail(value: string): true | string {
|
|
124
|
-
if (!value) {
|
|
125
|
-
return true
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return isValidEmail(value) ? true : 'Must either be a valid email or empty'
|
|
129
|
-
}
|