@plugjs/tsrun 0.4.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/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@plugjs/tsrun",
3
+ "version": "0.4.0",
4
+ "type": "module",
5
+ "module": "./dist/cli.mjs",
6
+ "types": "./dist/cli.d.mts",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/cli.d.mts",
11
+ "default": "./dist/cli.mjs"
12
+ }
13
+ }
14
+ },
15
+ "bin": {
16
+ "tsrun": "./dist/tsrun.mjs"
17
+ },
18
+ "scripts": {
19
+ "build": "./build.sh"
20
+ },
21
+ "author": "Juit Developers <developers@juit.com>",
22
+ "license": "Apache-2.0",
23
+ "dependencies": {
24
+ "esbuild": "^0.17.17"
25
+ },
26
+ "devDependencies": {
27
+ "@plugjs/eslint-plugin": "^0.1.5",
28
+ "@types/node": "<19",
29
+ "@types/yargs-parser": "^21.0.0",
30
+ "eslint": "^8.38.0",
31
+ "typescript": "^5.0.4",
32
+ "yargs-parser": "^21.1.1"
33
+ },
34
+ "files": [
35
+ "*.md",
36
+ "dist/",
37
+ "src/"
38
+ ]
39
+ }
package/src/cli.mts ADDED
@@ -0,0 +1,126 @@
1
+ /* eslint-disable no-console */
2
+ import _childProcess from 'node:child_process'
3
+ import _module from 'node:module'
4
+ import _url from 'node:url'
5
+ import _util from 'node:util'
6
+
7
+ import _yargs from './parser.mjs'
8
+
9
+ /* ========================================================================== *
10
+ * TS LOADER FORCE TYPE *
11
+ * ========================================================================== */
12
+
13
+ function forceType(type: 'commonjs' | 'module'): void {
14
+ const debug = _util.debuglog('plug:cli')
15
+
16
+ const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
17
+
18
+ if (!(tsLoaderMarker in globalThis)) {
19
+ throw new Error('TypeScript Loader not available')
20
+ }
21
+ debug(`Forcing type to "${type}"`)
22
+ ;(globalThis as any)[tsLoaderMarker] = type
23
+ }
24
+
25
+ /* ========================================================================== *
26
+ * ESPORTS *
27
+ * ========================================================================== */
28
+
29
+ /** Bundled-in `yargs-parser` */
30
+ export const yargsParser = _yargs
31
+
32
+ /**
33
+ * Wrap around the `main` process of a CLI.
34
+ *
35
+ * This function must be invoked with a script URL (the `import.meta.url`
36
+ * variable of the script being executed) and a callback, which will be invoked
37
+ * once the proper environment for TypeScript has been setup.
38
+ *
39
+ * The callback _might_ return a promise (can be asynchronous) which will be
40
+ * awaited for potential rejections.
41
+ */
42
+ export function main(
43
+ scriptUrl: string,
44
+ callback: (args: string[]) => void | Promise<void>,
45
+ ): void {
46
+ const debug = _util.debuglog('plug:cli')
47
+
48
+ /* Check for source maps and typescript support */
49
+ const sourceMapsEnabled = process.execArgv.indexOf('--enable-source-maps') >= 0
50
+
51
+ /* Check if our `loader` loader is enabled */
52
+ const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
53
+ const typeScriptEnabled = (globalThis as any)[tsLoaderMarker]
54
+
55
+ /* Some debugging if needed */
56
+ debug('SourceMaps enabled =', sourceMapsEnabled)
57
+ debug('TypeScript enabled =', typeScriptEnabled || false)
58
+
59
+ /* If both source maps and typescript are on, run! */
60
+ if (sourceMapsEnabled && typeScriptEnabled) {
61
+ const args = process.argv.slice(2).filter((arg: string): boolean => {
62
+ if (arg === '--force-esm') {
63
+ return (forceType('module'), false)
64
+ } else if (arg === '--force-cjs') {
65
+ return (forceType('commonjs'), false)
66
+ } else {
67
+ return true
68
+ }
69
+ })
70
+
71
+ /* Wrap into a promise to better catch errors from the real "main" */
72
+ Promise.resolve().then(async () => {
73
+ process.exitCode = 0
74
+ await callback(args)
75
+ }).catch((error) => {
76
+ console.error(error)
77
+ process.exitCode = 1
78
+
79
+ setTimeout(() => {
80
+ console.log('\n\nProcess %d did not exit in 5 seconds', process.pid)
81
+ process.exit(2)
82
+ }, 5000).unref()
83
+ })
84
+ } else {
85
+ const script = _url.fileURLToPath(scriptUrl)
86
+
87
+ /* Fork out ourselves with new options */
88
+ const execArgv = [ ...process.execArgv ]
89
+
90
+ /* Enable source maps if not done already */
91
+ if (! sourceMapsEnabled) execArgv.push('--enable-source-maps')
92
+
93
+ /* Enable our ESM TypeScript loader if not done already */
94
+ if (! typeScriptEnabled) {
95
+ const require = _module.createRequire(import.meta.url)
96
+ const loader = require.resolve('./loader.mjs')
97
+ debug(`TypeScript loader resolved to "${loader}"`)
98
+ execArgv.push(`--experimental-loader=${loader}`, '--no-warnings')
99
+ }
100
+
101
+ /* Fork ourselves! */
102
+ debug('Forking', script, ...process.argv.slice(2))
103
+ const child = _childProcess.fork(script, [ ...process.argv.slice(2) ], {
104
+ stdio: [ 'inherit', 'inherit', 'inherit', 'ipc' ],
105
+ execArgv,
106
+ })
107
+
108
+ /* Monitor child process... */
109
+ child.on('error', (error) => {
110
+ console.log('Error respawning CLI', error)
111
+ process.exit(1)
112
+ })
113
+
114
+ child.on('exit', (code, signal) => {
115
+ if (signal) {
116
+ console.log(`CLI process exited with signal ${signal}`)
117
+ process.exit(1)
118
+ } else if (typeof code !== 'number') {
119
+ console.log('CLI process failed for an unknown reason')
120
+ process.exit(1)
121
+ } else {
122
+ process.exit(code)
123
+ }
124
+ })
125
+ }
126
+ }