forked from DanielXMoore/Civet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
esm.civet
119 lines (91 loc) · 3.17 KB
/
esm.civet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
@file Civet ESM loader.
In Node 20.6.0+, use Civet's `register` to install this ESM loader:
@example
```bash
node --import @danielx/civet/register source.civet
```
In older Node, use `--loader` to install this ESM loader:
@example
```bash
node --loader @danielx/civet/esm source.civet
```
Previously depended on ts-node esm loader being downstream:
@example
```bash
node --loader ts-node/esm --loader @danielx/civet/esm source.civet
```
*/
{ readFileSync } from fs
{ pathToFileURL, fileURLToPath } from url
sourceMapSupport from @cspotcode/source-map-support
Civet from ./main.civet
{ compile, util } := Civet
{ SourceMap } := util
baseURL := pathToFileURL(process.cwd() + '/').href
extensionsRegex := /\.civet$/
let registered = false
outputCache: Map<string, string> := new Map
directorySeparator := '/'
backslashRegExp := /\\/g
/**
* Replace backslashes with forward slashes.
*/
function normalizeSlashes(value: string): string {
return value.replace(backslashRegExp, directorySeparator);
}
ensureRegister := ->
return if registered
installation := {
environment: 'node' as const
retrieveFile(pathOrUrl: string)
let path = pathOrUrl
// If it's a file URL, convert to local path
// I could not find a way to handle non-URLs except to swallow an error
if path.startsWith('file:')
try
path = fileURLToPath(path)
path = normalizeSlashes(path)
return outputCache.get(path)
}
sourceMapSupport.install installation
registered = true
export function resolve(specifier: string, context: any, next: any)
{ parentURL = baseURL } := context
if extensionsRegex.test specifier
return
shortCircuit: true
format: "civet"
url: new URL(specifier, parentURL).href
// Let Node.js handle all other specifiers.
return next specifier, context
export async function load(url: string, context: any, next: any)
if context.format is "civet"
path := fileURLToPath url
source := readFileSync path, "utf8"
{code: tsSource, sourceMap} := await compile source,
filename: path
sourceMap: true
js: true
// NOTE: Append .tsx to URL so ts-node treats as TypeScript
transpiledUrl := url + ".tsx"
// NOTE: Assuming ts-node hook follows load hook
result := await next transpiledUrl,
// ts-node won't transpile unless this is module
// can't use commonjs since we don't rewrite imports
format: "module"
// NOTE: Setting the source in the context makes it available when ts-node uses defaultLoad
source: tsSource
// NOTE: we must install our source map support after ts-node does to take priority
ensureRegister()
// Remove .tsx extension for final URL
result.responseURL = (result.responseURL ?? transpiledUrl)
.replace /.tsx$/, ''
// parse source map from downstream (ts-node) result
// compose with civet source map
result.source = SourceMap.remap(result.source, sourceMap, url, result.responseURL)
// NOTE: This path needs to match what ts-node uses so we can override the source map
outputCache.set(normalizeSlashes(path), result.source)
return result
// Other URLs continue unchanged.
return next url, context