@plugjs/plug 0.1.4 → 0.2.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 (111) hide show
  1. package/README.md +2 -2
  2. package/cli/plug.mjs +1397 -0
  3. package/cli/ts-loader.mjs +273 -0
  4. package/cli/tsrun.mjs +136 -0
  5. package/dist/asserts.cjs +1 -0
  6. package/dist/asserts.cjs.map +1 -1
  7. package/dist/asserts.mjs +1 -0
  8. package/dist/asserts.mjs.map +1 -1
  9. package/dist/build.cjs +9 -6
  10. package/dist/build.cjs.map +1 -1
  11. package/dist/build.mjs +9 -6
  12. package/dist/build.mjs.map +1 -1
  13. package/dist/files.cjs +9 -0
  14. package/dist/files.cjs.map +1 -1
  15. package/dist/files.mjs +9 -0
  16. package/dist/files.mjs.map +1 -1
  17. package/dist/fork.cjs +2 -0
  18. package/dist/fork.cjs.map +1 -1
  19. package/dist/fork.mjs +2 -0
  20. package/dist/fork.mjs.map +1 -1
  21. package/dist/fs.cjs +11 -4
  22. package/dist/fs.cjs.map +1 -1
  23. package/dist/fs.mjs +7 -4
  24. package/dist/fs.mjs.map +1 -1
  25. package/dist/helpers.cjs +1 -1
  26. package/dist/helpers.cjs.map +1 -1
  27. package/dist/helpers.mjs +1 -1
  28. package/dist/helpers.mjs.map +1 -1
  29. package/dist/index.cjs +7 -0
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.mjs +2 -0
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/logging/levels.cjs.map +1 -1
  35. package/dist/logging/levels.mjs.map +1 -1
  36. package/dist/logging/logger.cjs.map +1 -1
  37. package/dist/logging/logger.mjs.map +1 -1
  38. package/dist/logging/options.cjs +5 -0
  39. package/dist/logging/options.cjs.map +1 -1
  40. package/dist/logging/options.mjs +5 -0
  41. package/dist/logging/options.mjs.map +1 -1
  42. package/dist/logging/report.cjs.map +1 -1
  43. package/dist/logging/report.mjs.map +1 -1
  44. package/dist/logging/spinner.cjs +12 -0
  45. package/dist/logging/spinner.cjs.map +1 -1
  46. package/dist/logging/spinner.mjs +12 -0
  47. package/dist/logging/spinner.mjs.map +1 -1
  48. package/dist/paths.cjs.map +1 -1
  49. package/dist/paths.mjs.map +1 -1
  50. package/dist/pipe.cjs +34 -0
  51. package/dist/pipe.cjs.map +1 -1
  52. package/dist/pipe.mjs +34 -0
  53. package/dist/pipe.mjs.map +1 -1
  54. package/dist/plugs/debug.cjs.map +1 -1
  55. package/dist/plugs/debug.mjs.map +1 -1
  56. package/dist/plugs/edit.cjs +1 -1
  57. package/dist/plugs/edit.cjs.map +1 -1
  58. package/dist/plugs/edit.d.ts +2 -2
  59. package/dist/plugs/edit.mjs +1 -1
  60. package/dist/plugs/edit.mjs.map +1 -1
  61. package/dist/plugs/esbuild/fix-extensions.cjs +4 -0
  62. package/dist/plugs/esbuild/fix-extensions.cjs.map +1 -1
  63. package/dist/plugs/esbuild/fix-extensions.mjs.map +1 -1
  64. package/dist/plugs/esbuild.cjs +6 -2
  65. package/dist/plugs/esbuild.cjs.map +1 -1
  66. package/dist/plugs/esbuild.mjs +6 -2
  67. package/dist/plugs/esbuild.mjs.map +1 -1
  68. package/dist/plugs/exec.cjs.map +1 -1
  69. package/dist/plugs/exec.mjs.map +1 -1
  70. package/dist/plugs/exports.cjs +122 -0
  71. package/dist/plugs/exports.cjs.map +6 -0
  72. package/dist/plugs/exports.d.ts +17 -0
  73. package/dist/plugs/exports.mjs +105 -0
  74. package/dist/plugs/exports.mjs.map +6 -0
  75. package/dist/plugs/filter.cjs.map +1 -1
  76. package/dist/plugs/filter.mjs.map +1 -1
  77. package/dist/plugs.cjs +1 -0
  78. package/dist/plugs.cjs.map +1 -1
  79. package/dist/plugs.d.ts +1 -0
  80. package/dist/plugs.mjs +1 -0
  81. package/dist/plugs.mjs.map +1 -1
  82. package/dist/utils/exec.cjs +9 -0
  83. package/dist/utils/exec.cjs.map +1 -1
  84. package/dist/utils/exec.mjs +5 -0
  85. package/dist/utils/exec.mjs.map +1 -1
  86. package/dist/utils/match.cjs +5 -0
  87. package/dist/utils/match.cjs.map +1 -1
  88. package/dist/utils/match.mjs +1 -0
  89. package/dist/utils/match.mjs.map +1 -1
  90. package/dist/utils/options.cjs.map +1 -1
  91. package/dist/utils/options.mjs.map +1 -1
  92. package/dist/utils/walk.cjs.map +1 -1
  93. package/dist/utils/walk.mjs.map +1 -1
  94. package/extra/plug.mts +373 -0
  95. package/extra/ts-loader.mts +545 -0
  96. package/extra/tsrun.mts +64 -0
  97. package/extra/utils.ts +168 -0
  98. package/package.json +9 -19
  99. package/src/build.ts +10 -7
  100. package/src/fork.ts +1 -0
  101. package/src/helpers.ts +1 -1
  102. package/src/index.ts +4 -0
  103. package/src/plugs/edit.ts +4 -3
  104. package/src/plugs/esbuild.ts +0 -1
  105. package/src/plugs/exports.ts +175 -0
  106. package/src/plugs.ts +1 -0
  107. package/types/plugjs.d.ts +0 -2
  108. package/LICENSE.md +0 -211
  109. package/NOTICE.md +0 -13
  110. package/extra/cli.mjs +0 -1356
  111. package/extra/ts-loader.mjs +0 -223
