@sanity/pkg-utils 2.2.17 → 2.3.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.
Files changed (46) hide show
  1. package/README.md +16 -7
  2. package/dist/_chunks/{build-45e5ded8.cjs → build-0aed2000.cjs} +11 -8
  3. package/dist/_chunks/{build-45e5ded8.cjs.map → build-0aed2000.cjs.map} +1 -1
  4. package/dist/_chunks/{buildAction-afc0a1a6.cjs → buildAction-196fba7b.cjs} +2 -2
  5. package/dist/_chunks/{buildAction-afc0a1a6.cjs.map → buildAction-196fba7b.cjs.map} +1 -1
  6. package/dist/_chunks/{check-33e163bb.cjs → check-2deafe2a.cjs} +22 -19
  7. package/dist/_chunks/{check-33e163bb.cjs.map → check-2deafe2a.cjs.map} +1 -1
  8. package/dist/_chunks/{checkAction-6fd7b2bc.cjs → checkAction-7ac5a05e.cjs} +2 -2
  9. package/dist/_chunks/{checkAction-6fd7b2bc.cjs.map → checkAction-7ac5a05e.cjs.map} +1 -1
  10. package/dist/_chunks/{index-f3c22a05.cjs → index-984e18d1.cjs} +4 -2
  11. package/dist/_chunks/{index-f3c22a05.cjs.map → index-984e18d1.cjs.map} +1 -1
  12. package/dist/_chunks/init-ab36343b.cjs +469 -0
  13. package/dist/_chunks/init-ab36343b.cjs.map +1 -0
  14. package/dist/_chunks/initAction-d18cf4f2.cjs +16 -0
  15. package/dist/_chunks/initAction-d18cf4f2.cjs.map +1 -0
  16. package/dist/_chunks/logger-c593f06b.cjs +97 -0
  17. package/dist/_chunks/logger-c593f06b.cjs.map +1 -0
  18. package/dist/_chunks/{resolveBuildContext-6666f1ab.cjs → resolveBuildContext-5ef90110.cjs} +10 -91
  19. package/dist/_chunks/resolveBuildContext-5ef90110.cjs.map +1 -0
  20. package/dist/_chunks/{watch-2bff1357.cjs → watch-63a93eb0.cjs} +10 -7
  21. package/dist/_chunks/{watch-2bff1357.cjs.map → watch-63a93eb0.cjs.map} +1 -1
  22. package/dist/_chunks/{watchAction-39b0210b.cjs → watchAction-95c0b481.cjs} +2 -2
  23. package/dist/_chunks/{watchAction-39b0210b.cjs.map → watchAction-95c0b481.cjs.map} +1 -1
  24. package/dist/cli.cjs +14 -4
  25. package/dist/cli.cjs.map +1 -1
  26. package/dist/index.cjs +12 -7
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +87 -0
  29. package/dist/index.js +449 -8
  30. package/dist/index.js.map +1 -1
  31. package/package.json +10 -2
  32. package/src/cli/index.ts +8 -0
  33. package/src/cli/initAction.ts +13 -0
  34. package/src/node/core/index.ts +1 -0
  35. package/src/node/core/pkg/types.ts +13 -0
  36. package/src/node/core/template/createFromTemplate.ts +85 -0
  37. package/src/node/core/template/define.ts +6 -0
  38. package/src/node/core/template/index.ts +3 -0
  39. package/src/node/core/template/types.ts +45 -0
  40. package/src/node/index.ts +1 -0
  41. package/src/node/init.ts +55 -0
  42. package/src/node/isEmptyDirectory.ts +5 -0
  43. package/src/node/templates/default/index.ts +1 -0
  44. package/src/node/templates/default/template.ts +553 -0
  45. package/src/node/templates/index.ts +1 -0
  46. package/dist/_chunks/resolveBuildContext-6666f1ab.cjs.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/pkg-utils",
