Skip to content

Commit e085b19

Browse files
committed
add tests
1 parent 10ec8be commit e085b19

6 files changed

Lines changed: 307 additions & 39 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ result-*
88

99
# npm
1010
node_modules
11-
package-lock.json
11+
package-lock.json
12+
package.json

examples/test_always_failing.png

7.75 KB
Loading

src/ffi.effekt

Lines changed: 128 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,88 @@ module ffi
1313
/// Many of these are image manipulation utilities.
1414
/// These are not minimal amount of code, but expose the least amount of
1515
/// surface area to and from Effekt/JavaScript.
16-
extern js """
16+
17+
extern jsNode """
18+
const { createCanvas, ImageData, Image } = require('canvas');
19+
20+
21+
function $newDrawingCtx(width, height) {
22+
const canvas = createCanvas(width, height);
23+
return canvas.getContext("2d");
24+
}
25+
function $drawInto(ctx, data, x, y) {
26+
ctx.putImageData(data, x, y);
27+
}
28+
function $blitFx(source, sourceX, sourceY, sourceWidth, sourceHeight) {
29+
const src = source.data;
30+
const srcW = source.width;
31+
32+
const result = new ImageData(sourceWidth, sourceHeight);
33+
const dst = result.data;
34+
35+
const rowLength = sourceWidth * 4;
36+
37+
for (let y = 0; y < sourceHeight; y++) {
38+
const srcStart = ((sourceY + y) * srcW + sourceX) * 4;
39+
const dstStart = y * rowLength;
40+
41+
dst.set(src.subarray(srcStart, srcStart + rowLength), dstStart);
42+
}
43+
44+
return result;
45+
}
46+
function $shuffled(array) {
47+
const result = array.slice();
48+
49+
for (let i = result.length - 1; i > 0; i--) {
50+
const j = Math.floor(Math.random() * (i + 1));
51+
[result[i], result[j]] = [result[j], result[i]];
52+
}
53+
54+
return result;
55+
}
56+
function $imageDataFromFile(file, callback) {
57+
throw new Error("Not implemented in Node.js environment");
58+
}
59+
function $downloadImageDataAsPNG(imageData, filename) {
60+
throw new Error("Not implemented in Node.js environment");
61+
}
62+
function $scaleImageData(imageData, scale) {
63+
const srcCanvas = createCanvas(imageData.width, imageData.height);
64+
const srcCtx = srcCanvas.getContext("2d");
65+
srcCtx.putImageData(imageData, 0, 0);
66+
67+
const dstCanvas = createCanvas(imageData.width * scale, imageData.height * scale);
68+
const dstCtx = dstCanvas.getContext("2d");
69+
70+
dstCtx.imageSmoothingEnabled = false;
71+
72+
dstCtx.drawImage(
73+
srcCanvas,
74+
0, 0, srcCanvas.width, srcCanvas.height,
75+
0, 0, dstCanvas.width, dstCanvas.height
76+
);
77+
78+
return dstCtx.getImageData(0, 0, dstCanvas.width, dstCanvas.height);
79+
}
80+
81+
function $showMessage(message, color) {
82+
console.log(message);
83+
}
84+
85+
function $imageFromImageData(imageData) {
86+
const canvas = createCanvas(imageData.width, imageData.height);
87+
const ctx = canvas.getContext('2d');
88+
ctx.putImageData(imageData, 0, 0);
89+
90+
const img = new Image();
91+
img.src = canvas.toDataURL("image/png");
92+
93+
return img;
94+
}
95+
"""
96+
97+
extern jsWeb """
1798
function $newDrawingCtx(width, height) {
1899
const canvas = document.createElement("canvas");
19100
canvas.width = width;
@@ -174,6 +255,10 @@ extern type _Context2D // lib/canvas.effekt
174255

175256
namespace FFI {
176257

258+
extern def isBrowserEnv() at io: Bool =
259+
jsWeb "true"
260+
jsNode "false"
261+
177262
namespace Dom {
178263
extern def setupPopupHook() at io: Unit =
179264
jsWeb """
@@ -193,31 +278,40 @@ namespace FFI {
193278
"""
194279

195280
extern def getDocumentBody() at {}: _Node =
196-
js "(document.body)"
281+
jsWeb "(document.body)"
282+
jsNode "undefined"
197283

198284
extern def getDocumentElement() at {}: _Node =
199-
js "(document.documentElement)"
285+
jsWeb "(document.documentElement)"
286+
jsNode "undefined"
200287

201288
extern def getElementByIdUnsafe(id: String) at io: _Node =
202-
js "document.getElementById(${id})"
289+
jsWeb "document.getElementById(${id})"
290+
jsNode "undefined"
203291

204292
extern def createElement(tag: String) at io: _Node =
205-
js "document.createElement(${tag})"
293+
jsWeb "document.createElement(${tag})"
294+
jsNode "undefined"
206295

207296
extern def createTextNode(text: String) at io: _Node =
208-
js "document.createTextNode(${text})"
297+
jsWeb "document.createTextNode(${text})"
298+
jsNode "undefined"
209299

210300
extern def clone(node: _Node) at io: _Node =
211-
js "(${node}.cloneNode(true))"
301+
jsWeb "(${node}.cloneNode(true))"
302+
jsNode "undefined"
212303

213304
extern def removeContent(node: _Node) at io: Unit =
214-
js "${node}.innerHTML = ''"
305+
jsWeb "${node}.innerHTML = ''"
306+
jsNode "undefined"
215307

216308
extern def appendChild(node: _Node, child: _Node) at io: _Node =
217-
js "${node}.appendChild(${child})"
309+
jsWeb "${node}.appendChild(${child})"
310+
jsNode "undefined"
218311

219312
extern def onClick(node: _Node, handler: () => Unit at {io, global}) at io: Unit =
220-
js "(${node}.addEventListener('click', () => { $effekt.runToplevel((ks, k) => ${handler}(ks, k)) }))"
313+
jsWeb "(${node}.addEventListener('click', () => { $effekt.runToplevel((ks, k) => ${handler}(ks, k)) }))"
314+
jsNode "undefined"
221315

222316
extern def wait(time: Int, handler: () => Unit at {io, global}) at io: Unit =
223317
js "(setTimeout(() => $effekt.runToplevel((ks, k) => ${handler}(ks, k)), ${time}))"
@@ -231,7 +325,7 @@ namespace FFI {
231325
"""
232326

233327
extern def getInputNumber(node: _Node): Int =
234-
js """
328+
jsWeb """
235329
(function() {
236330
const num = ${node}.valueAsNumber
237331
if (Number.isNaN(num)) {
@@ -241,40 +335,51 @@ namespace FFI {
241335
}
242336
}) ()
243337
"""
338+
jsNode "undefined"
244339

245340
extern def getInputBool(node: _Node): Bool =
246-
js "${node}.checked"
341+
jsWeb "${node}.checked"
342+
jsNode "undefined"
247343

248344
extern def onWindowResize(handler: () => Unit at {io, global}) at io: Int =
249345
jsWeb "window.addEventListener('resize', () => { $effekt.runToplevel((ks, k) => ${handler}(ks, k)) })"
250346
jsNode "undefined"
251347

252348
extern def windowWidth() at io: Int =
253-
js "(window.innerWidth)"
349+
jsWeb "(window.innerWidth)"
350+
jsNode "undefined"
254351

255352
extern def windowHeight() at io: Int =
256-
js "(window.innerHeight)"
353+
jsWeb "(window.innerHeight)"
354+
jsNode "undefined"
257355

258356
extern def setAttribute(node: _Node, key: String, value: String) at io: _Node =
259-
js "(function() { ${node}.setAttribute(${key}, ${value}); return ${node} })()"
357+
jsWeb "(function() { ${node}.setAttribute(${key}, ${value}); return ${node} })()"
358+
jsNode "undefined"
260359

261360
extern def style(node: _Node) at io: _Style =
262-
js "(${node}.style)"
361+
jsWeb "(${node}.style)"
362+
jsNode "undefined"
263363

264364
extern def setProperty(style: _Style, key: String, value: String) at io: Unit =
265-
js "(function() { ${style}.setProperty(${key}, ${value}); return ${style} })()"
365+
jsWeb "(function() { ${style}.setProperty(${key}, ${value}); return ${style} })()"
366+
jsNode "undefined"
266367

267368
extern def clientWidth(node: _Node): Int =
268-
js "Number(${node}.clientWidth)"
369+
jsWeb "Number(${node}.clientWidth)"
370+
jsNode "undefined"
269371

270372
extern def clientHeight(node: _Node): Int =
271-
js "Number(${node}.clientHeight)"
373+
jsWeb "Number(${node}.clientHeight)"
374+
jsNode "undefined"
272375

273376
extern def setWidth(node: _Node, width: Int): Int =
274-
js "${node}.width = ${width}"
377+
jsWeb "${node}.width = ${width}"
378+
jsNode "undefined"
275379

276380
extern def setHeight(node: _Node, height: Int): Int =
277-
js "${node}.height = ${height}"
381+
jsWeb "${node}.height = ${height}"
382+
jsNode "undefined"
278383
}
279384
namespace Canvas {
280385
extern def width(img: _Image) at io: Int =
@@ -284,8 +389,7 @@ namespace FFI {
284389
js "(${img}.height)"
285390

286391
extern def loadImageFromInputUnsafe(inputNode: _Node, handler: _Image => Unit at {io, global}) at io: Unit =
287-
js
288-
"""
392+
jsWeb """
289393
(function() {
290394
const files = ${inputNode}.files
291395
const f = imageData => { $effekt.runToplevel((ks, k) => ${handler}(imageData, ks, k)) };
@@ -296,6 +400,7 @@ namespace FFI {
296400
}
297401
}) ()
298402
"""
403+
jsNode "undefined"
299404

300405
extern def data(img: _Image) at io: _ImageData =
301406
js "(${img}.data)"

src/lib/dom.effekt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ def css(node: Node) { scope: => Unit / SetProperty }: Node = {
6868
node
6969
}
7070

71+
def isBrowserEnv(): Bool = {
72+
FFI::isBrowserEnv()
73+
}
7174

7275

7376
interface HTMLElement {
@@ -274,6 +277,7 @@ def popup[E, T](proxy: on[E]) { prog: => T / Exception[E] }: T / Popup = {
274277
}
275278

276279
}
280+
277281
/// Unwrap an option or show a popup with the given message
278282
def orShow[T](self: Option[T], message: String): T / Popup = self match {
279283
case Some(v) => v

0 commit comments

Comments
 (0)