@maizzle/framework 4.0.0-alpha.8 → 4.0.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 (84) hide show
  1. package/.editorconfig +9 -9
  2. package/.github/media/logo-dark.svg +1 -0
  3. package/.github/media/logo-light.svg +1 -0
  4. package/.github/workflows/nodejs.yml +28 -28
  5. package/LICENSE +21 -21
  6. package/README.md +42 -35
  7. package/bin/maizzle +3 -0
  8. package/package.json +91 -87
  9. package/src/commands/serve.js +15 -5
  10. package/src/generators/config.js +32 -32
  11. package/src/generators/output/index.js +4 -4
  12. package/src/generators/output/to-disk.js +208 -208
  13. package/src/generators/output/to-string.js +67 -71
  14. package/src/generators/postcss.js +29 -29
  15. package/src/generators/posthtml.js +66 -66
  16. package/src/generators/tailwindcss.js +116 -116
  17. package/src/index.js +17 -17
  18. package/src/transformers/attributeToStyle.js +90 -90
  19. package/src/transformers/baseUrl.js +69 -45
  20. package/src/transformers/extraAttributes.js +26 -26
  21. package/src/transformers/filters/defaultFilters.js +126 -0
  22. package/src/transformers/{transform.js → filters/index.js} +55 -51
  23. package/src/transformers/index.js +63 -60
  24. package/src/transformers/inlineCss.js +37 -50
  25. package/src/transformers/markdown.js +19 -19
  26. package/src/transformers/minify.js +21 -21
  27. package/src/transformers/plaintext.js +23 -23
  28. package/src/transformers/posthtmlMso.js +10 -10
  29. package/src/transformers/prettify.js +27 -20
  30. package/src/transformers/preventWidows.js +13 -13
  31. package/src/transformers/removeAttributes.js +17 -17
  32. package/src/transformers/removeInlineBackgroundColor.js +52 -52
  33. package/src/transformers/removeInlineSizes.js +41 -41
  34. package/src/transformers/removeInlinedSelectors.js +70 -71
  35. package/src/transformers/removeUnusedCss.js +40 -35
  36. package/src/transformers/replaceStrings.js +14 -14
  37. package/src/transformers/safeClassNames.js +24 -24
  38. package/src/transformers/shorthandInlineCSS.js +19 -0
  39. package/src/transformers/sixHex.js +33 -33
  40. package/src/transformers/urlParameters.js +17 -17
  41. package/src/utils/helpers.js +17 -17
  42. package/test/expected/posthtml/component.html +13 -13
  43. package/test/expected/posthtml/extend-template.html +2 -2
  44. package/test/expected/posthtml/fetch.html +5 -5
  45. package/test/expected/posthtml/layout.html +3 -3
  46. package/test/expected/transformers/atimport-in-style.html +2 -1
  47. package/test/expected/transformers/{base-image-url.html → base-url.html} +18 -2
  48. package/test/expected/transformers/filters.html +81 -0
  49. package/test/expected/transformers/preserve-transform-css.html +12 -3
  50. package/test/expected/useConfig.html +9 -9
  51. package/test/fixtures/basic.html +6 -6
  52. package/test/fixtures/posthtml/component.html +19 -19
  53. package/test/fixtures/posthtml/extend-template.html +7 -7
  54. package/test/fixtures/posthtml/fetch.html +9 -9
  55. package/test/fixtures/posthtml/layout.html +11 -11
  56. package/test/fixtures/transformers/{base-image-url.html → base-url.html} +18 -2
  57. package/test/fixtures/transformers/filters.html +87 -0
  58. package/test/fixtures/useConfig.html +9 -9
  59. package/test/stubs/assets/foo.bar +1 -1
  60. package/test/stubs/breaking/bad.html +5 -5
  61. package/test/stubs/components/component.html +5 -5
  62. package/test/stubs/config/config.js +10 -10
  63. package/test/stubs/config/config.maizzle-ci.js +10 -10
  64. package/test/stubs/data.json +14 -14
  65. package/test/stubs/events/before-create.html +1 -1
  66. package/test/stubs/layouts/basic.html +1 -1
  67. package/test/stubs/layouts/full.html +12 -12
  68. package/test/stubs/layouts/template.html +5 -5
  69. package/test/stubs/main.css +5 -5
  70. package/test/stubs/tailwind/content-source.html +1 -1
  71. package/test/stubs/tailwind/tailwind.css +3 -3
  72. package/test/stubs/template.html +10 -10
  73. package/test/stubs/templates/1.html +1 -1
  74. package/test/stubs/templates/2.test +1 -0
  75. package/test/test-config.js +19 -19
  76. package/test/test-postcss.js +8 -8
  77. package/test/test-posthtml.js +72 -66
  78. package/test/test-tailwindcss.js +117 -117
  79. package/test/test-todisk.js +42 -28
  80. package/test/test-tostring.js +148 -142
  81. package/test/test-transformers.js +78 -46
  82. package/xo.config.js +22 -22
  83. package/test/stubs/templates/2.html +0 -1
  84. package/test/stubs/templates/3.mzl +0 -1
