-
Notifications
You must be signed in to change notification settings - Fork 33
/
esbuild-plugin.civet
135 lines (112 loc) · 3.07 KB
/
esbuild-plugin.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
@file esbuild plugin for Civet language
Simple zero config example
@example
```javascript
import esbuild from 'esbuild'
import civetPlugin from '@danielx/civet/esbuild-plugin'
esbuild.build({
...,
plugins: [
civetPlugin
]
}).catch(() => process.exit(1))
```
Chain civet output into another esbuild plugin, solid for example
@example
```javascript
import esbuild from 'esbuild'
const { solidPlugin } = require('esbuild-plugin-solid');
import civetPlugin from '@danielx/civet/esbuild-plugin'
esbuild.build({
...,
plugins: [
civetPlugin(
next: solidPlugin()
)
]
}).catch(() => process.exit(1))
```
*/
import type { Plugin, OnLoadArgs, OnLoadResult } from 'esbuild'
interface Options {
filter?: RegExp
inlineMap?: boolean
js?: boolean
next?: Plugin
}
{ readFile, writeFile, mkdtemp, rmdir } from 'fs/promises'
path from 'path'
{ compile } from "./main.civet"
// NOTE: this function is named civet so esbuild gets "civet" as the name of the plugin
civet := (options: Options = {}): Plugin ->
{
filter=/\.civet$/
inlineMap=true
js=true
next
} := options
let nextTransform: (args: OnLoadArgs) => OnLoadResult | Promise<OnLoadResult | null | undefined> | null | undefined
let tmpPath: null | string
if next
next.setup {
onEnd();
onStart();
resolve();
onResolve();
initialOptions();
esbuild();
onLoad(_, handler)
nextTransform = handler
}
return {
name: "civet"
setup(build)
build.onStart ->
if next
{ tmpdir } := require 'os'
tmpPath = await mkdtemp path.join tmpdir(), "civet-"
return
build.onEnd ->
if tmpPath
await rmdir tmpPath, { recursive: true }
return
build.onLoad { filter }, (args) ->
try
source := await readFile args.path, 'utf8'
filename := path.relative(process.cwd(), args.path)
compiled := await compile source, {
filename
inlineMap
js
}
if next and tmpPath
outputFileName := filename + js ? '.jsx' : '.tsx'
outputFilePath := path.join tmpPath, outputFileName
// I'd prefer not to use temp files but I can't find a way to pass a stream to fs.readFile which is what
// most esbuild plugins use
await writeFile outputFilePath, compiled
return await nextTransform {
...args
path: outputFilePath
}
return
contents: compiled
catch e
return
errors: [{
text: e.message
location:
file: args.path
namespace: args.namespace
line: e.line
column: e.column
detail: e
}]
}
defaultPlugin := civet()
// Default zero-config plugin
civet.setup = defaultPlugin.setup
// This gets rewritten to roughly `module.exports = civet` in `build/esbuild.civet`.
// It assumes that there are no named exports, only a default.
export default civet