dlintr 0.1.1 → 0.2.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/README.md +82 -22
- package/ghc_wasm_jsffi.js +114 -0
- package/hadolint.wasm +0 -0
- package/lib/api.d.ts +4 -4
- package/lib/api.js +29 -30
- package/lib/api.js.map +1 -1
- package/lib/browser.d.ts +3 -4
- package/lib/browser.js +22 -3
- package/lib/browser.js.map +1 -1
- package/lib/index.cjs +212 -172
- package/lib/index.d.ts +3 -4
- package/lib/index.js +21 -3
- package/lib/index.js.map +1 -1
- package/lib/memoize.d.ts +1 -0
- package/lib/memoize.js +14 -0
- package/lib/memoize.js.map +1 -0
- package/lib/reactor.d.ts +6 -0
- package/lib/reactor.js +21 -0
- package/lib/reactor.js.map +1 -0
- package/lib/types.d.ts +0 -10
- package/lib/wasi.d.ts +11 -0
- package/lib/wasi.js +88 -0
- package/lib/wasi.js.map +1 -0
- package/package.json +7 -15
- package/lib/runtime.d.ts +0 -6
- package/lib/runtime.js +0 -3
- package/lib/runtime.js.map +0 -1
- package/lib/wasi-browser.d.ts +0 -2
- package/lib/wasi-browser.js +0 -48
- package/lib/wasi-browser.js.map +0 -1
- package/lib/wasi-node.d.ts +0 -2
- package/lib/wasi-node.js +0 -127
- package/lib/wasi-node.js.map +0 -1
package/lib/index.cjs
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var node_fs = require('node:fs');
|
|
4
3
|
var promises = require('node:fs/promises');
|
|
5
|
-
var node_os = require('node:os');
|
|
6
4
|
var path = require('node:path');
|
|
7
5
|
var node_url = require('node:url');
|
|
8
|
-
var node_wasi = require('node:wasi');
|
|
9
6
|
|
|
10
|
-
var
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __defProps = Object.defineProperties;
|
|
9
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
10
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
13
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
|
+
var __spreadValues = (a, b) => {
|
|
15
|
+
for (var prop in b || (b = {}))
|
|
16
|
+
if (__hasOwnProp.call(b, prop))
|
|
17
|
+
__defNormalProp(a, prop, b[prop]);
|
|
18
|
+
if (__getOwnPropSymbols)
|
|
19
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
20
|
+
if (__propIsEnum.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
}
|
|
23
|
+
return a;
|
|
24
|
+
};
|
|
25
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
26
|
+
var __async$2 = (__this, __arguments, generator) => {
|
|
11
27
|
return new Promise((resolve, reject) => {
|
|
12
28
|
var fulfilled = (value) => {
|
|
13
29
|
try {
|
|
@@ -27,63 +43,156 @@ var __async$1 = (__this, __arguments, generator) => {
|
|
|
27
43
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
28
44
|
});
|
|
29
45
|
};
|
|
30
|
-
const
|
|
31
|
-
|
|
46
|
+
const HOME = "HOME=/";
|
|
47
|
+
const createDlinter = (load) => {
|
|
48
|
+
const reactors = /* @__PURE__ */ new Map();
|
|
49
|
+
const instance = (env) => {
|
|
50
|
+
const pairs = [
|
|
51
|
+
HOME,
|
|
52
|
+
...Object.entries(env != null ? env : {}).map(([key2, value]) => `${key2}=${value}`)
|
|
53
|
+
];
|
|
54
|
+
const key = JSON.stringify(pairs);
|
|
55
|
+
let reactor = reactors.get(key);
|
|
56
|
+
if (!reactor) {
|
|
57
|
+
reactor = load(pairs);
|
|
58
|
+
reactors.set(key, reactor);
|
|
59
|
+
reactor.catch(() => reactors.delete(key));
|
|
60
|
+
}
|
|
61
|
+
return reactor;
|
|
62
|
+
};
|
|
32
63
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
(
|
|
42
|
-
)) {
|
|
43
|
-
if (level) {
|
|
44
|
-
args.push(`--${level}`, code);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
args.push("-");
|
|
48
|
-
const { stdout, stderr } = yield runtime.run(args, {
|
|
49
|
-
stdin: dockerfile,
|
|
50
|
-
env: options.env
|
|
64
|
+
lint: (_0, ..._1) => __async$2(null, [_0, ..._1], function* (dockerfile, options = {}) {
|
|
65
|
+
var _a;
|
|
66
|
+
const { lint } = yield instance(options.env);
|
|
67
|
+
const findings = JSON.parse(yield lint(dockerfile));
|
|
68
|
+
const ignored = new Set((_a = options.ignore) != null ? _a : []);
|
|
69
|
+
return findings.filter(({ code }) => !ignored.has(code)).map((finding) => {
|
|
70
|
+
var _a2;
|
|
71
|
+
const level = (_a2 = options.severityOverrides) == null ? void 0 : _a2[finding.code];
|
|
72
|
+
return level ? __spreadProps(__spreadValues({}, finding), { level }) : finding;
|
|
51
73
|
});
|
|
52
|
-
if (!stdout) {
|
|
53
|
-
if (stderr) {
|
|
54
|
-
throw new Error(stderr.trim());
|
|
55
|
-
}
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
return JSON.parse(stdout);
|
|
59
74
|
}),
|
|
60
|
-
getVersion: () =>
|
|
61
|
-
version =
|
|
62
|
-
|
|
75
|
+
getVersion: () => __async$2(null, null, function* () {
|
|
76
|
+
const { version } = yield instance();
|
|
77
|
+
return version();
|
|
63
78
|
})
|
|
64
79
|
};
|
|
65
80
|
};
|
|
66
81
|
|
|
67
|
-
const
|
|
68
|
-
|
|
82
|
+
const memoize = (load) => {
|
|
83
|
+
let pending;
|
|
84
|
+
return () => {
|
|
85
|
+
if (!pending) {
|
|
86
|
+
const started = load();
|
|
87
|
+
started.catch(() => {
|
|
88
|
+
pending = void 0;
|
|
89
|
+
});
|
|
90
|
+
pending = started;
|
|
91
|
+
}
|
|
92
|
+
return pending;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
69
95
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
96
|
+
const CLOCK_MONOTONIC = 1;
|
|
97
|
+
const POINTER_SIZE = 4;
|
|
98
|
+
const NANOSECONDS_PER_MILLISECOND = 1e6;
|
|
99
|
+
const ERRNO_SUCCESS = 0;
|
|
100
|
+
const NOT_IMPLEMENTED = [
|
|
101
|
+
"fd_close",
|
|
102
|
+
"fd_fdstat_get",
|
|
103
|
+
"fd_fdstat_set_flags",
|
|
104
|
+
"fd_filestat_get",
|
|
105
|
+
"fd_filestat_set_size",
|
|
106
|
+
"fd_prestat_get",
|
|
107
|
+
"fd_prestat_dir_name",
|
|
108
|
+
"fd_read",
|
|
109
|
+
"fd_seek",
|
|
110
|
+
"fd_write",
|
|
111
|
+
"path_create_directory",
|
|
112
|
+
"path_filestat_get",
|
|
113
|
+
"path_open",
|
|
114
|
+
"poll_oneoff",
|
|
115
|
+
"proc_exit"
|
|
116
|
+
];
|
|
117
|
+
const createWasiHost = (env) => {
|
|
118
|
+
let memory;
|
|
119
|
+
const requireMemory = () => {
|
|
120
|
+
if (!memory) {
|
|
121
|
+
throw new Error("dlintr: WASI called before initialize()");
|
|
83
122
|
}
|
|
84
|
-
|
|
123
|
+
return memory;
|
|
124
|
+
};
|
|
125
|
+
const view = () => new DataView(requireMemory().buffer);
|
|
126
|
+
const bytes = () => new Uint8Array(requireMemory().buffer);
|
|
127
|
+
const encoder = new TextEncoder();
|
|
128
|
+
const entries = env.map((entry) => encoder.encode(`${entry}\0`));
|
|
129
|
+
const argsSizesGet = (countPointer, sizePointer) => {
|
|
130
|
+
const data = view();
|
|
131
|
+
data.setUint32(countPointer, 0, true);
|
|
132
|
+
data.setUint32(sizePointer, 0, true);
|
|
133
|
+
return ERRNO_SUCCESS;
|
|
134
|
+
};
|
|
135
|
+
const environSizesGet = (countPointer, sizePointer) => {
|
|
136
|
+
const data = view();
|
|
137
|
+
data.setUint32(countPointer, entries.length, true);
|
|
138
|
+
data.setUint32(
|
|
139
|
+
sizePointer,
|
|
140
|
+
entries.reduce((total, entry) => total + entry.length, 0),
|
|
141
|
+
true
|
|
142
|
+
);
|
|
143
|
+
return ERRNO_SUCCESS;
|
|
144
|
+
};
|
|
145
|
+
const environGet = (pointerTable, buffer) => {
|
|
146
|
+
const data = view();
|
|
147
|
+
const target = bytes();
|
|
148
|
+
let offset = buffer;
|
|
149
|
+
for (const [index, entry] of entries.entries()) {
|
|
150
|
+
data.setUint32(pointerTable + index * POINTER_SIZE, offset, true);
|
|
151
|
+
target.set(entry, offset);
|
|
152
|
+
offset += entry.length;
|
|
153
|
+
}
|
|
154
|
+
return ERRNO_SUCCESS;
|
|
155
|
+
};
|
|
156
|
+
const clockTimeGet = (id, _precision, timePointer) => {
|
|
157
|
+
if (id !== CLOCK_MONOTONIC) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`dlintr: clock_time_get(${id}) is not the monotonic clock`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const nanoseconds = BigInt(
|
|
163
|
+
Math.round(performance.now() * NANOSECONDS_PER_MILLISECOND)
|
|
164
|
+
);
|
|
165
|
+
view().setBigUint64(timePointer, nanoseconds, true);
|
|
166
|
+
return ERRNO_SUCCESS;
|
|
167
|
+
};
|
|
168
|
+
const wasiImport = {
|
|
169
|
+
args_get: () => ERRNO_SUCCESS,
|
|
170
|
+
args_sizes_get: argsSizesGet,
|
|
171
|
+
clock_time_get: clockTimeGet,
|
|
172
|
+
environ_get: environGet,
|
|
173
|
+
environ_sizes_get: environSizesGet
|
|
174
|
+
};
|
|
175
|
+
for (const name of NOT_IMPLEMENTED) {
|
|
176
|
+
wasiImport[name] = () => {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`dlintr: the reactor called \`${name}\`, which this WASI shim does not implement.
|
|
179
|
+
The imports actually used are measured, not assumed \u2014 run \`node wasm/calls.mjs\`
|
|
180
|
+
to see the current set. Seeing this means the module now reaches further than
|
|
181
|
+
when that measurement was taken, so implement \`${name}\` rather than retrying.`
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
wasiImport,
|
|
187
|
+
initialize: (instance) => {
|
|
188
|
+
var _a, _b;
|
|
189
|
+
memory = instance.exports.memory;
|
|
190
|
+
(_b = (_a = instance.exports)._initialize) == null ? void 0 : _b.call(_a);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
85
193
|
};
|
|
86
|
-
|
|
194
|
+
|
|
195
|
+
var __async$1 = (__this, __arguments, generator) => {
|
|
87
196
|
return new Promise((resolve, reject) => {
|
|
88
197
|
var fulfilled = (value) => {
|
|
89
198
|
try {
|
|
@@ -103,135 +212,66 @@ var __async = (__this, __arguments, generator) => {
|
|
|
103
212
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
104
213
|
});
|
|
105
214
|
};
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
215
|
+
const createReactor = (module, glue, env) => __async$1(null, null, function* () {
|
|
216
|
+
const names = WebAssembly.Module.exports(module).map(({ name }) => name);
|
|
217
|
+
if (!names.includes("_initialize") || names.includes("_start")) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`dlintr: expected a reactor exporting \`_initialize\` and no \`_start\`, got: ${names.join(", ")}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const wasi = createWasiHost(env);
|
|
223
|
+
const deferred = {};
|
|
224
|
+
const instance = yield WebAssembly.instantiate(module, {
|
|
225
|
+
ghc_wasm_jsffi: glue(deferred),
|
|
226
|
+
wasi_snapshot_preview1: wasi.wasiImport
|
|
116
227
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
let offset = 0;
|
|
124
|
-
const views = () => {
|
|
125
|
-
const buffer = memory();
|
|
126
|
-
return { view: new DataView(buffer), bytes: new Uint8Array(buffer) };
|
|
127
|
-
};
|
|
128
|
-
const iovecs = (iovs, iovsLen) => {
|
|
129
|
-
const { view } = views();
|
|
130
|
-
const result = [];
|
|
131
|
-
for (let index = 0; index < iovsLen; index++) {
|
|
132
|
-
result.push({
|
|
133
|
-
offset: view.getUint32(iovs + index * IOVEC_SIZE, true),
|
|
134
|
-
length: view.getUint32(
|
|
135
|
-
iovs + index * IOVEC_SIZE + IOVEC_LENGTH_OFFSET,
|
|
136
|
-
true
|
|
137
|
-
)
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return result;
|
|
228
|
+
Object.assign(deferred, instance.exports);
|
|
229
|
+
const reactor = instance.exports;
|
|
230
|
+
wasi.initialize({ exports: reactor });
|
|
231
|
+
return {
|
|
232
|
+
lint: (dockerfile) => reactor.lint(dockerfile),
|
|
233
|
+
version: () => reactor.version()
|
|
141
234
|
};
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
var __async = (__this, __arguments, generator) => {
|
|
238
|
+
return new Promise((resolve, reject) => {
|
|
239
|
+
var fulfilled = (value) => {
|
|
240
|
+
try {
|
|
241
|
+
step(generator.next(value));
|
|
242
|
+
} catch (e) {
|
|
243
|
+
reject(e);
|
|
149
244
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
imports.fd_write = (fd, iovs, iovsLen, nwrittenPtr) => {
|
|
158
|
-
const { view, bytes } = views();
|
|
159
|
-
let written = 0;
|
|
160
|
-
for (const { offset: source, length } of iovecs(iovs, iovsLen)) {
|
|
161
|
-
const chunk = decoder.decode(bytes.subarray(source, source + length));
|
|
162
|
-
if (fd === 1) {
|
|
163
|
-
state.stdout += chunk;
|
|
164
|
-
} else if (fd === 2) {
|
|
165
|
-
state.stderr += chunk;
|
|
245
|
+
};
|
|
246
|
+
var rejected = (value) => {
|
|
247
|
+
try {
|
|
248
|
+
step(generator.throw(value));
|
|
249
|
+
} catch (e) {
|
|
250
|
+
reject(e);
|
|
166
251
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
};
|
|
172
|
-
return state;
|
|
173
|
-
};
|
|
174
|
-
const memoryOf = (instance) => instance.exports.memory.buffer;
|
|
175
|
-
const openStdio = () => ({
|
|
176
|
-
stdin: node_fs.openSync(node_os.devNull, "r"),
|
|
177
|
-
stdout: node_fs.openSync(node_os.devNull, "w"),
|
|
178
|
-
stderr: node_fs.openSync(node_os.devNull, "w")
|
|
179
|
-
});
|
|
180
|
-
const closeQuietly = (fd) => {
|
|
181
|
-
try {
|
|
182
|
-
node_fs.closeSync(fd);
|
|
183
|
-
} catch (e) {
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const closeStdio = (stdio) => {
|
|
187
|
-
closeQuietly(stdio.stdin);
|
|
188
|
-
closeQuietly(stdio.stdout);
|
|
189
|
-
closeQuietly(stdio.stderr);
|
|
252
|
+
};
|
|
253
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
254
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
255
|
+
});
|
|
190
256
|
};
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
env: __spreadValues(__spreadValues({}, DEFAULT_ENV), options.env),
|
|
202
|
-
stdin: stdio.stdin,
|
|
203
|
-
stdout: stdio.stdout,
|
|
204
|
-
stderr: stdio.stderr
|
|
205
|
-
});
|
|
206
|
-
const nodeWasi = wasi;
|
|
207
|
-
const intercepted = intercept(
|
|
208
|
-
nodeWasi.wasiImport,
|
|
209
|
-
() => {
|
|
210
|
-
if (!instance) {
|
|
211
|
-
throw new Error(
|
|
212
|
-
"dlintr: hadolint touched stdio before it was instantiated"
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
return memoryOf(instance);
|
|
216
|
-
},
|
|
217
|
-
encoder.encode((_a = options.stdin) != null ? _a : "")
|
|
218
|
-
);
|
|
219
|
-
instance = yield WebAssembly.instantiate(module, {
|
|
220
|
-
wasi_snapshot_preview1: nodeWasi.wasiImport
|
|
221
|
-
});
|
|
222
|
-
const exitCode = nodeWasi.start(instance);
|
|
223
|
-
return __spreadValues({ exitCode: exitCode != null ? exitCode : 0 }, intercepted);
|
|
224
|
-
} finally {
|
|
225
|
-
closeStdio(stdio);
|
|
226
|
-
}
|
|
257
|
+
const import_meta = {};
|
|
258
|
+
const packageRoot = () => typeof __dirname === "string" ? path.join(__dirname, "..") : node_url.fileURLToPath(new URL("..", import_meta.url));
|
|
259
|
+
const loadAssets = memoize(
|
|
260
|
+
() => __async(null, null, function* () {
|
|
261
|
+
const root = packageRoot();
|
|
262
|
+
const [bytes, glue] = yield Promise.all([
|
|
263
|
+
promises.readFile(path.join(root, "hadolint.wasm")),
|
|
264
|
+
import(node_url.pathToFileURL(path.join(root, "ghc_wasm_jsffi.js")).href)
|
|
265
|
+
]);
|
|
266
|
+
return [yield WebAssembly.compile(bytes), glue.default];
|
|
227
267
|
})
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
268
|
+
);
|
|
269
|
+
const dlinter = createDlinter((env) => __async(null, null, function* () {
|
|
270
|
+
const [module, glue] = yield loadAssets();
|
|
271
|
+
return createReactor(module, glue, env);
|
|
272
|
+
}));
|
|
232
273
|
const lint = dlinter.lint;
|
|
233
274
|
const getVersion = dlinter.getVersion;
|
|
234
275
|
|
|
235
276
|
exports.getVersion = getVersion;
|
|
236
277
|
exports.lint = lint;
|
|
237
|
-
exports.run = run;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export declare const run: (args: string[], options?: import("./types.js").RunOptions) => Promise<import("./types.js").RunResult>;
|
|
2
1
|
export declare const lint: (dockerfile: string, options?: import("./types.js").LintOptions) => Promise<import("./types.js").LintResult[]>;
|
|
3
2
|
export declare const getVersion: () => Promise<string>;
|
|
4
|
-
export type { Dlinter } from './api.js';
|
|
5
|
-
export type {
|
|
6
|
-
export type { LintOptions, LintResult,
|
|
3
|
+
export type { Dlinter, LoadReactor } from './api.js';
|
|
4
|
+
export type { Reactor } from './reactor.js';
|
|
5
|
+
export type { LintOptions, LintResult, Severity } from './types.js';
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
import { __rewriteRelativeImportExtension } from "tslib";
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
1
5
|
import { createDlinter } from './api.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
import { memoize } from './memoize.js';
|
|
7
|
+
import { createReactor } from './reactor.js';
|
|
8
|
+
const packageRoot = () => typeof __dirname === 'string'
|
|
9
|
+
? path.join(__dirname, '..')
|
|
10
|
+
: fileURLToPath(new URL('..', import.meta.url));
|
|
11
|
+
const loadAssets = memoize(async () => {
|
|
12
|
+
const root = packageRoot();
|
|
13
|
+
const [bytes, glue] = await Promise.all([
|
|
14
|
+
readFile(path.join(root, 'hadolint.wasm')),
|
|
15
|
+
import(__rewriteRelativeImportExtension(pathToFileURL(path.join(root, 'ghc_wasm_jsffi.js')).href, true)),
|
|
16
|
+
]);
|
|
17
|
+
return [await WebAssembly.compile(bytes), glue.default];
|
|
18
|
+
});
|
|
19
|
+
const dlinter = createDlinter(async (env) => {
|
|
20
|
+
const [module, glue] = await loadAssets();
|
|
21
|
+
return createReactor(module, glue, env);
|
|
22
|
+
});
|
|
5
23
|
export const lint = dlinter.lint;
|
|
6
24
|
export const getVersion = dlinter.getVersion;
|
|
7
25
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAU5C,MAAM,WAAW,GAAG,GAAW,EAAE,CAC/B,OAAO,SAAS,KAAK,QAAQ;IAC3B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;IAC5B,CAAC,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAMnD,MAAM,UAAU,GAAG,OAAO,CACxB,KAAK,IAA0D,EAAE;IAC/D,MAAM,IAAI,GAAG,WAAW,EAAE,CAAA;IAC1B,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC1C,MAAM,kCACJ,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,IAAI,QAGxD;KACH,CAAC,CAAA;IACF,OAAO,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAU,CAAA;AAClE,CAAC,CACF,CAAA;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAC,GAAG,EAAC,EAAE;IACxC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAM,UAAU,EAAE,CAAA;IACzC,OAAO,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;AACzC,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA"}
|
package/lib/memoize.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const memoize: <T>(load: () => Promise<T>) => (() => Promise<T>);
|
package/lib/memoize.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const memoize = (load) => {
|
|
2
|
+
let pending;
|
|
3
|
+
return () => {
|
|
4
|
+
if (!pending) {
|
|
5
|
+
const started = load();
|
|
6
|
+
started.catch(() => {
|
|
7
|
+
pending = undefined;
|
|
8
|
+
});
|
|
9
|
+
pending = started;
|
|
10
|
+
}
|
|
11
|
+
return pending;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=memoize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoize.js","sourceRoot":"","sources":["../src/memoize.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAI,IAAsB,EAAsB,EAAE;IACvE,IAAI,OAA+B,CAAA;IAEnC,OAAO,GAAG,EAAE;QACV,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,IAAI,EAAE,CAAA;YAMtB,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;gBACjB,OAAO,GAAG,SAAS,CAAA;YACrB,CAAC,CAAC,CAAA;YAEF,OAAO,GAAG,OAAO,CAAA;QACnB,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;AACH,CAAC,CAAA"}
|
package/lib/reactor.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type GhcWasmJsffi = (exports: WebAssembly.Exports) => Record<string, WebAssembly.ExportValue>;
|
|
2
|
+
export interface Reactor {
|
|
3
|
+
lint: (dockerfile: string) => Promise<string>;
|
|
4
|
+
version: () => Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
export declare const createReactor: (module: WebAssembly.Module, glue: GhcWasmJsffi, env: readonly string[]) => Promise<Reactor>;
|
package/lib/reactor.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createWasiHost } from './wasi.js';
|
|
2
|
+
export const createReactor = async (module, glue, env) => {
|
|
3
|
+
const names = WebAssembly.Module.exports(module).map(({ name }) => name);
|
|
4
|
+
if (!names.includes('_initialize') || names.includes('_start')) {
|
|
5
|
+
throw new Error(`dlintr: expected a reactor exporting \`_initialize\` and no \`_start\`, got: ${names.join(', ')}`);
|
|
6
|
+
}
|
|
7
|
+
const wasi = createWasiHost(env);
|
|
8
|
+
const deferred = {};
|
|
9
|
+
const instance = await WebAssembly.instantiate(module, {
|
|
10
|
+
ghc_wasm_jsffi: glue(deferred),
|
|
11
|
+
wasi_snapshot_preview1: wasi.wasiImport,
|
|
12
|
+
});
|
|
13
|
+
Object.assign(deferred, instance.exports);
|
|
14
|
+
const reactor = instance.exports;
|
|
15
|
+
wasi.initialize({ exports: reactor });
|
|
16
|
+
return {
|
|
17
|
+
lint: dockerfile => reactor.lint(dockerfile),
|
|
18
|
+
version: () => reactor.version(),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=reactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactor.js","sourceRoot":"","sources":["../src/reactor.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAuC1C,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,MAA0B,EAC1B,IAAkB,EAClB,GAAsB,EACJ,EAAE;IACpB,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IAKxE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CACb,gFAAgF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnG,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;IAShC,MAAM,QAAQ,GAAwB,EAAE,CAAA;IAExC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE;QACrD,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC;QAC9B,sBAAsB,EAAE,IAAI,CAAC,UAAU;KACxC,CAAC,CAAA;IAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IAKzC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAyB,CAAA;IAUlD,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAErC,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;QAC5C,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;KACjC,CAAA;AACH,CAAC,CAAA"}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export type Severity = 'error' | 'info' | 'style' | 'warning';
|
|
2
|
-
export type OutputFormat = 'checkstyle' | 'codacy' | 'codeclimate' | 'gitlab_codeclimate' | 'gnu' | 'json' | 'sarif' | 'sonarqube' | 'tty';
|
|
3
2
|
export interface LintResult {
|
|
4
3
|
code: string;
|
|
5
4
|
line: number;
|
|
@@ -8,15 +7,6 @@ export interface LintResult {
|
|
|
8
7
|
message: string;
|
|
9
8
|
file: string;
|
|
10
9
|
}
|
|
11
|
-
export interface RunResult {
|
|
12
|
-
exitCode: number;
|
|
13
|
-
stdout: string;
|
|
14
|
-
stderr: string;
|
|
15
|
-
}
|
|
16
|
-
export interface RunOptions {
|
|
17
|
-
stdin?: string;
|
|
18
|
-
env?: Record<string, string>;
|
|
19
|
-
}
|
|
20
10
|
export interface LintOptions {
|
|
21
11
|
ignore?: string[];
|
|
22
12
|
severityOverrides?: Partial<Record<string, Severity>>;
|
package/lib/wasi.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface WasiInstance {
|
|
2
|
+
exports: {
|
|
3
|
+
memory: WebAssembly.Memory;
|
|
4
|
+
_initialize?: () => unknown;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export interface WasiHost {
|
|
8
|
+
wasiImport: Record<string, WebAssembly.ExportValue>;
|
|
9
|
+
initialize: (instance: WasiInstance) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const createWasiHost: (env: readonly string[]) => WasiHost;
|
package/lib/wasi.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const CLOCK_MONOTONIC = 1;
|
|
2
|
+
const POINTER_SIZE = 4;
|
|
3
|
+
const NANOSECONDS_PER_MILLISECOND = 1e6;
|
|
4
|
+
const ERRNO_SUCCESS = 0;
|
|
5
|
+
const NOT_IMPLEMENTED = [
|
|
6
|
+
'fd_close',
|
|
7
|
+
'fd_fdstat_get',
|
|
8
|
+
'fd_fdstat_set_flags',
|
|
9
|
+
'fd_filestat_get',
|
|
10
|
+
'fd_filestat_set_size',
|
|
11
|
+
'fd_prestat_get',
|
|
12
|
+
'fd_prestat_dir_name',
|
|
13
|
+
'fd_read',
|
|
14
|
+
'fd_seek',
|
|
15
|
+
'fd_write',
|
|
16
|
+
'path_create_directory',
|
|
17
|
+
'path_filestat_get',
|
|
18
|
+
'path_open',
|
|
19
|
+
'poll_oneoff',
|
|
20
|
+
'proc_exit',
|
|
21
|
+
];
|
|
22
|
+
export const createWasiHost = (env) => {
|
|
23
|
+
let memory;
|
|
24
|
+
const requireMemory = () => {
|
|
25
|
+
if (!memory) {
|
|
26
|
+
throw new Error('dlintr: WASI called before initialize()');
|
|
27
|
+
}
|
|
28
|
+
return memory;
|
|
29
|
+
};
|
|
30
|
+
const view = () => new DataView(requireMemory().buffer);
|
|
31
|
+
const bytes = () => new Uint8Array(requireMemory().buffer);
|
|
32
|
+
const encoder = new TextEncoder();
|
|
33
|
+
const entries = env.map(entry => encoder.encode(`${entry}\0`));
|
|
34
|
+
const argsSizesGet = (countPointer, sizePointer) => {
|
|
35
|
+
const data = view();
|
|
36
|
+
data.setUint32(countPointer, 0, true);
|
|
37
|
+
data.setUint32(sizePointer, 0, true);
|
|
38
|
+
return ERRNO_SUCCESS;
|
|
39
|
+
};
|
|
40
|
+
const environSizesGet = (countPointer, sizePointer) => {
|
|
41
|
+
const data = view();
|
|
42
|
+
data.setUint32(countPointer, entries.length, true);
|
|
43
|
+
data.setUint32(sizePointer, entries.reduce((total, entry) => total + entry.length, 0), true);
|
|
44
|
+
return ERRNO_SUCCESS;
|
|
45
|
+
};
|
|
46
|
+
const environGet = (pointerTable, buffer) => {
|
|
47
|
+
const data = view();
|
|
48
|
+
const target = bytes();
|
|
49
|
+
let offset = buffer;
|
|
50
|
+
for (const [index, entry] of entries.entries()) {
|
|
51
|
+
data.setUint32(pointerTable + index * POINTER_SIZE, offset, true);
|
|
52
|
+
target.set(entry, offset);
|
|
53
|
+
offset += entry.length;
|
|
54
|
+
}
|
|
55
|
+
return ERRNO_SUCCESS;
|
|
56
|
+
};
|
|
57
|
+
const clockTimeGet = (id, _precision, timePointer) => {
|
|
58
|
+
if (id !== CLOCK_MONOTONIC) {
|
|
59
|
+
throw new Error(`dlintr: clock_time_get(${id}) is not the monotonic clock`);
|
|
60
|
+
}
|
|
61
|
+
const nanoseconds = BigInt(Math.round(performance.now() * NANOSECONDS_PER_MILLISECOND));
|
|
62
|
+
view().setBigUint64(timePointer, nanoseconds, true);
|
|
63
|
+
return ERRNO_SUCCESS;
|
|
64
|
+
};
|
|
65
|
+
const wasiImport = {
|
|
66
|
+
args_get: () => ERRNO_SUCCESS,
|
|
67
|
+
args_sizes_get: argsSizesGet,
|
|
68
|
+
clock_time_get: clockTimeGet,
|
|
69
|
+
environ_get: environGet,
|
|
70
|
+
environ_sizes_get: environSizesGet,
|
|
71
|
+
};
|
|
72
|
+
for (const name of NOT_IMPLEMENTED) {
|
|
73
|
+
wasiImport[name] = () => {
|
|
74
|
+
throw new Error(`dlintr: the reactor called \`${name}\`, which this WASI shim does not implement.\n` +
|
|
75
|
+
`The imports actually used are measured, not assumed — run \`node wasm/calls.mjs\`\n` +
|
|
76
|
+
`to see the current set. Seeing this means the module now reaches further than\n` +
|
|
77
|
+
`when that measurement was taken, so implement \`${name}\` rather than retrying.`);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
wasiImport,
|
|
82
|
+
initialize: instance => {
|
|
83
|
+
memory = instance.exports.memory;
|
|
84
|
+
instance.exports._initialize?.();
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=wasi.js.map
|
package/lib/wasi.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasi.js","sourceRoot":"","sources":["../src/wasi.ts"],"names":[],"mappings":"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"}
|