package/extra/utils.ts ADDED
@@ -0,0 +1,168 @@
1
+ /* eslint-disable no-console */
2
+ import _childProcess from 'node:child_process'
3
+ import _fs from 'node:fs'
4
+ import _path from 'node:path'
5
+ import _url from 'node:url'
6
+ import _util from 'node:util'
7
+
8
+ /* ========================================================================== *
9
+ * PRETTY COLORS *
10
+ * ========================================================================== */
11
+
12
+ export const $rst = process.stdout.isTTY ? '\u001b[0m' : '' // reset all colors to default
13
+ export const $und = process.stdout.isTTY ? '\u001b[4m' : '' // underline on
14
+ export const $gry = process.stdout.isTTY ? '\u001b[38;5;240m' : '' // somewhat gray
15
+ export const $blu = process.stdout.isTTY ? '\u001b[38;5;69m' : '' // brighter blue
16
+ export const $wht = process.stdout.isTTY ? '\u001b[1;38;5;255m' : '' // full-bright white
17
+ export const $tsk = process.stdout.isTTY ? '\u001b[38;5;141m' : '' // the color for tasks (purple)
18
+
19
+
20
+ /* ========================================================================== *
21
+ * PACKAGE VERSION *
22
+ * ========================================================================== */
23
+
24
+ export function version(): string {
25
+ const debug = _util.debuglog('plug:cli')
26
+
27
+ try {
28
+ const thisFile = _url.fileURLToPath(import.meta.url)
29
+ const packageFile = _path.resolve(thisFile, '..', '..', 'package.json')
30
+ const packageData = _fs.readFileSync(packageFile, 'utf-8')
31
+ return JSON.parse(packageData).version || '(unknown)'
32
+ } catch (error) {
33
+ debug('Error parsing version:', error)
34
+ return '(error)'
35
+ }
36
+ }
37
+
38
+ /* ========================================================================== *
39
+ * TS LOADER FORCE TYPE *
40
+ * ========================================================================== */
41
+
42
+ function forceType(type: 'commonjs' | 'module'): void {
43
+ const debug = _util.debuglog('plug:cli')
44
+
45
+ const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
46
+
47
+ if (!(tsLoaderMarker in globalThis)) {
48
+ throw new Error('TypeScript Loader not available')
49
+ }
50
+ debug(`Forcing type to "${type}"`)
51
+ ;(globalThis as any)[tsLoaderMarker] = type
52
+ }
53
+
54
+
55
+ /* ========================================================================== *
56
+ * FILES UTILITIES *
57
+ * ========================================================================== */
58
+
59
+ /* Returns a boolean indicating whether the specified file exists or not */
60
+ export function isFile(path: string): boolean {
61
+ try {
62
+ return _fs.statSync(path).isFile()
63
+ } catch (error) {
64
+ return false
65
+ }
66
+ }
67
+
68
+ /* Returns a boolean indicating whether the specified directory exists or not */
69
+ export function isDirectory(path: string): boolean {
70
+ try {
71
+ return _fs.statSync(path).isDirectory()
72
+ } catch (error) {
73
+ return false
74
+ }
75
+ }
76
+
77
+
78
+ /* ========================================================================== *
79
+ * MAIN ENTRY POINT *
80
+ * ========================================================================== */
81
+ export function main(callback: (args: string[]) => void | Promise<void>): void {
82
+ const debug = _util.debuglog('plug:cli')
83
+
84
+ /* Check for source maps and typescript support */
85
+ const sourceMapsEnabled = process.execArgv.indexOf('--enable-source-maps') >= 0
86
+
87
+ /* Check if our `ts-loader` loader is enabled */
88
+ const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
89
+ const typeScriptEnabled = (globalThis as any)[tsLoaderMarker]
90
+
91
+ /* Some debugging if needed */
92
+ debug('SourceMaps enabled =', sourceMapsEnabled)
93
+ debug('TypeScript enabled =', typeScriptEnabled || false)
94
+
95
+ /* If both source maps and typescript are on, run! */
96
+ if (sourceMapsEnabled && typeScriptEnabled) {
97
+ const args = process.argv.slice(2).filter((arg: string): string | void => {
98
+ if (arg === '--force-esm') {
99
+ return forceType('module')
100
+ } else if (arg === '--force-cjs') {
101
+ return forceType('commonjs')
102
+ } else {
103
+ return arg
104
+ }
105
+ })
106
+
107
+
108
+ Promise.resolve().then(() => callback(args)).catch(console.error)
109
+ } else {
110
+ const script = _url.fileURLToPath(import.meta.url)
111
+
112
+ /* Fork out ourselves with new options */
113
+ const execArgv = [ ...process.execArgv ]
114
+
115
+ /* Enable source maps if not done already */
116
+ if (! sourceMapsEnabled) execArgv.push('--enable-source-maps')
117
+
118
+ /* Enable our ESM TypeScript loader if not done already */
119
+ if (! typeScriptEnabled) {
120
+ const directory = _path.dirname(script)
121
+ const extension = _path.extname(script) // .mts or .mjs
122
+ const loader = _path.resolve(directory, `ts-loader${extension}`)
123
+ execArgv.push(`--experimental-loader=${loader}`, '--no-warnings')
124
+ }
125
+
126
+ /*
127
+ * It seems that setting "type" as "module" in "package.json" creates some
128
+ * problems when the module is being imported from a "commonjs" one.
129
+ *
130
+ * TypeScript _incorrectly_ says (regardless of how we set up our conditional
131
+ * exports) that we must use dynamic imports:
132
+ *
133
+ * Module '@plugjs/plug' cannot be imported using this construct. The
134
+ * specifier only resolves to an ES module, which cannot be imported
135
+ * synchronously. Use dynamic import instead.
136
+ * TS(1471)
137
+ *
138
+ * So for now our only option is to leave "type" as "commonjs", and for those
139
+ * brave souls willing to force ESM irregardless of what's in "package.json",
140
+ * we allow the "--force-esm" option, and instruct `ts-loader` that the
141
+ * current directory (and subdirs) will transpile as ESM always.
142
+ */
143
+
144
+ /* Fork ourselves! */
145
+ const child = _childProcess.fork(script, [ ...process.argv.slice(2) ], {
146
+ stdio: [ 'inherit', 'inherit', 'inherit', 'ipc' ],
147
+ execArgv,
148
+ })
149
+
150
+ /* Monitor child process... */
151
+ child.on('error', (error) => {
152
+ console.log('Error respawning CLI', error)
153
+ process.exit(1)
154
+ })
155
+
156
+ child.on('exit', (code, signal) => {
157
+ if (signal) {
158
+ console.log(`CLI process exited with signal ${signal}`)
159
+ process.exit(1)
160
+ } else if (typeof code !== 'number') {
161
+ console.log('CLI process failed for an unknown reason')
162
+ process.exit(1)
163
+ } else {
164
+ process.exit(code)
165
+ }
166
+ })
167
+ }
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugjs/plug",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "type": "commonjs",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -98,37 +98,27 @@
98
98
  }
