@maizzle/framework 4.0.0-alpha.1 → 4.0.0-alpha.10

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 (67) hide show
  1. package/.github/workflows/nodejs.yml +1 -1
  2. package/bin/maizzle +3 -0
  3. package/package.json +16 -12
  4. package/src/commands/build.js +32 -0
  5. package/src/commands/serve.js +156 -0
  6. package/src/functions/plaintext.js +5 -0
  7. package/src/functions/render.js +5 -0
  8. package/src/generators/output/to-disk.js +90 -77
  9. package/src/generators/output/to-string.js +2 -6
  10. package/src/generators/plaintext.js +49 -52
  11. package/src/generators/postcss.js +29 -0
  12. package/src/generators/posthtml.js +11 -6
  13. package/src/generators/tailwindcss.js +116 -115
  14. package/src/index.js +14 -148
  15. package/src/transformers/baseUrl.js +33 -9
  16. package/src/transformers/filters/defaultFilters.js +126 -0
  17. package/src/transformers/filters/index.js +55 -0
  18. package/src/transformers/index.js +13 -7
  19. package/src/transformers/inlineCss.js +1 -14
  20. package/src/transformers/minify.js +1 -1
  21. package/src/transformers/prettify.js +16 -9
  22. package/src/transformers/removeInlineBackgroundColor.js +1 -1
  23. package/src/transformers/removeInlinedSelectors.js +70 -0
  24. package/src/transformers/removeUnusedCss.js +40 -20
  25. package/src/transformers/shorthandInlineCSS.js +19 -0
  26. package/src/transformers/sixHex.js +24 -1
  27. package/test/expected/posthtml/component.html +13 -0
  28. package/test/expected/{inheritance.html → posthtml/extend-template.html} +2 -2
  29. package/test/expected/posthtml/fetch.html +5 -0
  30. package/test/expected/posthtml/layout.html +3 -0
  31. package/test/expected/transformers/atimport-in-style.html +15 -0
  32. package/test/expected/transformers/{base-image-url.html → base-url.html} +18 -2
  33. package/test/expected/transformers/filters.html +81 -0
  34. package/test/expected/transformers/preserve-transform-css.html +36 -0
  35. package/test/expected/useConfig.html +9 -9
  36. package/test/fixtures/basic.html +9 -9
  37. package/test/fixtures/posthtml/component.html +19 -0
  38. package/test/fixtures/{inheritance.html → posthtml/extend-template.html} +7 -7
  39. package/test/fixtures/posthtml/fetch.html +9 -0
  40. package/test/fixtures/posthtml/layout.html +11 -0
  41. package/test/fixtures/transformers/atimport-in-style.html +11 -0
  42. package/test/fixtures/transformers/{base-image-url.html → base-url.html} +18 -2
  43. package/test/fixtures/transformers/filters.html +87 -0
  44. package/test/fixtures/transformers/preserve-transform-css.html +25 -0
  45. package/test/fixtures/useConfig.html +9 -9
  46. package/test/stubs/components/component.html +5 -0
  47. package/test/stubs/data.json +14 -0
  48. package/test/stubs/layouts/basic.html +1 -0
  49. package/test/stubs/{layout.html → layouts/full.html} +0 -0
  50. package/test/stubs/{layout-basic.html → layouts/template.html} +5 -5
  51. package/test/stubs/post.css +6 -0
  52. package/test/stubs/tailwind/{preserve.html → content-source.html} +0 -0
  53. package/test/stubs/tailwind/tailwind.css +3 -0
  54. package/test/stubs/template.html +10 -10
  55. package/test/stubs/templates/1.html +1 -1
  56. package/test/stubs/templates/2.test +1 -0
  57. package/test/test-config.js +19 -19
  58. package/test/test-postcss.js +8 -0
  59. package/test/test-posthtml.js +72 -0
  60. package/test/{test-tailwind.js → test-tailwindcss.js} +117 -100
  61. package/test/test-todisk.js +79 -28
  62. package/test/test-tostring.js +148 -132
  63. package/test/test-transformers.js +216 -49
  64. package/src/transformers/transform.js +0 -22
  65. package/test/expected/transformers/transform-postcss.html +0 -19
  66. package/test/stubs/templates/2.html +0 -1
  67. package/test/stubs/templates/3.mzl +0 -1
