@maizzle/framework 4.8.7 → 5.0.0-beta.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 (80) hide show
  1. package/bin/maizzle +3 -1
  2. package/package.json +65 -58
  3. package/src/commands/build.js +244 -19
  4. package/src/commands/serve.js +2 -197
  5. package/src/generators/plaintext.js +192 -91
  6. package/src/generators/render.js +128 -0
  7. package/src/index.js +46 -14
  8. package/src/{generators/posthtml → posthtml}/defaultComponentsConfig.js +6 -4
  9. package/src/{generators/posthtml → posthtml}/defaultConfig.js +1 -1
  10. package/src/posthtml/index.js +74 -0
  11. package/src/posthtml/plugins/expandLinkTag.js +36 -0
  12. package/src/server/client.js +181 -0
  13. package/src/server/index.js +383 -0
  14. package/src/server/routes/hmr.js +24 -0
  15. package/src/server/routes/index.js +38 -0
  16. package/src/server/views/error.html +83 -0
  17. package/src/server/views/index.html +24 -0
  18. package/src/server/websockets.js +27 -0
  19. package/src/transformers/addAttributes.js +30 -0
  20. package/src/transformers/attributeToStyle.js +30 -36
  21. package/src/transformers/baseUrl.js +52 -23
  22. package/src/transformers/comb.js +51 -0
  23. package/src/transformers/core.js +20 -0
  24. package/src/transformers/filters/defaultFilters.js +90 -70
  25. package/src/transformers/filters/index.js +14 -78
  26. package/src/transformers/index.js +268 -63
  27. package/src/transformers/inline.js +240 -0
  28. package/src/transformers/markdown.js +13 -14
  29. package/src/transformers/minify.js +21 -16
  30. package/src/transformers/posthtmlMso.js +13 -8
  31. package/src/transformers/prettify.js +16 -15
  32. package/src/transformers/preventWidows.js +32 -26
  33. package/src/transformers/removeAttributes.js +17 -17
  34. package/src/transformers/replaceStrings.js +30 -9
  35. package/src/transformers/safeClassNames.js +24 -24
  36. package/src/transformers/shorthandCss.js +22 -0
  37. package/src/transformers/sixHex.js +15 -15
  38. package/src/transformers/urlParameters.js +18 -16
  39. package/src/transformers/useAttributeSizes.js +65 -0
  40. package/src/utils/getConfigByFilePath.js +124 -0
  41. package/src/utils/node.js +68 -0
  42. package/src/utils/string.js +117 -0
  43. package/types/build.d.ts +117 -57
  44. package/types/components.d.ts +130 -112
  45. package/types/config.d.ts +454 -242
  46. package/types/css/inline.d.ts +234 -0
  47. package/types/css/purge.d.ts +125 -0
  48. package/types/events.d.ts +5 -105
  49. package/types/index.d.ts +148 -116
  50. package/types/markdown.d.ts +20 -18
  51. package/types/minify.d.ts +122 -120
  52. package/types/plaintext.d.ts +46 -52
  53. package/types/posthtml.d.ts +103 -136
  54. package/types/render.d.ts +0 -117
  55. package/types/urlParameters.d.ts +21 -20
  56. package/types/widowWords.d.ts +9 -7
  57. package/src/functions/plaintext.js +0 -5
  58. package/src/functions/render.js +0 -5
  59. package/src/generators/config.js +0 -52
  60. package/src/generators/output/index.js +0 -4
  61. package/src/generators/output/to-disk.js +0 -254
  62. package/src/generators/output/to-string.js +0 -73
  63. package/src/generators/postcss.js +0 -23
  64. package/src/generators/posthtml/index.js +0 -75
  65. package/src/generators/tailwindcss.js +0 -157
  66. package/src/transformers/extraAttributes.js +0 -33
  67. package/src/transformers/inlineCss.js +0 -42
  68. package/src/transformers/removeInlineBackgroundColor.js +0 -56
  69. package/src/transformers/removeInlineSizes.js +0 -43
  70. package/src/transformers/removeInlinedSelectors.js +0 -100
  71. package/src/transformers/removeUnusedCss.js +0 -48
  72. package/src/transformers/shorthandInlineCSS.js +0 -26
  73. package/src/utils/helpers.js +0 -13
  74. package/types/baseUrl.d.ts +0 -79
  75. package/types/fetch.d.ts +0 -143
  76. package/types/inlineCss.d.ts +0 -207
  77. package/types/layouts.d.ts +0 -39
  78. package/types/removeUnusedCss.d.ts +0 -115
  79. package/types/tailwind.d.ts +0 -22
  80. package/types/templates.d.ts +0 -181
