boxwood 0.60.2 → 0.61.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 +0 -358
- package/index.js +402 -4
- package/package.json +12 -37
- package/src/Bundler.js +0 -13
- package/src/Cache.js +0 -35
- package/src/Compiler.js +0 -28
- package/src/Importer.js +0 -142
- package/src/Optimizer.js +0 -96
- package/src/Scope.js +0 -20
- package/src/Statistics.js +0 -58
- package/src/bundlers/esbuild/index.js +0 -55
- package/src/bundlers/esbuild/plugins/css.js +0 -40
- package/src/bundlers/esbuild/plugins/html.js +0 -27
- package/src/bundlers/esbuild/plugins/image.js +0 -38
- package/src/bundlers/esbuild/plugins/resolve.js +0 -11
- package/src/bundlers/esbuild/plugins/yaml.js +0 -38
- package/src/bundlers/esbuild/utilities/asset.js +0 -19
- package/src/bundlers/rollup.js +0 -38
- package/src/compile.js +0 -6
- package/src/compilers/any/Compiler.js +0 -16
- package/src/compilers/compile.js +0 -17
- package/src/compilers/html/Analyzer.js +0 -24
- package/src/compilers/html/Compiler.js +0 -47
- package/src/compilers/html/Generator.js +0 -19
- package/src/compilers/html/Parser.js +0 -11
- package/src/compilers/html/Preprocessor.js +0 -130
- package/src/compilers/html/Renderer.js +0 -167
- package/src/compilers/html/Transpiler.js +0 -76
- package/src/compilers/js/Bundler.js +0 -84
- package/src/compilers/js/Compiler/index.js +0 -27
- package/src/conditions/isEqual.js +0 -5
- package/src/lexers/html.js +0 -49
- package/src/lexers/internal.js +0 -49
- package/src/linters/html/bracket.js +0 -36
- package/src/linters/html/component.js +0 -43
- package/src/linters/html/import.js +0 -35
- package/src/linters/html/index.js +0 -19
- package/src/linters/html/tag.js +0 -36
- package/src/optimizers/html.js +0 -15
- package/src/plugins/BoxModelPlugin/index.js +0 -109
- package/src/plugins/CurlyStylesPlugin/index.js +0 -39
- package/src/plugins/DataPlugin/index.js +0 -53
- package/src/plugins/InlinePlugin/css.js +0 -131
- package/src/plugins/InlinePlugin/index.js +0 -39
- package/src/plugins/InternationalizationPlugin/index.js +0 -111
- package/src/plugins/Plugin.js +0 -22
- package/src/plugins/ScopedStylesPlugin/css.js +0 -56
- package/src/plugins/ScopedStylesPlugin/html.js +0 -112
- package/src/plugins/ScopedStylesPlugin/index.js +0 -48
- package/src/plugins/SwappedStylesPlugin/index.js +0 -20
- package/src/render.js +0 -48
- package/src/tags/case.js +0 -28
- package/src/tags/catch.js +0 -17
- package/src/tags/data.js +0 -7
- package/src/tags/default.js +0 -20
- package/src/tags/doctype.js +0 -8
- package/src/tags/else.js +0 -18
- package/src/tags/elseif.js +0 -25
- package/src/tags/elseunless.js +0 -30
- package/src/tags/font.js +0 -37
- package/src/tags/for.js +0 -90
- package/src/tags/foreach.js +0 -80
- package/src/tags/if.js +0 -19
- package/src/tags/img.js +0 -25
- package/src/tags/index.js +0 -53
- package/src/tags/link.js +0 -14
- package/src/tags/script/index.js +0 -83
- package/src/tags/script/scoped.js +0 -26
- package/src/tags/slot.js +0 -9
- package/src/tags/style.js +0 -9
- package/src/tags/switch.js +0 -13
- package/src/tags/template.js +0 -22
- package/src/tags/translate.js +0 -22
- package/src/tags/translation.js +0 -38
- package/src/tags/try.js +0 -17
- package/src/tags/unless.js +0 -24
- package/src/tags/var.js +0 -32
- package/src/transpilers/css/index.js +0 -34
- package/src/transpilers/html/expression.js +0 -101
- package/src/transpilers/html/index.js +0 -189
- package/src/transpilers/html/node.js +0 -46
- package/src/transpilers/html/tags/any.js +0 -53
- package/src/transpilers/html/tags/comment.js +0 -7
- package/src/transpilers/html/tags/doctype.js +0 -6
- package/src/transpilers/html/tags/for.js +0 -30
- package/src/transpilers/html/tags/if.js +0 -55
- package/src/transpilers/html/tags/import.js +0 -7
- package/src/transpilers/html/tags/index.js +0 -13
- package/src/transpilers/html/tags/partial.js +0 -17
- package/src/transpilers/html/tags/slot.js +0 -7
- package/src/transpilers/html/tags/text.js +0 -6
- package/src/transpilers/html/tags/try.js +0 -30
- package/src/transpilers/html/tags/unless.js +0 -58
- package/src/transpilers/html/utilities/path.js +0 -9
- package/src/utilities/action.js +0 -208
- package/src/utilities/array.js +0 -80
- package/src/utilities/assets.js +0 -18
- package/src/utilities/ast.js +0 -13
- package/src/utilities/attributes.js +0 -23
- package/src/utilities/collect.js +0 -404
- package/src/utilities/conditions.js +0 -159
- package/src/utilities/convert.js +0 -359
- package/src/utilities/data.js +0 -55
- package/src/utilities/enum.js +0 -103
- package/src/utilities/errors.js +0 -96
- package/src/utilities/factory.js +0 -237
- package/src/utilities/files.js +0 -55
- package/src/utilities/filters.js +0 -140
- package/src/utilities/globals.js +0 -43
- package/src/utilities/html.js +0 -60
- package/src/utilities/inline.js +0 -200
- package/src/utilities/js.js +0 -15
- package/src/utilities/keywords.js +0 -35
- package/src/utilities/log.js +0 -31
- package/src/utilities/node.js +0 -149
- package/src/utilities/object.js +0 -8
- package/src/utilities/optimize.js +0 -268
- package/src/utilities/options.js +0 -99
- package/src/utilities/request.js +0 -13
- package/src/utilities/string.js +0 -144
- package/src/utilities/style.js +0 -15
- package/src/utilities/translations.js +0 -78
- package/src/utilities/url.js +0 -24
- package/src/vdom/browser/app.js +0 -19
- package/src/vdom/browser/diff.js +0 -104
- package/src/vdom/browser/index.js +0 -15
- package/src/vdom/browser/mount.js +0 -10
- package/src/vdom/browser/render.js +0 -66
- package/src/vdom/browser/replace.js +0 -7
- package/src/vdom/node.js +0 -10
- package/src/vdom/nodes.js +0 -116
- package/src/vdom/server/State.js +0 -21
- package/src/vdom/server/boxwood.js +0 -5
- package/src/vdom/server/index.js +0 -19
- package/src/vdom/server/render.js +0 -66
- package/src/vdom/tag.js +0 -33
- package/src/vdom/utilities/classes.js +0 -22
- package/src/vdom/utilities/css.js +0 -17
- package/src/vdom/utilities/escape.js +0 -50
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
const ScopedStylesPlugin = require('../../plugins/ScopedStylesPlugin')
|
|
2
|
-
const InlinePlugin = require('../../plugins/InlinePlugin')
|
|
3
|
-
const SwappedStylesPlugin = require('../../plugins/SwappedStylesPlugin')
|
|
4
|
-
|
|
5
|
-
const plugins = [
|
|
6
|
-
new InlinePlugin(),
|
|
7
|
-
new ScopedStylesPlugin(),
|
|
8
|
-
new SwappedStylesPlugin()
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
function walk (node, callback) {
|
|
12
|
-
let children
|
|
13
|
-
if (Array.isArray(node)) {
|
|
14
|
-
children = node
|
|
15
|
-
} else {
|
|
16
|
-
callback(node)
|
|
17
|
-
children = node.children
|
|
18
|
-
}
|
|
19
|
-
if (children) {
|
|
20
|
-
let child = children[0]
|
|
21
|
-
let i = 0
|
|
22
|
-
while (child) {
|
|
23
|
-
walk(child, callback)
|
|
24
|
-
child = children[++i]
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function remove (tree, callback) {
|
|
30
|
-
tree = tree.map(node => {
|
|
31
|
-
if (callback(node)) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
return node
|
|
35
|
-
}).filter(Boolean)
|
|
36
|
-
walk(tree, node => {
|
|
37
|
-
if (node.children) {
|
|
38
|
-
for (let i = 0, ilen = node.children.length; i < ilen; i++) {
|
|
39
|
-
if (callback(node.children[i])) {
|
|
40
|
-
node.children[i] = null
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
node.children = node.children.filter(Boolean)
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
return tree
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
class Preprocessor {
|
|
50
|
-
preprocess (tree, assets, options) {
|
|
51
|
-
const references = {}
|
|
52
|
-
const styles = []
|
|
53
|
-
|
|
54
|
-
// things that are missing
|
|
55
|
-
// - use the scoped styles plugin first
|
|
56
|
-
// - handle imported components
|
|
57
|
-
|
|
58
|
-
// it would be nicer to do this in a more functional way, like `abstract-syntax-tree` lib
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
plugins.forEach(plugin => {
|
|
62
|
-
plugin.depth += 1
|
|
63
|
-
plugin.beforeprerun()
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
walk(tree, node => {
|
|
67
|
-
if (node.tagName === 'head') {
|
|
68
|
-
references.head = node
|
|
69
|
-
} else if (node.tagName === 'style') {
|
|
70
|
-
styles.push(node)
|
|
71
|
-
plugins.forEach(plugin => {
|
|
72
|
-
plugin.prerun({
|
|
73
|
-
tag: node.tagName,
|
|
74
|
-
keys: node.attributes.map(leaf => leaf.key),
|
|
75
|
-
attributes: node.attributes,
|
|
76
|
-
attrs: node.attributes,
|
|
77
|
-
children: node.children || [],
|
|
78
|
-
fragment: node,
|
|
79
|
-
assets,
|
|
80
|
-
options
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
plugins.forEach(plugin => { plugin.afterprerun() })
|
|
86
|
-
plugins.forEach(plugin => { plugin.beforerun() })
|
|
87
|
-
walk(tree, node => {
|
|
88
|
-
plugins.forEach(plugin => {
|
|
89
|
-
plugin.run({
|
|
90
|
-
tag: node.tagName,
|
|
91
|
-
keys: node.attributes && node.attributes.map(leaf => leaf.key),
|
|
92
|
-
fragment: node,
|
|
93
|
-
attributes: node.attributes,
|
|
94
|
-
assets,
|
|
95
|
-
options,
|
|
96
|
-
children: node.children || []
|
|
97
|
-
})
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
plugins.forEach(plugin => {
|
|
101
|
-
plugin.afterrun()
|
|
102
|
-
plugin.depth -= 1
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
tree = remove(tree, node => {
|
|
106
|
-
return node && node.tagName === 'style'
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
if (styles.length > 0 && references.head) {
|
|
110
|
-
references.head.children.push({
|
|
111
|
-
type: 'element',
|
|
112
|
-
tagName: 'style',
|
|
113
|
-
attributes: [],
|
|
114
|
-
children: [
|
|
115
|
-
{
|
|
116
|
-
type: 'text',
|
|
117
|
-
content: styles.reduce((result, style) => {
|
|
118
|
-
const { content } = style.children[0]
|
|
119
|
-
return result + content
|
|
120
|
-
}, '')
|
|
121
|
-
}
|
|
122
|
-
]
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return { tree, styles }
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
module.exports = Preprocessor
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const AbstractSyntaxTree = require('abstract-syntax-tree')
|
|
4
|
-
const walk = require('himalaya-walk')
|
|
5
|
-
const { TEMPLATE_VARIABLE, OBJECT_VARIABLE, ESCAPE_VARIABLE, BUILT_IN_VARIABLES } = require('../../utilities/enum')
|
|
6
|
-
const { getTemplateVariableDeclaration, getTemplateReturnStatement, getTemplateAssignmentExpression } = require('../../utilities/factory')
|
|
7
|
-
const collect = require('../../utilities/collect')
|
|
8
|
-
const { getFilter } = require('../../utilities/filters')
|
|
9
|
-
const { concatenateScripts } = require('../../utilities/js')
|
|
10
|
-
const { unique } = require('pure-utilities/array')
|
|
11
|
-
const Statistics = require('../../Statistics')
|
|
12
|
-
const DataPlugin = require('../../plugins/DataPlugin')
|
|
13
|
-
const CurlyStylesPlugin = require('../../plugins/CurlyStylesPlugin')
|
|
14
|
-
const ScopedStylesPlugin = require('../../plugins/ScopedStylesPlugin')
|
|
15
|
-
const InternationalizationPlugin = require('../../plugins/InternationalizationPlugin')
|
|
16
|
-
const BoxModelPlugin = require('../../plugins/BoxModelPlugin')
|
|
17
|
-
const InlinePlugin = require('../../plugins/InlinePlugin')
|
|
18
|
-
const SwappedStylesPlugin = require('../../plugins/SwappedStylesPlugin')
|
|
19
|
-
const Importer = require('../../Importer')
|
|
20
|
-
const Optimizer = require('../../Optimizer')
|
|
21
|
-
const Scope = require('../../Scope')
|
|
22
|
-
const { getLiteral } = require('../../utilities/ast')
|
|
23
|
-
const Preprocessor = require('./Preprocessor')
|
|
24
|
-
const { transpile: transpileCSS } = require('../../transpilers/css')
|
|
25
|
-
|
|
26
|
-
function replaceNeedleOrAppend (tree, { needles, needle, tag, content }) {
|
|
27
|
-
if (content) {
|
|
28
|
-
const all = `<${tag}>${content}</${tag}>`
|
|
29
|
-
if (needles[needle]) {
|
|
30
|
-
const node = tree.first(`Literal[value=__NEEDLE_${needle.toUpperCase()}__]`)
|
|
31
|
-
node.value = all
|
|
32
|
-
} else {
|
|
33
|
-
tree.append(getTemplateAssignmentExpression(TEMPLATE_VARIABLE, getLiteral(all)))
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
tree.replace((node) => {
|
|
37
|
-
if (node.type === 'ExpressionStatement' &&
|
|
38
|
-
node.expression.type === 'AssignmentExpression' &&
|
|
39
|
-
node.expression.right.type === 'Literal' &&
|
|
40
|
-
node.expression.right.value === `__NEEDLE_${needle.toUpperCase()}__`) {
|
|
41
|
-
return null
|
|
42
|
-
}
|
|
43
|
-
return node
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
class Renderer {
|
|
49
|
-
async render (source, htmltree, options) {
|
|
50
|
-
if (!htmltree) { return null }
|
|
51
|
-
const tree = new AbstractSyntaxTree('')
|
|
52
|
-
const variables = [
|
|
53
|
-
TEMPLATE_VARIABLE,
|
|
54
|
-
OBJECT_VARIABLE,
|
|
55
|
-
ESCAPE_VARIABLE
|
|
56
|
-
].concat(BUILT_IN_VARIABLES)
|
|
57
|
-
const filters = []
|
|
58
|
-
const components = []
|
|
59
|
-
const statistics = new Statistics()
|
|
60
|
-
const importer = new Importer(source, options)
|
|
61
|
-
const { assets, warnings } = await importer.import()
|
|
62
|
-
assets.forEach(asset => {
|
|
63
|
-
if (asset.type === 'COMPONENT') {
|
|
64
|
-
statistics.components.push(asset)
|
|
65
|
-
} else if (asset.type === 'PARTIAL') {
|
|
66
|
-
statistics.partials.push(asset)
|
|
67
|
-
} else if (asset.type === 'SCRIPT') {
|
|
68
|
-
statistics.scripts.push(asset)
|
|
69
|
-
} else if (asset.type === 'STYLESHEET') {
|
|
70
|
-
statistics.stylesheets.push(asset)
|
|
71
|
-
} else if (asset.type === 'IMAGE') {
|
|
72
|
-
statistics.images.push(asset)
|
|
73
|
-
} else if (asset.type === 'TRANSLATION') {
|
|
74
|
-
statistics.translations.push(asset)
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
const scripts = []
|
|
78
|
-
const stack = [options.path]
|
|
79
|
-
const store = {}
|
|
80
|
-
const translations = {}
|
|
81
|
-
const needles = {}
|
|
82
|
-
const promises = []
|
|
83
|
-
const errors = []
|
|
84
|
-
const plugins = [
|
|
85
|
-
new DataPlugin(),
|
|
86
|
-
new InlinePlugin(),
|
|
87
|
-
new BoxModelPlugin(options),
|
|
88
|
-
new CurlyStylesPlugin(),
|
|
89
|
-
new ScopedStylesPlugin(),
|
|
90
|
-
new SwappedStylesPlugin(),
|
|
91
|
-
new InternationalizationPlugin({ translations, filters, errors })
|
|
92
|
-
]
|
|
93
|
-
const depth = 0
|
|
94
|
-
tree.append(getTemplateVariableDeclaration(TEMPLATE_VARIABLE))
|
|
95
|
-
plugins.forEach(plugin => {
|
|
96
|
-
plugin.depth = 0
|
|
97
|
-
plugin.beforeprerun()
|
|
98
|
-
})
|
|
99
|
-
const preprocessor = new Preprocessor()
|
|
100
|
-
const output = preprocessor.preprocess(htmltree, assets, options)
|
|
101
|
-
htmltree = output.tree
|
|
102
|
-
const styles = output.styles
|
|
103
|
-
? output.styles.map(style => style.children[0] && style.children[0].content).filter(Boolean)
|
|
104
|
-
: []
|
|
105
|
-
|
|
106
|
-
assets.forEach(asset => {
|
|
107
|
-
if (asset.type === 'COMPONENT' && asset.path.endsWith('.css')) {
|
|
108
|
-
const css = transpileCSS(asset.source)
|
|
109
|
-
styles.push(css)
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
walk(htmltree, async fragment => {
|
|
113
|
-
try {
|
|
114
|
-
const attrs = fragment.attributes || []
|
|
115
|
-
plugins.forEach(plugin => {
|
|
116
|
-
plugin.prerun({
|
|
117
|
-
source,
|
|
118
|
-
tag: fragment.tagName,
|
|
119
|
-
keys: attrs.map(attribute => attribute.key),
|
|
120
|
-
attrs,
|
|
121
|
-
fragment,
|
|
122
|
-
options,
|
|
123
|
-
assets,
|
|
124
|
-
stack,
|
|
125
|
-
errors,
|
|
126
|
-
...fragment,
|
|
127
|
-
pass: 'renderer'
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
} catch (exception) {
|
|
131
|
-
errors.push(exception)
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
plugins.forEach(plugin => { plugin.afterprerun() })
|
|
135
|
-
|
|
136
|
-
const severities = warnings.map(warning => warning.severity)
|
|
137
|
-
if (!severities.includes('critical')) {
|
|
138
|
-
walk(htmltree, async fragment => {
|
|
139
|
-
await collect({ source, tree, fragment, assets, variables, filters, components, styles, scripts, translations, plugins, stack, store, depth, options, promises, errors, warnings, needles })
|
|
140
|
-
})
|
|
141
|
-
await Promise.all(promises)
|
|
142
|
-
|
|
143
|
-
const style = unique(styles).join(' ')
|
|
144
|
-
replaceNeedleOrAppend(tree, { needles, needle: 'head', tag: 'style', content: style })
|
|
145
|
-
|
|
146
|
-
const script = concatenateScripts(scripts)
|
|
147
|
-
replaceNeedleOrAppend(tree, { needles, needle: 'body', tag: 'script', content: script })
|
|
148
|
-
|
|
149
|
-
const used = []
|
|
150
|
-
unique(filters).forEach(name => {
|
|
151
|
-
const filter = getFilter(name, translations, options)
|
|
152
|
-
if (filter && !used.includes(filter.id.name)) {
|
|
153
|
-
tree.prepend(filter)
|
|
154
|
-
used.push(filter.id.name)
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
}
|
|
158
|
-
tree.append(getTemplateReturnStatement())
|
|
159
|
-
const scope = new Scope()
|
|
160
|
-
scope.flatten(tree)
|
|
161
|
-
const optimizer = new Optimizer()
|
|
162
|
-
optimizer.optimize(tree)
|
|
163
|
-
return { tree, statistics, warnings, errors }
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
module.exports = Renderer
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { isCurlyTag, getTagValue } = require('../../utilities/string')
|
|
4
|
-
const { SPECIAL_TAGS } = require('../../utilities/enum')
|
|
5
|
-
const tokenize = require('../../lexers/html')
|
|
6
|
-
|
|
7
|
-
const transform = (tokens) => {
|
|
8
|
-
const output = []
|
|
9
|
-
const contexts = []
|
|
10
|
-
const imports = []
|
|
11
|
-
let lastTag
|
|
12
|
-
tokens.forEach((token, index) => {
|
|
13
|
-
const [type, value] = token
|
|
14
|
-
const next = tokens[index + 1]
|
|
15
|
-
if (type === 'tagName') {
|
|
16
|
-
lastTag = value
|
|
17
|
-
if (value === 'if' || value === 'unless') {
|
|
18
|
-
contexts.push(value)
|
|
19
|
-
} else if (value === 'elseif' || value === 'else' || value === 'elseunless') {
|
|
20
|
-
const context = contexts[contexts.length - 1]
|
|
21
|
-
if (context === 'if' || context === 'elseif' || context === 'unless') {
|
|
22
|
-
const last = output.pop()
|
|
23
|
-
output.push(['beginEndTag', '</'])
|
|
24
|
-
output.push(['tagName', context])
|
|
25
|
-
output.push(['finishTag', '>'])
|
|
26
|
-
output.push(last)
|
|
27
|
-
contexts.push(value)
|
|
28
|
-
}
|
|
29
|
-
} else if (value === 'end') {
|
|
30
|
-
const context = contexts[contexts.length - 1]
|
|
31
|
-
if (context === 'if' || context === 'unless' || context === 'elseunless' || context === 'else' || context === 'elseif') {
|
|
32
|
-
tokens[index - 1][0] = 'beginEndTag'
|
|
33
|
-
tokens[index - 1][1] = '</'
|
|
34
|
-
token[1] = context
|
|
35
|
-
contexts.pop()
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
output.push(token)
|
|
39
|
-
} else if (type === 'attributeName' && (lastTag === 'import' || lastTag === 'require')) {
|
|
40
|
-
const [, value] = token
|
|
41
|
-
if (value !== 'from' && value !== '{' && value !== '}') {
|
|
42
|
-
// TODO unify with getComponentNames
|
|
43
|
-
const parts = value.replace('{', '').replace('}', '').split(/,/g).map(key => key.trim()).filter(Boolean)
|
|
44
|
-
parts.forEach(part => imports.push(part))
|
|
45
|
-
}
|
|
46
|
-
output.push(token)
|
|
47
|
-
} else if (type === 'attributeName' && isCurlyTag(value) && next && next[0] !== 'attributeAssign') {
|
|
48
|
-
const tags = SPECIAL_TAGS.filter(tag => !imports.includes(tag))
|
|
49
|
-
if (tags.includes(lastTag)) {
|
|
50
|
-
output.push(token)
|
|
51
|
-
} else {
|
|
52
|
-
output.push(['attributeName', getTagValue(value)])
|
|
53
|
-
output.push(['attributeAssign', '='])
|
|
54
|
-
output.push(['beginAttributeValue', '"'])
|
|
55
|
-
output.push(['attributeData', value])
|
|
56
|
-
output.push(['finishAttributeValue', '"'])
|
|
57
|
-
}
|
|
58
|
-
} else {
|
|
59
|
-
output.push(token)
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
return output
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const stringify = (tokens) => {
|
|
66
|
-
return tokens.map(([type, value]) => value).join('')
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
class Transpiler {
|
|
70
|
-
transpile (source) {
|
|
71
|
-
const tokens = tokenize(source)
|
|
72
|
-
return stringify(transform(tokens))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = Transpiler
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
const AbstractSyntaxTree = require('abstract-syntax-tree')
|
|
2
|
-
const { join } = require('path')
|
|
3
|
-
const ESBundler = require('../../Bundler')
|
|
4
|
-
const { OBJECT_VARIABLE } = require('../../utilities/enum')
|
|
5
|
-
|
|
6
|
-
const { CallExpression, ExpressionStatement, FunctionExpression, Identifier, ImportDeclaration, ImportSpecifier, Literal } = AbstractSyntaxTree
|
|
7
|
-
|
|
8
|
-
function getRenderImportSpecifier () {
|
|
9
|
-
const identifier = new Identifier('render')
|
|
10
|
-
return new ImportSpecifier({
|
|
11
|
-
local: identifier,
|
|
12
|
-
imported: identifier
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function getRenderCallExpression (node) {
|
|
17
|
-
return new CallExpression({
|
|
18
|
-
callee: new Identifier('render'),
|
|
19
|
-
arguments: [
|
|
20
|
-
new CallExpression({
|
|
21
|
-
callee: new FunctionExpression(node.declaration),
|
|
22
|
-
arguments: [new Identifier(OBJECT_VARIABLE)]
|
|
23
|
-
})
|
|
24
|
-
]
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function isBoxwoodImportDeclaration (node) {
|
|
29
|
-
return AbstractSyntaxTree.match(node, 'ImportDeclaration[source.value="boxwood"]')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function getBoxwoodImportDeclaration () {
|
|
33
|
-
return new ImportDeclaration({
|
|
34
|
-
specifiers: [getRenderImportSpecifier()],
|
|
35
|
-
source: new Literal('boxwood')
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function isFunctionExportDeclaration (node) {
|
|
40
|
-
return AbstractSyntaxTree.match(node, 'ExportDefaultDeclaration[declaration.type="FunctionDeclaration"]')
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
class Bundler {
|
|
44
|
-
constructor (options) {
|
|
45
|
-
this.options = options
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async bundle (input) {
|
|
49
|
-
const tree = this.parse(input)
|
|
50
|
-
|
|
51
|
-
const bundler = new ESBundler()
|
|
52
|
-
return await bundler.bundle(tree.source, {
|
|
53
|
-
platform: 'node',
|
|
54
|
-
format: 'iife',
|
|
55
|
-
paths: [
|
|
56
|
-
join(__dirname, '../../vdom/server'),
|
|
57
|
-
...this.options.paths
|
|
58
|
-
]
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
parse (input) {
|
|
63
|
-
const tree = new AbstractSyntaxTree(input)
|
|
64
|
-
let imported = false
|
|
65
|
-
tree.replace(node => {
|
|
66
|
-
if (isBoxwoodImportDeclaration(node)) {
|
|
67
|
-
imported = true
|
|
68
|
-
node.specifiers.push(getRenderImportSpecifier())
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
if (!imported) {
|
|
72
|
-
tree.prepend(getBoxwoodImportDeclaration())
|
|
73
|
-
}
|
|
74
|
-
tree.replace(node => {
|
|
75
|
-
if (isFunctionExportDeclaration(node)) {
|
|
76
|
-
return new ExpressionStatement({ expression: getRenderCallExpression(node) })
|
|
77
|
-
}
|
|
78
|
-
return node
|
|
79
|
-
})
|
|
80
|
-
return tree
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = Bundler
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const AbstractSyntaxTree = require('abstract-syntax-tree')
|
|
2
|
-
const Bundler = require('../Bundler')
|
|
3
|
-
const { OBJECT_VARIABLE } = require('../../../utilities/enum')
|
|
4
|
-
const { getOptions, validateOptions } = require('../../../utilities/options')
|
|
5
|
-
|
|
6
|
-
class Compiler {
|
|
7
|
-
constructor (options) {
|
|
8
|
-
this.options = getOptions(options)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async compile (input) {
|
|
12
|
-
const { options } = this
|
|
13
|
-
const errors = validateOptions(options)
|
|
14
|
-
if (errors.length > 0) { return { errors } }
|
|
15
|
-
const bundler = new Bundler(options)
|
|
16
|
-
const bundle = await bundler.bundle(input)
|
|
17
|
-
const tree = new AbstractSyntaxTree(bundle)
|
|
18
|
-
const expression = tree.first('CallExpression > ArrowFunctionExpression')
|
|
19
|
-
const { body } = expression.body
|
|
20
|
-
const lastNode = body.pop()
|
|
21
|
-
body.push({ type: 'ReturnStatement', argument: lastNode.expression })
|
|
22
|
-
const template = new Function(`return function render(${OBJECT_VARIABLE}) {\nreturn ${tree.source}}`)() // eslint-disable-line
|
|
23
|
-
return { template, errors: [] }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = Compiler
|
package/src/lexers/html.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
const Lexer = require('html-lexer')
|
|
2
|
-
|
|
3
|
-
const tokenize = (source) => {
|
|
4
|
-
const tokens = []
|
|
5
|
-
const delegate = {
|
|
6
|
-
write: (token) => tokens.push(token),
|
|
7
|
-
end: () => null
|
|
8
|
-
}
|
|
9
|
-
const lexer = new Lexer(delegate)
|
|
10
|
-
lexer.write(source)
|
|
11
|
-
lexer.end()
|
|
12
|
-
return reduce(normalize(tokens))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const normalize = (tokens) => {
|
|
16
|
-
for (let i = 0, ilen = tokens.length; i < ilen; i += 1) {
|
|
17
|
-
const current = tokens[i]
|
|
18
|
-
if (current[0] === 'endTagPrefix') {
|
|
19
|
-
const previous = tokens[i - 1]
|
|
20
|
-
const next = tokens[i + 1]
|
|
21
|
-
if (previous && next && previous[0] === 'rawtext' && next[0] === 'rawtext') {
|
|
22
|
-
current[0] = 'rawtext'
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return tokens
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const reduce = (tokens) => {
|
|
30
|
-
const newTokens = []
|
|
31
|
-
for (let i = 0, ilen = tokens.length; i < ilen; i += 1) {
|
|
32
|
-
const current = tokens[i]
|
|
33
|
-
if (current[0] === 'rawtext') {
|
|
34
|
-
let text = current[1]
|
|
35
|
-
let next = tokens[i + 1]
|
|
36
|
-
while (next && next[0] === 'rawtext') {
|
|
37
|
-
i++
|
|
38
|
-
text += next[1]
|
|
39
|
-
next = tokens[i + 1]
|
|
40
|
-
}
|
|
41
|
-
newTokens.push(['rawtext', text])
|
|
42
|
-
} else {
|
|
43
|
-
newTokens.push(tokens[i])
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return newTokens
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = tokenize
|
package/src/lexers/internal.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const START_TAG = '{'
|
|
4
|
-
const END_TAG = '}'
|
|
5
|
-
|
|
6
|
-
const TEXT = 'text'
|
|
7
|
-
const EXPRESSION = 'expression'
|
|
8
|
-
|
|
9
|
-
module.exports = function tokenize (input) {
|
|
10
|
-
const tokens = []
|
|
11
|
-
const length = input.length
|
|
12
|
-
let index = 0
|
|
13
|
-
let character = input[0]
|
|
14
|
-
function advance () {
|
|
15
|
-
index += 1
|
|
16
|
-
character = input[index]
|
|
17
|
-
return character
|
|
18
|
-
}
|
|
19
|
-
function current (tag) {
|
|
20
|
-
return character === tag
|
|
21
|
-
}
|
|
22
|
-
function push (type, value) {
|
|
23
|
-
if (value) tokens.push({ type, value })
|
|
24
|
-
}
|
|
25
|
-
let value = ''
|
|
26
|
-
let type = current(START_TAG) ? EXPRESSION : TEXT
|
|
27
|
-
let depth = 0
|
|
28
|
-
while (index < length) {
|
|
29
|
-
if (current(START_TAG)) { depth += 1 } else if (current(END_TAG)) { depth -= 1 }
|
|
30
|
-
|
|
31
|
-
if (current(START_TAG) && depth === 1) {
|
|
32
|
-
push(type, value)
|
|
33
|
-
advance()
|
|
34
|
-
value = ''
|
|
35
|
-
type = EXPRESSION
|
|
36
|
-
} else if (current(END_TAG) && depth === 0) {
|
|
37
|
-
push(type, value)
|
|
38
|
-
advance()
|
|
39
|
-
value = ''
|
|
40
|
-
type = TEXT
|
|
41
|
-
} else {
|
|
42
|
-
value += character
|
|
43
|
-
advance()
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
push(type, value)
|
|
47
|
-
|
|
48
|
-
return tokens
|
|
49
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const tokenize = require('../../lexers/html')
|
|
2
|
-
|
|
3
|
-
const OPENING_ANGLE_BRACKET = '<'
|
|
4
|
-
const CLOSING_ANGLE_BRACKET = '>'
|
|
5
|
-
|
|
6
|
-
function isOpeningBracket (character) {
|
|
7
|
-
return character === OPENING_ANGLE_BRACKET
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function isClosingBracket (character) {
|
|
11
|
-
return character === CLOSING_ANGLE_BRACKET
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function verifyBrackets (source) {
|
|
15
|
-
const tokens = tokenize(source).filter(token => token[0] !== 'rawtext')
|
|
16
|
-
const text = tokens.map(token => token[1]).join('')
|
|
17
|
-
|
|
18
|
-
const errors = []
|
|
19
|
-
let bracket = null
|
|
20
|
-
for (const character of text) {
|
|
21
|
-
if (isOpeningBracket(character)) {
|
|
22
|
-
if (isOpeningBracket(bracket)) {
|
|
23
|
-
errors.push({ type: 'CLOSING_ANGLE_BRACKET_MISSING', message: 'closing angle bracket is missing' })
|
|
24
|
-
}
|
|
25
|
-
bracket = OPENING_ANGLE_BRACKET
|
|
26
|
-
} else if (isClosingBracket(character)) {
|
|
27
|
-
if (!isOpeningBracket(bracket)) {
|
|
28
|
-
errors.push({ type: 'OPENING_ANGLE_BRACKET_MISSING', message: 'opening angle bracket is missing' })
|
|
29
|
-
}
|
|
30
|
-
bracket = CLOSING_ANGLE_BRACKET
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return errors
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = { verifyBrackets }
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const walk = require('himalaya-walk')
|
|
4
|
-
const { unique } = require('pure-utilities/array')
|
|
5
|
-
const { isImportTag } = require('../../utilities/string')
|
|
6
|
-
const { getComponentNames } = require('../../utilities/attributes')
|
|
7
|
-
|
|
8
|
-
function isStyleImport (node) {
|
|
9
|
-
const from = node.attributes.find(attr => attr.key === 'from')
|
|
10
|
-
if (from && from.value.endsWith('.css')) {
|
|
11
|
-
return true
|
|
12
|
-
}
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function analyze (tree) {
|
|
17
|
-
const components = []
|
|
18
|
-
walk(tree, node => {
|
|
19
|
-
if (isImportTag(node.tagName) && !isStyleImport(node)) {
|
|
20
|
-
const names = getComponentNames(node.attributes)
|
|
21
|
-
names.forEach(name => components.push(name))
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
return { components: unique(components) }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function verifyComponents (tree) {
|
|
28
|
-
const warnings = []
|
|
29
|
-
const { components } = analyze(tree)
|
|
30
|
-
walk(tree, node => {
|
|
31
|
-
const index = components.indexOf(node.tagName)
|
|
32
|
-
if (index !== -1) {
|
|
33
|
-
components.splice(index, 1)
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
// TODO: unify warnings.
|
|
37
|
-
components.forEach(component => {
|
|
38
|
-
warnings.push({ type: 'UNUSED_COMPONENT', message: `${component} component is unused` })
|
|
39
|
-
})
|
|
40
|
-
return warnings
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
module.exports = { verifyComponents, analyze }
|