@@ -67,9 +67,9 @@ test('outputs files at the correct location', async t => {
67
67
  }
68
68
  })
69
69
 
70
- t.true(fs.pathExistsSync(t.context.folder))
71
- t.is(string.length, 3)
72
- t.is(array.length, 3)
70
+ t.true(await fs.pathExists(t.context.folder))
71
+ t.is(string.length, 2)
72
+ t.is(array.length, 2)
73
73
  })
74
74
 
75
75
  test('outputs files at the correct location if multiple template sources are used', async t => {
@@ -93,8 +93,8 @@ test('outputs files at the correct location if multiple template sources are use
93
93
  }
94
94
  })
95
95
 
96
- t.true(fs.pathExistsSync(t.context.folder))
97
- t.is(files.length, 4)
96
+ t.true(await fs.pathExists(t.context.folder))
97
+ t.is(files.length, 3)
98
98
  })
99
99
 
100
100
  test('copies all files in the `filetypes` option to destination', async t => {
@@ -103,7 +103,7 @@ test('copies all files in the `filetypes` option to destination', async t => {
103
103
  fail: 'silent',
104
104
  templates: {
105
105
  source: 'test/stubs/templates',
106
- filetypes: ['html', 'mzl'],
106
+ filetypes: ['html', 'test'],
107
107
  destination: {
108
108
  path: t.context.folder
109
109
  }
@@ -116,8 +116,8 @@ test('copies all files in the `filetypes` option to destination', async t => {
116
116
  }
117
117
  })
118
118
 
119
- t.true(fs.pathExistsSync(t.context.folder))
120
- t.is(files.length, 4)
119
+ t.true(await fs.pathExists(t.context.folder))
120
+ t.is(files.length, 3)
121
121
  })
122
122
 
123
123
  test('outputs files with the correct extension', async t => {
@@ -139,7 +139,9 @@ test('outputs files with the correct extension', async t => {
139
139
  }
140
140
  })
141
141
 
142
- t.true(fs.readdirSync(t.context.folder).includes('1.blade.php'))
142
+ const filelist = await fs.readdir(t.context.folder)
143
+
144
+ t.true(filelist.includes('1.blade.php'))
143
145
  })
144
146
 
145
147
  test('outputs plaintext files', async t => {
@@ -228,8 +230,10 @@ test('copies assets to destination', async t => {
228
230
  }
229
231
  })
230
232
 
231
- t.is(fs.pathExistsSync(`${t.context.folder}/images`), true)
232
- t.is(fs.readdirSync(`${t.context.folder}/images`).length, 1)
233
+ const filelist = await fs.readdir(`${t.context.folder}/images`)
234
+
235
+ t.is(await fs.pathExists(`${t.context.folder}/images`), true)
236
+ t.is(filelist.length, 1)
233
237
  })
234
238
 
235
239
  test('runs the `beforeCreate` event', async t => {
@@ -255,9 +259,10 @@ test('runs the `beforeCreate` event', async t => {
255
259
  }
256
260
  })
257
261
 
258
- const html = fs.readFileSync(`${t.context.folder}/${fs.readdirSync(t.context.folder)[0]}`, 'utf8').trim()
262
+ const filename = await fs.readdir(t.context.folder)
263
+ const html = await fs.readFile(`${t.context.folder}/${filename[0]}`, 'utf8')
259
264
 
260
- t.is(html, 'Foo is bar')
265
+ t.is(html.trim(), 'Foo is bar')
261
266
  })
262
267
 
263
268
  test('runs the `afterBuild` event', async t => {
@@ -310,9 +315,9 @@ test('supports multiple asset paths', async t => {
310
315
  }
311
316
  })
312
317
 
313
- t.true(fs.existsSync(`${t.context.folder}/extras/foo.bar`))
314
- t.true(fs.existsSync(`${t.context.folder}/extras/plaintext.html`))
315
- t.false(fs.existsSync(`${t.context.folder}/extras/invalid`))
318
+ t.true(await fs.pathExists(`${t.context.folder}/extras/foo.bar`))
319
+ t.true(await fs.pathExists(`${t.context.folder}/extras/plaintext.html`))
320
+ t.false(await fs.pathExists(`${t.context.folder}/extras/invalid`))
316
321
  })
317
322
 
