@sanity/pkg-utils 1.1.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/pkg-utils",
3
- "version": "1.1.0",
3
+ "version": "1.3.1",
4
4
  "author": "Sanity.io <hello@sanity.io>",
5
5
  "license": "MIT",
6
6
  "description": "Simple utilities for modern npm packages.",
@@ -48,10 +48,12 @@
48
48
  "@rollup/plugin-json": "^4.1.0",
49
49
  "@rollup/plugin-node-resolve": "^13.3.0",
50
50
  "@sanity/tsdoc-to-portable-text": "^0.4.1",
51
+ "browserslist": "^4.21.3",
51
52
  "cac": "^6.7.12",
52
53
  "chalk": "^4.1.2",
53
54
  "esbuild": "^0.15.5",
54
55
  "esbuild-register": "^3.3.3",
56
+ "find-config": "^1.0.0",
55
57
  "jsonc-parser": "^3.1.0",
56
58
  "mkdirp": "^1.0.4",
57
59
  "pkg-up": "^3.1.0",
@@ -64,6 +66,7 @@
64
66
  "@commitlint/config-conventional": "^17.0.3",
65
67
  "@sanity/semantic-release-preset": "^2.0.0",
66
68
  "@types/cpx": "^1.5.2",
69
+ "@types/find-config": "^1.0.1",
67
70
  "@types/mkdirp": "^1.0.2",
68
71
  "@types/node": "^18.7.13",
69
72
  "@types/rimraf": "^3.0.2",
@@ -0,0 +1,60 @@
1
+ import browserslist from 'browserslist'
2
+
3
+ export interface _PackageTargetVersions {
4
+ chrome: string[]
5
+ ff: string[]
6
+ edge: string[]
7
+ iosSaf: string[]
8
+ saf: string[]
9
+ opera: string[]
10
+ node: string[]
11
+ }
12
+
13
+ function _sortAsNumber(a: string, b: string) {
14
+ const aVersion = Number(a)
15
+ const bVersion = Number(b)
16
+
17
+ return aVersion - bVersion
18
+ }
19
+
20
+ export function _parseBrowserslistVersions(query: string[]): _PackageTargetVersions {
21
+ const result = browserslist(query)
22
+
23
+ const entries = result.map((key) => {
24
+ const [name, version] = key.split(' ')
25
+
26
+ return {name, version: version.split('-')[0].split('.')[0]}
27
+ })
28
+
29
+ const andChr = entries.filter((b) => b.name === 'and_chr')
30
+ const andFf = entries.filter((b) => b.name === 'and_ff')
31
+ const chrome = entries.filter((b) => b.name === 'chrome')
32
+ const edge = entries.filter((b) => b.name === 'edge')
33
+ const ff = entries.filter((b) => b.name === 'firefox')
34
+ const iosSaf = entries.filter((b) => b.name === 'ios_saf')
35
+ const saf = entries.filter((b) => b.name === 'safari')
36
+ const opera = entries.filter((b) => b.name === 'opera')
37
+ const node = entries.filter((b) => b.name === 'node')
38
+
39
+ // versions
40
+ const versions: _PackageTargetVersions = {
41
+ chrome: andChr.concat(chrome).map((b) => b.version),
42
+ ff: andFf.concat(ff).map((b) => b.version),
43
+ edge: edge.map((b) => b.version),
44
+ iosSaf: iosSaf.map((b) => b.version),
45
+ saf: saf.map((b) => b.version),
46
+ opera: opera.map((b) => b.version),
47
+ node: node.map((b) => b.version),
48
+ }
49
+
50
+ // sort
51
+ versions.chrome.sort(_sortAsNumber)
52
+ versions.ff.sort(_sortAsNumber)
53
+ versions.edge.sort(_sortAsNumber)
54
+ versions.iosSaf.sort(_sortAsNumber)
55
+ versions.saf.sort(_sortAsNumber)
56
+ versions.opera.sort(_sortAsNumber)
57
+ versions.node.sort(_sortAsNumber)
58
+
59
+ return versions
60
+ }
@@ -0,0 +1,15 @@
1
+ import {_PackageTargetVersions} from './_parseBrowserslistVersions'
2
+
3
+ export function _parseNodeTarget(versions: _PackageTargetVersions): string[] | undefined {
4
+ const target: string[] = []
5
+
6
+ if (versions.node.length) {
7
+ target.push(`node${versions.node[0]}`)
8
+ }
9
+
10
+ if (target.length === 0) {
11
+ return undefined
12
+ }
13
+
14
+ return target
15
+ }
@@ -1,13 +1,13 @@
1
1
  import path from 'path'
