-
-
Notifications
You must be signed in to change notification settings - Fork 131
/
compiler.js
90 lines (81 loc) · 3.65 KB
/
compiler.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
'use strict'
const fs = require('fs')
const path = require('path')
const bfs = require('bestikk-fs')
const log = require('bestikk-log')
const OpalBuilder = require('opal-compiler').Builder
const compileExt = (name, environment, skipped) => {
if (fs.existsSync(`lib/asciidoctor/js/${name}_ext/${environment}.rb`)) {
const module = `asciidoctor/js/${name}_ext/${environment}`
log.debug(module)
// Build a new instance each time, otherwise the context is shared.
const target = `build/${name}-ext-${environment}.js`
if (fs.existsSync(target)) {
skipped.push(target)
return
}
const opalBuilder = OpalBuilder.create()
opalBuilder.appendPaths('lib')
opalBuilder.setCompilerOptions({ dynamic_require_severity: 'ignore', requirable: true })
// For performance reason we build "asciidoctor_ext" without "asciidoctor" core.
// As a result Ruby modules required in "asciidoctor_ext" won't be found at compile time but will be resolved at runtime.
opalBuilder.missing_require_severity = 'ignore'
let data = opalBuilder.build(module).toString()
fs.writeFileSync(target, data, 'utf8')
}
}
const compileRuntimeEnvironments = (environments) => {
log.task('compile runtime environments')
const skipped = []
environments.forEach((environment) => {
compileExt('opal', environment, skipped)
compileExt('asciidoctor', environment, skipped)
})
if (skipped.length > 0) {
log.info(`${skipped.join(', ')} files already exist, skipping "compile" task.\nTIP: Use "npm run clean:ext" to compile again from Ruby sources.`)
}
}
const compileAsciidoctorCore = (asciidoctorCoreDependency) => {
log.task('compile core lib')
const module = `asciidoctor/lib`
log.debug(module)
const target = asciidoctorCoreDependency.target
if (fs.existsSync(target)) {
log.info(`${target} file already exists, skipping "compile" task.\nTIP: Use "npm run clean:core" to compile again from Asciidoctor Ruby.`)
return
}
const opalBuilder = OpalBuilder.create()
opalBuilder.appendPaths('build/asciidoctor/lib')
opalBuilder.appendPaths('node_modules/opal-compiler/src/stdlib')
opalBuilder.appendPaths('lib')
opalBuilder.setCompilerOptions({ dynamic_require_severity: 'ignore' })
fs.writeFileSync(target, opalBuilder.build('asciidoctor').toString(), 'utf8')
replaceUnsupportedFeatures(asciidoctorCoreDependency)
applyPatches(asciidoctorCoreDependency)
}
const replaceUnsupportedFeatures = (asciidoctorCoreDependency) => {
log.task('replace unsupported features')
const path = asciidoctorCoreDependency.target
let data = fs.readFileSync(path, 'utf8')
log.debug('replace (g)sub! with (g)sub')
data = data.replace(/\$send\(([^,]+), '(g?sub)!'/g, '$1 = $send($1, \'$2\'')
fs.writeFileSync(path, data, 'utf8')
}
const applyPatches = (asciidoctorCoreDependency) => {
log.task('apply patches')
const path = asciidoctorCoreDependency.target
let data = fs.readFileSync(path, 'utf8')
log.debug('preserve stack on Error (workaround: https://github.com/opal/opal/issues/1962)')
data = data.replace(/([\s]+)(wrapped_ex\.\$set_backtrace\(ex\.\$backtrace\(\)\);)/g, '$1$2$1wrapped_ex.stack = ex.stack;')
fs.writeFileSync(path, data, 'utf8')
}
module.exports.compile = (asciidoctorCoreDependency, environments) => {
bfs.mkdirsSync('build')
compileRuntimeEnvironments(environments)
compileAsciidoctorCore(asciidoctorCoreDependency)
log.task('copy resources')
log.debug('copy asciidoctor.css')
const asciidoctorPath = 'build/asciidoctor'
const asciidoctorCSSFile = path.join(asciidoctorPath, 'data/stylesheets/asciidoctor-default.css')
fs.createReadStream(asciidoctorCSSFile).pipe(fs.createWriteStream('build/css/asciidoctor.css'))
}