-
Notifications
You must be signed in to change notification settings - Fork 0
/
run-build.js
101 lines (94 loc) · 2.92 KB
/
run-build.js
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
import { join } from 'https://deno.land/[email protected]/path/mod.ts'
let writeReady = false
async function initWrite() {
if (!writeReady) {
for (const dir of ['build', 'out']) {
try {
await Deno.stat(join('.', dir))
} catch (e) {
if (e instanceof Deno.errors.NotFound) {
await Deno.mkdir(join('.', dir))
}
}
}
writeReady = true
}
}
async function* readPaths(suffix = '.md', parent = []) {
const dirs = []
for await (const file of Deno.readDir(join('.', ...parent))) {
if (!(file.name.startsWith('.') || file.name === '_notas')) {
if (file.isDirectory) {
dirs.push(file.name)
} else if (file.name.endsWith(suffix)) {
yield [...parent, file.name]
}
}
}
for (const dir of dirs) {
for await (const path of readPaths(suffix, [...parent, dir])) {
yield path
}
}
}
async function readFile(path) {
return await Deno.readFile(join('.', ...path))
}
async function writeFile(path, data) {
await initWrite()
const [topDir, ...rest] = path
if (['build', 'out'].includes(topDir)) {
const writePath = join('.', topDir, ...rest)
if (writePath.match(/\.(md|html|json|js|svg)$/)) {
await Deno.writeTextFile(writePath, new TextDecoder().decode(data))
} else if (writePath.match(/\.(png|webm|jpe?g|ico)$|Dockerfile\.?/)) {
await Deno.writeFile(writePath, data)
} else {
throw new Error('File type not allowed')
}
} else {
throw new Error('Access denied')
}
await Deno.readFile(join('.', ...path))
}
async function handleMessage(e) {
const [cmd, ...args] = e.data
const port = e.ports[0]
try {
if (cmd === 'readPaths') {
const paths = await Array.fromAsync(readPaths())
port.postMessage(paths)
} else if (cmd === 'readFile') {
const [path] = args
const data = await readFile(path)
port.postMessage(data, [data.buffer])
} else if (cmd === 'writeFile') {
const [path, data] = args
port.postMessage(await writeFile(path, data))
} else {
throw new Error(`Invalid command sent from worker: ${cmd}`)
}
} catch (err) {
console.error('Error providing output for worker', err)
port.postMessage(false)
}
port.close()
}
const re = /(?:^|\n)\s*\n`entry.js`\n\s*\n```.*?\n(.*?)```\s*(?:\n|$)/s
const runEntry = `
const re = new RegExp(${JSON.stringify(re.source)}, ${JSON.stringify(re.flags)})
addEventListener('message', async e => {
if (e.data[0] === 'notebook') {
globalThis.__source = new TextDecoder().decode(e.data[1])
const entrySrc = globalThis.__source.match(re)[1]
await import(\`data:text/javascript;base64,\${btoa(entrySrc)}\`)
}
}, {once: true})
`
const worker = new Worker(`data:text/javascript;base64,${btoa(runEntry)}`, {
type: 'module',
permissions: 'none',
})
worker.addEventListener('message', handleMessage)
const data = await readFile(['build.md'])
worker.postMessage(['notebook', data], [data.buffer])