2
2
  import {PackageSubPathExportEntry} from '../core'
3
3
  import {_BuildContext} from './_types'
4
- import {_RollupTask, _BuildTask, _DtsTask} from './tasks'
4
+ import {_BuildTask, _DtsTask, _RollupTask} from './tasks'
5
5
 
6
6
  /**
7
7
  * @internal
8
8
  */
9
9
  export function _parseTasks(ctx: _BuildContext): _BuildTask[] {
10
- const {pkg} = ctx
10
+ const {config, pkg} = ctx
11
11
 
12
12
  const entries = Object.entries(ctx.exports || {}).map(
13
13
  ([path, entry]) => ({path, ...entry} as PackageSubPathExportEntry & {path: string})
@@ -35,6 +35,8 @@ export function _parseTasks(ctx: _BuildContext): _BuildTask[] {
35
35
 
36
36
  // Parse `rollup` tasks
37
37
  for (const entry of entries) {
38
+ const runtime = entry.runtime || config?.runtime || 'web'
39
+
38
40
  const format: ('commonjs' | 'esm')[] = []
39
41
  const target: string[] = []
40
42
 
@@ -46,23 +48,23 @@ export function _parseTasks(ctx: _BuildContext): _BuildTask[] {
46
48
  format.push('esm')
47
49
  }
48
50
 
49
- if (entry.runtime === 'node') {
50
- target.push('node12')
51
+ if (runtime === 'node') {
52
+ target.push(...ctx.target.node)
51
53
  }
52
54
 
53
- if (entry.runtime === 'web') {
54
- target.push('chrome104')
55
+ if (runtime === 'web') {
56
+ target.push(...ctx.target.web)
55
57
  }
56
58
 
57
59
  for (const f of format) {
58
- const buildId = `${entry.runtime}:${f}:${target.join(',')}`
60
+ const buildId = `${runtime}:${f}:${target.join(',')}`
59
61
 
60
62
  if (!rollupTasks[buildId]) {
61
63
  rollupTasks[buildId] = {
62
64
  type: 'rollup',
63
65
  buildId,
64
66
  entries: [entry],
65
- runtime: entry.runtime,
67
+ runtime,
66
68
  format: f,
67
69
  target,
68
70
  }
@@ -0,0 +1,35 @@
1
+ import {_PackageTargetVersions} from './_parseBrowserslistVersions'
2
+
3
+ export function _parseWebTarget(versions: _PackageTargetVersions): string[] | undefined {
4
+ const target: string[] = []
5
+
6
+ if (versions.chrome.length) {
7
+ target.push(`chrome${versions.chrome[0]}`)
8
+ }
9
+
10
+ if (versions.ff.length) {
11
+ target.push(`firefox${versions.ff[0]}`)
12
+ }
13
+
14
+ if (versions.edge.length) {
15
+ target.push(`edge${versions.edge[0]}`)
16
+ }
17
+
18
+ if (versions.iosSaf.length) {
19
+ target.push(`ios${versions.iosSaf[0]}`)
20
+ }
21
+
22
+ if (versions.saf.length) {
23
+ target.push(`safari${versions.saf[0]}`)
24
+ }
25
+
26
+ if (versions.opera.length) {
27
+ target.push(`opera${versions.opera[0]}`)
28
+ }
29
+
30
+ if (target.length === 0) {
31
+ return undefined
32
+ }
33
+
34
+ return target
35
+ }
@@ -21,5 +21,6 @@ export interface _BuildContext {
21
21
  dist: string
22
22
  pkg: _PackageJSON
23
23
  src: string
24
+ target: {node: string[]; web: string[]}
24
25
  tsconfig?: string
25
26
  }
@@ -2,8 +2,18 @@
2
2
 
3
3
  import path from 'path'
4
4
  import chalk from 'chalk'
5
- import {PackageExports, _loadConfig, _loadPkg, _parseExports, _resolveConfigProperty} from '../core'
5
+ import {
6
+ PackageExports,
7
+ _DEFAULTS,
8
+ _loadConfig,
9
+ _loadPkg,
10
+ _parseExports,
11
+ _resolveConfigProperty,
12
+ } from '../core'
13
+ import {_parseBrowserslistVersions} from './_parseBrowserslistVersions'
14
+ import {_parseNodeTarget} from './_parseNodeTarget'
6
15
  import {_parseTasks} from './_parseTasks'
16
+ import {_parseWebTarget} from './_parseWebTarget'
7
17
  import {_BuildContext} from './_types'
8
18
  import {_dtsTask, _extractTask, _rollupTask} from './tasks'
9
19
 
@@ -19,33 +29,37 @@ export async function build(options: {
19
29
  const pkg = await _loadPkg({cwd})
20
30
  const config = await _loadConfig({cwd})
21
31
 
22
- // if (!config) {
23
- // console.log('no configuration found')
24
- // return
25
- // }
26
-
27
32
  const parsedExports = _parseExports(pkg).reduce<PackageExports>((acc, x) => {
28
33
  const {path: exportPath, ...exportEntry} = x
29
34
 
30
35
  return {...acc, [exportPath]: exportEntry}
31
36
  }, {})
32
37
 
33
- const exports = config?.exports
34
- ? _resolveConfigProperty(config.exports, parsedExports)
35
- : parsedExports
38
+ const exports = _resolveConfigProperty(config?.exports, parsedExports)
36
39
 
37
- const initialExternal = [
40
+ const parsedExternal = [
38
41
  ...(pkg.dependencies ? Object.keys(pkg.dependencies) : []),
39
42
  ...(pkg.peerDependencies ? Object.keys(pkg.peerDependencies) : []),
40
43
  ]
41
44
 
42
- const external = config?.external
43
- ? _resolveConfigProperty(config.external, initialExternal)
44
- : initialExternal
45
+ const external = _resolveConfigProperty(config?.external, parsedExternal)
46
+
47
+ const targetVersions = _parseBrowserslistVersions(pkg.browserslist || _DEFAULTS.browserslist)
45
48
 
46
49
  const srcPath = path.resolve(cwd, config?.src || 'src')
47
50
  const distPath = path.resolve(cwd, config?.dist || 'dist')
48
51
 
52
+ const nodeTarget = _parseNodeTarget(targetVersions)
53
+ const webTarget = _parseWebTarget(targetVersions)
54
+
55
+ if (!nodeTarget) {
56
+ throw new Error('no matching `node` target')
57
+ }
58
+
59
+ if (!webTarget) {
60
+ throw new Error('no matching `web` target')
61
+ }
62
+
49
63
  const context: _BuildContext = {
50
64
  config,
51
65
  cwd,
@@ -56,11 +70,11 @@ export async function build(options: {
56
70
  dist: path.relative(cwd, distPath),
57
71
  pkg,
58
72
  src: path.relative(cwd, srcPath),
73
+ target: {node: nodeTarget, web: webTarget},
59
74
  tsconfig,
60
75
  }
61
76
 
62
77
  console.log(chalk.gray('cwd '), context.cwd)
63
- // console.log('external ', context.external)
64
78
  console.log(chalk.gray('src '), context.src)
65
79
  console.log(chalk.gray('dist '), context.dist)
66
80
  console.log(chalk.gray('tsconfig '), context.tsconfig)
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export const _DEFAULTS = {
5
+ browserslist: [
6
+ '> 0.2% and supports es6-module and supports es6-module-dynamic-import',
7
+ 'not dead',
8
+ 'not IE 11',
9
+ 'maintained node versions',
10
+ ],
11
+ }
@@ -1,5 +1,6 @@
1
1
  import path from 'path'
2
2
  import {register} from 'esbuild-register/dist/node'
3
+ import findConfig from 'find-config'
3
4
  import pkgUp from 'pkg-up'
4
5
  import {PkgConfigOptions} from './types'
5
6
 
@@ -15,16 +16,40 @@ export async function _loadConfig(options: {cwd: string}): Promise<PkgConfigOpti
15
16
 
16
17
  const root = path.dirname(pkgPath)
17
18
 
19
+ const configFile = _findConfigFile(root)
20
+
21
+ if (!configFile) {
22
+ return undefined
23
+ }
24
+
18
25
  try {
19
- const {unregister} = register({extensions: ['.js', '.ts']})
26
+ const {unregister} = configFile.transform
27
+ ? register({extensions: ['.js', '.ts']})
28
+ : {unregister: () => undefined}
20
29
 
21
30
  // eslint-disable-next-line @typescript-eslint/no-var-requires
22
- const mod = require(path.resolve(root, 'package.config.ts'))
31
+ const mod = require(configFile.path)
23
32
 
24
33
  unregister()
25
34
 
26
- return mod.default
35
+ return mod?.default || mod || undefined
27
36
  } catch (_) {
28
37
  return undefined
29
38
  }
30
39
  }
40
+
41
+ // Looks for:
42
+ // 1. package.config.ts
43
+ // 2. package.config.cjs
44
+ //
45
+ function _findConfigFile(cwd: string): {path: string; transform: boolean} | null {
46
+ const ts = findConfig('package.config.ts', {cwd})
47
+
48
+ if (ts) return {path: ts, transform: true}
49
+
50
+ const cjs = findConfig('package.config.cjs', {cwd})
51
+
52
+ if (cjs) return {path: cjs, transform: false}
53
+
54
+ return null
55
+ }
@@ -3,7 +3,9 @@ import {ConfigProperty, ConfigPropertyResolver} from './types'
3
3
  /**
4
4
  * @internal
5
5
  */
6
- export function _resolveConfigProperty<T>(prop: ConfigProperty<T>, initialValue: T): T {
6
+ export function _resolveConfigProperty<T>(prop: ConfigProperty<T> | undefined, initialValue: T): T {
7
+ if (!prop) return initialValue
8
+
7
9
  if (typeof prop === 'function') {
8
10
  return (prop as ConfigPropertyResolver<T>)(initialValue)
9
11
  }
@@ -2,7 +2,7 @@
2
2
  * @public
3
3
  */
4
4
  export interface PackageSubPathExportEntry {
5
- runtime: 'node' | 'web'
5
+ runtime?: 'node' | 'web'
6
6
 
7
7
  // paths
8
8
  source: string
@@ -41,6 +41,10 @@ export interface PkgConfigOptions {
41
41
  * Packages to exclude from the bundles.
42
42
  */
43
43
  external?: ConfigProperty<string[]>
44
+ /**
45
+ * Default runtime of package exports
46
+ */
47
+ runtime?: 'node' | 'web'
44
48
  /**
45
49
  * Directory of source files.
46
50
  */
package/src/core/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './_defaults'
1
2
  export * from './_isRecord'
2
3
  export * from './config'
3
4
  export * from './pkg'
@@ -8,7 +8,7 @@ import {_PackageJSON} from './_types'
8
8
  export function _parseExports(pkg: _PackageJSON): (PackageSubPathExportEntry & {path: string})[] {
9
9
  const rootExport: PackageSubPathExportEntry & {path: string} = {
10
10
  path: '.',
11
- runtime: 'web',
11
+ runtime: undefined,
12
12
 
13
13
  source: pkg.source || 'index.js',
14
14
  require: pkg.main,
@@ -26,7 +26,6 @@ export function _parseExports(pkg: _PackageJSON): (PackageSubPathExportEntry & {
26
26
  } else {
27
27
  extraExports.push({
28
28
  path: exportPath,
29
- runtime: 'web',
30
29
  source: exportEntry.source,
31
30
  ...exportEntry,
32
31
  })
@@ -15,4 +15,5 @@ export interface _PackageJSON {
15
15
  source?: string
16
16
  module?: string
17
17
  types?: string
18
+ browserslist?: string[]
18
19
  }