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.
Files changed (139) hide show
  1. package/README.md +0 -358
  2. package/index.js +402 -4
  3. package/package.json +12 -37
  4. package/src/Bundler.js +0 -13
  5. package/src/Cache.js +0 -35
  6. package/src/Compiler.js +0 -28
  7. package/src/Importer.js +0 -142
  8. package/src/Optimizer.js +0 -96
  9. package/src/Scope.js +0 -20
  10. package/src/Statistics.js +0 -58
  11. package/src/bundlers/esbuild/index.js +0 -55
  12. package/src/bundlers/esbuild/plugins/css.js +0 -40
  13. package/src/bundlers/esbuild/plugins/html.js +0 -27
  14. package/src/bundlers/esbuild/plugins/image.js +0 -38
  15. package/src/bundlers/esbuild/plugins/resolve.js +0 -11
  16. package/src/bundlers/esbuild/plugins/yaml.js +0 -38
  17. package/src/bundlers/esbuild/utilities/asset.js +0 -19
  18. package/src/bundlers/rollup.js +0 -38
  19. package/src/compile.js +0 -6
  20. package/src/compilers/any/Compiler.js +0 -16
  21. package/src/compilers/compile.js +0 -17
  22. package/src/compilers/html/Analyzer.js +0 -24
  23. package/src/compilers/html/Compiler.js +0 -47
  24. package/src/compilers/html/Generator.js +0 -19
  25. package/src/compilers/html/Parser.js +0 -11
  26. package/src/compilers/html/Preprocessor.js +0 -130
  27. package/src/compilers/html/Renderer.js +0 -167
  28. package/src/compilers/html/Transpiler.js +0 -76
  29. package/src/compilers/js/Bundler.js +0 -84
  30. package/src/compilers/js/Compiler/index.js +0 -27
  31. package/src/conditions/isEqual.js +0 -5
  32. package/src/lexers/html.js +0 -49
  33. package/src/lexers/internal.js +0 -49
  34. package/src/linters/html/bracket.js +0 -36
  35. package/src/linters/html/component.js +0 -43
  36. package/src/linters/html/import.js +0 -35
  37. package/src/linters/html/index.js +0 -19
  38. package/src/linters/html/tag.js +0 -36
  39. package/src/optimizers/html.js +0 -15
  40. package/src/plugins/BoxModelPlugin/index.js +0 -109
  41. package/src/plugins/CurlyStylesPlugin/index.js +0 -39
  42. package/src/plugins/DataPlugin/index.js +0 -53
  43. package/src/plugins/InlinePlugin/css.js +0 -131
  44. package/src/plugins/InlinePlugin/index.js +0 -39
  45. package/src/plugins/InternationalizationPlugin/index.js +0 -111
  46. package/src/plugins/Plugin.js +0 -22
  47. package/src/plugins/ScopedStylesPlugin/css.js +0 -56
  48. package/src/plugins/ScopedStylesPlugin/html.js +0 -112
  49. package/src/plugins/ScopedStylesPlugin/index.js +0 -48
  50. package/src/plugins/SwappedStylesPlugin/index.js +0 -20
  51. package/src/render.js +0 -48
  52. package/src/tags/case.js +0 -28
  53. package/src/tags/catch.js +0 -17
  54. package/src/tags/data.js +0 -7
  55. package/src/tags/default.js +0 -20
  56. package/src/tags/doctype.js +0 -8
  57. package/src/tags/else.js +0 -18
  58. package/src/tags/elseif.js +0 -25
  59. package/src/tags/elseunless.js +0 -30
  60. package/src/tags/font.js +0 -37
  61. package/src/tags/for.js +0 -90
  62. package/src/tags/foreach.js +0 -80
  63. package/src/tags/if.js +0 -19
  64. package/src/tags/img.js +0 -25
  65. package/src/tags/index.js +0 -53
  66. package/src/tags/link.js +0 -14
  67. package/src/tags/script/index.js +0 -83
  68. package/src/tags/script/scoped.js +0 -26
  69. package/src/tags/slot.js +0 -9
  70. package/src/tags/style.js +0 -9
  71. package/src/tags/switch.js +0 -13
  72. package/src/tags/template.js +0 -22
  73. package/src/tags/translate.js +0 -22
  74. package/src/tags/translation.js +0 -38
  75. package/src/tags/try.js +0 -17
  76. package/src/tags/unless.js +0 -24
  77. package/src/tags/var.js +0 -32
  78. package/src/transpilers/css/index.js +0 -34
  79. package/src/transpilers/html/expression.js +0 -101
  80. package/src/transpilers/html/index.js +0 -189
  81. package/src/transpilers/html/node.js +0 -46
  82. package/src/transpilers/html/tags/any.js +0 -53
  83. package/src/transpilers/html/tags/comment.js +0 -7
  84. package/src/transpilers/html/tags/doctype.js +0 -6
  85. package/src/transpilers/html/tags/for.js +0 -30
  86. package/src/transpilers/html/tags/if.js +0 -55
  87. package/src/transpilers/html/tags/import.js +0 -7
  88. package/src/transpilers/html/tags/index.js +0 -13
  89. package/src/transpilers/html/tags/partial.js +0 -17
  90. package/src/transpilers/html/tags/slot.js +0 -7
  91. package/src/transpilers/html/tags/text.js +0 -6
  92. package/src/transpilers/html/tags/try.js +0 -30
  93. package/src/transpilers/html/tags/unless.js +0 -58
  94. package/src/transpilers/html/utilities/path.js +0 -9
  95. package/src/utilities/action.js +0 -208
  96. package/src/utilities/array.js +0 -80
  97. package/src/utilities/assets.js +0 -18
  98. package/src/utilities/ast.js +0 -13
  99. package/src/utilities/attributes.js +0 -23
  100. package/src/utilities/collect.js +0 -404
  101. package/src/utilities/conditions.js +0 -159
  102. package/src/utilities/convert.js +0 -359
  103. package/src/utilities/data.js +0 -55
  104. package/src/utilities/enum.js +0 -103
  105. package/src/utilities/errors.js +0 -96
  106. package/src/utilities/factory.js +0 -237
  107. package/src/utilities/files.js +0 -55
  108. package/src/utilities/filters.js +0 -140
  109. package/src/utilities/globals.js +0 -43
  110. package/src/utilities/html.js +0 -60
  111. package/src/utilities/inline.js +0 -200
  112. package/src/utilities/js.js +0 -15
  113. package/src/utilities/keywords.js +0 -35
  114. package/src/utilities/log.js +0 -31
  115. package/src/utilities/node.js +0 -149
  116. package/src/utilities/object.js +0 -8
  117. package/src/utilities/optimize.js +0 -268
  118. package/src/utilities/options.js +0 -99
  119. package/src/utilities/request.js +0 -13
  120. package/src/utilities/string.js +0 -144
  121. package/src/utilities/style.js +0 -15
  122. package/src/utilities/translations.js +0 -78
  123. package/src/utilities/url.js +0 -24
  124. package/src/vdom/browser/app.js +0 -19
  125. package/src/vdom/browser/diff.js +0 -104
  126. package/src/vdom/browser/index.js +0 -15
  127. package/src/vdom/browser/mount.js +0 -10
  128. package/src/vdom/browser/render.js +0 -66
  129. package/src/vdom/browser/replace.js +0 -7
  130. package/src/vdom/node.js +0 -10
  131. package/src/vdom/nodes.js +0 -116
  132. package/src/vdom/server/State.js +0 -21
  133. package/src/vdom/server/boxwood.js +0 -5
  134. package/src/vdom/server/index.js +0 -19
  135. package/src/vdom/server/render.js +0 -66
  136. package/src/vdom/tag.js +0 -33
  137. package/src/vdom/utilities/classes.js +0 -22
  138. package/src/vdom/utilities/css.js +0 -17
  139. package/src/vdom/utilities/escape.js +0 -50
