boxwood 0.57.2 → 0.59.1

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.
Files changed (46) hide show
  1. package/README.md +0 -126
  2. package/package.json +10 -11
  3. package/src/Linter.js +11 -3
  4. package/src/Statistics.js +0 -4
  5. package/src/bundlers/esbuild/index.js +55 -0
  6. package/src/bundlers/esbuild/plugins/css.js +40 -0
  7. package/src/bundlers/esbuild/plugins/html.js +27 -0
  8. package/src/bundlers/esbuild/plugins/image.js +38 -0
  9. package/src/bundlers/esbuild/plugins/resolve.js +11 -0
  10. package/src/bundlers/esbuild/plugins/yaml.js +38 -0
  11. package/src/bundlers/esbuild/utilities/asset.js +19 -0
  12. package/src/compilers/html/Renderer.js +32 -28
  13. package/src/compilers/js/Compiler/index.js +7 -3
  14. package/src/optimizers/html.js +5 -0
  15. package/src/plugins/InlinePlugin/css.js +2 -3
  16. package/src/plugins/ScopedStylesPlugin/css.js +2 -2
  17. package/src/plugins/ScopedStylesPlugin/index.js +12 -1
  18. package/src/render.js +5 -3
  19. package/src/tags/img.js +1 -8
  20. package/src/tags/index.js +0 -2
  21. package/src/tags/script/index.js +1 -19
  22. package/src/transpilers/css/index.js +34 -0
  23. package/src/transpilers/{expression.js → html/expression.js} +43 -22
  24. package/src/transpilers/{html.js → html/index.js} +16 -7
  25. package/src/transpilers/html/node.js +244 -0
  26. package/src/transpilers/{tags → html/tags}/doctype.js +0 -0
  27. package/src/transpilers/{tags → html/tags}/import.js +0 -0
  28. package/src/transpilers/{tags → html/tags}/index.js +2 -1
  29. package/src/transpilers/{tags → html/tags}/partial.js +1 -1
  30. package/src/transpilers/html/tags/slot.js +7 -0
  31. package/src/utilities/collect.js +6 -23
  32. package/src/utilities/convert.js +7 -10
  33. package/src/utilities/errors.js +0 -8
  34. package/src/utilities/node.js +2 -32
  35. package/src/utilities/options.js +0 -11
  36. package/src/utilities/string.js +8 -9
  37. package/src/vdom/browser/render.js +6 -0
  38. package/src/vdom/nodes.js +4 -1
  39. package/src/vdom/server/render.js +10 -2
  40. package/src/vdom/tag.js +1 -1
  41. package/src/bundlers/esbuild.js +0 -75
  42. package/src/plugins/RoutesPlugin/index.js +0 -29
  43. package/src/tags/svg.js +0 -18
  44. package/src/transpilers/node.js +0 -139
  45. package/src/utilities/css.js +0 -64
  46. package/src/utilities/routes.js +0 -69
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const { parse, walk, generate } = require('css-tree')
4
- const hash = require('string-hash')
4
+ const { hash } = require('../../utilities/string')
5
5
  const { normalizeNewline } = require('../../utilities/string')
6
6
 
