/
plugin.go
112 lines (93 loc) · 2.51 KB
/
plugin.go
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
package esbuildplugin
import (
"context"
"runtime/pprof"
"github.com/evanw/esbuild/pkg/api"
"github.com/samsarahq/go/oops"
"github.com/stephen/cssc"
"github.com/stephen/cssc/internal/ast"
"github.com/stephen/cssc/internal/sources"
"github.com/stephen/cssc/transforms"
)
type csscReporter []error
func (r *csscReporter) AddError(err error) {
*r = append(*r, err)
}
type locationError interface {
Location() (*sources.Source, ast.Span)
}
func (r *csscReporter) toEsbuild() []api.Message {
var errs []api.Message
for _, err := range *r {
if lErr, ok := err.(locationError); ok {
source, span := lErr.Location()
_, colNumber := source.LineAndCol(span)
lineSpan := source.FullLine(span)
errs = append(errs, api.Message{
Text: err.Error(),
Location: &api.Location{
File: source.Path,
Column: int(colNumber),
Line: lineSpan.Start,
Length: lineSpan.End - lineSpan.Start,
LineText: source.Content[lineSpan.Start:lineSpan.End],
},
})
}
errs = append(errs, api.Message{
Text: err.Error(),
})
}
return errs
}
// Option is an optional argument to the plugin.
type Option func(cssc.Options) cssc.Options
// WithTransforms sets the transform options for the plugin.
func WithTransforms(transforms transforms.Options) Option {
return func(opts cssc.Options) cssc.Options {
opts.Transforms = transforms
return opts
}
}
// WithResolver sets the import resolver for the plugin.
func WithResolver(resolver cssc.Resolver) Option {
return func(opts cssc.Options) cssc.Options {
opts.Resolver = resolver
return opts
}
}
// Plugin is an esbuild plugin for importing .css files.
func Plugin(opts ...Option) api.Plugin {
return api.Plugin{
Name: "cssc",
Setup: func(build api.PluginBuild) {
build.OnLoad(
api.OnLoadOptions{Filter: `\.css$`},
func(args api.OnLoadArgs) (res api.OnLoadResult, err error) {
res.Loader = api.LoaderCSS
var errors csscReporter
options := cssc.Options{
Entry: []string{args.Path},
Reporter: &errors,
}
for _, opt := range opts {
options = opt(options)
}
pprof.SetGoroutineLabels(pprof.WithLabels(context.TODO(), pprof.Labels("cssc-path", args.Path)))
result := cssc.Compile(options)
if len(errors) > 0 {
res.Errors = errors.toEsbuild()
return
}
f, ok := result.Files[args.Path]
if !ok {
err = oops.Errorf("cssc output did not contain %s", args.Path)
return
}
res.Contents = &f
return res, nil
},
)
},
}
}