3
- "version": "2.2.17",
3
+ "version": "2.3.0",
4
4
  "description": "Simple utilities for modern npm packages.",
5
5
  "keywords": [
6
6
  "sanity-io",
@@ -139,12 +139,18 @@
139
139
  "esbuild": "^0.17.19",
140
140
  "esbuild-register": "^3.4.2",
141
141
  "find-config": "^1.0.0",
142
+ "get-latest-version": "^5.0.1",
143
+ "git-url-parse": "^13.1.0",
142
144
  "globby": "^11.1.0",
143
145
  "jsonc-parser": "^3.2.0",
144
146
  "mkdirp": "^3.0.1",
147
+ "outdent": "^0.8.0",
148
+ "parse-git-config": "^3.0.0",
145
149
  "pkg-up": "^3.1.0",
146
150
  "prettier": "^2.8.8",
151
+ "prettier-plugin-packagejson": "^2.4.3",
147
152
  "pretty-bytes": "^5.6.0",
153
+ "prompts": "^2.4.2",
148
154
  "recast": "^0.23.2",
149
155
  "rimraf": "^5.0.1",
150
156
  "rollup": "^3.23.0",
@@ -162,8 +168,11 @@
162
168
  "@types/babel__core": "^7.20.1",
163
169
  "@types/cpx": "^1.5.2",
164
170
  "@types/find-config": "^1.0.1",
171
+ "@types/git-url-parse": "^9.0.1",
165
172
  "@types/node": "^20.2.5",
173
+ "@types/parse-git-config": "^3.0.1",
166
174
  "@types/prettier": "^2.7.2",
175
+ "@types/prompts": "^2.4.4",
167
176
  "@types/treeify": "^1.0.0",
168
177
  "@types/uuid": "^9.0.1",
169
178
  "@typescript-eslint/eslint-plugin": "^5.59.7",
@@ -180,7 +189,6 @@
180
189
  "lint-staged": "^13.2.2",
181
190
  "npm-run-all": "^4.1.5",
182
191
  "outdent": "^0.8.0",
183
- "prettier-plugin-packagejson": "^2.4.3",
184
192
  "rollup-plugin-visualizer": "^5.9.0",
185
193
  "semantic-release": "^21.0.2",
186
194
  "ts-node": "^10.9.1",
package/src/cli/index.ts CHANGED
@@ -26,6 +26,14 @@ cli
26
26
  return buildAction(options)
27
27
  })
28
28
 
29
+ cli.command('init [path]', 'Initialize package').action(async (p) => {
30
+ const {initAction} = await import('./initAction')
31
+
32
+ return initAction({
33
+ path: p,
34
+ })
35
+ })
36
+
29
37
  cli
30
38
  .command('watch', 'Watch package')
31
39
  .option('--strict', 'Strict mode')
@@ -0,0 +1,13 @@
1
+ import {init} from '../node/init'
2
+ import {handleError} from './handleError'
3
+
4
+ export async function initAction(options: {path: string}): Promise<void> {
5
+ try {
6
+ await init({
7
+ cwd: process.cwd(),
8
+ path: options.path,
9
+ })
10
+ } catch (err) {
11
+ handleError(err)
12
+ }
13
+ }
@@ -3,4 +3,5 @@ export * from './contexts'
3
3
  export * from './defaults'
4
4
  export * from './isRecord'
5
5
  export * from './pkg'
6
+ export * from './template'
6
7
  export * from './ts'