@@ -1,66 +1,66 @@
1
- const fm = require('front-matter')
2
- const posthtml = require('posthtml')
3
- const {get, merge} = require('lodash')
4
- const fetch = require('posthtml-fetch')
5
- const layouts = require('posthtml-extend')
6
- const modules = require('posthtml-modules')
7
- const expressions = require('posthtml-expressions')
8
-
9
- module.exports = async (html, config) => {
10
- const layoutsOptions = get(config, 'build.layouts', {})
11
-
12
- const modulesOptions = get(config, 'build.components', {})
13
- // Fake `from` option so we can reference modules relatively
14
- const modulesRoot = modulesOptions.root || './'
15
- const modulesFrom = modulesOptions.from || `${modulesRoot}/fake`
16
-
17
- const posthtmlOptions = get(config, 'build.posthtml.options', {})
18
- const posthtmlPlugins = get(config, 'build.posthtml.plugins', [])
19
-
20
- const expressionsOptions = merge({strictMode: false}, get(config, 'build.posthtml.expressions', {}))
21
-
22
- const locals = merge(
23
- get(expressionsOptions, 'locals', {}),
24
- get(config, 'locals', {}),
25
- {page: config}
26
- )
27
-
28
- const fetchPlugin = fetch(
29
- merge(
30
- {
31
- expressions: merge({...expressionsOptions, locals})
32
- },
33
- get(config, 'build.posthtml.fetch', {})
34
- )
35
- )
36
-
37
- return posthtml([
38
- fetchPlugin,
39
- expressions({...expressionsOptions, locals}),
40
- layouts(
41
- merge(
42
- {
43
- strict: false,
44
- expressions: merge({...expressionsOptions, locals})
45
- },
46
- layoutsOptions
47
- )
48
- ),
49
- modules({
50
- parser: posthtmlOptions,
51
- attributeAsLocals: true,
52
- from: modulesFrom,
53
- root: modulesRoot,
54
- tag: 'component',
55
- attribute: 'src',
56
- plugins: [
57
- fetchPlugin
58
- ],
59
- locals,
60
- ...modulesOptions
61
- }),
62
- ...posthtmlPlugins
63
- ])
64
- .process(html, {...posthtmlOptions})
65
- .then(result => fm(result.html).body)
66
- }
1
+ const fm = require('front-matter')
2
+ const posthtml = require('posthtml')
3
+ const {get, merge} = require('lodash')
4
+ const fetch = require('posthtml-fetch')
5
+ const layouts = require('posthtml-extend')
6
+ const modules = require('posthtml-modules')
7
+ const expressions = require('posthtml-expressions')
8
+
9
+ module.exports = async (html, config) => {
10
+ const layoutsOptions = get(config, 'build.layouts', {})
11
+
12
+ const modulesOptions = get(config, 'build.components', {})
13
+ // Fake `from` option so we can reference modules relatively
14
+ const modulesRoot = modulesOptions.root || './'
15
+ const modulesFrom = modulesOptions.from || `${modulesRoot}/fake`
16
+
17
+ const posthtmlOptions = get(config, 'build.posthtml.options', {})
18
+ const posthtmlPlugins = get(config, 'build.posthtml.plugins', [])
19
+
20
+ const expressionsOptions = merge({strictMode: false}, get(config, 'build.posthtml.expressions', {}))
21
+
22
+ const locals = merge(
23
+ get(expressionsOptions, 'locals', {}),
24
+ get(config, 'locals', {}),
25
+ {page: config}
26
+ )
27
+
28
+ const fetchPlugin = fetch(
29
+ merge(
30
+ {
31
+ expressions: merge({...expressionsOptions, locals})
32
+ },
33
+ get(config, 'build.posthtml.fetch', {})
34
+ )
35
+ )
36
+
37
+ return posthtml([
38
+ fetchPlugin,
39
+ expressions({...expressionsOptions, locals}),
40
+ layouts(
41
+ merge(
42
+ {
43
+ strict: false,
44
+ expressions: merge({...expressionsOptions, locals})
45
+ },
46
+ layoutsOptions
47
+ )
48
+ ),
49
+ modules({
50
+ parser: posthtmlOptions,
51
+ attributeAsLocals: true,
52
+ from: modulesFrom,
53
+ root: modulesRoot,
54
+ tag: 'component',
55
+ attribute: 'src',
56
+ plugins: [
57
+ fetchPlugin
58
+ ],
59
+ locals,
60
+ ...modulesOptions
61
+ }),
62
+ ...posthtmlPlugins
63
+ ])
64
+ .process(html, {...posthtmlOptions})
65
+ .then(result => fm(result.html).body)
66
+ }
@@ -1,116 +1,116 @@
1
- const path = require('path')
2
- const fs = require('fs-extra')
3
- const postcss = require('postcss')
4
- const tailwindcss = require('tailwindcss')
5
- const postcssImport = require('postcss-import')
6
- const postcssNested = require('tailwindcss/nesting')
7
- const {requireUncached} = require('../utils/helpers')
8
- const mergeLonghand = require('postcss-merge-longhand')
9
- const {get, isObject, isEmpty, merge} = require('lodash')
10
-
11
- module.exports = {
12
- compile: async (css = '', html = '', tailwindConfig = {}, maizzleConfig = {}, spinner = null) => {
13
- tailwindConfig = (isObject(tailwindConfig) && !isEmpty(tailwindConfig)) ? tailwindConfig : get(maizzleConfig, 'build.tailwind.config', 'tailwind.config.js')
14
-
15
- // Compute the Tailwind config to use
16
- const userConfig = () => {
17
- // If a custom config object was passed, use that
18
- if (isObject(tailwindConfig) && !isEmpty(tailwindConfig)) {
19
- return tailwindConfig
20
- }
21
-
22
- /**
23
- * Try loading a fresh tailwind.config.js, with fallback to an empty object.
24
- * This will use the default Tailwind config (with rem units etc)
25
- */
26
- try {
27
- return requireUncached(path.resolve(process.cwd(), tailwindConfig))
28
- } catch {
29
- return {}
30
- }
31
- }
32
-
33
- // Merge user's Tailwind config on top of a 'base' config
34
- const config = merge({
35
- important: true,
36
- content: {
37
- files: [
38
- './src/**/*.*',
39
- {raw: html, extension: 'html'}
40
- ]
41
- }
42
- }, userConfig())
43
-
44
- // Add back the `{raw: html}` option if user provided own config
45
- if (Array.isArray(config.content)) {
46
- config.content = {
47
- files: [
48
- ...config.content,
49
- './src/**/*.*',
50
- {raw: html, extension: 'html'}
51
- ]
52
- }
53
- }
54
-
55
- // Include all `build.templates.source` paths when scanning for selectors to preserve
56
- const buildTemplates = get(maizzleConfig, 'build.templates')
57
-
58
- if (buildTemplates) {
59
- const templateObjects = Array.isArray(buildTemplates) ? buildTemplates : [buildTemplates]
60
- const templateSources = templateObjects.map(template => {
61
- const source = get(template, 'source')
62
-
63
- if (typeof source === 'function') {
64
- const sources = source(maizzleConfig)
65
-
66
- if (Array.isArray(sources)) {
67
- sources.map(s => config.content.files.push(s))
68
- } else if (typeof sources === 'string') {
69
- config.content.files.push(sources)
70
- }
71
-
72
- // Must return a valid `content` entry
73
- return {raw: '', extension: 'html'}
74
- }
75
-
76
- // Support single-file sources i.e. src/templates/index.html
77
- if (typeof source === 'string' && Boolean(path.extname(source))) {
78
- config.content.files.push(source)
79
-
80
- return {raw: '', extension: 'html'}
81
- }
82
-
83
- return `${source}/**/*.*`
84
- })
85
-
86
- config.content.files.push(...templateSources)
87
- }
88
-
89
- const userFilePath = get(maizzleConfig, 'build.tailwind.css', path.join(process.cwd(), 'src/css/tailwind.css'))
90
- const userFileExists = await fs.pathExists(userFilePath)
91
-
92
- if (userFileExists) {
93
- css = await fs.readFile(path.resolve(userFilePath), 'utf8') + css
94
- } else {
95
- css = `@import "tailwindcss/components"; @import "tailwindcss/utilities"; ${css}`
96
- }
97
-
98
- return postcss([
99
- postcssImport({path: path.dirname(userFilePath)}),
100
- postcssNested(),
101
- tailwindcss(config),
102
- maizzleConfig.env === 'local' ? () => {} : mergeLonghand(),
103
- ...get(maizzleConfig, 'build.postcss.plugins', [])
104
- ])
105
- .process(css, {from: undefined})
106
- .then(result => result.css)
107
- .catch(error => {
108
- console.error(error)
109
- if (spinner) {
110
- spinner.stop()
111
- }
112
-
113
- throw new Error(`Tailwind CSS compilation failed`)
114
- })
115
- }
116
- }
1
+ const path = require('path')
2
+ const fs = require('fs-extra')
3
+ const postcss = require('postcss')
4
+ const tailwindcss = require('tailwindcss')
5
+ const postcssImport = require('postcss-import')
6
+ const postcssNested = require('tailwindcss/nesting')
7
+ const {requireUncached} = require('../utils/helpers')
8
+ const mergeLonghand = require('postcss-merge-longhand')
9
+ const {get, isObject, isEmpty, merge} = require('lodash')
10
+
11
+ module.exports = {
12
+ compile: async (css = '', html = '', tailwindConfig = {}, maizzleConfig = {}, spinner = null) => {
13
+ tailwindConfig = (isObject(tailwindConfig) && !isEmpty(tailwindConfig)) ? tailwindConfig : get(maizzleConfig, 'build.tailwind.config', 'tailwind.config.js')
14
+
15
+ // Compute the Tailwind config to use
16
+ const userConfig = () => {
17
+ // If a custom config object was passed, use that
18
+ if (isObject(tailwindConfig) && !isEmpty(tailwindConfig)) {
19
+ return tailwindConfig
20
+ }
21
+
22
+ /**
23
+ * Try loading a fresh tailwind.config.js, with fallback to an empty object.
24
+ * This will use the default Tailwind config (with rem units etc)
25
+ */
26
+ try {
27
+ return requireUncached(path.resolve(process.cwd(), tailwindConfig))
28
+ } catch {
29
+ return {}
30
+ }
31
+ }
32
+
33
+ // Merge user's Tailwind config on top of a 'base' config
34
+ const config = merge({
35
+ important: true,
36
+ content: {
37
+ files: [
38
+ './src/**/*.*',
39
+ {raw: html, extension: 'html'}
40
+ ]
41
+ }
42
+ }, userConfig())
43
+
44
+ // Add back the `{raw: html}` option if user provided own config
45
+ if (Array.isArray(config.content)) {
46
+ config.content = {
47
+ files: [
48
+ ...config.content,
49
+ './src/**/*.*',
50
+ {raw: html, extension: 'html'}
51
+ ]
52
+ }
53
+ }
54
+
55
+ // Include all `build.templates.source` paths when scanning for selectors to preserve
56
+ const buildTemplates = get(maizzleConfig, 'build.templates')
57
+
58
+ if (buildTemplates) {
59
+ const templateObjects = Array.isArray(buildTemplates) ? buildTemplates : [buildTemplates]
60
+ const templateSources = templateObjects.map(template => {
61
+ const source = get(template, 'source')
62
+
63
+ if (typeof source === 'function') {
64
+ const sources = source(maizzleConfig)
65
+
66
+ if (Array.isArray(sources)) {
67
+ sources.map(s => config.content.files.push(s))
68
+ } else if (typeof sources === 'string') {
69
+ config.content.files.push(sources)
70
+ }
71
+
72
+ // Must return a valid `content` entry
73
+ return {raw: '', extension: 'html'}
74
+ }
75
+
76
+ // Support single-file sources i.e. src/templates/index.html
77
+ if (typeof source === 'string' && Boolean(path.extname(source))) {
78
+ config.content.files.push(source)
79
+
80
+ return {raw: '', extension: 'html'}
81
+ }
82
+
83
+ return `${source}/**/*.*`
84
+ })
85
+
86
+ config.content.files.push(...templateSources)
87
+ }
88
+
89
+ const userFilePath = get(maizzleConfig, 'build.tailwind.css', path.join(process.cwd(), 'src/css/tailwind.css'))
90
+ const userFileExists = await fs.pathExists(userFilePath)
91
+
92
+ if (userFileExists) {
93
+ css = await fs.readFile(path.resolve(userFilePath), 'utf8') + css
94
+ } else {
95
+ css = `@import "tailwindcss/components"; @import "tailwindcss/utilities"; ${css}`
96
+ }
97
+
98
+ return postcss([
99
+ postcssImport({path: path.dirname(userFilePath)}),
100
+ postcssNested(),
101
+ tailwindcss(config),
102
+ maizzleConfig.env === 'local' ? () => {} : mergeLonghand(),
103
+ ...get(maizzleConfig, 'build.postcss.plugins', [])
104
+ ])
105
+ .process(css, {from: undefined})
106
+ .then(result => result.css)
107
+ .catch(error => {
108
+ console.error(error)
109
+ if (spinner) {
110
+ spinner.stop()
111
+ }
112
+
113
+ throw new Error(`Tailwind CSS compilation failed`)
114
+ })
115
+ }
116
+ }
package/src/index.js CHANGED
@@ -1,17 +1,17 @@
1
- const serve = require('./commands/serve')
2
- const toFile = require('./commands/build')
3
- const transformers = require('./transformers')
4
- const toString = require('./functions/render')
5
- const PostCSS = require('./generators/postcss')
6
- const toPlaintext = require('./functions/plaintext')
7
- const TailwindCSS = require('./generators/tailwindcss')
8
-
9
- module.exports = {
10
- serve,
11
- build: toFile,
12
- ...transformers,
13
- render: toString,
14
- postcss: PostCSS,
15
- plaintext: toPlaintext,
16
- tailwindcss: TailwindCSS
17
- }
1
+ const serve = require('./commands/serve')
2
+ const toFile = require('./commands/build')
3
+ const transformers = require('./transformers')
4
+ const toString = require('./functions/render')
5
+ const PostCSS = require('./generators/postcss')
6
+ const toPlaintext = require('./functions/plaintext')
7
+ const TailwindCSS = require('./generators/tailwindcss')
8
+
9
+ module.exports = {
10
+ serve,
11
+ build: toFile,
12
+ ...transformers,
13
+ render: toString,
14
+ postcss: PostCSS,
15
+ plaintext: toPlaintext,
16
+ tailwindcss: TailwindCSS
17
+ }
@@ -1,90 +1,90 @@
1
- const posthtml = require('posthtml')
2
- const parseAttrs = require('posthtml-attrs-parser')
3
- const {get, forEach, intersection, keys, isEmpty} = require('lodash')
4
-
5
- module.exports = async (html, config = {}, direct = false) => {
6
- const posthtmlOptions = get(config, 'build.posthtml.options', {})
7
- const attributes = get(config, 'inlineCSS.attributeToStyle', false)
8
-
9
- if (typeof attributes === 'boolean' && attributes) {
10
- return posthtml([attributesToStyle()]).process(html, posthtmlOptions).then(result => result.html)
11
- }
12
-
13
- if (Array.isArray(attributes) && !isEmpty(attributes)) {
14
- return posthtml([attributesToStyle({attributes})]).process(html, posthtmlOptions).then(result => result.html)
15
- }
16
-
17
- if (direct) {
18
- return posthtml([
19
- attributesToStyle({
20
- attributes: Array.isArray(config) ? config : []
21
- })
22
- ]).process(html).then(result => result.html)
23
- }
24
-
25
- return html
26
- }
27
-
28
- const attributesToStyle = (options = {}) => tree => {
29
- options.attributes = options.attributes || ['width', 'height', 'bgcolor', 'background', 'align', 'valign']
30
-
31
- const process = node => {
32
- const nodeAttributes = parseAttrs(node.attrs)
33
- const matches = intersection(keys(nodeAttributes), options.attributes)
34
- const nodeStyle = get(node.attrs, 'style')
35
- const csstoInline = []
36
-
37
- forEach(matches, attribute => {
38
- let value = get(node.attrs, attribute)
39
-
40
- switch (attribute) {
41
- case 'bgcolor':
42
- csstoInline.push(`background-color: ${value}`)
43
- break
44
-
45
- case 'background':
46
- csstoInline.push(`background-image: url('${value}')`)
47
- break
48
-
49
- case 'width':
50
- value = Number.parseInt(value, 10) + (value.match(/px|%/) || 'px')
51
- csstoInline.push(`width: ${value}`)
52
- break
53
-
54
- case 'height':
55
- value = Number.parseInt(value, 10) + (value.match(/px|%/) || 'px')
56
- csstoInline.push(`height: ${value}`)
57
- break
58
-
59
- case 'align':
60
- if (node.tag !== 'table') {
61
- return csstoInline.push(`text-align: ${value}`)
62
- }
63
-
64
- if (['left', 'right'].includes(value)) {
65
- csstoInline.push(`float: ${value}`)
66
- }
67
-
68
- if (value === 'center') {
69
- csstoInline.push('margin-left: auto', 'margin-right: auto')
70
- }
71
-
72
- break
73
-
74
- case 'valign':
75
- csstoInline.push(`vertical-align: ${value}`)
76
- break
77
-
78
- // No default
79
- }
80
- })
81
-
82
- nodeAttributes.style = nodeStyle ? `${nodeStyle} ${csstoInline.join('; ')}` : `${csstoInline.join('; ')}`
83
-
84
- node.attrs = nodeAttributes.compose()
85
-
86
- return node
87
- }
88
-
89
- return tree.walk(process)
90
- }
1
+ const posthtml = require('posthtml')
2
+ const parseAttrs = require('posthtml-attrs-parser')
3
+ const {get, forEach, intersection, keys, isEmpty} = require('lodash')
4
+
5
+ module.exports = async (html, config = {}, direct = false) => {
6
+ const posthtmlOptions = get(config, 'build.posthtml.options', {})
7
+ const attributes = get(config, 'inlineCSS.attributeToStyle', false)
8
+
9
+ if (typeof attributes === 'boolean' && attributes) {
10
+ return posthtml([attributesToStyle()]).process(html, posthtmlOptions).then(result => result.html)
11
+ }
12
+
13
+ if (Array.isArray(attributes) && !isEmpty(attributes)) {
14
+ return posthtml([attributesToStyle({attributes})]).process(html, posthtmlOptions).then(result => result.html)
15
+ }
16
+
17
+ if (direct) {
18
+ return posthtml([
19
+ attributesToStyle({
20
+ attributes: Array.isArray(config) ? config : []
21
+ })
22
+ ]).process(html).then(result => result.html)
23
+ }
24
+
25
+ return html
26
+ }
27
+
28
+ const attributesToStyle = (options = {}) => tree => {
29
+ options.attributes = options.attributes || ['width', 'height', 'bgcolor', 'background', 'align', 'valign']
30
+
31
+ const process = node => {
32
+ const nodeAttributes = parseAttrs(node.attrs)
33
+ const matches = intersection(keys(nodeAttributes), options.attributes)
34
+ const nodeStyle = get(node.attrs, 'style')
35
+ const csstoInline = []
36
+
37
+ forEach(matches, attribute => {
38
+ let value = get(node.attrs, attribute)
39
+
40
+ switch (attribute) {
41
+ case 'bgcolor':
42
+ csstoInline.push(`background-color: ${value}`)
43
+ break
44
+
45
+ case 'background':
46
+ csstoInline.push(`background-image: url('${value}')`)
47
+ break
48
+
49
+ case 'width':
50
+ value = Number.parseInt(value, 10) + (value.match(/px|%/) || 'px')
51
+ csstoInline.push(`width: ${value}`)
52
+ break
53
+
54
+ case 'height':
55
+ value = Number.parseInt(value, 10) + (value.match(/px|%/) || 'px')
56
+ csstoInline.push(`height: ${value}`)
57
+ break
58
+
59
+ case 'align':
60
+ if (node.tag !== 'table') {
61
+ return csstoInline.push(`text-align: ${value}`)
62
+ }
63
+
64
+ if (['left', 'right'].includes(value)) {
65
+ csstoInline.push(`float: ${value}`)
66
+ }
67
+
68
+ if (value === 'center') {
69
+ csstoInline.push('margin-left: auto', 'margin-right: auto')
70
+ }
71
+
72
+ break
73
+
74
+ case 'valign':
75
+ csstoInline.push(`vertical-align: ${value}`)
76
+ break
77
+
78
+ // No default
79
+ }
80
+ })
81
+
82
+ nodeAttributes.style = nodeStyle ? `${nodeStyle} ${csstoInline.join('; ')}` : `${csstoInline.join('; ')}`
83
+
84
+ node.attrs = nodeAttributes.compose()
85
+
86
+ return node
87
+ }
88
+
89
+ return tree.walk(process)
90
+ }