318
323
  test('warns if a template cannot be rendered and `fail` option is undefined', async t => {
@@ -392,31 +397,42 @@ test('spins up local development server', async t => {
392
397
  }
393
398
  })
394
399
 
395
- t.true(fs.existsSync(t.context.folder))
400
+ t.true(await fs.pathExists(t.context.folder))
396
401
  })
397
402
 
398
403
  test('local server does not compile unwanted file types', async t => {
399
404
  await Maizzle.serve('local', {
400
405
  build: {
406
+ console: {
407
+ clear: true
408
+ },
401
409
  browsersync: {
402
410
  ui: false
403
411
  },
404
412
  templates: {
405
413
  source: 'test/stubs/templates',
406
414
  destination: {
407
- path: t.context.folder
415
+ path: `${t.context.folder}`
408
416
  }
409
417
  }
418
+ },
419
+ events: {
420
+ beforeCreate(config) {
421
+ config.foo = 'bar'
422
+ }
410
423
  }
411
424
  })
412
425
 
413
- fs.outputFileSync(`test/stubs/templates/1.html`, '<a href="https://example.com">Test</a>\n')
414
- fs.outputFileSync(`test/stubs/templates/3.mzl`, '<a href="https://example.com">Test</a>\n')
426
+ t.true(await fs.pathExists(`${t.context.folder}`))
427
+ t.true(await fs.pathExists(`${t.context.folder}/2.test`))
415
428
 
416
- t.is(fs.readFileSync(`${t.context.folder}/1.html`, 'utf8'), '<a href="https://example.com">Test</a>\n')
417
- t.is(fs.readFileSync(`${t.context.folder}/3.mzl`, 'utf8'), '<a href="https://example.com">Test</a>\n')
429
+ // Tests watching changes to files
430
+ await fs.outputFile('test/stubs/templates/1.html', 'html\n')
431
+ t.is(await fs.readFile('test/stubs/templates/1.html', 'utf8'), 'html\n')
418
432
 
419
- fs.removeSync(t.context.folder)
433
+ // Don't trigger rebuilds on files not in filetypes
434
+ await fs.outputFile('test/stubs/templates/2.test', 'test\n')
435
+ t.is(await fs.readFile('test/stubs/templates/2.test', 'utf8'), 'test\n')
420
436
  })
421
437
 
422
438
  test('throws if it cannot spin up local development server', async t => {
@@ -438,16 +454,19 @@ test('works with templates.source defined as function (string paths)', async t =
438
454
  }
439
455
  })
440
456
 
441
- t.true(fs.pathExistsSync(t.context.folder))
442
- t.is(files.length, 3)
457
+ t.true(await fs.pathExists(t.context.folder))
458
+ t.is(files.length, 2)
443
459
  })
444
460
 
