@lipemat/js-boilerplate 10.9.0 → 10.10.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.
@@ -1,11 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- // Update notifier.
5
- const updateNotifier = require( 'update-notifier' );
6
- const pkg = require( '../package.json' );
7
- updateNotifier( {pkg, shouldNotifyInNpmScript: true} ).notify();
8
-
9
4
  const spawn = require( 'cross-spawn' );
10
5
  const args = process.argv.slice( 2 );
11
6
 
@@ -1,51 +1,45 @@
1
- const {getLocalIdent, usingShortCssClasses} = require( '../helpers/css-classnames' );
2
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const css_classnames_1 = require("../helpers/css-classnames");
3
4
  /**
4
5
  * Options for the Webpack `css-loader`.
5
6
  *
6
7
  * Extracted to its on file to allow easy overrides.
7
8
  */
8
-
9
9
  /**
10
10
  * Default to :global for classes in "global" or "pcss" directories.
11
11
  *
12
12
  * @param {string} resourcePath
13
13
  * @return {string}
14
14
  */
15
- const mode = resourcePath => {
16
- if ( /globals?\//i.test( resourcePath.replace( /\\/g, '/' ) ) ) {
17
- return 'global';
18
- }
19
- if ( /pcss?\//i.test( resourcePath.replace( /\\/g, '/' ) ) ) {
20
- return 'global';
21
- }
22
- return 'local';
15
+ const mode = (resourcePath) => {
16
+ if (/globals?\//i.test(resourcePath.replace(/\\/g, '/'))) {
17
+ return 'global';
18
+ }
19
+ if (/pcss?\//i.test(resourcePath.replace(/\\/g, '/'))) {
20
+ return 'global';
21
+ }
22
+ return 'local';
23
23
  };
24
-
25
- let cssLoader = {
26
- importLoaders: 1,
27
- modules: {
28
- exportLocalsConvention: 'camelCase',
29
- localIdentName: 'Ⓜ[name]__[local]__[contenthash:base64:2]',
30
- mode,
31
- },
32
- sourceMap: true,
33
- url: false,
24
+ const cssLoader = {
25
+ importLoaders: 1,
26
+ modules: {
27
+ exportLocalsConvention: 'camelCase',
28
+ localIdentName: 'Ⓜ[name]__[local]__[contenthash:base64:2]',
29
+ mode,
30
+ },
31
+ sourceMap: true,
32
+ url: false,
34
33
  };
35
-
36
- if ( 'production' === process.env.NODE_ENV ) {
37
- cssLoader = {
38
- importLoaders: 1,
39
- modules: {
40
- exportLocalsConvention: 'camelCase',
41
- // Use short CSS Classes if enabled.
42
- ...usingShortCssClasses() ? {getLocalIdent} : {},
43
- // Hash used when short CSS classes are not enabled.
44
- localIdentName: '[contenthash:base64:5]',
45
- mode,
46
- },
47
- url: false,
48
- };
34
+ if ('production' === process.env.NODE_ENV) {
35
+ cssLoader.modules = {
36
+ exportLocalsConvention: 'camelCase',
37
+ // Use short CSS Classes if enabled.
38
+ ...(0, css_classnames_1.usingShortCssClasses)() ? { getLocalIdent: css_classnames_1.getLocalIdent } : {},
39
+ // Hash used when short CSS classes are not enabled.
40
+ localIdentName: '[contenthash:base64:5]',
41
+ mode,
42
+ };
43
+ cssLoader.sourceMap = false;
49
44
  }
50
-
51
45
  module.exports = cssLoader;
@@ -0,0 +1,52 @@
1
+ import {getLocalIdent, usingShortCssClasses} from '../helpers/css-classnames';
2
+ import type {Config, Mode} from '../types/css-loader';
3
+ import type {AtLeast} from '../types/utility';
4
+
5
+ export type CssLoaderConfig = AtLeast<Config, 'importLoaders' | 'modules' | 'sourceMap' | 'url'>
6
+
7
+ /**
8
+ * Options for the Webpack `css-loader`.
9
+ *
10
+ * Extracted to its on file to allow easy overrides.
11
+ */
12
+
13
+ /**
14
+ * Default to :global for classes in "global" or "pcss" directories.
15
+ *
16
+ * @param {string} resourcePath
17
+ * @return {string}
18
+ */
19
+ const mode = ( resourcePath: string ): Mode => {
20
+ if ( /globals?\//i.test( resourcePath.replace( /\\/g, '/' ) ) ) {
21
+ return 'global';
22
+ }
23
+ if ( /pcss?\//i.test( resourcePath.replace( /\\/g, '/' ) ) ) {
24
+ return 'global';
25
+ }
26
+ return 'local';
27
+ };
28
+
29
+ const cssLoader: CssLoaderConfig = {
30
+ importLoaders: 1,
31
+ modules: {
32
+ exportLocalsConvention: 'camelCase',
33
+ localIdentName: 'Ⓜ[name]__[local]__[contenthash:base64:2]',
34
+ mode,
35
+ },
36
+ sourceMap: true,
37
+ url: false,
38
+ };
39
+
40
+ if ( 'production' === process.env.NODE_ENV ) {
41
+ cssLoader.modules = {
42
+ exportLocalsConvention: 'camelCase',
43
+ // Use short CSS Classes if enabled.
44
+ ...usingShortCssClasses() ? {getLocalIdent} : {},
45
+ // Hash used when short CSS classes are not enabled.
46
+ localIdentName: '[contenthash:base64:5]',
47
+ mode,
48
+ }
49
+ cssLoader.sourceMap = false;
50
+ }
51
+
52
+ module.exports = cssLoader;
@@ -5,6 +5,7 @@ const fs_1 = require("fs");
5
5
  const config_1 = require("../helpers/config");
6
6
  const package_config_1 = require("../helpers/package-config");
7
7
  const postcss_pretty_1 = require("../lib/postcss-pretty");
8
+ const postcss_clean_1 = require("../lib/postcss-clean");
8
9
  const postcssPresetEnv = require('postcss-preset-env');
9
10
  function isPluginsArray(value) {
10
11
  return Array.isArray(value);
@@ -88,7 +89,7 @@ const config = {
88
89
  if (isPluginsArray(config.plugins)) {
89
90
  if ('production' === process.env.NODE_ENV) {
90
91
  // For production, we minify it.
91
- config.plugins.push(require('../lib/postcss-clean')({
92
+ config.plugins.push((0, postcss_clean_1.default)({
92
93
  level: 2,
93
94
  }));
94
95
  }
@@ -5,6 +5,7 @@ import type Processor from 'postcss/lib/processor';
5
5
  import {getBrowsersList} from '../helpers/config';
6
6
  import {getPackageConfig} from '../helpers/package-config';
7
7
  import PrettyPlugin from '../lib/postcss-pretty';
8
+ import cleanCSS from '../lib/postcss-clean';
8
9
  import type {Config, ConfigPlugin} from 'postcss-load-config';
9
10
  import type {LoaderContext} from 'webpack';
10
11
  import type {Plugin} from 'postcss';
@@ -16,7 +17,7 @@ export type PostCSSConfig = Config & Partial<LoaderContext<Config>> & {
16
17
  parser: string;
17
18
  }
18
19
 
19
- function isPluginsArray( value: unknown ): value is ConfigPlugin[] {
20
+ function isPluginsArray( value: ConfigPlugin[]|false ): value is ConfigPlugin[] {
20
21
  return Array.isArray( value );
21
22
  }
22
23
 
@@ -108,7 +109,7 @@ const config: PostCSSConfig = {
108
109
  if ( isPluginsArray( config.plugins ) ) {
109
110
  if ( 'production' === process.env.NODE_ENV ) {
110
111
  // For production, we minify it.
111
- config.plugins.push( require( '../lib/postcss-clean' )( {
112
+ config.plugins.push( cleanCSS( {
112
113
  level: 2,
113
114
  } ) );
114
115
  } else {
@@ -9,7 +9,6 @@ const ForkTsCheckerWebpackPlugin = require( 'fork-ts-checker-webpack-plugin' );
9
9
  const WebpackAssetsHash = require( '../helpers/WebpackAssetsHash' );
10
10
 
11
11
  const {getConfig, getTsConfigFile, getBrowsersList} = require( '../helpers/config' );
12
- const moduleHelpers = require( '../helpers/modules' );
13
12
  const config = require( '../helpers/package-config' );
14
13
  const {getEntries} = require( '../helpers/entries' );
15
14
  const {getPackageConfig} = require( '../helpers/package-config' );
@@ -122,7 +121,7 @@ module.exports = {
122
121
  {
123
122
  test: /\.[jt]sx?$/,
124
123
  loader: 'babel-loader',
125
- exclude: moduleHelpers.getBabelExcludeRegex(),
124
+ exclude: /node_modules/,
126
125
  options: babelOptions,
127
126
  },
128
127
  {
package/helpers/config.js CHANGED
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.adjustBrowserslist = exports.getDefaultBrowsersList = exports.getBrowsersList = exports.getTsConfigFile = exports.getExtensionsConfig = exports.getConfig = exports.hasLocalOverride = void 0;
3
+ exports.getDefaultBrowsersList = void 0;
4
+ exports.hasLocalOverride = hasLocalOverride;
5
+ exports.getConfig = getConfig;
6
+ exports.getExtensionsConfig = getExtensionsConfig;
7
+ exports.getTsConfigFile = getTsConfigFile;
8
+ exports.getBrowsersList = getBrowsersList;
9
+ exports.adjustBrowserslist = adjustBrowserslist;
4
10
  const fs_1 = require("fs");
5
11
  const path_1 = require("path");
6
12
  const package_config_1 = require("./package-config");
@@ -32,10 +38,14 @@ function hasLocalOverride(fileName, inWorkingDirectory = false) {
32
38
  }
33
39
  }
34
40
  catch (e) {
41
+ if (e instanceof Error) {
42
+ if (!('code' in e) || 'MODULE_NOT_FOUND' !== e.code) {
43
+ console.error(e);
44
+ }
45
+ }
35
46
  }
36
47
  return hasLocal;
37
48
  }
38
- exports.hasLocalOverride = hasLocalOverride;
39
49
  /**
40
50
  * Get a config from our /config directory merged with any
41
51
  * matching configuration from the project directory.
@@ -77,10 +87,14 @@ function getConfig(fileName) {
77
87
  }
78
88
  }
79
89
  catch (e) {
90
+ if (e instanceof Error) {
91
+ if (!('code' in e) || 'MODULE_NOT_FOUND' !== e.code) {
92
+ console.error(e);
93
+ }
94
+ }
80
95
  }
81
96
  return mergedConfig;
82
97
  }
83
- exports.getConfig = getConfig;
84
98
  /**
85
99
  * Get a config from any existing extension's /config directories
86
100
  * merged into one.
@@ -106,11 +120,15 @@ function getExtensionsConfig(fileName, defaultConfig) {
106
120
  }
107
121
  }
108
122
  catch (e) {
123
+ if (e instanceof Error) {
124
+ if (!('code' in e) || 'MODULE_NOT_FOUND' !== e.code) {
125
+ console.error(e);
126
+ }
127
+ }
109
128
  }
110
129
  });
111
130
  return mergedConfig;
112
131
  }
113
- exports.getExtensionsConfig = getExtensionsConfig;
114
132
  /**
115
133
  * Get the path to the "tsconfig.json" file if it exists.
116
134
  *
@@ -134,7 +152,6 @@ function getTsConfigFile() {
134
152
  });
135
153
  return tsConfig;
136
154
  }
137
- exports.getTsConfigFile = getTsConfigFile;
138
155
  /**
139
156
  * Get the browserslist from the current project.
140
157
  *
@@ -150,7 +167,6 @@ function getBrowsersList() {
150
167
  }
151
168
  return projectBrowsersList;
152
169
  }
153
- exports.getBrowsersList = getBrowsersList;
154
170
  /**
155
171
  * If browserslist is not specified, we fall back to WordPress defaults.
156
172
  *
@@ -183,4 +199,3 @@ function adjustBrowserslist(browserRules) {
183
199
  browserRules.push('not op_mini all');
184
200
  return browserRules;
185
201
  }
186
- exports.adjustBrowserslist = adjustBrowserslist;
package/helpers/config.ts CHANGED
@@ -6,6 +6,7 @@ import type {JestConfig} from '../config/jest.config';
6
6
  import {getPackageConfig} from './package-config';
7
7
  import type {EntriesConfig} from '../config/entries.config';
8
8
  import type {Config as PostCSSConfig} from 'postcss-load-config';
9
+ import type {CssLoaderConfig} from '../config/css-loader.config';
9
10
 
10
11
  // Must be required to avoid issues with browserslist.
11
12
  const browserslist = require( 'browserslist' );
@@ -13,6 +14,7 @@ const browserslist = require( 'browserslist' );
13
14
 
14
15
  type Configs = {
15
16
  'babel.config': BabelConfig;
17
+ 'css-loader.config': CssLoaderConfig;
16
18
  'entries.config': EntriesConfig;
17
19
  'jest.config': JestConfig;
18
20
  'postcss.config': PostCSSConfig;
@@ -46,6 +48,11 @@ export function hasLocalOverride( fileName: string, inWorkingDirectory: boolean
46
48
  hasLocal = true;
47
49
  }
48
50
  } catch ( e ) {
51
+ if ( e instanceof Error ) {
52
+ if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) {
53
+ console.error( e );
54
+ }
55
+ }
49
56
  }
50
57
 
51
58
  return hasLocal;
@@ -91,6 +98,11 @@ export function getConfig<T extends keyof Configs>( fileName: T ): Configs[T] {
91
98
  mergedConfig = {...mergedConfig, ...localConfig};
92
99
  }
93
100
  } catch ( e ) {
101
+ if ( e instanceof Error ) {
102
+ if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) {
103
+ console.error( e );
104
+ }
105
+ }
94
106
  }
95
107
  return mergedConfig;
96
108
  }
@@ -119,6 +131,11 @@ export function getExtensionsConfig<T extends object>( fileName: string, default
119
131
  mergedConfig = {...mergedConfig, ...extensionConfig};
120
132
  }
121
133
  } catch ( e ) {
134
+ if ( e instanceof Error ) {
135
+ if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) {
136
+ console.error( e );
137
+ }
138
+ }
122
139
  }
123
140
  } );
124
141
 
@@ -1,34 +1,35 @@
1
- const {getPackageConfig} = require( './package-config' );
2
-
3
- const SHORT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
4
- const ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
5
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLocalIdent = exports.ALPHABET = exports.SHORT_ALPHABET = void 0;
4
+ exports.usingShortCssClasses = usingShortCssClasses;
5
+ exports.resetCounters = resetCounters;
6
+ exports.getNextClass = getNextClass;
7
+ const package_config_1 = require("./package-config");
8
+ exports.SHORT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
9
+ exports.ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
6
10
  const classes = {};
7
- let counters = [ -1 ];
8
-
11
+ let counters = [-1];
9
12
  /**
10
13
  * Check if short CSS classes are enabled.
11
14
  *
12
15
  * Using a helper function to allow for future enhancements.
13
16
  *
14
- * @since 10.3.0
17
+ * @since 4.6.0
15
18
  */
16
19
  function usingShortCssClasses() {
17
- return getPackageConfig().shortCssClasses;
20
+ return Boolean((0, package_config_1.getPackageConfig)().shortCssClasses);
18
21
  }
19
-
20
22
  /**
21
23
  * Reset all counters.
22
24
  *
23
25
  * @notice Mostly here for unit tests.
24
26
  */
25
27
  function resetCounters() {
26
- counters = [ -1 ];
28
+ counters = [-1];
27
29
  }
28
-
29
30
  /**
30
31
  * Get the next class is sequence based on:
31
- * 1. Single character from SHORT_ALPHABET (prevent conflicts with CSS boilerplate).
32
+ * 1. Single character from SHORT_ALPHABET (prevent conflicts with JS boilerplate).
32
33
  * 2. Incremented character from the `ALPHABET`.
33
34
  * 1. Used once require 2+ characters.
34
35
  * 2. Grows to 3+ characters as needed.
@@ -36,26 +37,22 @@ function resetCounters() {
36
37
  * @return {string}
37
38
  */
38
39
  function getNextClass() {
39
- const last = counters.length - 1;
40
- let totalLetters = ALPHABET.length - 1;
41
-
42
- // First level uses the SHORT_ALPHABET.
43
- if ( 0 === last ) {
44
- totalLetters = SHORT_ALPHABET.length - 1;
45
- }
46
-
47
- if ( counters[ last ] < totalLetters ) {
48
- counters[ last ]++;
49
- } else {
50
- incrementParent();
51
- }
52
-
53
- return counters.map( ( counter, i ) => {
54
- return 0 === i ? SHORT_ALPHABET[ counter ] : ALPHABET[ counter ];
55
- } ).join( '' );
40
+ const last = counters.length - 1;
41
+ let totalLetters = exports.ALPHABET.length - 1;
42
+ // First level uses the SHORT_ALPHABET.
43
+ if (0 === last) {
44
+ totalLetters = exports.SHORT_ALPHABET.length - 1;
45
+ }
46
+ if (counters[last] < totalLetters) {
47
+ counters[last]++;
48
+ }
49
+ else {
50
+ incrementParent();
51
+ }
52
+ return counters.map((counter, i) => {
53
+ return 0 === i ? exports.SHORT_ALPHABET[counter] : exports.ALPHABET[counter];
54
+ }).join('');
56
55
  }
57
-
58
-
59
56
  /**
60
57
  * When we run out of characters on the current level:
61
58
  * 1. Increment the parent level.
@@ -68,31 +65,28 @@ function getNextClass() {
68
65
  *
69
66
  */
70
67
  function incrementParent() {
71
- let parent = counters.length - 2;
72
- let totalLetters = ALPHABET.length - 1;
73
-
74
- while ( counters[ parent ] !== undefined ) {
75
- // First level uses the SHORT_ALPHABET.
76
- if ( 0 === parent ) {
77
- totalLetters = SHORT_ALPHABET.length - 1;
78
- }
79
- if ( counters[ parent ] < totalLetters ) {
80
- counters[ parent ]++;
81
- // Reset all child levels to 0.
82
- while ( counters[ parent + 1 ] !== undefined ) {
83
- counters[ parent + 1 ] = 0;
84
- parent++;
85
- }
86
- return;
87
- }
88
- parent--;
89
- }
90
-
91
- // Add a new level and reset all existing levels.
92
- counters.forEach( ( _, i ) => counters[ i ] = 0 );
93
- counters.push( 0 );
68
+ let parent = counters.length - 2;
69
+ let totalLetters = exports.ALPHABET.length - 1;
70
+ while (counters[parent] !== undefined) {
71
+ // First level uses the SHORT_ALPHABET.
72
+ if (0 === parent) {
73
+ totalLetters = exports.SHORT_ALPHABET.length - 1;
74
+ }
75
+ if (counters[parent] < totalLetters) {
76
+ counters[parent]++;
77
+ // Reset all child levels to 0.
78
+ while (counters[parent + 1] !== undefined) {
79
+ counters[parent + 1] = 0;
80
+ parent++;
81
+ }
82
+ return;
83
+ }
84
+ parent--;
85
+ }
86
+ // Add a new level and reset all existing levels.
87
+ counters.forEach((_, i) => counters[i] = 0);
88
+ counters.push(0);
94
89
  }
95
-
96
90
  /**
97
91
  * Return a single character unique CSS class name based on WebPack
98
92
  * css-loader's `getLocalIdentName` callback.
@@ -104,17 +98,9 @@ function incrementParent() {
104
98
  *
105
99
  * @link https://webpack.js.org/loaders/css-loader/#getlocalident
106
100
  */
107
- const getLocalIdent = ( {resourcePath}, _, localName ) => {
108
- classes[ resourcePath ] ||= {};
109
- classes[ resourcePath ][ localName ] ||= getNextClass();
110
- return classes[ resourcePath ][ localName ];
111
- };
112
-
113
- module.exports = {
114
- ALPHABET,
115
- SHORT_ALPHABET,
116
- getLocalIdent,
117
- getNextClass,
118
- usingShortCssClasses,
119
- resetCounters,
101
+ const getLocalIdent = ({ resourcePath }, _, localName) => {
102
+ classes[resourcePath] ||= {};
103
+ classes[resourcePath][localName] ||= getNextClass();
104
+ return classes[resourcePath][localName];
120
105
  };
106
+ exports.getLocalIdent = getLocalIdent;
@@ -0,0 +1,117 @@
1
+ import {getPackageConfig} from './package-config';
2
+ import type {GetLocalIdent, Resource} from '../types/css-loader';
3
+
4
+ export const SHORT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
5
+ export const ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
6
+
7
+ const classes: {
8
+ [ filename: string ]: {
9
+ [ className: string ]: string
10
+ }
11
+ } = {};
12
+
13
+ let counters = [ -1 ];
14
+
15
+ /**
16
+ * Check if short CSS classes are enabled.
17
+ *
18
+ * Using a helper function to allow for future enhancements.
19
+ *
20
+ * @since 4.6.0
21
+ */
22
+ export function usingShortCssClasses(): boolean {
23
+ return Boolean( getPackageConfig().shortCssClasses );
24
+ }
25
+
26
+ /**
27
+ * Reset all counters.
28
+ *
29
+ * @notice Mostly here for unit tests.
30
+ */
31
+ export function resetCounters(): void {
32
+ counters = [ -1 ];
33
+ }
34
+
35
+ /**
36
+ * Get the next class is sequence based on:
37
+ * 1. Single character from SHORT_ALPHABET (prevent conflicts with JS boilerplate).
38
+ * 2. Incremented character from the `ALPHABET`.
39
+ * 1. Used once require 2+ characters.
40
+ * 2. Grows to 3+ characters as needed.
41
+ *
42
+ * @return {string}
43
+ */
44
+ export function getNextClass(): string {
45
+ const last = counters.length - 1;
46
+ let totalLetters = ALPHABET.length - 1;
47
+
48
+ // First level uses the SHORT_ALPHABET.
49
+ if ( 0 === last ) {
50
+ totalLetters = SHORT_ALPHABET.length - 1;
51
+ }
52
+
53
+ if ( counters[ last ] < totalLetters ) {
54
+ counters[ last ]++;
55
+ } else {
56
+ incrementParent();
57
+ }
58
+
59
+ return counters.map( ( counter, i ) => {
60
+ return 0 === i ? SHORT_ALPHABET[ counter ] : ALPHABET[ counter ];
61
+ } ).join( '' );
62
+ }
63
+
64
+
65
+ /**
66
+ * When we run out of characters on the current level:
67
+ * 1. Increment the parent level.
68
+ * 2. Reset current level and all child levels back to 0.
69
+ *
70
+ * If we are out of characters on the parent level or have
71
+ * no parent level:
72
+ * 1. Add a new child level.
73
+ * 2. Reset all levels back to 0.
74
+ *
75
+ */
76
+ function incrementParent() {
77
+ let parent = counters.length - 2;
78
+ let totalLetters = ALPHABET.length - 1;
79
+
80
+ while ( counters[ parent ] !== undefined ) {
81
+ // First level uses the SHORT_ALPHABET.
82
+ if ( 0 === parent ) {
83
+ totalLetters = SHORT_ALPHABET.length - 1;
84
+ }
85
+ if ( counters[ parent ] < totalLetters ) {
86
+ counters[ parent ]++;
87
+ // Reset all child levels to 0.
88
+ while ( counters[ parent + 1 ] !== undefined ) {
89
+ counters[ parent + 1 ] = 0;
90
+ parent++;
91
+ }
92
+ return;
93
+ }
94
+ parent--;
95
+ }
96
+
97
+ // Add a new level and reset all existing levels.
98
+ counters.forEach( ( _, i ) => counters[ i ] = 0 );
99
+ counters.push( 0 );
100
+ }
101
+
102
+ /**
103
+ * Return a single character unique CSS class name based on WebPack
104
+ * css-loader's `getLocalIdentName` callback.
105
+ *
106
+ * Tracks CSS classes per each file so duplicate uses of the
107
+ * same class in a file receive the same result.
108
+ *
109
+ * @notice Only enabled if the `package.json` has `shortCssClasses` set to true.
110
+ *
111
+ * @link https://webpack.js.org/loaders/css-loader/#getlocalident
112
+ */
113
+ export const getLocalIdent: GetLocalIdent = ( {resourcePath}: Resource, _: string, localName: string ): string => {
114
+ classes[ resourcePath ] ||= {};
115
+ classes[ resourcePath ][ localName ] ||= getNextClass();
116
+ return classes[ resourcePath ][ localName ];
117
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEntries = void 0;
3
+ exports.getEntries = getEntries;
4
4
  const config_1 = require("./config");
5
5
  const package_config_1 = require("./package-config");
6
6
  const fs_1 = require("fs");
@@ -28,4 +28,3 @@ function getEntries() {
28
28
  });
29
29
  return matches;
30
30
  }
31
- exports.getEntries = getEntries;
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPackageConfig = void 0;
3
+ exports.getPackageConfig = getPackageConfig;
4
4
  const path_1 = require("path");
5
5
  const node_fs_1 = require("node:fs");
6
6
  const workingDirectory = (0, node_fs_1.realpathSync)(process.cwd());
7
7
  const defaults = {
8
8
  brotliFiles: false,
9
9
  cssTsFiles: false,
10
- es6Modules: [],
11
10
  jsPath: './',
12
11
  packageDirectory: workingDirectory,
13
12
  shortCssClasses: false,
@@ -33,7 +32,6 @@ catch (e) {
33
32
  function getPackageConfig() {
34
33
  return packageConfig;
35
34
  }
36
- exports.getPackageConfig = getPackageConfig;
37
35
  packageConfig.getPackageConfig = getPackageConfig;
38
36
  packageConfig.default = packageConfig;
39
37
  module.exports = packageConfig;
@@ -12,7 +12,6 @@ export interface PackageConfig {
12
12
  dependencies: Dependencies;
13
13
  description?: string;
14
14
  devDependencies: Dependencies;
15
- es6Modules: string[];
16
15
  getPackageConfig: () => PackageConfig;
17
16
  jsPath: string;
18
17
  license?: string;
@@ -51,7 +50,6 @@ const workingDirectory = realpathSync( process.cwd() );
51
50
  const defaults: Partial<PackageConfig> = {
52
51
  brotliFiles: false,
53
52
  cssTsFiles: false,
54
- es6Modules: [],
55
53
  jsPath: './',
56
54
  packageDirectory: workingDirectory,
57
55
  shortCssClasses: false,
@@ -1,10 +1,11 @@
1
- 'use strict';
2
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.postcss = void 0;
3
4
  /**
4
- * Mimic the postcss-clean plugin.
5
+ * Mimic the `postcss-clean` plugin.
5
6
  *
6
- * Override due to the plugin using version 4 of clean-css, which
7
- * has issues with PostCSS 7/8 and results in inconstant CSS.
7
+ * Override due to the plugin using version 4 of `clean-css`, which
8
+ * has issues with PostCSS 7/8 and results in inconsistent CSS.
8
9
  *
9
10
  * This may potentially be removed in favor of using that plugin again if
10
11
  * they change the version of PostCSS to 8 and Clean CSS to 5.
@@ -14,31 +15,28 @@
14
15
  * @link https://www.npmjs.com/package/postcss-clean
15
16
  *
16
17
  */
17
- const postcss = require( 'postcss' );
18
- const CleanCss = require( 'clean-css' );
19
-
20
- module.exports = ( opts = {} ) => {
21
- const clean = new CleanCss( opts );
22
-
23
- return {
24
- postcssPlugin: 'clean',
25
- OnceExit( css, {result} ) {
26
- return new Promise( ( resolve, reject ) => {
27
- clean.minify( css.toString(), ( err, min ) => {
28
- if ( err ) {
29
- return reject( new Error( err.join( '\n' ) ) );
30
- }
31
-
32
- if ( min.warnings.length > 0 ) {
33
- return reject( new Error( 'postcss-clean minify failed! \n' + min.warnings.join( '\n' ) ) );
34
- }
35
-
36
- result.root = postcss.parse( min.styles );
37
- resolve();
38
- } );
39
- } );
40
- },
41
- };
18
+ const postcss_1 = require("postcss");
19
+ // Can't use `import` due to the plugin not supporting a default export.
20
+ const CleanCSS = require('clean-css');
21
+ const cleaner = (opts = {}) => {
22
+ const clean = new CleanCSS(opts);
23
+ return {
24
+ postcssPlugin: 'clean',
25
+ OnceExit(css, { result }) {
26
+ return new Promise((resolve, reject) => {
27
+ clean.minify(css.toString(), (err, min) => {
28
+ if (null !== err) {
29
+ return reject(new Error(err.join('\n')));
30
+ }
31
+ if (min.warnings.length > 0) {
32
+ return reject(new Error('postcss-clean minify failed! \n' + min.warnings.join('\n')));
33
+ }
34
+ result.root = postcss_1.default.parse(min.styles);
35
+ resolve();
36
+ });
37
+ });
38
+ },
39
+ };
42
40
  };
43
-
44
- module.exports.postcss = true;
41
+ exports.postcss = true;
42
+ exports.default = cleaner;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Mimic the `postcss-clean` plugin.
3
+ *
4
+ * Override due to the plugin using version 4 of `clean-css`, which
5
+ * has issues with PostCSS 7/8 and results in inconsistent CSS.
6
+ *
7
+ * This may potentially be removed in favor of using that plugin again if
8
+ * they change the version of PostCSS to 8 and Clean CSS to 5.
9
+ *
10
+ * Decided to use this `lib` instead of maintaining another fork.
11
+ *
12
+ * @link https://www.npmjs.com/package/postcss-clean
13
+ *
14
+ */
15
+ import postCss, {type Helpers, type Plugin, type Root} from 'postcss';
16
+ import type {MinifierOutput, OptionsOutput, Output} from 'clean-css';
17
+
18
+ // Can't use `import` due to the plugin not supporting a default export.
19
+ const CleanCSS = require( 'clean-css' );
20
+
21
+ const cleaner = ( opts: OptionsOutput = {} ): Plugin => {
22
+ const clean: MinifierOutput = new CleanCSS( opts );
23
+
24
+ return {
25
+ postcssPlugin: 'clean',
26
+ OnceExit( css: Root, {result}: Helpers ) {
27
+ return new Promise( ( resolve, reject ) => {
28
+ clean.minify( css.toString(), ( err, min: Output ) => {
29
+ if ( null !== err ) {
30
+ return reject( new Error( err.join( '\n' ) ) );
31
+ }
32
+
33
+ if ( min.warnings.length > 0 ) {
34
+ return reject( new Error( 'postcss-clean minify failed! \n' + min.warnings.join( '\n' ) ) );
35
+ }
36
+
37
+ result.root = postCss.parse( min.styles );
38
+ resolve();
39
+ } );
40
+ } );
41
+ },
42
+ };
43
+ };
44
+
45
+ export const postcss = true;
46
+ export default cleaner;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@lipemat/js-boilerplate",
3
- "version": "10.9.0",
3
+ "version": "10.10.0",
4
4
  "description": "Dependencies and scripts for a no config JavaScript app",
5
5
  "author": "Mat Lipe",
6
6
  "license": "MIT",
7
7
  "engines": {
8
- "node": ">=16.14.2"
8
+ "node": ">=20.11.0"
9
9
  },
10
10
  "bugs": {
11
11
  "url": "https://github.com/lipemat/js-boilerplate/issues"
@@ -17,7 +17,6 @@
17
17
  },
18
18
  "sideEffects": false,
19
19
  "keywords": [
20
- "react",
21
20
  "boilerplate",
22
21
  "ES6",
23
22
  "no-config"
@@ -28,7 +27,8 @@
28
27
  "config/",
29
28
  "helpers/",
30
29
  "lib/",
31
- "scripts/"
30
+ "scripts/",
31
+ "types/"
32
32
  ],
33
33
  "bin": {
34
34
  "lipemat-js-boilerplate": "bin/lipemat-js-boilerplate.js"
@@ -43,23 +43,22 @@
43
43
  "watch": "ts-node ./bin/watch.ts"
44
44
  },
45
45
  "dependencies": {
46
- "@babel/core": "^7.4.3",
46
+ "@babel/core": "^7.24.7",
47
47
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
48
- "@babel/plugin-transform-react-jsx-source": "^7.12.1",
49
- "@babel/preset-env": "^7.22.9",
50
- "@babel/preset-react": "^7.12.10",
51
- "@babel/preset-typescript": "^7.12.7",
48
+ "@babel/plugin-transform-react-jsx-source": "^7.24.7",
49
+ "@babel/preset-env": "^7.24.7",
50
+ "@babel/preset-react": "^7.24.7",
51
+ "@babel/preset-typescript": "^7.24.7",
52
52
  "@csstools/postcss-global-data": "2.0.0",
53
53
  "@lipemat/eslint-config": "^3.1.3",
54
54
  "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
55
55
  "@statoscope/webpack-plugin": "^5.28.2",
56
56
  "@teamsupercell/typings-for-css-modules-loader": "^2.5.2",
57
57
  "@types/babel__preset-env": "^7.9.6",
58
- "@types/node": "^16",
58
+ "@types/clean-css": "^4.2.11",
59
59
  "@types/postcss-load-config": "^3.0.1",
60
60
  "@types/postcss-preset-env": "^7.7.0",
61
61
  "@wordpress/browserslist-config": "^5.19.0",
62
- "are-you-es5": "^2.1.1",
63
62
  "babel-jest": "^29.0.0",
64
63
  "babel-loader": "9.1.2",
65
64
  "browserslist": "^4.21.9",
@@ -89,13 +88,10 @@
89
88
  "postcss-scss": "^4.0.4",
90
89
  "postcss-sort-media-queries": "^5.2.0",
91
90
  "prettier": "^3.1.1",
92
- "react": "^18.2.0",
93
- "react-dom": "^18.2.0",
94
91
  "react-refresh": "^0.14.0",
95
92
  "style-loader": "^3.3.1",
96
93
  "ts-node": "^10.9.1",
97
- "typescript": "^5.1.3",
98
- "update-notifier": "^4.1.3",
94
+ "typescript": "^5.5.2",
99
95
  "webpack": "^5.72.1",
100
96
  "webpack-assets-manifest": "^5.0.6",
101
97
  "webpack-cli": "^4.9.1",
@@ -105,11 +101,12 @@
105
101
  "devDependencies": {
106
102
  "@types/jest": "^29.5.3",
107
103
  "@types/minimist": "^1",
104
+ "@types/node": "~20.11.0",
108
105
  "chokidar": "^3.5.3",
109
106
  "eslint": "^8",
110
107
  "glob": "^10.3.3",
111
108
  "memfs": "^3.5.3",
112
109
  "setimmediate": "^1.0.5"
113
110
  },
114
- "packageManager": "yarn@4.1.1"
111
+ "packageManager": "yarn@4.3.1"
115
112
  }
package/tsconfig.json CHANGED
@@ -9,7 +9,8 @@
9
9
  "lib/**/*",
10
10
  "jest/**/*",
11
11
  "scripts/**/*",
12
- "src/**/*"
12
+ "src/**/*",
13
+ "types/**/*",
13
14
  ],
14
15
  "compilerOptions": {
15
16
  "esModuleInterop": true,
@@ -0,0 +1,87 @@
1
+ /**
2
+ * No public types available.
3
+ *
4
+ * @link https://webpack.js.org/loaders/css-loader/#options
5
+ */
6
+
7
+ import type {LoaderContext} from 'webpack';
8
+
9
+ export type Mode = 'local' | 'global' | 'pure' | 'icss';
10
+
11
+ export type Resource = LoaderContext<{
12
+ resourcePath: string
13
+ }>;
14
+
15
+ export type GetLocalIdent = ( context: Resource, localIdentName: string, localName: string ) => string;
16
+
17
+ export type Modules =
18
+ | boolean
19
+ | 'local'
20
+ | 'global'
21
+ | 'pure'
22
+ | 'icss'
23
+ | {
24
+ auto: boolean | RegExp | ( ( resourcePath: string ) => boolean );
25
+ mode: Mode | ( ( resourcePath: string ) => Mode );
26
+ localIdentName: string;
27
+ localIdentContext: string;
28
+ localIdentHashSalt: string;
29
+ localIdentHashFunction: string;
30
+ localIdentHashDigest: string;
31
+ localIdentRegExp: string | RegExp;
32
+ getLocalIdent: GetLocalIdent;
33
+ namedExport: boolean;
34
+ exportGlobals: boolean;
35
+ exportLocalsConvention:
36
+ | 'asIs'
37
+ | 'camelCase'
38
+ | 'camelCaseOnly'
39
+ | 'dashes'
40
+ | 'dashesOnly'
41
+ | ( ( name: string ) => string );
42
+ exportOnlyLocals: boolean;
43
+ getJSON: ( {
44
+ resourcePath,
45
+ imports,
46
+ exports,
47
+ replacements,
48
+ }: {
49
+ resourcePath: string;
50
+ imports: object[];
51
+ exports: object[];
52
+ replacements: object[];
53
+ } ) => Promise<void> | void;
54
+ };
55
+
56
+ type Base = {
57
+ importLoaders?: number;
58
+ sourceMap?: boolean;
59
+ url?: boolean | {
60
+ filter: ( url: string, resourcePath: string ) => boolean;
61
+ };
62
+ importFn?: boolean | {
63
+ filter: (
64
+ url: string,
65
+ media: string,
66
+ resourcePath: string,
67
+ supports?: string,
68
+ layer?: string,
69
+ ) => boolean;
70
+ };
71
+ esModule?: boolean;
72
+ };
73
+
74
+
75
+ type CssStyleSheetExport = Base & {
76
+ exportType?: 'css-style-sheet' | 'string';
77
+ modules?: Partial<Modules> & {
78
+ exportLocalsConvention: 'camelCaseOnly' | 'dashesOnly'
79
+ };
80
+ };
81
+
82
+ type ArrayExport = Base & {
83
+ exportType?: 'array';
84
+ modules: Partial<Modules>
85
+ };
86
+
87
+ export type Config = CssStyleSheetExport | ArrayExport;
@@ -0,0 +1 @@
1
+ export type AtLeast<T, K extends keyof T> = Partial<T> & Required<Pick<T, K>>;
@@ -1,28 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBabelExcludeRegex = void 0;
4
- const babel_loader_regex_builder_1 = require("are-you-es5/dist/babel-loader-regex-builder");
5
- const package_config_1 = require("./package-config");
6
- const are_you_es5_1 = require("are-you-es5");
7
- /**
8
- * Using `are-you-es5` generate a list of top level dependencies
9
- * which are not ES5 safe. Create a regular expression which excludes
10
- * the `node_modules` directory except for any ES6 modules.
11
- *
12
- * Allows Babel to transpile any node_modules which are not available in ES5.
13
- *
14
- * @notice Only checks packages listed in package.json, not sub packages.
15
- *
16
- * @return {RegExp}
17
- */
18
- function getBabelExcludeRegex() {
19
- const nonES5 = (0, are_you_es5_1.checkModules)({});
20
- // Support specifying additional es5Modules in package.json.
21
- const regex = (0, babel_loader_regex_builder_1.getBabelLoaderIgnoreRegex)([
22
- ...nonES5.es6Modules,
23
- ...(0, package_config_1.getPackageConfig)().es6Modules,
24
- ]);
25
- // We must strip off the leading and trailing '/'.
26
- return new RegExp(regex.replace(/^\/|\/$/g, ''));
27
- }
28
- exports.getBabelExcludeRegex = getBabelExcludeRegex;
@@ -1,26 +0,0 @@
1
- import {getBabelLoaderIgnoreRegex} from 'are-you-es5/dist/babel-loader-regex-builder';
2
- import {getPackageConfig} from './package-config';
3
- import {checkModules} from 'are-you-es5';
4
-
5
- /**
6
- * Using `are-you-es5` generate a list of top level dependencies
7
- * which are not ES5 safe. Create a regular expression which excludes
8
- * the `node_modules` directory except for any ES6 modules.
9
- *
10
- * Allows Babel to transpile any node_modules which are not available in ES5.
11
- *
12
- * @notice Only checks packages listed in package.json, not sub packages.
13
- *
14
- * @return {RegExp}
15
- */
16
- export function getBabelExcludeRegex(): RegExp {
17
- const nonES5 = checkModules( {} );
18
- // Support specifying additional es5Modules in package.json.
19
- const regex = getBabelLoaderIgnoreRegex( [
20
- ...nonES5.es6Modules,
21
- ...getPackageConfig().es6Modules,
22
- ] );
23
-
24
- // We must strip off the leading and trailing '/'.
25
- return new RegExp( regex.replace( /^\/|\/$/g, '' ) );
26
- }