Skip to content

Commit 504e6f3

Browse files
committed
feat: typescript types
1 parent 5e263d8 commit 504e6f3

45 files changed

Lines changed: 708 additions & 516 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/nodejs.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
with:
2222
node-version: ${{ matrix.node-version }}
2323
- run: yarn
24+
- run: yarn build
2425
- run: yarn test
2526

2627
build_windows:
@@ -37,4 +38,5 @@ jobs:
3738
with:
3839
node-version: ${{ matrix.node-version }}
3940
- run: yarn
41+
- run: yarn build
4042
- run: yarn test
Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import { parser } from 'typescript-eslint'
1010

1111
export default defineConfig(
1212
{
13-
ignores: ['node_modules', 'coverage', 'docs', '.yarn', '.husky', 'tmp']
13+
ignores: ['lib', 'node_modules', 'coverage', 'docs', '.yarn', '.husky', 'tmp']
1414
},
1515
{
16-
files: ['**/*.ts', '**/*.mjs', '**/*.js'],
16+
files: ['**/*.ts', '**/*.js', '**/*.mjs', '**/*.cjs'],
1717
plugins: {
1818
// @ts-ignore
1919
'@typescript-eslint': typescriptEslintPlugin,
@@ -25,7 +25,12 @@ export default defineConfig(
2525
'@stylistic': stylisticPlugin
2626
},
2727
languageOptions: {
28-
parser
28+
parser,
29+
parserOptions: {
30+
projectService: {
31+
allowDefaultProject: ['.*']
32+
}
33+
}
2934
},
3035
rules: {
3136
'@import/no-deprecated': 'warn',
@@ -125,9 +130,23 @@ export default defineConfig(
125130
}
126131
],
127132
'@typescript-eslint/naming-convention': 'off',
133+
'@typescript-eslint/no-deprecated': ['error', {
134+
allow: [
135+
{
136+
from: 'package',
137+
name: ['GlobalPreloadHook'],
138+
package: 'module'
139+
},
140+
{
141+
from: 'lib',
142+
name: ['RequireExtensions']
143+
}
144+
]
145+
}],
128146
'@typescript-eslint/no-empty-function': 'off',
129147
'@typescript-eslint/no-empty-object-type': 'off',
130148
'@typescript-eslint/no-explicit-any': 'off',
149+
'@typescript-eslint/no-floating-promises': 'error',
131150
'@typescript-eslint/no-inferrable-types': 'off',
132151
'@typescript-eslint/no-misused-new': 'error',
133152
'@typescript-eslint/no-namespace': 'off',
@@ -273,18 +292,20 @@ export default defineConfig(
273292
}
274293
},
275294
{
276-
files: ['**/*.test.ts', '**/*.test.mjs', '**/*.config.mjs', '**/*.config.ts', '**/*.config.js', 'test/**/*.js', 'test/**/*.mjs', 'test/**/*.ts'],
295+
files: ['**/*.config.js', '**/*.config.ts', '**/*.config.cjs', 'test/**/*.mjs', 'test/**/*.cjs', 'test/**/*.js'],
277296
rules: {
278297
'@import/no-extraneous-dependencies': [
279298
'error',
280299
{
281-
devDependencies: true
300+
devDependencies: true,
301+
packageDir: import.meta.dirname
282302
}
283-
]
303+
],
304+
'@typescript-eslint/no-floating-promises': 'off'
284305
}
285306
},
286307
{
287-
files: ['**/*.js'],
308+
files: ['test/**/*.js'],
288309
rules: {
289310
'@typescript-eslint/no-require-imports': 'off'
290311
}

‎package.json‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
},
1111
"bin": "lib/entrypoint.js",
1212
"files": [
13-
"lib"
13+
"lib",
14+
"icons"
1415
],
1516
"dependencies": {
1617
"dateformat": "^5.0.3",
17-
"dynamic-dedupe": "^0.3.0",
18-
"filewatcher": "^3.0.1",
18+
"debounce": "^3.0.0",
1919
"get-package-type": "^0.1.0",
2020
"minimist": "^1.2.8",
2121
"node-notifier": "^10.0.1",
@@ -26,7 +26,12 @@
2626
"@commitlint/cli": "^20.4.1",
2727
"@commitlint/config-conventional": "^20.4.1",
2828
"@stylistic/eslint-plugin": "^5.8.0",
29+
"@types/dateformat": "^5.0.3",
30+
"@types/get-package-type": "^0.1.0",
2931
"@types/node": "^20.0.0",
32+
"@types/node-notifier": "^8.0.5",
33+
"@types/resolve": "^1.20.6",
34+
"@types/semver": "^7.7.1",
3035
"@typescript-eslint/eslint-plugin": "^8.55.0",
3136
"clean-package": "^2.2.0",
3237
"commit-and-tag-version": "^12.6.1",
@@ -39,16 +44,16 @@
3944
"npm-check-updates": "^19.3.2",
4045
"rimraf": "^6.1.2",
4146
"tap": "^21.5.1",
42-
"tap-xunit": "^2.4.1",
4347
"touch": "^3.1.1",
4448
"ts-node-maintained": "^10.9.6",
4549
"typescript": "^5.9.3",
4650
"typescript-eslint": "^8.55.0"
4751
},
4852
"scripts": {
4953
"build": "rimraf lib && tsc -p tsconfig.lib.json",
50-
"test": "node test",
54+
"test": "node test/index.mjs",
5155
"lint": "eslint . --fix",
56+
"prepublishOnly": "npm run build",
5257
"prepare": "husky",
5358
"release": "git diff --exit-code && commit-and-tag-version && git push --follow-tags origin",
5459
"prepack": "clean-package",

src/cfg.ts renamed to src/cfg.cts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
const { existsSync, readFileSync } = require('fs')
2-
const { dirname, resolve } = require('path')
1+
import { existsSync, readFileSync } from 'fs'
2+
import { dirname, resolve } from 'path'
3+
import { type Options } from './cli.js'
4+
import { resolveMain } from './resolve-main.cjs'
35

4-
const resolveMain = require('./resolve-main')
5-
6-
const defaultConfig = {
6+
const defaultConfig: Options = {
77
clear: false,
88
debounce: 10,
99
dedupe: false,
@@ -24,24 +24,24 @@ const defaultConfig = {
2424
vm: true
2525
}
2626

27-
function read(dir) {
27+
function read(dir: string) {
2828
const f = resolve(dir, '.node-dev.json')
29-
return existsSync(f) ? JSON.parse(readFileSync(f)) : {}
29+
return existsSync(f) ? JSON.parse(readFileSync(f, 'utf-8')) : {}
3030
}
3131

32-
function getConfig(script) {
32+
function getConfig(script: string) {
3333
const main = resolveMain(script)
3434
const dir = main ? dirname(main) : '.'
3535

3636
return Object.assign(
3737
defaultConfig,
38-
read(process.env.HOME || process.env.USERPROFILE),
38+
read((process.env.HOME || process.env.USERPROFILE)!),
3939
read(process.cwd()),
4040
read(dir)
4141
)
4242
}
4343

44-
module.exports = {
44+
export {
4545
defaultConfig,
4646
getConfig
4747
}

‎src/clear.cts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const control = '\u001bc'
2+
const clearFactory = (clear?: boolean) => (clear ? () => process.stdout.write(control) : () => { })
3+
4+
export { clearFactory, control }

‎src/clear.ts‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎src/cli.ts‎

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
const assert = require('assert')
2-
const { resolve } = require('path')
3-
const minimist = require('minimist')
1+
import assert from 'node:assert'
2+
import { resolve } from 'node:path'
3+
import minimist, { ParsedArgs } from 'minimist'
4+
import { getConfig } from './cfg.cjs'
45

5-
const { getConfig } = require('./cfg')
6+
const arrayify = <T>(v: T | T[]) => (Array.isArray(v) ? [...v] : [v])
7+
const argify = (key: string) => ({ arg: `--${key}`, key })
68

7-
const arrayify = v => (Array.isArray(v) ? [...v] : [v])
8-
const argify = key => ({ arg: `--${key}`, key })
9-
10-
const resolvePath = p => resolve(process.cwd(), p)
9+
const resolvePath = (p: string) => resolve(process.cwd(), p)
1110

1211
const nodeAlias = { require: 'r' }
1312
const nodeBoolean = ['expose_gc', 'preserve-symlinks']
@@ -23,8 +22,8 @@ const boolean = [...nodeBoolean, ...nodeDevBoolean]
2322
const string = [...nodeString, ...nodeDevString]
2423

2524
const nodeArgsReducer =
26-
opts =>
27-
(out, { arg, key }) => {
25+
(opts: ParsedArgs) =>
26+
(out: string[], { arg, key }: { arg: string, key: string }) => {
2827
const value = opts[key]
2928

3029
if (typeof value === 'boolean') {
@@ -44,22 +43,40 @@ const nodeArgsReducer =
4443
return out
4544
}
4645

47-
const nodeCustomFactory = args => arg => {
46+
const nodeCustomFactory = (args: any[]) => (arg: string) => {
4847
const isNodeCustom = nodeCustom.includes(arg.substring(2))
4948
if (isNodeCustom) args.push(arg)
5049
return !isNodeCustom
5150
}
5251

53-
const unknownFactory = args => arg => {
52+
const unknownFactory = (args: Array<{ arg: string, key: string }>) => (arg: string) => {
5453
const [, key] = Object.keys(minimist([arg]))
5554
key && !nodeDevNumber.includes(key) && args.push({ arg, key })
55+
return true
56+
}
57+
58+
export interface Options {
59+
clear: boolean
60+
dedupe: boolean
61+
fork: boolean
62+
notify: boolean
63+
poll: boolean
64+
respawn: boolean
65+
vm: boolean
66+
debounce: number
67+
deps: number
68+
extensions: Record<string, string>
69+
graceful_ipc: string
70+
ignore: string[]
71+
interval: number
72+
timestamp: string
5673
}
5774

58-
module.exports = argv => {
59-
const nodeCustomArgs = []
75+
export const cli = (argv: string[]) => {
76+
const nodeCustomArgs = new Array<string>()
6077
const args = argv.slice(2).filter(nodeCustomFactory(nodeCustomArgs))
6178

62-
const unknownArgs = []
79+
const unknownArgs = new Array<{ arg: string, key: string }>()
6380
const unknown = unknownFactory(unknownArgs)
6481

6582
const {
@@ -70,10 +87,10 @@ module.exports = argv => {
7087

7188
const opts = minimist(args, { alias, boolean, default: getConfig(script) })
7289
const nodeArgs = [...nodeBoolean.map(argify), ...nodeString.map(argify), ...unknownArgs]
73-
.sort((a, b) => a.key - b.key)
90+
.sort((a, b) => parseFloat(a.key) - parseFloat(b.key))
7491
.reduce(nodeArgsReducer(opts), [...nodeCustomArgs])
7592

7693
opts.ignore = arrayify(opts.ignore).map(resolvePath)
7794

78-
return { nodeArgs, opts, script, scriptArgs }
95+
return { nodeArgs, opts: opts as any as Options, script, scriptArgs }
7996
}

‎src/dedupe.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/entrypoint.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env node
22

3-
const cli = require('./cli')
4-
const dev = require('.')
3+
import { cli } from './cli.js'
4+
import { dev } from './index.js'
55

66
const {
77
script,

‎src/hook.cts‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import vm from 'vm'
2+
import NodeModule from 'node:module'
3+
4+
export const hook = (patchVM: boolean, callback: (file: string) => void) => {
5+
// Hook into Node's `require(...)`
6+
updateHooks()
7+
8+
// Patch the vm module Script class to watch files executed as vm scripts:
9+
if (patchVM) {
10+
vm.Script = class Script extends vm.Script {
11+
constructor(...args: any[]) {
12+
const opts = args[1]
13+
let file: string | undefined
14+
if (opts) {
15+
file = typeof opts === 'string' ? opts : opts.filename
16+
}
17+
if (file) callback(file)
18+
// @ts-ignore
19+
super(...args)
20+
}
21+
}
22+
}
23+
24+
/**
25+
* (Re-)install hooks for all registered file extensions.
26+
*/
27+
function updateHooks() {
28+
// @ts-ignore
29+
const extensions: NodeJS.RequireExtensions = NodeModule._extensions
30+
Object.keys(extensions).forEach(ext => {
31+
const fn = extensions[ext]
32+
if (typeof fn === 'function' && fn.name !== 'nodeDevHook') {
33+
extensions[ext] = createHook(fn)
34+
}
35+
})
36+
}
37+
38+
/**
39+
* Returns a function that can be put into `NodeModule._extensions` in order to
40+
* invoke the callback when a module is required for the first time.
41+
*/
42+
function createHook(handler: (module: NodeJS.Module, filename: string) => any) {
43+
return function nodeDevHook(module: NodeJS.Module, filename: string) {
44+
if (!module.loaded) callback(module.filename)
45+
46+
// Invoke the original handler
47+
handler(module, filename)
48+
49+
// Make sure the module did not hijack the handler
50+
updateHooks()
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)