445
461
  test('works with templates.source defined as function (array paths)', async t => {
446
462
  const {files} = await Maizzle.build('maizzle-ci', {
447
463
  build: {
448
464
  fail: 'silent',
465
+ customSources: ['test/stubs/templates', 'test/stubs/templates'],
449
466
  templates: {
450
- source: () => ['test/stubs/templates', 'test/stubs/templates'],
467
+ source: config => {
468
+ return config.build.customSources
469
+ },
451
470
  destination: {
452
471
  path: t.context.folder
453
472
  }
@@ -455,6 +474,38 @@ test('works with templates.source defined as function (array paths)', async t =>
455
474
  }
456
475
  })
457
476
 
458
- t.true(fs.pathExistsSync(t.context.folder))
459
- t.is(files.length, 3)
477
+ t.true(await fs.pathExists(t.context.folder))
478
+ t.is(files.length, 2)
479
+ })
480
+
481
+ test('throws if templates path is invalid', async t => {
482
+ await t.throwsAsync(async () => {
483
+ await Maizzle.build('maizzle-ci', {
484
+ build: {
485
+ fail: 'silent',
486
+ templates: {
487
+ source: false,
488
+ destination: {
489
+ path: t.context.folder
490
+ }
491
+ }
492
+ }
493
+ })
494
+ }, {instanceOf: TypeError})
495
+ })
496
+
497
+ test('throws if templates path is invalid (function)', async t => {
498
+ await t.throwsAsync(async () => {
499
+ await Maizzle.build('maizzle-ci', {
500
+ build: {
501
+ fail: 'silent',
502
+ templates: {
503
+ source: () => {},
504
+ destination: {
505
+ path: t.context.folder
506
+ }
507
+ }
508
+ }
509
+ })
510
+ }, {instanceOf: TypeError})
460
511
  })
@@ -1,132 +1,148 @@
1
- const test = require('ava')
2
- const Maizzle = require('../src')
3
-
4
- const path = require('path')
5
- const {readFileSync} = require('fs')
6
-
7
- const fixture = file => readFileSync(path.join(__dirname, 'fixtures', `${file}.html`), 'utf8')
8
- const expected = file => readFileSync(path.join(__dirname, 'expected', `${file}.html`), 'utf8')
9
-
10
- const renderString = (string, options = {}) => Maizzle.render(string, options).then(({html}) => html)
11
-
12
- test('compiles HTML string if no options are passed', async t => {
13
- const source = fixture('basic')
14
-
15
- const html = await renderString(source)
16
-
17
- t.is(html, source)
18
- })
19
-
20
- test('uses environment config file(s) if available', async t => {
21
- const source = fixture('useConfig')
22
-
23
- const html = await renderString(source, {maizzle: {env: 'maizzle-ci'}})
24
-
25
- t.is(html, expected('useConfig'))
26
- })
27
-
28
- test('inheritance', async t => {
29
- let html = await renderString(fixture('inheritance'))
30
- html = html.replace(/[^\S\r\n]+$/gm, '').trim()
31
-
32
- t.is(html, expected('inheritance').trim())
33
- })
34
-
35
- test('throws if first argument is not an HTML string', async t => {
36
- await t.throwsAsync(async () => {
37
- await renderString(false)
38
- }, {instanceOf: TypeError, message: 'first argument must be an HTML string, received false'})
39
- })
40
-
41
- test('throws if first argument is an empty string', async t => {
42
- await t.throwsAsync(async () => {
43
- await renderString('')
44
- }, {instanceOf: RangeError, message: 'received empty string'})
45
- })
46
-
47
- test('runs the `beforeRender` event', async t => {
48
- const html = await renderString(`<div>{{ page.foo }}</div>`, {
49
- beforeRender(html, config) {
50
- config.foo = 'bar'
51
-
52
- return html
53
- }
54
- })
55
-
56
- t.is(html, `<div>bar</div>`)
57
- })
58
-
59
- test('runs the `afterRender` event', async t => {
60
- const result = await renderString(`<div>foo</div>`, {
61
- afterRender(html, config) {
62
- config.replaceStrings = {
63
- foo: 'baz'
64
- }
65
-
66
- return html
67
- }
68
- })
69
-
70
- t.is(result, `<div>baz</div>`)
71
- })
72
-
73
- test('runs the `afterTransformers` event', async t => {
74
- const result = await renderString(`<div>foo</div>`, {
75
- maizzle: {
76
- title: 'bar'
77
- },
78
- afterTransformers(html, config) {
79
- return html.replace('foo', config.title)
80
- }
81
- })
82
-
83
- t.is(result, `<div>bar</div>`)
84
- })
85
-
86
- test('multiple locals', async t => {
87
- const result = await renderString(`{{ page.one }}, {{ two }}, {{ three }}`, {
88
- maizzle: {
89
- one: 1,
90
- build: {
91
- posthtml: {
92
- expressions: {
93
- locals: {
94
- two: 2
95
- }
96
- }
97
- }
98
- },
99
- locals: {
100
- three: 3
101
- }
102
- }
103
- })
104
-
105
- t.is(result, `1, 2, 3`)
106
- })
107
-
108
- test('prevents overwriting page object', async t => {
109
- const result = await renderString(`{{ page.one }}, {{ two }}, {{ three }}`, {
110
- maizzle: {
111
- one: 1,
112
- build: {
113
- posthtml: {
114
- expressions: {
115
- locals: {
116
- page: {
117
- two: 2
118
- }
119
- }
120
- }
121
- }
122
- },
123
- locals: {
124
- page: {
125
- three: 3
126
- }
127
- }
128
- }
129
- })
130
-
131
- t.is(result, `1, undefined, undefined`)
132
- })
1
+ const test = require('ava')
2
+ const Maizzle = require('../src')
3
+
4
+ const path = require('path')
5
+ const fs = require('fs')
6
+
7
+ const readFile = (dir, filename) => fs.promises
8
+ .readFile(path.join(__dirname, dir, `${filename}.html`), 'utf8')
9
+ .then(html => html.trim())
10
+
11
+ const fixture = file => readFile('fixtures', file)
12
+ const expected = file => readFile('expected', file)
13
+
14
+ const renderString = (string, options = {}) => Maizzle.render(string, options).then(({html}) => html)
15
+
16
+ test('compiles HTML string if no options are passed', async t => {
17
+ const source = await fixture('basic')
18
+
19
+ const html = await renderString(source)
20
+
21
+ t.is(html, source)
22
+ })
23
+
24
+ test('uses environment config file(s) if available', async t => {
25
+ const source = await fixture('useConfig')
26
+
27
+ const html = await renderString(source, {maizzle: {env: 'maizzle-ci'}})
28
+
29
+ t.is(html, await expected('useConfig'))
30
+ })
31
+
32
+ test('throws if first argument is not an HTML string', async t => {
33
+ await t.throwsAsync(async () => {
34
+ await renderString()
35
+ }, {instanceOf: TypeError, message: 'first argument must be an HTML string, received undefined'})
36
+ })
37
+
38
+ test('throws if first argument is an empty string', async t => {
39
+ await t.throwsAsync(async () => {
40
+ await renderString('')
41
+ }, {instanceOf: RangeError, message: 'received empty string'})
42
+ })
43
+
44
+ test('runs the `beforeRender` event', async t => {
45
+ const html = await renderString(`<div>{{ page.foo }}</div>`, {
46
+ beforeRender(html, config) {
47
+ config.foo = 'bar'
48
+
49
+ return html
50
+ }
51
+ })
52
+
53
+ t.is(html, `<div>bar</div>`)
54
+ })
55
+
56
+ test('runs the `afterRender` event', async t => {
57
+ const result = await renderString(`<div>foo</div>`, {
58
+ afterRender(html, config) {
59
+ config.replaceStrings = {
60
+ foo: 'baz'
61
+ }
62
+
63
+ return html
64
+ }
65
+ })
66
+
67
+ t.is(result, `<div>baz</div>`)
68
+ })
69
+
70
+ test('runs the `afterTransformers` event', async t => {
71
+ const result = await renderString(`<div>foo</div>`, {
72
+ maizzle: {
73
+ title: 'bar'
74
+ },
75
+ afterTransformers(html, config) {
76
+ return html.replace('foo', config.title)
77
+ }
78
+ })
79
+
80
+ t.is(result, `<div>bar</div>`)
81
+ })
82
+
83
+ test('locals work when defined in all supported places', async t => {
84
+ const result = await renderString(`{{ page.one }}, {{ two }}, {{ three }}`, {
85
+ maizzle: {
86
+ one: 1,
87
+ build: {
88
+ posthtml: {
89
+ expressions: {
90
+ locals: {
91
+ two: 2
92
+ }
93
+ }
94
+ }
95
+ },
96
+ locals: {
97
+ three: 3
98
+ }
99
+ }
100
+ })
101
+
102
+ t.is(result, `1, 2, 3`)
103
+ })
104
+
105
+ test('prevents overwriting page object', async t => {
106
+ const result = await renderString(`{{ page.one }}, {{ two }}, {{ three }}`, {
107
+ maizzle: {
108
+ one: 1,
109
+ build: {
110
+ posthtml: {
111
+ expressions: {
112
+ locals: {
113
+ page: {
114
+ two: 2
115
+ }
116
+ }
117
+ }
118
+ }
119
+ },
120
+ locals: {
121
+ page: {
122
+ three: 3
123
+ }
124
+ }
125
+ }
126
+ })
127
+
128
+ t.is(result, `1, undefined, undefined`)
129
+ })
130
+
131
+ test('preserves css in marked style tags (tailwindcss)', async t => {
132
+ const source = await fixture('transformers/preserve-transform-css')
133
+ const html = await renderString(source, {
134
+ // So that we don't compile twice
135
+ tailwind: {
136
+ compiled: ''
137
+ }
138
+ })
139
+
140
+ t.is(html, await expected('transformers/preserve-transform-css'))
141
+ })
142
+
143
+ test('@import css files in marked style tags', async t => {
144
+ const source = await fixture('transformers/atimport-in-style')
145
+ const html = await renderString(source)
146
+
147
+ t.is(html, await expected('transformers/atimport-in-style'))
148
+ })