@@ -3,7 +3,10 @@ export interface PackageJSON {
3
3
  type?: 'commonjs' | 'module'
4
4
  version: string
5
5
  private?: boolean
6
+ author?: string | {name: string; email?: string; url?: string}
6
7
  name: string
8
+ description?: string
9
+ keywords?: string[]
7
10
  bin?: Record<string, string>
8
11
  dependencies?: Record<string, string>
9
12
  devDependencies?: Record<string, string>
@@ -34,5 +37,15 @@ export interface PackageJSON {
34
37
  source?: string
35
38
  module?: string
36
39
  types?: string
40
+ files?: string[]
41
+ scripts?: Record<string, string>
37
42
  browserslist?: string[]
43
+ engines?: {
44
+ node?: string
45
+ npm?: string
46
+ }
47
+ repository?: string | {type: 'git'; url: string}
48
+ bugs?: string | {url: string; email?: string}
49
+ homepage?: string
50
+ license?: string
38
51
  }
@@ -0,0 +1,85 @@
1
+ import {writeFile} from 'fs/promises'
2
+ import {mkdirp} from 'mkdirp'
3
+ import {dirname, relative, resolve} from 'path'
4
+ import prompts from 'prompts'
5
+
6
+ import {Logger} from '../../logger'
7
+ import {PkgTemplate} from './types'
8
+
9
+ const promptsTypes = {
10
+ string: 'text' as const,
11
+ }
12
+
13
+ /** @internal */
14
+ export async function createFromTemplate(options: {
15
+ cwd: string
16
+ logger: Logger
17
+ packagePath: string
18
+ template: PkgTemplate
19
+ }): Promise<void> {
20
+ const {cwd, logger, packagePath, template: templateOrResolver} = options
21
+
22
+ const template =
23
+ typeof templateOrResolver === 'function'
24
+ ? await templateOrResolver({cwd, logger, packagePath})
25
+ : templateOrResolver
26
+
27
+ logger.log('create new package at', relative(cwd, packagePath))
28
+
29
+ const templateOptions: Record<string, string> = {}
30
+
31
+ for (const templateOption of template.options) {
32
+ const templateValidate = templateOption.validate
33
+
34
+ const res = await prompts(
35
+ {
36
+ type: promptsTypes[templateOption.type],
37
+ name: templateOption.name,
38
+ message: templateOption.description,
39
+ validate: templateValidate ? (prev) => templateValidate(prev) : undefined,
40
+ initial:
41
+ typeof templateOption.initial === 'function'
42
+ ? templateOption.initial(templateOptions)
43
+ : templateOption.initial,
44
+ },
45
+ {onCancel: () => process.exit(0)}
46
+ )
47
+
48
+ templateOptions[templateOption.name] = templateOption.parse
49
+ ? templateOption.parse(res[templateOption.name])
50
+ : res[templateOption.name]
51
+ }
52
+
53
+ const features: Record<string, boolean> = {}
54
+
55
+ for (const templateFeature of template.features) {
56
+ const res = templateFeature.optional
57
+ ? await prompts(
58
+ {
59
+ type: 'confirm',
60
+ name: 'confirm',
61
+ message: `use ${templateFeature.name}?`,
62
+ initial: templateFeature.initial,
63
+ },
64
+ {onCancel: () => process.exit(0)}
65
+ )
66
+ : undefined
67
+
68
+ features[templateFeature.name] = res?.confirm || !templateFeature.optional
69
+ }
70
+
71
+ const files = await template.getFiles(templateOptions, features)
72
+
73
+ files.sort((a, b) => {
74
+ return a.name.localeCompare(b.name)
75
+ })
76
+
77
+ for (const file of files) {
78
+ const filePath = resolve(packagePath, file.name)
79
+
80
+ await mkdirp(dirname(filePath))
81
+ await writeFile(filePath, file.contents.trim() + '\n')
82
+
83
+ logger.success(`wrote ${relative(cwd, filePath)}`)
84
+ }
85
+ }
@@ -0,0 +1,6 @@
1
+ import {PkgTemplateOption} from './types'
2
+
3
+ /** @public */
4
+ export function defineTemplateOption<T>(option: PkgTemplateOption<T>): PkgTemplateOption<T> {
5
+ return option
6
+ }
@@ -0,0 +1,3 @@
1
+ export * from './createFromTemplate'
2
+ export * from './define'
3
+ export * from './types'
@@ -0,0 +1,45 @@
1
+ import {Logger} from '../../logger'
2
+
3
+ /** @public */
4
+ export interface PkgTemplateFile {
5
+ name: string
6
+ contents: string
7
+ }
8
+
9
+ /** @public */
10
+ export interface PkgTemplateStringOption<T = string> {
11
+ name: string
12
+ type: 'string'
13
+ description: string
14
+ initial?: T | ((options: Record<string, any>) => T)
15
+ parse?: (v: string) => T | null
16
+ validate?: (v: string) => string | true
17
+ }
18
+
19
+ /** @public */
20
+ export type PkgTemplateOption<T = string> = PkgTemplateStringOption<T>
21
+
22
+ /** @public */
23
+ export interface PkgTemplateDefinition {
24
+ options: PkgTemplateStringOption<any>[]
25
+ features: {
26
+ name: string
27
+ optional: boolean
28
+ initial: boolean
29
+ }[]
30
+ getFiles: (
31
+ options: Record<string, any>,
32
+ features: Record<string, boolean>
33
+ ) => Promise<PkgTemplateFile[]>
34
+ }
35
+
36
+ /** @public */
37
+ export type PkgTemplateResolver = (options: {
38
+ cwd: string
39
+ /** @internal */
40
+ logger: Logger
41
+ packagePath: string
42
+ }) => PkgTemplateDefinition | Promise<PkgTemplateDefinition>
43
+
44
+ /** @public */
45
+ export type PkgTemplate = PkgTemplateDefinition | PkgTemplateResolver
package/src/node/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './build'
2
2
  export * from './check'
3
3
  export * from './core'
4
+ export * from './init'
4
5
  export * from './logger'
5
6
  export * from './resolveBuildTasks'
6
7
  export * from './tasks'
@@ -0,0 +1,55 @@
1
+ import {lstat} from 'fs/promises'
2
+ import {mkdirp} from 'mkdirp'
3
+ import {resolve} from 'path'
4
+
5
+ import {createFromTemplate} from './core/template'
6
+ import {fileExists} from './fileExists'
7
+ import {isEmptyDirectory} from './isEmptyDirectory'
8
+ import {createLogger} from './logger'
9
+ import {defaultTemplate} from './templates'
10
+
11
+ /** @public */
12
+ export async function init(options: {cwd: string; path: string}): Promise<void> {
13
+ if (!options.cwd) {
14
+ throw new Error('Missing required option: cwd')
15
+ }
16
+
17
+ if (!options.path) {
18
+ throw new Error('Missing required option: path')
19
+ }
20
+
21
+ const logger = createLogger()
22
+
23
+ const packagePath = resolve(options.cwd, options.path)
24
+
25
+ await ensurePackagePath(packagePath)
26
+
27
+ await createFromTemplate({
28
+ cwd: options.cwd,
29
+ logger,
30
+ template: defaultTemplate,
31
+ packagePath,
32
+ })
33
+ }
34
+
35
+ async function ensurePackagePath(packagePath: string): Promise<void> {
36
+ const exists = fileExists(packagePath)
37
+
38
+ if (!exists) {
39
+ await mkdirp(packagePath)
40
+
41
+ return
42
+ }
43
+
44
+ const dir = (await lstat(packagePath)).isDirectory()
45
+
46
+ if (!dir) {
47
+ throw new Error('the package path is a file, not a directory')
48
+ }
49
+
50
+ const empty = await isEmptyDirectory(packagePath)
51
+
52
+ if (!empty) {
53
+ throw new Error('the package directory is not empty')
54
+ }
55
+ }
@@ -0,0 +1,5 @@
1
+ import {readdir} from 'fs/promises'
2
+
3
+ export async function isEmptyDirectory(dirPath: string): Promise<boolean> {
4
+ return (await readdir(dirPath)).length === 0
5
+ }
@@ -0,0 +1 @@
1
+ export * from './template'