99
99
  },
100
100
  "bin": {
101
- "plug": "./extra/cli.mjs"
101
+ "plug": "./cli/plug.mjs",
102
+ "tsrun": "./cli/tsrun.mjs"
102
103
  },
103
- "scripts": {
104
- "bootstrap": "./bootstrap.sh",
105
- "build": "./bootstrap.sh && ./extra/cli.mjs",
106
- "dev": "./extra/cli.mjs -w ./src -w ./test"
107
- },
108
- "author": "",
109
- "license": "ISC",
104
+ "author": "Juit Developers <developers@juit.com>",
105
+ "license": "Apache-2.0",
110
106
  "dependencies": {
111
107
  "@types/node": "<19",
112
- "esbuild": "^0.15.18",
108
+ "esbuild": "^0.17.10",
113
109
  "picomatch": "^2.3.1",
114
- "typescript": "^4.9.3"
110
+ "typescript": "^4.9.5"
115
111
  },
116
112
  "devDependencies": {
117
- "@plugjs/cov8": "^0.1.2",
118
- "@plugjs/eslint": "^0.1.2",
119
- "@plugjs/eslint-plugin": "^0.1.1",
120
- "@plugjs/jasmine": "^0.1.2",
121
- "@plugjs/typescript": "^0.1.2",
122
113
  "@types/picomatch": "^2.3.0",
123
114
  "@types/yargs-parser": "^21.0.0",
124
- "chai": "^4.3.7",
125
- "chai-as-promised": "^7.1.1",
126
115
  "yargs-parser": "^21.1.1"
127
116
  },