@@ -1,8 +1,10 @@
1
- /* eslint-disable camelcase */
2
- const pretty = require('pretty')
3
- const {get, merge, isEmpty, isObject} = require('lodash')
1
+ import pretty from 'pretty'
2
+ import posthtml from 'posthtml'
3
+ import { defu as merge } from 'defu'
4
+ import { render } from 'posthtml-render'
5
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
4
6
 
5
- module.exports = async (html, config = {}, direct = false) => {
7
+ const posthtmlPlugin = (options = {}) => tree => {
6
8
  const defaultConfig = {
7
9
  space_around_combinator: true, // Preserve space around CSS selector combinators
8
10
  newline_between_rules: false, // Remove empty lines between CSS rules
@@ -10,18 +12,17 @@ module.exports = async (html, config = {}, direct = false) => {
10
12
  extra_liners: [] // Don't add extra new line before any tag
11
13
  }
12
14
 
13
- config = direct ? config : get(config, 'prettify')
15
+ const config = merge(options, defaultConfig)
14
16
 
15
- // Don't prettify if not explicitly enabled in config
16
- if (!config || (isObject(config) && isEmpty(config))) {
17
- return html
18
- }
19
-
20
- if (typeof config === 'boolean' && config) {
21
- return pretty(html, defaultConfig)
22
- }
17
+ return pretty(render(tree), config)
18
+ }
23
19
 
24
- config = merge(defaultConfig, config)
20
+ export default posthtmlPlugin
25
21
 
26
- return pretty(html, config)
22
+ export async function prettify(html = '', options = {}, posthtmlOptions = {}) {
23
+ return posthtml([
24
+ posthtmlPlugin(options)
25
+ ])
26
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
27
+ .then(result => result.html)
27
28
  }
@@ -1,22 +1,13 @@
1
- const posthtml = require('posthtml')
2
- const {get, merge, isEmpty} = require('lodash')
3
- const {removeWidows} = require('string-remove-widows')
4
- const defaultConfig = require('../generators/posthtml/defaultConfig')
1
+ import posthtml from 'posthtml'
2
+ import { defu as merge } from 'defu'
3
+ import { removeWidows } from 'string-remove-widows'
4
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
5
5
 
6
- module.exports = async (html, config = {}) => {
7
- if (isEmpty(config)) {
8
- return removeWidows(html).res
9
- }
10
-
11
- const posthtmlOptions = merge(defaultConfig, get(config, 'build.posthtml.options', {}))
12
-
13
- return posthtml([removeWidowsPlugin(config)]).process(html, posthtmlOptions).then(result => result.html)
14
- }
15
-
16
- const removeWidowsPlugin = options => tree => {
17
- const {attrName = 'prevent-widows', ...removeWidowsOptions} = get(options, 'widowWords', options)
18
-
19
- removeWidowsOptions.minWordCount = removeWidowsOptions.minWordCount || 3
6
+ const posthtmlPlugin = (options = {}) => tree => {
7
+ options = merge(options, {
8
+ minWordCount: 3,
9
+ attrName: 'prevent-widows'
10
+ })
20
11
 
21
12
  // Ignore defaults
22
13
  const mappings = [
@@ -58,20 +49,19 @@ const removeWidowsPlugin = options => tree => {
58
49
  }
59
50
  ]
60
51
 
61
- if (Array.isArray(removeWidowsOptions.ignore)) {
62
- removeWidowsOptions.ignore.forEach(pair => mappings.push(pair))
52
+ if (Array.isArray(options.ignore)) {
53
+ options.ignore.forEach(pair => mappings.push(pair))
63
54
  }
64
55
 
65
- if (typeof removeWidowsOptions.ignore !== 'string') {
66
- removeWidowsOptions.ignore = mappings
56
+ if (typeof options.ignore !== 'string') {
57
+ options.ignore = mappings
67
58
  }
68
59
 
69
60
  const process = node => {
70
- if (node.attrs && Object.keys(node.attrs).includes(attrName)) {
71
- const widowsRemovedString = removeWidows(tree.render(node.content), removeWidowsOptions).res
72
-
61
+ if (node.attrs && Object.keys(node.attrs).includes(options.attrName)) {
62
+ const widowsRemovedString = removeWidows(tree.render(node.content), options).res
73
63
  node.content = tree.render(tree.parser(widowsRemovedString))
74
- node.attrs[attrName] = false
64
+ delete node.attrs[options.attrName]
75
65
  }
76
66
 
77
67
  return node
@@ -79,3 +69,19 @@ const removeWidowsPlugin = options => tree => {
79
69
 
80
70
  return tree.walk(process)
81
71
  }
72
+
73
+ export default posthtmlPlugin
74
+
75
+ export async function preventWidows(html = '', options = {}, posthtmlOptions = {}) {
76
+ // Apply only to elements that contain the `prevent-widows` attribute
77
+ if (options.withAttributes) {
78
+ return posthtml([
79
+ posthtmlPlugin(options)
80
+ ])
81
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
82
+ .then(result => result.html)
83
+ }
84
+
85
+ // Apply to all elements
86
+ return removeWidows(html, options).res
87
+ }
@@ -1,19 +1,7 @@
1
- const posthtml = require('posthtml')
2
- const {get, merge} = require('lodash')
3
- const defaultConfig = require('../generators/posthtml/defaultConfig')
4
-
5
- module.exports = async (html, config = {}, direct = false) => {
6
- const attributes = direct ? (Array.isArray(config) ? [...config] : []) : get(config, 'removeAttributes', [])
7
- const posthtmlOptions = merge(defaultConfig, get(config, 'build.posthtml.options', {}))
8
-
9
- attributes.push('style', 'class')
10
-
11
- html = await posthtml([
12
- removeAttributes(attributes, posthtmlOptions)
13
- ]).process(html, posthtmlOptions).then(result => result.html)
14
-
15
- return html
16
- }
1
+ import posthtml from 'posthtml'
2
+ import get from 'lodash-es/get.js'
3
+ import { defu as merge } from 'defu'
4
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
17
5
 
18
6
  /**
19
7
  * Remove empty attributes with PostHTML
@@ -26,7 +14,9 @@ module.exports = async (html, config = {}, direct = false) => {
26
14
  *
27
15
  * Condition 3: same as 2, but for regular expressions
28
16
  */
29
- const removeAttributes = (attributes = {}, posthtmlOptions = {}) => tree => {
17
+ const posthtmlPlugin = (attributes = [], posthtmlOptions = {}) => tree => {
18
+ attributes.push('style', 'class')
19
+
30
20
  const process = node => {
31
21
  const normalizedAttrs = attributes.map(attribute => {
32
22
  return {
@@ -54,3 +44,13 @@ const removeAttributes = (attributes = {}, posthtmlOptions = {}) => tree => {
54
44
 
55
45
  return tree.walk(process)
56
46
  }
47
+
48
+ export default posthtmlPlugin
49
+
50
+ export async function removeAttributes(html = '', attributes = [], posthtmlOptions = {}) {
51
+ return posthtml([
52
+ posthtmlPlugin(attributes, merge(posthtmlOptions, posthtmlConfig))
53
+ ])
54
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
55
+ .then(result => result.html)
56
+ }
@@ -1,14 +1,35 @@
1
- const {get, isEmpty} = require('lodash')
2
-
3
- module.exports = async (html, config = {}, direct = false) => {
4
- const replacements = direct ? config : get(config, 'replaceStrings', {})
1
+ import posthtml from 'posthtml'
2
+ import { defu as merge } from 'defu'
3
+ import { render } from 'posthtml-render'
4
+ import isEmpty from 'lodash-es/isEmpty.js'
5
+ import { parser as parse } from 'posthtml-parser'
6
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
5
7
 
8
+ const posthtmlPlugin = (replacements = {}) => tree => {
6
9
  if (!isEmpty(replacements)) {
7
- Object.entries(replacements).forEach(([k, v]) => {
8
- const regex = new RegExp(k, 'gi')
9
- html = html.replace(regex, v)
10
- })
10
+ const regexes = Object.entries(replacements).map(([k, v]) => [new RegExp(k, 'gi'), v])
11
+ const patterns = new RegExp(Object.keys(replacements).join('|'), 'gi')
12
+
13
+ return parse(
14
+ render(tree).replace(patterns, matched => {
15
+ for (const [regex, replacement] of regexes) {
16
+ if (regex.test(matched)) {
17
+ return replacement
18
+ }
19
+ }
20
+ })
21
+ )
11
22
  }
12
23
 
13
- return html
24
+ return tree
25
+ }
26
+
27
+ export default posthtmlPlugin
28
+
29
+ export async function replaceStrings(html = '', replacements = {}, posthtmlOptions = {}) {
30
+ return posthtml([
31
+ posthtmlPlugin(replacements)
32
+ ])
33
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
34
+ .then(result => result.html)
14
35
  }
@@ -1,29 +1,29 @@
1
- const posthtml = require('posthtml')
2
- const {get, merge, isEmpty} = require('lodash')
3
- const safeClassNames = require('posthtml-safe-class-names')
4
- const defaultConfig = require('../generators/posthtml/defaultConfig')
1
+ import posthtml from 'posthtml'
2
+ import { defu as merge } from 'defu'
3
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
4
+ import posthtmlSafeClassNames from 'posthtml-safe-class-names'
5
5
 
6
- module.exports = async (html, config = {}, direct = false) => {
7
- /*
8
- * Don't run when:
9
- * - `config` is falsy or empty
10
- * - developing locally and `safeClassNames` is not explicitly `true`
11
- * - `safeClassNames` is explicitly `false`
12
- */
13
- if (
14
- !config
15
- || isEmpty(config)
16
- || (get(config, 'env') === 'local' && get(config, 'safeClassNames') !== true)
17
- || get(config, 'safeClassNames') === false
18
- ) {
19
- return html
6
+ export default function posthtmlPlugin(options = {}) {
7
+ // If options is boolean, convert to object
8
+ if (typeof options === 'boolean') {
9
+ options = {}
20
10
  }
21
11
 
22
- const posthtmlOptions = merge(defaultConfig, get(config, 'build.posthtml.options', {}))
23
- const replacements = direct ? config : get(config, 'safeClassNames', {
24
- '{': '{',
25
- '}': '}'
26
- })
12
+ // Default options
13
+ options = merge({
14
+ replacements: {
15
+ '{': '{',
16
+ '}': '}'
17
+ }
18
+ }, options)
27
19
 
28
- return posthtml([safeClassNames({replacements})]).process(html, posthtmlOptions).then(result => result.html)
20
+ return posthtmlSafeClassNames(options)
21
+ }
22
+
23
+ export async function safeClassNames(html = '', options = {}, posthtmlOptions = {}) {
24
+ return posthtml([
25
+ posthtmlPlugin(options)
26
+ ])
27
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
28
+ .then(result => result.html)
29
29
  }
@@ -0,0 +1,22 @@
1
+ import posthtml from 'posthtml'
2
+ import { defu as merge } from 'defu'
3
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
4
+ import posthtmlMergeLonghand from 'posthtml-postcss-merge-longhand'
5
+
6
+ export default function posthtmlPlugin(options = {}) {
7
+ if (Array.isArray(options.tags)) {
8
+ return posthtmlMergeLonghand({
9
+ tags: options.tags,
10
+ })
11
+ }
12
+
13
+ return posthtmlMergeLonghand()
14
+ }
15
+
16
+ export async function shorthandCSS(html = '', options = {}, posthtmlOptions = {}) {
17
+ return posthtml([
18
+ posthtmlPlugin(options)
19
+ ])
20
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
21
+ .then(result => result.html)
22
+ }
@@ -1,19 +1,9 @@
1
- const posthtml = require('posthtml')
2
- const {get, merge} = require('lodash')
3
- const {conv} = require('color-shorthand-hex-to-six-digit')
4
- const defaultConfig = require('../generators/posthtml/defaultConfig')
1
+ import posthtml from 'posthtml'
2
+ import { defu as merge } from 'defu'
3
+ import { conv } from 'color-shorthand-hex-to-six-digit'
4
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
5
5
 
6
- module.exports = async (html, config = {}) => {
7
- if (get(config, 'sixHex') === false) {
8
- return html
9
- }
10
-
11
- const posthtmlOptions = merge(defaultConfig, get(config, 'build.posthtml.options', {}))
12
-
13
- return posthtml([sixHex()]).process(html, posthtmlOptions).then(result => result.html)
14
- }
15
-
16
- const sixHex = () => tree => {
6
+ const posthtmlPlugin = () => tree => {
17
7
  const targets = new Set(['bgcolor', 'color'])
18
8
 
19
9
  const process = node => {
@@ -30,3 +20,13 @@ const sixHex = () => tree => {
30
20
 
31
21
  return tree.walk(process)
32
22
  }
23
+
24
+ export default posthtmlPlugin
25
+
26
+ export async function sixHEX(html = '', posthtmlOptions = {}) {
27
+ return posthtml([
28
+ posthtmlPlugin()
29
+ ])
30
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
31
+ .then(result => result.html)
32
+ }
@@ -1,20 +1,22 @@
1
- const posthtml = require('posthtml')
2
- const {get, merge, isEmpty} = require('lodash')
3
- const urlParams = require('posthtml-url-parameters')
4
- const defaultConfig = require('../generators/posthtml/defaultConfig')
1
+ import posthtml from 'posthtml'
2
+ import get from 'lodash-es/get.js'
3
+ import { defu as merge } from 'defu'
4
+ import urlParameters from 'posthtml-url-parameters'
5
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
5
6
 
6
- module.exports = async (html, config = {}, direct = false) => {
7
- const urlParameters = direct ? config : get(config, 'urlParameters', {})
7
+ export default function posthtmlPlugin(options = {}) {
8
+ const { _options, ...parameters } = options
9
+ const tags = get(_options, 'tags', ['a'])
10
+ const strict = get(_options, 'strict', true)
11
+ const qs = get(_options, 'qs', { encode: false })
8
12
 
9
- if (!isEmpty(urlParameters)) {
10
- const posthtmlOptions = merge(defaultConfig, get(config, 'build.posthtml.options', {}))
11
- const {_options, ...parameters} = urlParameters
12
- const tags = get(_options, 'tags', ['a'])
13
- const strict = get(_options, 'strict', true)
14
- const qs = get(_options, 'qs', {encode: false})
15
-
16
- return posthtml([urlParams({parameters, tags, qs, strict})]).process(html, posthtmlOptions).then(result => result.html)
17
- }
13
+ return urlParameters({ parameters, tags, qs, strict })
14
+ }
18
15
 
19
- return html
16
+ export async function addURLParams(html = '', options = {}, posthtmlOptions = {}) {
17
+ return posthtml([
18
+ posthtmlPlugin(options)
19
+ ])
20
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
21
+ .then(result => result.html)
20
22
  }
@@ -0,0 +1,65 @@
1
+ import postcss from 'postcss'
2
+ import posthtml from 'posthtml'
3
+ import get from 'lodash-es/get.js'
4
+ import { defu as merge } from 'defu'
5
+ import posthtmlConfig from '../posthtml/defaultConfig.js'
6
+
7
+ const posthtmlPlugin = (mappings = {}) => tree => {
8
+ if (!Object.keys(mappings).length) {
9
+ return tree
10
+ }
11
+
12
+ // Normalize tags in mappings by lowercasing them
13
+ for (const key in mappings) {
14
+ if (Array.isArray(mappings[key])) {
15
+ mappings[key] = mappings[key].map(value => value.toLowerCase())
16
+ }
17
+ }
18
+
19
+ const process = node => {
20
+ // Check if the node is defined in mappings
21
+ if (
22
+ get(mappings, 'width', []).includes(node.tag)
23
+ || get(mappings, 'height', []).includes(node.tag)
24
+ ) {
25
+ // Check if the node has an inline CSS property equal to one of the keys in mappings
26
+ if (node.attrs.style) {
27
+ const { root } = postcss().process(`${node.attrs.style}`, { from: undefined })
28
+
29
+ root.walkDecls(decl => {
30
+ if (mappings.width.includes(node.tag) && decl.prop === 'width') {
31
+ // Set its value as an attribute on the node; the attribute name is the key in mappings
32
+ node.attrs.width = decl.value.replace('px', '')
33
+ // Remove the inline CSS property from the declaration
34
+ decl.remove()
35
+ }
36
+
37
+ if (mappings.height.includes(node.tag) && decl.prop === 'height') {
38
+ // Set its value as an attribute on the node; the attribute name is the key in mappings
39
+ node.attrs.height = decl.value.replace('px', '')
40
+ // Remove the inline CSS property from the declaration
41
+ decl.remove()
42
+ }
43
+ })
44
+
45
+ // Set the remaining inline CSS as the `style` attribute on the node
46
+ // If there are no remaining declarations, remove the `style` attribute
47
+ node.attrs.style = root.toString().trim() || false
48
+ }
49
+ }
50
+
51
+ return node
52
+ }
53
+
54
+ return tree.walk(process)
55
+ }
56
+
57
+ export default posthtmlPlugin
58
+
59
+ export async function useAttributeSizes(html = '', mappings = {}, posthtmlOptions = {}) {
60
+ return posthtml([
61
+ posthtmlPlugin(mappings)
62
+ ])
63
+ .process(html, merge(posthtmlOptions, posthtmlConfig))
64
+ .then(result => result.html)
65
+ }
@@ -0,0 +1,124 @@
1
+ import { resolve } from 'pathe'
2
+ import get from 'lodash/get.js'
3
+ import { defu as merge } from 'defu'
4
+ import { lstat } from 'node:fs/promises'
5
+ import isEmpty from 'lodash-es/isEmpty.js'
6
+
7
+ /**
8
+ * Compute the Maizzle config object.
9
+ *
10
+ * If a config file path is provided, that file will be read
11
+ * instead of trying to merge the base and environment configs.
12
+ *
13
+ * If an environment is provided, the config object will be
14
+ * computed based on a base config and the resolved
15
+ * environment config.
16
+ *
17
+ * @param {string} env - The environment name to use.
18
+ * @param {string} path - The path to the config file to use.
19
+ * @returns {Promise<object>} The computed config object.
20
+ */
21
+ export async function readFileConfig(config) {
22
+ try {
23
+ /**
24
+ * If `config` is string, try to read and return
25
+ * the config object from it.
26
+ */
27
+ if (typeof config === 'string' && config) {
28
+ const { default: resolvedConfig } = await import(`file://${resolve(config)}?d=${Date.now()}`)
29
+ .catch(() => { throw new Error('Could not read config file') })
30
+
31
+ return merge(resolvedConfig, { env: config })
32
+ }
33
+
34
+ /**
35
+ * Otherwise, default to the Environment config approach,
36
+ * where we check for config files that follow a
37
+ * specific naming convention.
38
+ *
39
+ * First, we check for a base config file, in this order:
40
+ */
41
+ const baseConfigFileNames = [
42
+ './maizzle.config.js',
43
+ './maizzle.config.local.js',
44
+ './config.js',
45
+ './config.local.js',
46
+ './maizzle.config.cjs',
47
+ './maizzle.config.local.cjs',
48
+ './config.cjs',
49
+ './config.local.cjs',
50
+ ]
51
+
52
+ const env = get(config, 'env', 'local')
53
+ let baseConfig = merge({ env }, config)
54
+ let envConfig = merge({ env }, config)
55
+
56
+ const cwd = env === 'maizzle-ci' ? './test/stubs/config' : process.cwd()
57
+
58
+ // We load the first base config found
59
+ for (const module of baseConfigFileNames) {
60
+ // Check if the file exists, go to next one if not
61
+ const configFileExists = await lstat(resolve(cwd, module)).catch(() => false)
62
+
63
+ if (!configFileExists) {
64
+ continue
65
+ }
66
+
67
+ // Load the config file
68
+ try {
69
+ const { default: baseConfigFile } = await import(`file://${resolve(cwd, module)}?d=${Date.now()}`)
70
+
71
+ // Use the first base config found
72
+ if (!isEmpty(baseConfigFile)) {
73
+ baseConfig = merge(baseConfigFile, baseConfig)
74
+ break
75
+ }
76
+ } catch (error) {
77
+ break
78
+ }
79
+
80
+ }
81
+
82
+ // Then, we load and compute the first Environment config found
83
+ if (env !== 'local') {
84
+ let loaded = false
85
+ const modulesToTry = [
86
+ `./maizzle.config.${env}.js`,
87
+ `./config.${env}.js`,
88
+ `./maizzle.config.${env}.cjs`,
89
+ `./config.${env}.cjs`,
90
+ ]
91
+
92
+ for (const module of modulesToTry) {
93
+ // Check if the file exists, go to next one if not
94
+ const configFileExists = await lstat(resolve(cwd, module)).catch(() => false)
95
+
96
+ if (!configFileExists) {
97
+ continue
98
+ }
99
+
100
+ // Load the config file
101
+ try {
102
+ const { default: envConfigFile } = await import(`file://${resolve(cwd, module)}?d=${Date.now()}`)
103
+
104
+ // If it's not an empty object, merge it with the base config
105
+ if (!isEmpty(envConfigFile)) {
106
+ envConfig = merge(envConfigFile, envConfig)
107
+ loaded = true
108
+ break
109
+ }
110
+ } catch (error) {
111
+ break
112
+ }
113
+ }
114
+
115
+ if (!loaded) {
116
+ throw new Error(`Failed to load the \`${env}\` environment config, do you have one of these files in your project root?\n\n${modulesToTry.join('\n')}`)
117
+ }
118
+ }
119
+
120
+ return merge(envConfig, baseConfig)
121
+ } catch (error) {
122
+ throw new Error('Could not compute config')
123
+ }
124
+ }
@@ -0,0 +1,68 @@
1
+ import os from 'node:os'
2
+ import gm from 'gray-matter'
3
+ import pico from 'picocolors'
4
+ import { humanFileSize } from './string.js'
5
+
6
+ // Return a local IP address
7
+ export function getLocalIP() {
8
+ const interfaces = os.networkInterfaces()
9
+
10
+ for (const iface in interfaces) {
11
+ const ifaceInfo = interfaces[iface]
12
+
13
+ for (const alias of ifaceInfo) {
14
+ if (alias.family === 'IPv4' && !alias.internal) {
15
+ return alias.address
16
+ }
17
+ }
18
+ }
19
+
20
+ return '127.0.0.1' // Default to localhost if no suitable IP is found
21
+ }
22
+
23
+ /**
24
+ * Return the file size of a string
25
+ *
26
+ * @param {string} string The HTML string to calculate the file size of
27
+ * @returns {number} The file size in bytes, a floating-point number
28
+ * */
29
+ export function getFileSize(string) {
30
+ const blob = new Blob([string], { type: 'text/html' })
31
+
32
+ return blob.size.toFixed(2)
33
+ }
34
+
35
+ /**
36
+ * Color-code a formatted file size string depending on the size
37
+ *
38
+ * 0-49 KB: green
39
+ * 50-102 KB: yellow
40
+ * >102 KB: red
41
+ *
42
+ * @param {string} string The HTML string to calculate the file size of
43
+ * @returns {string} The formatted, color-coded file size
44
+ * */
45
+ export function getColorizedFileSize(string) {
46
+ const size = getFileSize(string)
47
+ const formattedSize = humanFileSize(size)
48
+
49
+ if (size / 1024 < 50) {
50
+ return formattedSize
51
+ }
52
+
53
+ if (size / 1024 < 102) {
54
+ return pico.yellow(formattedSize)
55
+ }
56
+
57
+ return pico.red(formattedSize)
58
+ }
59
+
60
+ export function parseFrontMatter(html) {
61
+ /**
62
+ * Need to pass empty options object to gray-matter
63
+ * in order to disable caching.
64
+ * https://github.com/jonschlinkert/gray-matter/issues/43
65
+ */
66
+ const { content, data, matter, stringify } = gm(html, {})
67
+ return { content, data, matter, stringify }
68
+ }