@@ -1,35 +0,0 @@
1
- const { duplicates } = require('pure-utilities/array')
2
- const { getAssetPaths, isImageNode } = require('../../utilities/node')
3
- const { isImportTag } = require('../../utilities/string')
4
- const { getComponentNames } = require('../../utilities/attributes')
5
-
6
- function verifyImports (imports, options) {
7
- const warnings = []
8
- const allNames = []
9
- let allPaths = []
10
- imports.forEach(node => {
11
- if (isImportTag(node.tagName)) {
12
- const names = getComponentNames(node.attributes)
13
- names.forEach(name => {
14
- if (allNames.includes(name)) {
15
- warnings.push({ message: `Component name duplicate: ${name}`, type: 'COMPONENT_NAME_DUPLICATE' })
16
- } else {
17
- allNames.push(name)
18
- }
19
- })
20
- }
21
- })
22
- imports.forEach(node => {
23
- let assetPaths = getAssetPaths(node)
24
- if (isImageNode(node, options)) {
25
- assetPaths = assetPaths.filter(item => !assetPaths.includes(item))
26
- }
27
- allPaths = allPaths.concat(assetPaths)
28
- })
29
- duplicates(allPaths).forEach(duplicate => {
30
- warnings.push({ message: `Component path duplicate: ${duplicate}`, type: 'COMPONENT_PATH_DUPLICATE' })
31
- })
32
- return warnings
33
- }
34
-
35
- module.exports = { verifyImports }
@@ -1,19 +0,0 @@
1
- 'use strict'
2
-
3
- const { parse } = require('../../utilities/html')
4
- const { verifyBrackets } = require('./bracket')
5
- const { verifyTags } = require('./tag')
6
- const { verifyComponents } = require('./component')
7
- const { verifyImports } = require('./import')
8
-
9
- function lint (source, imports = [], options = {}) {
10
- const tree = parse(source)
11
- return [
12
- ...verifyBrackets(source),
13
- ...verifyTags(tree),
14
- ...verifyComponents(tree),
15
- ...verifyImports(imports, options)
16
- ]
17
- }
18
-
19
- module.exports = { lint }
@@ -1,36 +0,0 @@
1
- const walk = require('himalaya-walk')
2
- const { analyze } = require('./component')
3
-
4
- const ANCHOR_TAG = 'a'
5
- const IMAGE_TAG = 'img'
6
-
7
- function isExternalUrl (url) {
8
- if (!url) { return false }
9
- return url.startsWith('http://') || url.startsWith('https://')
10
- }
11
-
12
- function verifyTags (tree) {
13
- const warnings = []
14
- const { components } = analyze(tree)
15
- walk(tree, node => {
16
- if (node.tagName === ANCHOR_TAG && !components.includes(ANCHOR_TAG)) {
17
- const href = node.attributes.find(attribute => attribute.key === 'href')
18
- if (href && isExternalUrl(href.value)) {
19
- const rel = node.attributes.find(attribute => attribute.key === 'rel')
20
- if (!rel) {
21
- warnings.push({ message: `${ANCHOR_TAG} tag with external href should have a rel attribute (e.g. rel="noopener")`, type: 'REL_ATTRIBUTE_MISSING' })
22
- }
23
- }
24
- }
25
-
26
- if (node.tagName === IMAGE_TAG && !components.includes(IMAGE_TAG)) {
27
- const alt = node.attributes.find(attribute => attribute.key === 'alt' || attribute.key.startsWith('alt|'))
28
- if (!alt) {
29
- warnings.push({ message: `${IMAGE_TAG} tag should have an alt attribute`, type: 'ALT_ATTRIBUTE_MISSING' })
30
- }
31
- }
32
- })
33
- return warnings
34
- }
35
-
36
- module.exports = { verifyTags }
@@ -1,15 +0,0 @@
1
- const { minify } = require('html-minifier')
2
-
3
- function optimize (html) {
4
- return minify(html.trim(), {
5
- collapseWhitespace: true,
6
- conservativeCollapse: true,
7
- removeComments: true,
8
- sortAttributes: true,
9
- sortClassName: true,
10
- minifyCSS: true,
11
- minifyJS: true
12
- })
13
- }
14
-
15
- module.exports = { optimize }
@@ -1,109 +0,0 @@
1
- 'use strict'
2
-
3
- const { isCurlyTag, getTagValue, isImportTag, isPartialTag } = require('../../utilities/string')
4
- const { findAttributeByKey, removeAttributeByKey } = require('../../utilities/attributes')
5
- const { isNumeric } = require('pure-conditions')
6
- const AbstractSyntaxTree = require('abstract-syntax-tree')
7
- const Plugin = require('../Plugin')
8
- const { hyphenate, capitalize } = require('pure-utilities/string')
9
-
10
- const ATTRIBUTES = ['padding', 'margin', 'border']
11
- const DIRECTIONS = ['top', 'right', 'bottom', 'left']
12
- const BOX_MODEL_ATTRIBUTES = Array.from(ATTRIBUTES)
13
- for (const attribute of ATTRIBUTES) {
14
- for (const direction of DIRECTIONS) {
15
- const boxModelAttribute = attribute.concat(capitalize(direction))
16
- BOX_MODEL_ATTRIBUTES.push(boxModelAttribute, hyphenate(boxModelAttribute))
17
- }
18
- }
19
-
20
- function convert (value) {
21
- if (isCurlyTag(value)) {
22
- value = value.replace(/\s+/g, '')
23
- value = getTagValue(value)
24
- const { expression } = new AbstractSyntaxTree(`(${value})`).body[0]
25
- if (expression.type === 'ObjectExpression') {
26
- return AbstractSyntaxTree.serialize(expression)
27
- }
28
- return expression.value
29
- }
30
- return value
31
- }
32
-
33
- function getStyles (attributeKey, key, value, variables = {}) {
34
- if (value in variables) {
35
- value = variables[value]
36
- }
37
- if (attributeKey === 'border') {
38
- return `border: ${value};`
39
- }
40
- let styles = ''
41
- if (typeof value === 'object') {
42
- for (const property in value) {
43
- if (variables[value[property]]) {
44
- value[property] = variables[value[property]]
45
- }
46
- const suffix = getSuffix(value[property])
47
- styles += `${key}-${property}: ${value[property]}${suffix} `
48
- }
49
- styles = styles.trim()
50
- } else {
51
- const suffix = getSuffix(value)
52
- styles = `${hyphenate(key)}: ${value}${suffix}`
53
- }
54
- return styles
55
- }
56
-
57
- function getSuffix (value) {
58
- return (isNumeric(value) && Number(value) !== 0) ? 'px;' : ';'
59
- }
60
-
61
- function appendStyles (attributes, value) {
62
- const attribute = findAttributeByKey(attributes, 'style')
63
- if (attribute) {
64
- attribute.value += ` ${value}`
65
- } else {
66
- attributes.push({ key: 'style', value })
67
- }
68
- }
69
-
70
- class BoxModelPlugin extends Plugin {
71
- constructor (options = {}) {
72
- super()
73
- if (options.style) {
74
- this.variables = options.style.variables
75
- }
76
- }
77
-
78
- beforeprerun () {
79
- this.components = []
80
- }
81
-
82
- prerun ({ tag, keys, fragment }) {
83
- const variables = this.variables
84
- function transform (key) {
85
- const attribute = findAttributeByKey(fragment.attributes, key)
86
- if (attribute) {
87
- attribute.value = convert(attribute.value)
88
- const inlineStyles = getStyles(key, attribute.key, attribute.value, variables)
89
- appendStyles(fragment.attributes, inlineStyles)
90
- removeAttributeByKey(fragment.attributes, key)
91
- }
92
- }
93
- if (isImportTag(tag)) {
94
- const name = keys[0]
95
- this.components.push(name)
96
- }
97
- if (!this.components.includes(tag) && !isPartialTag(tag)) {
98
- BOX_MODEL_ATTRIBUTES.forEach(transform)
99
- }
100
- }
101
-
102
- afterprerun () {
103
- this.components = []
104
- }
105
-
106
- run () {}
107
- }
108
-
109
- module.exports = BoxModelPlugin
@@ -1,39 +0,0 @@
1
- 'use strict'
2
-
3
- const AbstractSyntaxTree = require('abstract-syntax-tree')
4
- const Plugin = require('../Plugin')
5
- const { isCurlyTag, getTagValue } = require('../../utilities/string')
6
- const { convertObjectToStyleString } = require('../../utilities/style')
7
-
8
- class CurlyStylesPlugin extends Plugin {
9
- constructor () {
10
- super()
11
- this.scopes = []
12
- }
13
-
14
- prerun ({ keys, fragment, attrs }) {
15
- function inline (name) {
16
- if (keys.includes(name)) {
17
- const attr = attrs.find(attr => attr.key === name)
18
- if (isCurlyTag(attr.value)) {
19
- try {
20
- const expression = getTagValue(attr.value)
21
- const tree = new AbstractSyntaxTree(`(${expression})`)
22
- const object = AbstractSyntaxTree.serialize(tree.first('ObjectExpression'))
23
- attr.key = 'style'
24
- attr.value = convertObjectToStyleString(object)
25
- } catch (exception) {
26
- // TODO implement
27
- }
28
- } else {
29
- attr.key = 'style'
30
- }
31
- }
32
- }
33
-
34
- inline('style')
35
- inline('css')
36
- }
37
- }
38
-
39
- module.exports = CurlyStylesPlugin
@@ -1,53 +0,0 @@
1
- const Plugin = require('../Plugin')
2
- const { parseData, getDataFormat } = require('../../utilities/data')
3
- const { isPlainObject } = require('pure-conditions')
4
- const { optimizeNode } = require('../../utilities/optimize')
5
- const { createTranslationError } = require('../../utilities/errors')
6
- const CODE_TAGS = ['style', 'script']
7
-
8
- class DataPlugin extends Plugin {
9
- beforeprerun () {
10
- this.variables = []
11
- }
12
-
13
- prerun ({ tag, fragment, keys, errors, stack, pass }) {
14
- if (pass !== 'renderer') return null
15
- // TODO right data must be defined above usage
16
- // consider changing interface of plugins
17
- // to allow having 2 passes of walk instead of just one
18
- // it could be declarative, e.g. new Plugin({ passes: 2 })
19
- if (tag === 'data') {
20
- if (keys.length > 0) {
21
- const format = getDataFormat(keys)
22
- const { content } = fragment.children[0]
23
- const data = parseData(format, content)
24
- if (isPlainObject(data)) {
25
- for (const key in data) {
26
- if (Object.prototype.hasOwnProperty.call(data, key)) {
27
- const value = data[key]
28
- this.variables.push({ key, value })
29
- }
30
- }
31
- }
32
- } else {
33
- errors.push(createTranslationError('Data tag must specify a format (js, json or yaml).', stack))
34
- }
35
- }
36
-
37
- if (CODE_TAGS.includes(tag)) {
38
- fragment.children.forEach(node => {
39
- node.skipDataOptimization = true
40
- })
41
- }
42
-
43
- if (this.variables.length > 0 && !fragment.skipDataOptimization) {
44
- optimizeNode(fragment, this.variables, [], true)
45
- }
46
- }
47
-
48
- afterrun () {
49
- this.variables = []
50
- }
51
- }
52
-
53
- module.exports = DataPlugin
@@ -1,131 +0,0 @@
1
- const { parse, walk, generate } = require('css-tree')
2
- const { getExtension, getBase64Extension } = require('../../utilities/string')
3
- const { findAsset, isFileSupported } = require('../../utilities/files')
4
-
5
- function getBase64String (base64, path, options, isFont) {
6
- const extension = getExtension(path)
7
- const dataType = isFont ? 'data:application/font-' : 'data:image/'
8
- return [
9
- `${dataType}${getBase64Extension(extension)}`,
10
- isFont && 'charset=utf-8',
11
- `base64,${base64}`
12
- ].filter(Boolean).join(';')
13
- }
14
-
15
- function convertElementValueToBase64 ({ element, value, assets, options, isFont }) {
16
- if (!isFileSupported(value)) return
17
- const asset = findAsset(value, assets, options)
18
- if (!asset) return
19
- element.value = getBase64String(asset.base64, asset.path, options, isFont)
20
- }
21
-
22
- function inlineUrls (tree, assets, options) {
23
- walk(tree, node => {
24
- if (node.type === 'Url') {
25
- let { type, value } = node.value
26
- value = value.replace(/'|"/g, '')
27
- convertElementValueToBase64({ element: node.value, value, assets, options, isFont: type === 'Raw' })
28
- }
29
- })
30
- return tree
31
- }
32
-
33
- function cutStyles (tree) {
34
- const styles = []
35
- walk(tree, {
36
- visit: 'Rule',
37
- enter: node => {
38
- walk(node.prelude, leaf => {
39
- if (leaf.type === 'TypeSelector' || leaf.type === 'ClassSelector') {
40
- const { name } = leaf
41
- const block = generate(node.block)
42
- if (name && block) {
43
- const declaration = block
44
- .replace(/^{/, '')
45
- .replace(/}$/, '')
46
- .replace(/"/g, "'")
47
- styles.push({ type: leaf.type, name: leaf.name, declaration })
48
- node.used = true
49
- }
50
- }
51
- })
52
- }
53
- })
54
- walk(tree, {
55
- enter: (node, item, list) => {
56
- if (item && item.data && item.data.used) {
57
- list.remove(item)
58
- }
59
- }
60
- })
61
- return { styles, tree }
62
- }
63
-
64
- function updateStyleAttribute (fragment, declaration) {
65
- const styleAttribute = fragment.attributes.find(attribute => attribute.key === 'style')
66
- if (styleAttribute) {
67
- if (!styleAttribute.value.includes(declaration)) {
68
- fragment.attributes = fragment.attributes.map(attribute => {
69
- if (attribute.key === 'style') {
70
- attribute.value += ';'.concat(declaration)
71
- }
72
- return attribute
73
- })
74
- }
75
- } else {
76
- fragment.attributes.push({ key: 'style', value: declaration })
77
- }
78
- }
79
-
80
- function applyStylesInFragment (fragment, styles) {
81
- styles.filter(({ type }) => type === 'TypeSelector').forEach(style => {
82
- if (style.name === fragment.tagName) {
83
- const { declaration } = style
84
- updateStyleAttribute(fragment, declaration)
85
- }
86
- })
87
-
88
- const classAttribute = fragment.attributes.find(attribute => attribute.key === 'class')
89
- if (classAttribute) {
90
- const localStyles = classAttribute.value.split(/\s/).filter(Boolean) || []
91
- fragment.attributes = fragment.attributes
92
- .map(attribute => {
93
- if (attribute.key === 'class') {
94
- styles.filter(({ type }) => type === 'ClassSelector').forEach(({ name }) => {
95
- attribute.value = attribute.value.replace(name, '')
96
- attribute.value = attribute.value.replace(/\s+/, '')
97
- return attribute.value ? attribute : null
98
- })
99
- }
100
- return attribute
101
- })
102
- .filter(attribute => attribute.value)
103
- styles
104
- .filter(({ name, type }) => type === 'ClassSelector' && localStyles.includes(name))
105
- .forEach(({ declaration }) => {
106
- updateStyleAttribute(fragment, declaration)
107
- })
108
- }
109
- }
110
-
111
- function prepareStyles (css, assets, options) {
112
- let tree = parse(css)
113
- tree = inlineUrls(tree, assets, options)
114
- const result = cutStyles(tree)
115
- return { styles: result.styles, output: generate(result.tree) }
116
- }
117
-
118
- function removeEmptyStyleTag (fragment) {
119
- if (fragment.tagName === 'style' &&
120
- fragment.attributes.find(({ key }) => key === 'inline') &&
121
- fragment.children &&
122
- fragment.children.length === 1 &&
123
- fragment.children[0].content === ''
124
- ) {
125
- fragment.type = 'text'
126
- fragment.content = ''
127
- fragment.children = []
128
- }
129
- }
130
-
131
- module.exports = { prepareStyles, applyStylesInFragment, removeEmptyStyleTag, convertElementValueToBase64 }
@@ -1,39 +0,0 @@
1
- 'use strict'
2
-
3
- const Plugin = require('../Plugin')
4
- const { convertElementValueToBase64, prepareStyles, applyStylesInFragment, removeEmptyStyleTag } = require('./css')
5
-
6
- class InlinePlugin extends Plugin {
7
- constructor () {
8
- super()
9
- this.styles = []
10
- }
11
-
12
- beforeprerun () {
13
- this.styles = []
14
- }
15
-
16
- prerun ({ fragment, keys, assets, options }) {
17
- if (fragment.tagName === 'style' && keys.includes('inline')) {
18
- const child = fragment.children[0]
19
- const { styles, output } = prepareStyles(child.content, assets, options)
20
- styles.forEach(style => this.styles.push(style))
21
- child.content = output
22
- }
23
- }
24
-
25
- run ({ fragment, keys, assets, options }) {
26
- if (fragment.tagName === 'font' && keys.includes('inline')) {
27
- const attribute = fragment.attributes.find(attribute => attribute.key === 'from')
28
- convertElementValueToBase64({ element: attribute, value: attribute.value, assets, options, isFont: true })
29
- }
30
- if (fragment.type === 'element' && fragment.tagName !== 'style' && this.styles.length) {
31
- applyStylesInFragment(fragment, this.styles)
32
- }
33
- if (fragment.tagName === 'style') {
34
- removeEmptyStyleTag(fragment)
35
- }
36
- }
37
- }
38
-
39
- module.exports = InlinePlugin
@@ -1,111 +0,0 @@
1
- 'use strict'
2
-
3
- const Plugin = require('../Plugin')
4
- const { findAsset } = require('../../utilities/files')
5
- const hash = require('string-hash')
6
- const { parseData, getDataFormat } = require('../../utilities/data')
7
- const { createTranslationError } = require('../../utilities/errors')
8
-
9
- function validateTranslations (value, translations, languages, errors, stack) {
10
- if (value.includes('{') || value.includes('}')) return translations
11
- if (!translations[value]) {
12
- errors.push(createTranslationError(`There is no translation for the ${value} key`, stack))
13
- return translations
14
- }
15
- languages.forEach((language, index) => {
16
- if (!translations[value][index] && !translations[value][language]) errors.push(createTranslationError(`There is no translation for the ${value} key in ${language} language.`, stack))
17
- })
18
- return translations
19
- }
20
-
21
- function getExtension (path) {
22
- const values = path.split('.')
23
- return values[values.length - 1]
24
- }
25
-
26
- function isI18nTag (tag, keys) {
27
- return (tag === 'script' && keys.includes('i18n')) || tag === 'i18n'
28
- }
29
-
30
- function isDataTag (tag) {
31
- return tag === 'data'
32
- }
33
-
34
- function hasTranslateModifier (attribute) {
35
- return attribute.key.endsWith('|translate')
36
- }
37
-
38
- function getTranslationKey (key) {
39
- if (key.includes('|')) {
40
- return `${key.split('|')[0]}`
41
- }
42
- return key
43
- }
44
-
45
- class InternationalizationPlugin extends Plugin {
46
- constructor ({ translations, filters, errors }) {
47
- super()
48
- this.translations = translations
49
- this.filters = filters
50
- this.errors = errors
51
- }
52
-
53
- prerun ({ source, tag, attrs, keys, fragment, assets, stack, options }) {
54
- const id = `__scope_${hash(source)}`
55
- if (isI18nTag(tag, keys)) {
56
- fragment.used = true
57
- let leaf = fragment.children[0]
58
- if (keys.includes('from')) {
59
- const { value: path } = attrs.find(attr => attr.key === 'from')
60
- const asset = findAsset(path, assets, options)
61
- if (!asset) return
62
- leaf = { content: asset.source }
63
- leaf.used = true
64
- keys.push(getExtension(path))
65
- } else if (!leaf || !leaf.content || !leaf.content.trim()) {
66
- return this.errors.push(createTranslationError('The translation script cannot be empty', stack))
67
- }
68
- leaf.used = true
69
- const format = getDataFormat(keys)
70
- const data = parseData(format, leaf.content)
71
- for (const key in data) {
72
- if (this.translations[key]) { return this.errors.push(createTranslationError('Translation already exists', stack)) }
73
- this.translations[`${key}_${id}`] = data[key]
74
- }
75
- } else if (isDataTag(tag)) {
76
- const format = getDataFormat(keys)
77
- const leaf = fragment.children[0]
78
- const data = parseData(format, leaf.content)
79
- const { i18n } = data
80
- for (const key in i18n) {
81
- if (this.translations[key]) { return this.errors.push(createTranslationError('Translation already exists', stack)) }
82
- this.translations[`${key}_${id}`] = i18n[key]
83
- }
84
- }
85
- attrs.forEach(attr => {
86
- if (hasTranslateModifier(attr)) {
87
- attr.key = attr.key.substring(0, attr.key.indexOf('|translate'))
88
- attr.value = `{"${attr.value}_${id}"|translate(language)}`
89
- }
90
- })
91
- }
92
-
93
- run ({ source, tag, attrs, options, stack, fragment }) {
94
- const id = `__scope_${hash(source)}`
95
- if (tag === 'translate' && !fragment.scopedTranslations) {
96
- fragment.scopedTranslations = true
97
- const { languages } = options
98
- const attribute = attrs[0]
99
- if (attribute) {
100
- const { key } = attribute
101
- this.filters.push('translate')
102
- this.translations = validateTranslations(`${getTranslationKey(key)}_${id}`, this.translations, languages, this.errors, stack)
103
- attribute.key = `${key}_${id}`
104
- } else {
105
- this.errors.push(createTranslationError('Translate tag must define a key', stack))
106
- }
107
- }
108
- }
109
- }
110
-
111
- module.exports = InternationalizationPlugin
@@ -1,22 +0,0 @@
1
- 'use strict'
2
-
3
- class Plugin {
4
- constructor () {
5
- this.depth = 0
6
- }
7
-
8
- prerun (options) {}
9
- run (options) {}
10
- postrun (options) {}
11
-
12
- beforeprerun (options) {}
13
- afterprerun (options) {}
14
-
15
- beforerun (options) {}
16
- afterrun (options) {}
17
-
18
- beforepostrun (options) {}
19
- afterpostrun (options) {}
20
- }
21
-
22
- module.exports = Plugin
@@ -1,56 +0,0 @@
1
- 'use strict'
2
-
3
- const { parse, walk, generate } = require('css-tree')
4
- const { hash } = require('../../utilities/string')
5
- const { normalizeNewline } = require('../../utilities/string')
6
-
7
- function addScopeToCssSelectors (input, scopes) {
8
- const content = normalizeNewline(input).trim()
9
- const id = hash(content)
10
- const tree = parse(content)
11
- const keyframes = {}
12
- walk(tree, node => {
13
- if (node.type === 'Atrule' && node.name === 'keyframes') {
14
- const child = node.prelude.children.first()
15
- const marker = `${child.name}-${id}`
16
- keyframes[child.name] = marker
17
- child.name = marker
18
- }
19
- if (node.type === 'SelectorList') {
20
- node.children.forEach(child => {
21
- if (child.type === 'Selector') {
22
- let hasScope = false
23
- child.children.forEach(leaf => {
24
- if (leaf.type === 'ClassSelector' && !hasScope) {
25
- scopes.push({ type: 'class', name: leaf.name, id })
26
- hasScope = true
27
- } else if (leaf.type === 'TypeSelector' && !hasScope) {
28
- scopes.push({ type: 'tag', name: leaf.name, id })
29
- hasScope = true
30
- }
31
- })
32
- if (hasScope) {
33
- const node = child.children.first()
34
- if (node.type === 'TypeSelector') { child.children.shift() }
35
- child.children.unshift({ type: 'ClassSelector', loc: null, name: id })
36
- if (node.type === 'TypeSelector') { child.children.unshift(node) }
37
- }
38
- }
39
- })
40
- }
41
- })
42
- function isAnimationProperty (property) {
43
- return property === 'animation' || property === 'animation-name'
44
- }
45
- walk(tree, node => {
46
- if (node.type === 'Declaration' && isAnimationProperty(node.property)) {
47
- const child = node.value.children.first()
48
- if (keyframes[child.name]) {
49
- child.name = keyframes[child.name]
50
- }
51
- }
52
- })
53
- return generate(tree)
54
- }
55
-
56
- module.exports = { addScopeToCssSelectors }