128
117
  "files": [
129
118
  "*.md",
119
+ "cli/",
130
120
  "dist/",
131
- "extra/*.mjs",
121
+ "extra/",
132
122
  "src/",
133
123
  "types/"
134
124
  ]
package/src/build.ts CHANGED
@@ -80,7 +80,8 @@ function makeTask(
80
80
  const promise = runAsync(context, taskName, async () => {
81
81
  return await _def.call(build) || undefined
82
82
  }).then((result) => {
83
- context.log.notice(`Success ${$ms(Date.now() - now)}`)
83
+ const level = taskName.startsWith('_') ? 'info' : 'notice'
84
+ context.log[level](`Success ${$ms(Date.now() - now)}`)
84
85
  return result
85
86
  }).catch((error) => {
86
87
  throw context.log.fail(`Failure ${$ms(Date.now() - now)}`, error)
@@ -102,8 +103,10 @@ function makeTask(
102
103
  return invoke(state, _name)
103
104
  }, { buildFile, tasks, props, invoke })
104
105
 
105
- /* Assign the task name (nicely) and return it */
106
- return Object.defineProperty(task, 'name', { value: _name })
106
+ /* Assign the task's marker and name and return it */
107
+ Object.defineProperty(task, taskMarker, { value: true })
108
+ Object.defineProperty(task, 'name', { value: _name })
109
+ return task
107
110
  }
108
111
 
109
112
  /* ========================================================================== *
@@ -124,14 +127,14 @@ export function build<
124
127
  /* Iterate through all definition extracting properties and tasks */
125
128
  for (const [ key, val ] of Object.entries(def)) {
126
129
  let len = 0
127
- if (typeof val === 'string') {
130
+ if (isTask(val)) { // this goes first, tasks _are_ functions!
131
+ tasks[key] = val
132
+ len = key.length
133
+ } else if (typeof val === 'string') {
128
134
  props[key] = val
129
135
  } else if (typeof val === 'function') {
130
136
  tasks[key] = makeTask(buildFile, tasks, props, val, key)
131
137
  len = key.length
132
- } else if (isTask(val)) {
133
- tasks[key] = val
134
- len = key.length
135
138
  }
136
139
 
137
140
  /* Update the logger's own "taskLength" for nice printing */
package/src/fork.ts CHANGED
@@ -200,6 +200,7 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
200
200
  assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export a default constructor`)
201
201
  } else {
202
202
  Ctor = script[exportName]
203
+ if ((! Ctor) && (script.default)) Ctor = script.default[exportName]
203
204
  assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export "${exportName}"`)
204
205
  }
205
206
 
package/src/helpers.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import { mkdtempSync } from 'node:fs'
1
2
  import { tmpdir } from 'node:os'
2
3
  import { join } from 'node:path'
3
- import { mkdtempSync } from 'node:fs'
4
4
 
5
5
  import { assert, assertPromises } from './asserts'
6
6
  import { requireContext } from './async'
package/src/index.ts CHANGED
@@ -6,6 +6,10 @@
6
6
  import type { Files } from './files'
7
7
  import type { Plug, PlugFunction } from './pipe'
8
8
 
9
+ export { Files } from './files'
10
+ export type { AbsolutePath } from './paths'
11
+ export type { Plug, PlugFunction } from './pipe'
12
+
9
13
  /**
10
14
  * The {@link Pipe} interface defines a processing pipeline where multiple
11
15
  * {@link Plug}s can transform lists of {@link Files}.
package/src/plugs/edit.ts CHANGED
@@ -2,12 +2,13 @@ import { readFile, writeFile } from '../fs'
2
2
  import { install } from '../pipe'
3
3
 
4
4
  import type { Files } from '../files'
5
+ import type { AbsolutePath } from '../paths'
5
6
  import type { PipeParameters, Plug } from '../pipe'
6
7
 
7
8
  declare module '../index' {
8
9
  export interface Pipe {
9
10
  /** Edits the content of all files in a pipeline. */
10
- edit(callback: (content: string) => string | void | Promise<string | void>): Pipe
11
+ edit(callback: (content: string, fileName: AbsolutePath) => string | void | Promise<string | void>): Pipe
11
12
  }