7
7
  function addScopeToCssSelectors (input, scopes) {
8
8
  const content = normalizeNewline(input).trim()
9
- const id = `scope-${hash(content)}`
9
+ const id = hash(content)
10
10
  const tree = parse(content)
11
11
  const keyframes = {}
12
12
  walk(tree, node => {
@@ -3,6 +3,7 @@
3
3
  const Plugin = require('../Plugin')
4
4
  const { addScopeToCssSelectors } = require('./css')
5
5
  const { addScopeToHtmlClassAttribute, addClassAttributeWithScopeToHtmlTag } = require('./html')
6
+ const { transpile: transpileCss, getSelectors } = require('../../transpilers/css')
6
7
 
7
8
  class ScopedStylesPlugin extends Plugin {
8
9
  constructor () {
@@ -14,7 +15,17 @@ class ScopedStylesPlugin extends Plugin {
14
15
  this.scopes[this.depth] = []
15
16
  }
16
17
 
17
- prerun ({ tag, keys, children, attributes }) {
18
+ prerun ({ fragment, tag, keys, assets, children, attributes }) {
19
+ if (tag === 'import') {
20
+ const from = attributes.find(attribute => attribute.key === 'from')
21
+ if (from && from.value.endsWith('.css')) {
22
+ fragment.tagName = 'var'
23
+ const { key } = attributes[0]
24
+ /* do we need a better check here? */
25
+ const asset = assets.find(asset => asset.name === key)
26
+ fragment.attributes = [{ key, value: getSelectors(transpileCss(asset.source)) }]
27
+ }
28
+ }
18
29
  if (tag === 'style' && keys.includes('scoped')) {
19
30
  children.forEach(node => {
20
31
  node.content = addScopeToCssSelectors(node.content, this.scopes[this.depth])
package/src/render.js CHANGED
@@ -4,11 +4,12 @@ const { readFile } = require('fs')
4
4
  const { dirname } = require('path')
5
5
  const { promisify } = require('util')
6
6
  const { print } = require('./utilities/log')
7
+ const { optimize } = require('./optimizers/html')
7
8
 
8
9
  const read = promisify(readFile)
9
10
 
10
11
  function createRender ({
11
- compilerOptions = {},
12
+ compilerOptions = { paths: [] },
12
13
  globals = {},
13
14
  cacheEnabled = true,
14
15
  log = false
@@ -32,8 +33,9 @@ function createRender ({
32
33
  const template = await compileFile(path)
33
34
  const params = typeof globals === 'function' ? globals(path, options) : globals
34
35
  const html = template({ ...params, ...options }, escape)
35
- if (callback) return callback(null, html)
36
- return html
36
+ const optimizedHtml = optimize(html)
37
+ if (callback) return callback(null, optimizedHtml)
38
+ return optimizedHtml
37
39
  } catch (exception) {
38
40
  if (callback) return callback(exception)
39
41
  return exception.message
package/src/tags/img.js CHANGED
@@ -1,17 +1,10 @@
1
1
  'use strict'
2
2
 
3
- const { convertAttributeToInlineStyle, convertSizeToWidthAndHeight, setAutoDimension } = require('../utilities/css')
4
3
  const { findAsset } = require('../utilities/files')
5
4
  const { getExtension, getBase64Extension, normalizeNewline } = require('../utilities/string')
6
5
 
7
6
  module.exports = function ({ fragment, attrs, keys, assets, options }) {
8
- convertAttributeToInlineStyle(attrs, ['fluid', 'responsive'], 'max-width: 100%; height: auto;')
9
- convertAttributeToInlineStyle(attrs, ['cover'], 'object-fit: cover; object-position: right top;')
10
- convertAttributeToInlineStyle(attrs, ['contain'], 'object-fit: contain; object-position: center;')
11
- convertSizeToWidthAndHeight(attrs)
12
- setAutoDimension(attrs, keys, 'width', assets, options)
13
- setAutoDimension(attrs, keys, 'height', assets, options)
14
- if (keys.includes('inline') || options.inline.includes('images')) {
7
+ if (keys.includes('inline')) {
15
8
  fragment.attributes = fragment.attributes.map(attr => {
16
9
  if (attr.key === 'inline') return null
17
10
  if (attr.key === 'src') {
package/src/tags/index.js CHANGED
@@ -19,7 +19,6 @@ const slotTag = require('./slot')
19
19
  const imgTag = require('./img')
20
20
  const scriptTag = require('./script')
21
21
  const styleTag = require('./style')
22
- const svgTag = require('./svg')
23
22
  const templateTag = require('./template')
24
23
  const translateTag = require('./translate')
25
24
  const translationTag = require('./translation')
@@ -46,7 +45,6 @@ module.exports = {
46
45
  img: imgTag,
47
46
  script: scriptTag,
48
47
  style: styleTag,
49
- svg: svgTag,
50
48
  template: templateTag,
51
49
  translate: translateTag,
52
50
  translation: translationTag,
@@ -10,7 +10,7 @@ const scoped = require('./scoped')
10
10
  const script = { scoped }
11
11
 
12
12
  module.exports = async function ({ tree, keys, attrs, fragment, assets, variables, promises, warnings, filters, translations, languages, append, scripts, options }) {
13
- if (keys.includes('inline') || options.inline.includes('scripts')) {
13
+ if (keys.includes('inline')) {
14
14
  if (keys.includes('src')) {
15
15
  const { value: path } = attrs.find(attr => attr.key === 'src')
16
16
  const asset = findAsset(path, assets, options)
@@ -24,24 +24,6 @@ module.exports = async function ({ tree, keys, attrs, fragment, assets, variable
24
24
  ast.each('VariableDeclarator', node => variables.push(node.id.name))
25
25
  ast.body.forEach(node => tree.append(node))
26
26
  }
27
- } else if (keys.includes('polyfills')) {
28
- let content = ''
29
- const { value } = attrs.find(attr => attr.key === 'polyfills')
30
- const ast = new AbstractSyntaxTree(value)
31
- const polyfills = AbstractSyntaxTree.serialize(ast.body[0].expression)
32
- polyfills.forEach(polyfill => {
33
- const asset = findAsset(polyfill, assets, options)
34
- if (asset) {
35
- content += asset.source
36
- } else {
37
- warnings.push({ type: 'POLYFILL_NOT_FOUND', message: `${polyfill} polyfill not found` })
38
- }
39
- })
40
- fragment.children.forEach(node => {
41
- node.used = true
42
- content += node.content
43
- })
44
- scripts.push(content)
45
27
  } else if (keys.includes('scoped')) {
46
28
  const leaf = fragment.children[0]
47
29
  if (!leaf) return
@@ -0,0 +1,34 @@
1
+ 'use strict'
2
+
3
+ const { parse, walk, generate } = require('css-tree')
4
+ const createHash = require('string-hash')
5
+ const { camelize } = require('pure-utilities/string')
6
+
7
+ function transpile (source) {
8
+ const hash = createHash(source)
9
+ const tree = parse(source)
10
+ walk(tree, node => {
11
+ if (node.type === 'ClassSelector') {
12
+ node.name = `${camelize(node.name)}-${hash}`
13
+ }
14
+ if (node.type === 'TypeSelector') {
15
+ node.type = 'ClassSelector'
16
+ node.name = `${camelize(node.name)}-${hash}`
17
+ }
18
+ })
19
+ return generate(tree)
20
+ }
21
+
22
+ function getSelectors (source) {
23
+ const tree = parse(source)
24
+ const selectors = {}
25
+ walk(tree, node => {
26
+ if (node.type === 'ClassSelector') {
27
+ const [key] = node.name.split('-')
28
+ selectors[key] = node.name
29
+ }
30
+ })
31
+ return selectors
32
+ }
33
+
34
+ module.exports = { transpile, getSelectors }
@@ -1,7 +1,7 @@
1
1
  const AbstractSyntaxTree = require('abstract-syntax-tree')
2
2
  const { unique } = require('pure-utilities/array')
3
- const lexer = require('../utilities/lexer')
4
- const { BUILT_IN_VARIABLES } = require('../utilities/enum')
3
+ const lexer = require('../../utilities/lexer')
4
+ const { BUILT_IN_VARIABLES } = require('../../utilities/enum')
5
5
 
6
6
  const { ArrayExpression, CallExpression, Identifier, Literal, ObjectPattern, Property, toBinaryExpression } = AbstractSyntaxTree
7
7
 
@@ -36,37 +36,58 @@ function findParams (body) {
36
36
  return unique(nodes.map(node => node.name))
37
37
  }
38
38
 
39
+ function findChildren (body) {
40
+ const tree = new AbstractSyntaxTree(body)
41
+ const node = tree.first('Identifier[name="__children__"]')
42
+ return node
43
+ }
44
+
39
45
  function deduceParams (body) {
40
46
  const params = findParams(body)
41
- if (params.length === 0) {
42
- return []
47
+ const children = findChildren(body)
48
+ return [
49
+ params.length > 0
50
+ ? new ObjectPattern({
51
+ properties: params.map(param => {
52
+ const node = new Identifier(param)
53
+ return new Property({
54
+ key: node,
55
+ value: node,
56
+ kind: 'init',
57
+ computed: false,
58
+ method: false,
59
+ shorthand: true
60
+ })
61
+ })
62
+ })
63
+ : children && new Identifier('__UNUSED_PARAM__'),
64
+ children
65
+ ].filter(Boolean)
66
+ }
67
+
68
+ function normalizeTokenValue (value) {
69
+ if (value.trim().startsWith('{') && value.trim().endsWith('}')) {
70
+ return `(${value})`
43
71
  }
44
- return new ObjectPattern({
45
- properties: params.map(param => {
46
- const node = new Identifier(param)
47
- return new Property({
48
- key: node,
49
- value: node,
50
- kind: 'init',
51
- computed: false,
52
- method: false,
53
- shorthand: true
54
- })
55
- })
56
- })
72
+ return value
57
73
  }
58
74
 
59
- function transpileExpression (source) {
75
+ function transpileExpression (source, escape = true) {
60
76
  const tokens = lexer(source)
61
77
  const nodes = tokens.map(token => {
62
78
  if (token.type === 'expression') {
79
+ token.value = normalizeTokenValue(token.value)
63
80
  const tree = new AbstractSyntaxTree(token.value)
64
81
  const { expression } = tree.first('ExpressionStatement')
65
82
  markNodes(expression)
66
- return new CallExpression({
67
- callee: new Identifier({ name: 'escape' }),
68
- arguments: [expression]
69
- })
83
+ if (escape) {
84
+ return new CallExpression({
85
+ callee: new Identifier({ name: 'escape' }),
86
+ arguments: [expression]
87
+ })
88
+ } else {
89
+ return expression
90
+ }
70
91
  }
71
92
  if (token.type === 'text') {
72
93
  return new Literal({ value: token.value })
@@ -2,12 +2,14 @@
2
2
 
3
3
  const AbstractSyntaxTree = require('abstract-syntax-tree')
4
4
  const { camelize } = require('pure-utilities/string')
5
- const { parse, walk } = require('../utilities/html')
6
- const { findAttributeByKey } = require('../utilities/attributes')
7
5
  const { deduceParams } = require('./expression')
8
- const BoxModelPlugin = require('../plugins/BoxModelPlugin')
9
- const CurlyStylesPlugin = require('../plugins/CurlyStylesPlugin')
6
+ const BoxModelPlugin = require('../../plugins/BoxModelPlugin')
7
+ const CurlyStylesPlugin = require('../../plugins/CurlyStylesPlugin')
8
+ const { parse, walk } = require('../../utilities/html')
9
+ const { findAttributeByKey } = require('../../utilities/attributes')
10
10
  const { transpileNode } = require('./node')
11
+ // TODO: initial transpilation, move to a separate dir? or inline here after removing the outdated compiler
12
+ const Transpiler = require('../../compilers/html/Transpiler')
11
13
 
12
14
  const {
13
15
  ArrayExpression,
@@ -18,6 +20,10 @@ const {
18
20
  Literal
19
21
  } = AbstractSyntaxTree
20
22
 
23
+ function pathToIdentifier (path) {
24
+ return `__${camelize(path).replace('.', 'Dot')}__`
25
+ }
26
+
21
27
  const program = (body) => {
22
28
  const params = deduceParams(body)
23
29
  return AbstractSyntaxTree.program(
@@ -35,7 +41,7 @@ function createComponentImportDeclarations (imports) {
35
41
  return new ImportDeclaration({
36
42
  specifiers: [
37
43
  new ImportDefaultSpecifier({
38
- local: new Identifier(`__${camelize(path)}__`)
44
+ local: new Identifier(pathToIdentifier(path))
39
45
  })
40
46
  ],
41
47
  source: new Literal(path)
@@ -112,7 +118,6 @@ function prerunPlugins (tree, plugins) {
112
118
 
113
119
  function body (tree, options) {
114
120
  const plugins = [
115
- // new RoutesPlugin(options, errors),
116
121
  // new DataPlugin(),
117
122
  // new InlinePlugin(),
118
123
  new BoxModelPlugin(options),
@@ -132,6 +137,8 @@ function body (tree, options) {
132
137
  }
133
138
 
134
139
  function transpile (source, options) {
140
+ source = new Transpiler().transpile(source)
141
+
135
142
  const tree = parse(source)
136
143
  const outputTree = new AbstractSyntaxTree(
137
144
  program(body(tree, options))
@@ -147,7 +154,7 @@ function transpile (source, options) {
147
154
  if (node.type === 'CallExpression' && node.callee.name === 'tag') {
148
155
  imports.forEach(leaf => {
149
156
  if (node.arguments[0].value === leaf.tag) {
150
- node.callee.name = `__${camelize(leaf.path)}__`
157
+ node.callee.name = pathToIdentifier(leaf.path)
151
158
  node.arguments.shift()
152
159
  }
153
160
  })
@@ -155,6 +162,8 @@ function transpile (source, options) {
155
162
  })
156
163
  }
157
164
 
165
+ // console.log(outputTree.source)
166
+
158
167
  imports = deducePartials(outputTree)
159
168
  if (imports.length > 0) {
160
169
  outputTree.prepend(createPartialImportDeclarations(imports))
@@ -0,0 +1,244 @@
1
+ 'use strict'
2
+
3
+ const AbstractSyntaxTree = require('abstract-syntax-tree')
4
+ const { transpileExpression } = require('./expression')
5
+ const tags = require('./tags')
6
+
7
+ const {
8
+ ArrayExpression,
9
+ BlockStatement,
10
+ CallExpression,
11
+ Identifier,
12
+ IfStatement,
13
+ Literal,
14
+ ObjectExpression,
15
+ Property,
16
+ ReturnStatement,
17
+ TryStatement,
18
+ CatchClause,
19
+ UnaryExpression
20
+ } = AbstractSyntaxTree
21
+
22
+ let FOR_LOOP_INDEX = 0
23
+
24
+ function mapForStatement (htmlNode, parent, index) {
25
+ FOR_LOOP_INDEX++
26
+ const [node] = AbstractSyntaxTree.template(`
27
+ (function () {
28
+ var __output__ = [];
29
+ for (var <%= index %> = 0, <%= length %> = <%= array %>.length; <%= index %> < <%= length %>; <%= index %>++) {
30
+ var <%= item %> = <%= array %>[<%= index %>];
31
+ __output__.push(%= children %);
32
+ }
33
+ return __output__;
34
+ })();
35
+ `, {
36
+ index: new Identifier(`__i${FOR_LOOP_INDEX}__`),
37
+ length: new Identifier(`__ilen${FOR_LOOP_INDEX}__`),
38
+ item: new Identifier(htmlNode.attributes[0].key),
39
+ // TODO we should not mark params which were created on the fly, e.g. for nested loops
40
+ array: new Identifier({ name: htmlNode.attributes[2].key, parameter: true }),
41
+ children: htmlNode.children.map((child, index) =>
42
+ transpileNode({ node: child, parent: htmlNode, index: index })
43
+ )
44
+ })
45
+ return node.expression
46
+ }
47
+
48
+ function transpileNode ({ node: htmlNode, parent, index }) {
49
+ function mapAttributes (attributes) {
50
+ function getAttributeValue (value) {
51
+ if (value === null) { return new Literal(true) }
52
+ return transpileExpression(value, false)
53
+ }
54
+ return attributes.length > 0
55
+ ? new ObjectExpression({
56
+ properties: attributes.map(attribute => {
57
+ return new Property({
58
+ key: new Identifier(attribute.key),
59
+ value: getAttributeValue(attribute.value),
60
+ kind: 'init',
61
+ computed: false,
62
+ method: false,
63
+ shorthand: false
64
+ })
65
+ })
66
+ })
67
+ : new ObjectExpression({ properties: [] })
68
+ }
69
+ function mapChildren (children) {
70
+ return children.length > 0 && new ArrayExpression({
71
+ elements: children.map((childNode, index) => {
72
+ return transpileNode({ node: childNode, parent: children, index })
73
+ }).filter(Boolean)
74
+ })
75
+ }
76
+ function mapIfStatement (htmlNode, parent, index) {
77
+ function mapAttributesToTest ({ attributes }) {
78
+ if (attributes.length === 1) {
79
+ if (attributes[0].key === 'true' || attributes[0].key === '{true}') {
80
+ return new Literal(true)
81
+ } else if (attributes[0].key === 'false' || attributes[0].key === '{false}') {
82
+ return new Literal(false)
83
+ } else {
84
+ return new Identifier({ name: attributes[0].key, parameter: true })
85
+ }
86
+ }
87
+ throw new Error('Unsupported length of attributes (if)')
88
+ }
89
+
90
+ function mapCurrentNodeToConsequent (htmlNode) {
91
+ const body = htmlNode.children.map((node, index) => transpileNode({ node, parent: htmlNode.children, index })).filter(Boolean)
92
+ const argument = body.pop()
93
+ body.push(new ReturnStatement({ argument }))
94
+ return new BlockStatement({ body })
95
+ }
96
+
97
+ function mapNextNodeToAlternate (nextNode) {
98
+ if (nextNode && nextNode.tagName === 'else') {
99
+ const body = nextNode.children.map((node, index) => transpileNode({ node, parent: nextNode.children, index })).filter(Boolean)
100
+ const argument = body.pop()
101
+ body.push(new ReturnStatement({ argument }))
102
+ return new BlockStatement({ body })
103
+ } else if (nextNode && nextNode.tagName === 'elseif') {
104
+ return mapIfStatement(nextNode, parent, index + 1)
105
+ }
106
+ return new BlockStatement({
107
+ body: [
108
+ new ReturnStatement({
109
+ argument: new Literal('')
110
+ })
111
+ ]
112
+ })
113
+ }
114
+
115
+ return new IfStatement({
116
+ test: mapAttributesToTest(htmlNode),
117
+ consequent: mapCurrentNodeToConsequent(htmlNode),
118
+ alternate: mapNextNodeToAlternate(parent[index + 1])
119
+ })
120
+ }
121
+
122
+ function mapUnlessStatement (htmlNode, parent, index) {
123
+ function mapAttributesToTest ({ attributes }) {
124
+ if (attributes.length === 1) {
125
+ if (attributes[0].key === 'true' || attributes[0].key === '{true}') {
126
+ return new Literal(true)
127
+ } else if (attributes[0].key === 'false' || attributes[0].key === '{false}') {
128
+ return new Literal(false)
129
+ } else {
130
+ return new Identifier({ name: attributes[0].key, parameter: true })
131
+ }
132
+ }
133
+ throw new Error('Unsupported length of attributes (unless)')
134
+ }
135
+
136
+ function mapCurrentNodeToConsequent (htmlNode) {
137
+ const body = htmlNode.children.map((node, index) => transpileNode({ node, parent: htmlNode.children, index })).filter(Boolean)
138
+ const argument = body.pop()
139
+ body.push(new ReturnStatement({ argument }))
140
+ return new BlockStatement({ body })
141
+ }
142
+
143
+ function mapNextNodeToAlternate (nextNode) {
144
+ if (nextNode && nextNode.tagName === 'else') {
145
+ const body = nextNode.children.map((node, index) => transpileNode({ node, parent: nextNode.children, index })).filter(Boolean)
146
+ const argument = body.pop()
147
+ body.push(new ReturnStatement({ argument }))
148
+ return new BlockStatement({ body })
149
+ } else if (nextNode && nextNode.tagName === 'elseunless') {
150
+ return mapUnlessStatement(nextNode, parent, index + 1)
151
+ } else if (nextNode && nextNode.tagName === 'elseif') {
152
+ return mapIfStatement(nextNode, parent, index + 1)
153
+ }
154
+ return new BlockStatement({
155
+ body: [
156
+ new ReturnStatement({
157
+ argument: new Literal('')
158
+ })
159
+ ]
160
+ })
161
+ }
162
+
163
+ return new IfStatement({
164
+ test: new UnaryExpression({
165
+ operator: '!',
166
+ argument: mapAttributesToTest(htmlNode),
167
+ prefix: true
168
+ }),
169
+ consequent: mapCurrentNodeToConsequent(htmlNode),
170
+ alternate: mapNextNodeToAlternate(parent[index + 1])
171
+ })
172
+ }
173
+
174
+ function mapTryStatement (htmlNode, parent, index) {
175
+ function mapCurrentNodeToBlockStatement (htmlNode) {
176
+ const body = htmlNode.children.map((node, index) => transpileNode({ node, parent: htmlNode.children, index })).filter(Boolean)
177
+ const argument = body.pop()
178
+ body.push(new ReturnStatement({ argument }))
179
+ return new BlockStatement({ body })
180
+ }
181
+
182
+ function mapNextNodeToCatchClause (nextNode) {
183
+ if (nextNode && nextNode.tagName === 'catch') {
184
+ const body = nextNode.children.map((node, index) => transpileNode({ node, parent: htmlNode.children, index })).filter(Boolean)
185
+ const argument = body.pop()
186
+ body.push(new ReturnStatement({ argument }))
187
+ return new CatchClause({
188
+ body: new BlockStatement({ body })
189
+ })
190
+ }
191
+ return null
192
+ }
193
+ return new TryStatement({
194
+ block: mapCurrentNodeToBlockStatement(htmlNode),
195
+ handler: mapNextNodeToCatchClause(parent[index + 1])
196
+ })
197
+ }
198
+
199
+ if (htmlNode.type === 'element' && htmlNode.tagName === 'if') {
200
+ const statement = mapIfStatement(htmlNode, parent, index)
201
+ const { expression } = AbstractSyntaxTree.iife(statement)
202
+ return expression
203
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'else') {
204
+ return null
205
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'elseif') {
206
+ return null
207
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'unless') {
208
+ const statement = mapUnlessStatement(htmlNode, parent, index)
209
+ const { expression } = AbstractSyntaxTree.iife(statement)
210
+ return expression
211
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'elseunless') {
212
+ return null
213
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'try') {
214
+ const statement = mapTryStatement(htmlNode, parent, index)
215
+ const { expression } = AbstractSyntaxTree.iife(statement)
216
+ return expression
217
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'catch') {
218
+ return null
219
+ } else if (htmlNode.type === 'element' && htmlNode.tagName === 'for') {
220
+ return mapForStatement(htmlNode, parent, index)
221
+ } else if (htmlNode.type === 'element') {
222
+ if (htmlNode.tagName === 'import') { return tags.import(htmlNode) }
223
+ if (htmlNode.tagName === '!doctype') { return tags.doctype() }
224
+ if (htmlNode.tagName === 'partial') { return tags.partial(htmlNode) }
225
+ if (htmlNode.tagName === 'slot') { return tags.slot(htmlNode) }
226
+ const { tagName, attributes, children } = htmlNode
227
+ const node = new CallExpression({
228
+ callee: new Identifier('tag'),
229
+ arguments: [
230
+ new Literal(tagName),
231
+ mapAttributes(attributes),
232
+ mapChildren(children)
233
+ ].filter(Boolean)
234
+ })
235
+ return node
236
+ } else if (htmlNode.type === 'text') {
237
+ const { content } = htmlNode
238
+ return transpileExpression(content)
239
+ } else if (htmlNode.type === 'comment') {
240
+ return new Literal('')
241
+ }
242
+ }
243
+
244
+ module.exports = { transpileNode }
File without changes
File without changes
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  import: require('./import'),
3
3
  doctype: require('./doctype'),
4
- partial: require('./partial')
4
+ partial: require('./partial'),
5
+ slot: require('./slot')
5
6
  }
@@ -1,6 +1,6 @@
1
1
  const AbstractSyntaxTree = require('abstract-syntax-tree')
2
2
  const { camelize } = require('pure-utilities/string')
3
- const { findAttributeByKey } = require('../../utilities/attributes')
3
+ const { findAttributeByKey } = require('../../../utilities/attributes')
4
4
 
5
5
  const { CallExpression, Identifier } = AbstractSyntaxTree
6
6
 
@@ -0,0 +1,7 @@
1
+ const AbstractSyntaxTree = require('abstract-syntax-tree')
2
+
3
+ const { Identifier } = AbstractSyntaxTree
4
+
5
+ module.exports = function slotTag (node) {
6
+ return new Identifier({ name: '__children__' })
7
+ }