@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/src/tsrun.mts ADDED
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ import _os from 'node:os'
5
+ import _path from 'node:path'
6
+ import _repl from 'node:repl'
7
+ import _module from 'node:module'
8
+
9
+ import _yargs from 'yargs-parser'
10
+
11
+ import { main } from './cli.mjs'
12
+
13
+ /** Reset all colors to default */
14
+ const $rst = process.stdout.isTTY ? '\u001b[0m' : ''
15
+ /** Set _underline_ on */
16
+ const $und = process.stdout.isTTY ? '\u001b[4m' : ''
17
+ /** Set _somewhat gray_ on */
18
+ const $gry = process.stdout.isTTY ? '\u001b[38;5;240m' : ''
19
+ /** Set _brighter blue_ on */
20
+ const $blu = process.stdout.isTTY ? '\u001b[38;5;69m' : ''
21
+ /** Set _full bright white_ on */
22
+ const $wht = process.stdout.isTTY ? '\u001b[1;38;5;255m' : ''
23
+
24
+ /** Version injected by esbuild */
25
+ declare const __version: string
26
+
27
+ /** Our minimalistic help */
28
+ function _help(): void {
29
+ console.log(`${$blu}${$und}Usage:${$rst}
30
+
31
+ ${$wht}tsrun${$rst} ${$gry}[${$rst}--options${$gry}] script.ts [...${$rst}script args${$gry}]${$rst}
32
+
33
+ ${$blu}${$und}Options:${$rst}
34
+
35
+ ${$wht}-h --help ${$rst} Help! You're reading it now!
36
+ ${$wht}-v --version ${$rst} Version! This one: ${__version}!
37
+ ${$wht}-e --eval ${$rst} Evaluate the script
38
+ ${$wht}-p --print ${$rst} Evaluate the script and print the result
39
+ ${$wht} --force-esm${$rst} Force transpilation of ".ts" files to EcmaScript modules
40
+ ${$wht} --force-cjs${$rst} Force transpilation of ".ts" files to CommonJS modules
41
+
42
+ ${$blu}${$und}Description:${$rst}
43
+
44
+ ${$wht}tsrun${$rst} is a minimalistic TypeScript loader, using "esbuild" to transpile TS
45
+ code to JavaScript, and running it. Being extremely un-sofisticated, it's
46
+ not meant to to be in any way a replacement for more complete alternatives
47
+ like "ts-node".
48
+ `)
49
+
50
+ process.exitCode = 1
51
+ }
52
+
53
+ /** Process the command line */
54
+ main(import.meta.url, (args: string[]): void | Promise<void> => {
55
+ let _script: string | undefined
56
+ let _scriptArgs: string[] = []
57
+ let _print: boolean = false
58
+ let _eval: boolean = false
59
+
60
+ /* Yargs-parse our arguments */
61
+ const parsed = _yargs(args, {
62
+ configuration: {
63
+ 'camel-case-expansion': false,
64
+ 'halt-at-non-option': true,
65
+ 'strip-aliased': true,
66
+ 'strip-dashed': true,
67
+ },
68
+
69
+ alias: {
70
+ 'version': [ 'v' ],
71
+ 'help': [ 'h' ],
72
+ 'eval': [ 'e' ],
73
+ 'print': [ 'p' ],
74
+ },
75
+
76
+ boolean: [ 'help', 'eval', 'print', 'force-esm', 'version', 'force-cjs' ],
77
+ })
78
+
79
+ // Parse options, leaving script and scriptArgs with our code to run
80
+ for (const [ key, value ] of Object.entries(parsed)) {
81
+ switch (key) {
82
+ case '_': // extra arguments
83
+ [ _script, ..._scriptArgs ] = value
84
+ break
85
+ case 'help': // help screen
86
+ return _help()
87
+ case 'version': // version dump
88
+ console.log(`v${__version}`)
89
+ process.exitCode = 1
90
+ return
91
+ case 'eval': // eval script
92
+ _eval = value
93
+ break
94
+ case 'print': // eval script and print return value
95
+ _print = true
96
+ _eval = true
97
+ break
98
+ }
99
+ }
100
+
101
+ // Start the repl or run the script?
102
+ if (! _script) {
103
+ // No script? Then repl
104
+ return new Promise((resolve, reject) => {
105
+ // Some niceties for welcoming to tsrun
106
+ console.log(`Welcome to Node.js ${process.version} (tsrun v${__version}).`)
107
+ console.log('Type ".help" for more information.')
108
+
109
+ // Start our repl
110
+ const repl = _repl.start()
111
+
112
+ // Setup and track history
113
+ const history = _path.resolve(_os.homedir(), '.node_repl_history')
114
+ repl.setupHistory(history, (error) => {
115
+ if (! error) return
116
+ reject(error)
117
+ repl.close()
118
+ })
119
+
120
+ // On exit, let the process exit
121
+ repl.on('exit', () => resolve())
122
+ })
123
+ } else if (_eval) {
124
+ // If we are evaluating a script, we need to use some node internals to do
125
+ // all the tricks to run this... We a fake script running the code to
126
+ // evaluate, instrumenting "globalThis" with all required vars and modules
127
+ const script = `
128
+ globalThis.module = module;
129
+ globalThis.require = require;
130
+ globalThis.exports = exports;
131
+ globalThis.__dirname = __dirname;
132
+ globalThis.__filename = __filename;
133
+
134
+ for (const module of require('repl').builtinModules) {
135
+ if (module.indexOf('/') >= 0) continue;
136
+ if (Object.hasOwn(globalThis, module)) continue;
137
+ Object.defineProperty(globalThis, module, { get: () => require(module) });
138
+ }
139
+
140
+ return require('node:vm').runInThisContext(${JSON.stringify(_script)}, '[eval]')
141
+ `
142
+
143
+ // Use the Node internal "Module._compile" to compile and run our script
144
+ const result = (new _module('[eval]') as any)._compile(script, '[eval]')
145
+
146
+ // If we need to print, then let's do it!
147
+ if (_print) console.log(result)
148
+ } else {
149
+ // Resolve the _full_ path of the script, and tweak our process.argv
150
+ // arguments, them simply import the script and let Node do its thing...
151
+ _script = _path.resolve(process.cwd(), _script)
152
+ process.argv = [ process.argv0, _script, ..._scriptArgs ]
153
+ import(_script)
154
+ }
155
+ })