12
13
  }
13
14
 
@@ -17,7 +18,7 @@ declare module '../index' {
17
18
 
18
19
  /** Edits the content of all files in a pipeline. */
19
20
  install('edit', class Edit implements Plug<Files> {
20
- private readonly _callback: (content: string) => string | void | Promise<string | void>
21
+ private readonly _callback: (content: string, fileName: AbsolutePath) => string | void | Promise<string | void>
21
22
 
22
23
  constructor(...args: PipeParameters<'edit'>) {
23
24
  this._callback = args[0]
@@ -26,7 +27,7 @@ install('edit', class Edit implements Plug<Files> {
26
27
  async pipe(files: Files): Promise<Files> {
27
28
  for (const file of files.absolutePaths()) {
28
29
  const data = await readFile(file, 'utf-8')
29
- const edited = await this._callback(data)
30
+ const edited = await this._callback(data, file)
30
31
  if (edited !== undefined) await writeFile(file, edited, 'utf-8')
31
32
  }
32
33
  return files
@@ -65,7 +65,6 @@ install('esbuild', class ESBuild implements Plug<Files> {
65
65
  absWorkingDir,
66
66
  entryPoints,
67
67
  logLevel: 'silent',
68
- watch: false,
69
68
  }
70
69
 
71
70
  if (options.format === 'cjs') {
@@ -0,0 +1,175 @@
1
+ import { EOL } from 'node:os'
2
+ import { sep } from 'node:path'
3
+
4
+ import { Files } from '../files'
5
+ import { readFile, writeFile } from '../fs'
6
+ import { $p } from '../logging'
7
+ import { assertRelativeChildPath, getAbsoluteParent } from '../paths'
8
+ import { install } from '../pipe'
9
+
10
+ import type { Context, PipeParameters, Plug } from '../pipe'
11
+
12
+ /** Options for our `exports` plug. */
13
+ export interface ExportsOptions {
14
+ /** The `package.json` file used as the input for processing */
15
+ packageJson?: string
16
+ /** The `package.json` file to be written including the matching exports */
17
+ outputPackageJson?: string
18
+ /** The extension for CommonJS modules (default: `.cjs` or `.js`) */
19
+ cjsExtension?: string
20
+ /** The extension for EcmaScript modules (default: `.mjs` or `.js`) */
21
+ esmExtension?: string
22
+ }
23
+
24
+ declare module '../index' {
25
+ export interface Pipe {
26
+ /** Include the files piped into this task as `exports` in `package.json` */
27
+ exports(options?: ExportsOptions): Pipe
28
+ }
29
+ }
30
+
31
+ /* ========================================================================== *
32
+ * INSTALLATION / IMPLEMENTATION *
33
+ * ========================================================================== */
34
+
35
+ type ExportsDeclaration = {
36
+ [ name in string ]? : {
37
+ [ type in 'require' | 'import' ]? : {
38
+ [ kind in 'types' | 'default' ]? : string
39
+ }
40
+ }
41
+ }
42
+
43
+ install('exports', class Exports implements Plug<Files> {
44
+ private readonly _packageJson: string
45
+ private readonly _outputPackageJson: string
46
+ private readonly _cjsExtension?: string
47
+ private readonly _esmExtension?: string
48
+
49
+ constructor(...args: PipeParameters<'exports'>) {
50
+ const options = args[0] || {}
51
+ const {
52
+ packageJson = 'package.json',
53
+ outputPackageJson = packageJson,
54
+ cjsExtension,
55
+ esmExtension,
56
+ } = options
57
+ this._packageJson = packageJson,
58
+ this._outputPackageJson = outputPackageJson
59
+ this._cjsExtension = cjsExtension
60
+ this._esmExtension = esmExtension
61
+ }
62
+
63
+ async pipe(files: Files, context: Context): Promise<Files> {
64
+ // read up our package.json, we need it to figure out the default `type`
65
+ const incomingFile = context.resolve(this._packageJson)
66
+ const incomingData = await readFile(incomingFile, 'utf8')
67
+ const packageData = JSON.parse(incomingData)
68
+
69
+ // exports must be relative to the _output_ package.json
70
+ const outgoingFile = context.resolve(this._outputPackageJson)
71
+ const outgoingDirectory = getAbsoluteParent(outgoingFile)
72
+
73
+ // type here determines the extension of commonjs or ecmascript modules
74
+ const type =
75
+ packageData.type === 'module' ? 'module' :
76
+ packageData.type === 'commonjs' ? 'commonjs' :
77
+ packageData.type == null ? 'commonjs' :
78
+ undefined
79
+ if (! type) context.log.fail(`Unknown module type "${packageData.type}" in ${$p(incomingFile)}`)
80
+
81
+ context.log.debug(`Package file ${$p(incomingFile)} declares module type "${type}"`)
82
+
83
+ const cjsExtension = this._cjsExtension || (type === 'commonjs' ? '.js' : '.cjs')
84
+ const esmExtension = this._esmExtension || (type === 'module' ? '.js' : '.mjs')
85
+
86
+ // reject when commonjs and ecmascript modules have the same extension
87
+ if (cjsExtension === esmExtension) {
88
+ context.log.fail(`CommonJS and EcmaScript modules both resolve to same extension "${cjsExtension}"`)
89
+ }
90
+
91
+ const exports: ExportsDeclaration = {}
92
+ function addExport(
93
+ name: string,
94
+ type: 'require' | 'import',
95
+ kind: 'types' | 'default',
96
+ file: string,
97
+ ): void {
98
+ if (! exports[name]) exports[name] = {}
99
+ if (! exports[name]![type]) exports[name]![type] = {}
100
+ exports[name]![type]![kind] = file
101
+ }
102
+
103
+ // all extensions to match in the incoming files
104
+ const exts = [ '.d.mts', '.d.cts', '.d.ts', cjsExtension, esmExtension ]
105
+
106
+ // look up all the files we were piped in
107
+ for (const [ name, absolute ] of files.pathMappings()) {
108
+ const relative = assertRelativeChildPath(outgoingDirectory, absolute)
109
+
110
+ for (const ext of exts) {
111
+ if (! relative.endsWith(ext)) continue
112
+
113
+ const base = `.${sep}${name.slice(0, -ext.length)}`
114
+ const exp = base.endsWith(`${sep}index`) ? base.slice(0, -6) : base
115
+
116
+ switch (ext) {
117
+ case cjsExtension:
118
+ addExport(exp, 'require', 'default', `.${sep}${relative}`)
119
+ break
120
+ case esmExtension:
121
+ addExport(exp, 'import', 'default', `.${sep}${relative}`)
122
+ break
123
+ case '.d.cts':
124
+ addExport(exp, 'require', 'types', `.${sep}${relative}`)
125
+ break
126
+ case '.d.mts':
127
+ addExport(exp, 'import', 'types', `.${sep}${relative}`)
128
+ break
129
+ case '.d.ts':
130
+ addExport(exp, 'require', 'types', `.${sep}${relative}`)
131
+ addExport(exp, 'import', 'types', `.${sep}${relative}`)
132
+ break
133
+ }
134
+ }
135
+ }
136
+
137
+ // if we have a "." export, inject the "main", "module" and "types" fields
138
+ if ('.' in exports) {
139
+ const rootExport = exports['.']
140
+ packageData['main'] = rootExport?.require?.default
141
+ packageData['module'] = rootExport?.import?.default
142
+ packageData['types'] = packageData['type'] === 'module' ?
143
+ rootExport?.import?.types : rootExport?.require?.types
144
+ }
145
+
146
+ // correctly order the exports record (e.g. types comes before default)
147
+ packageData['exports'] = Object.keys(exports).sort().reduce((obj, name) => {
148
+ const current = exports[name]
149
+ if (! current) return obj
150
+
151
+ // json serialization will scrub all undefined... here we export the types
152
+ // only if the "default" export is available, or we scrub the whole thing!
153
+ obj[name] = current.require?.default || current.import?.default ? {
154
+ require: current.require?.default ? {
155
+ types: current.require.types || undefined,
156
+ default: current.require.default || undefined,
157
+ } : undefined,
158
+ import: current.import?.default ? {
159
+ types: current.import.types || undefined,
160
+ default: current.import.default || undefined,
161
+ } : undefined,
162
+ } : undefined
163
+
164
+ return obj
165
+ }, {} as ExportsDeclaration)
166
+
167
+ // convert back our package data into a json and write it
168
+ const outgoingData = JSON.stringify(packageData, null, 2)
169
+ context.log.info(`Writing new ${$p(outgoingFile)}`, outgoingData)
170
+ await writeFile(outgoingFile, outgoingData + EOL, 'utf8')
171
+
172
+ // return a `Files` instance with our `package.json` in there
173
+ return Files.builder(getAbsoluteParent(outgoingFile)).add(outgoingFile).build()
174
+ }
175
+ })
package/src/plugs.ts CHANGED
@@ -3,5 +3,6 @@ export * from './plugs/debug'
3
3
  export * from './plugs/edit'
4
4
  export * from './plugs/esbuild'
5
5
  export * from './plugs/exec'
6
+ export * from './plugs/exports'
6
7
  export * from './plugs/filter'
7
8
  export * from './plugs/rmf'
package/types/plugjs.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- /// <reference no-default-lib="true"/>
2
-
3
1
  /**
4
2
  * A pseudo-variable replaced by `ESBuild` resolving to either `__filename`
5
3
  * in CJS modules, or to `import.meta.url` in ESM modules.