@lipemat/js-boilerplate 8.3.0 → 8.5.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.
@@ -9,10 +9,7 @@ const presetEnv = {
9
9
  };
10
10
 
11
11
  /**
12
- * If browserslist is not specified, we fallback to WordPress defaults
13
- * except for IE11 which we don't support by default.
14
- *
15
- * @link https://babeljs.io/docs/en/babel-preset-env#targets
12
+ * Use shared browserslist configurations.
16
13
  */
17
14
  if ( getDefaultBrowsersList() ) {
18
15
  presetEnv.targets = getDefaultBrowsersList();
@@ -30,4 +27,3 @@ module.exports = {
30
27
  'react-hot-loader/babel',
31
28
  ],
32
29
  };
33
-
@@ -14,6 +14,9 @@ let jestConfig = {
14
14
  moduleNameMapper: {
15
15
  '\\.(pcss|less|css)$': 'identity-obj-proxy',
16
16
  },
17
+ roots: [
18
+ './tests',
19
+ ],
17
20
  testURL: packageConfig.url,
18
21
  transform: {
19
22
  '^.+\\.[tj]sx?$': [ 'babel-jest', babelConfig ],
@@ -1,4 +1,5 @@
1
1
  const moduleHelpers = require( '../helpers/modules' );
2
+ const {getLocalIdent} = require( '../helpers/css-classnames' );
2
3
  const webpack = require( 'webpack' );
3
4
  const path = require( 'path' );
4
5
  const fs = require( 'fs' );
@@ -102,6 +103,9 @@ module.exports = {
102
103
  importLoaders: 1,
103
104
  modules: {
104
105
  exportLocalsConvention: 'camelCase',
106
+ // Use short CSS Classes if enabled.
107
+ ...config.shortCssClasses ? {getLocalIdent} : {},
108
+ // Hash used when short CSS classes are not enabled.
105
109
  localIdentName: '[contenthash:base64:5]',
106
110
  // Default to :global for classes in "global" directories.
107
111
  mode: resourcePath => {
package/helpers/config.js CHANGED
@@ -37,6 +37,22 @@ function hasLocalOverride( fileName, inWorkingDirectory = false ) {
37
37
  * we will merge the contents with our config/babel.config.js in favor of whatever
38
38
  * is specified with the project's file.
39
39
  *
40
+ * If the `module.exports` are a function, the existing configuration will be passed
41
+ * as the only argument. Otherwise, standard `module.exports` are also supported.
42
+ *
43
+ * @example ```ts
44
+ * // standard
45
+ * module.export = {
46
+ * externals: {extra: 'Extra'}
47
+ * }
48
+ * // function
49
+ * module.exports = function( config ) {
50
+ * return {
51
+ * externals: {...config.externals, extra: 'Extra'}
52
+ * }
53
+ * }
54
+ * ```
55
+ *
40
56
  * @param {string} $fileName
41
57
  *
42
58
  * @return {Object}
@@ -45,7 +61,11 @@ function getConfig( $fileName ) {
45
61
  let config = {...require( '../config/' + $fileName ), ...getExtensionsConfig( $fileName )};
46
62
  try {
47
63
  const localConfig = require( path.resolve( packageConfig.packageDirectory + '/config', $fileName ) );
48
- config = {...config, ...localConfig};
64
+ if ( 'function' === typeof localConfig ) {
65
+ config = {...config, ...localConfig( config )};
66
+ } else {
67
+ config = {...config, ...localConfig};
68
+ }
49
69
  } catch ( e ) {
50
70
  }
51
71
  return config;
@@ -55,6 +75,8 @@ function getConfig( $fileName ) {
55
75
  * Get a config from any existing extension's /config directories
56
76
  * merged into one.
57
77
  *
78
+ * @see getConfig
79
+ *
58
80
  * @param {string} $fileName
59
81
  *
60
82
  * @return {Object}
@@ -64,7 +86,11 @@ function getExtensionsConfig( $fileName ) {
64
86
  extensions.forEach( extension => {
65
87
  try {
66
88
  const extensionConfig = require( extension + '/config/' + $fileName );
67
- config = {...config, ...extensionConfig};
89
+ if ( 'function' === typeof extensionConfig ) {
90
+ config = {...config, ...extensionConfig( config )};
91
+ } else {
92
+ config = {...config, ...extensionConfig};
93
+ }
68
94
  } catch ( e ) {
69
95
  }
70
96
  } );
@@ -73,8 +99,8 @@ function getExtensionsConfig( $fileName ) {
73
99
  }
74
100
 
75
101
  /**
76
- * If browserslist is not specified, we fallback to WordPress defaults
77
- * except for IE11 which we don't support by default.
102
+ * If browserslist is not specified, we fall back to WordPress defaults
103
+ * except for > 1% we don't support by default.
78
104
  *
79
105
  * Return false if a browserslist is specified in the current project.
80
106
  *
@@ -0,0 +1,106 @@
1
+ const SHORT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
2
+ const ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
3
+
4
+ const classes = {};
5
+ let counters = [ -1 ];
6
+
7
+ /**
8
+ * Reset all counters.
9
+ *
10
+ * @notice Mostly here for unit tests.
11
+ */
12
+ function resetCounters() {
13
+ counters = [ -1 ];
14
+ }
15
+
16
+ /**
17
+ * Get the next class is sequence based on:
18
+ * 1. Single character from shortAlphabet (prevent conflicts with CSS boilerplate).
19
+ * 2. Incremented character from the `alphabet`.
20
+ * 1. Used once require 2+ characters.
21
+ * 2. Grows to 3+ characters as needed.
22
+ *
23
+ * @return {string}
24
+ */
25
+ function getNextClass() {
26
+ const last = counters.length - 1;
27
+ let totalLetters = ALPHABET.length - 1;
28
+
29
+ // First level uses the SHORT_ALPHABET.
30
+ if ( 0 === last ) {
31
+ totalLetters = SHORT_ALPHABET.length - 1;
32
+ }
33
+
34
+ if ( counters[ last ] < totalLetters ) {
35
+ counters[ last ]++;
36
+ } else {
37
+ incrementParent();
38
+ }
39
+
40
+ return counters.map( ( counter, i ) => {
41
+ return 0 === i ? SHORT_ALPHABET[ counter ] : ALPHABET[ counter ];
42
+ } ).join( '' );
43
+ }
44
+
45
+
46
+ /**
47
+ * When we run out of characters on the current level:
48
+ * 1. Increment the parent level.
49
+ * 2. Reset current level and all child levels back to 0.
50
+ *
51
+ * If we are out of characters on the parent level or have
52
+ * no parent level:
53
+ * 1. Add a new child level.
54
+ * 2. Reset all levels back to 0.
55
+ *
56
+ */
57
+ function incrementParent() {
58
+ let parent = counters.length - 2;
59
+ let totalLetters = ALPHABET.length - 1;
60
+
61
+ while ( counters[ parent ] !== undefined ) {
62
+ // First level uses the SHORT_ALPHABET.
63
+ if ( 0 === parent ) {
64
+ totalLetters = SHORT_ALPHABET.length - 1;
65
+ }
66
+ if ( counters[ parent ] < totalLetters ) {
67
+ counters[ parent ]++;
68
+ // Reset all child levels to 0.
69
+ while ( counters[ parent + 1 ] !== undefined ) {
70
+ counters[ parent + 1 ] = 0;
71
+ parent++;
72
+ }
73
+ return;
74
+ }
75
+ parent--;
76
+ }
77
+
78
+ // Add a new level and reset all existing levels.
79
+ counters.forEach( ( _, i ) => counters[ i ] = 0 );
80
+ counters.push( 0 );
81
+ }
82
+
83
+ /**
84
+ * Return a single character unique CSS class name based on WebPack
85
+ * css-loader's `getLocalIdentName` callback.
86
+ *
87
+ * Tracks CSS classes per each file so duplicate uses of the
88
+ * same class in a file receive the same result.
89
+ *
90
+ * @notice Only enabled if the `package.json` has `shortCssClasses` set to true.
91
+ *
92
+ * @link https://webpack.js.org/loaders/css-loader/#getlocalident
93
+ */
94
+ const getLocalIdent = ( {resourcePath}, _, localName ) => {
95
+ classes[ resourcePath ] ||= {};
96
+ classes[ resourcePath ][ localName ] ||= getNextClass();
97
+ return classes[ resourcePath ][ localName ];
98
+ };
99
+
100
+ module.exports = {
101
+ ALPHABET,
102
+ SHORT_ALPHABET,
103
+ getLocalIdent,
104
+ getNextClass,
105
+ resetCounters,
106
+ };
package/package.json CHANGED
@@ -1,14 +1,21 @@
1
1
  {
2
2
  "name": "@lipemat/js-boilerplate",
3
- "version": "8.3.0",
3
+ "version": "8.5.0",
4
4
  "description": "Dependencies and scripts for a no config JavaScript app",
5
+ "author": "Mat Lipe",
6
+ "license": "MIT",
5
7
  "engines": {
6
8
  "node": ">=14.17.6"
7
9
  },
10
+ "bugs": {
11
+ "url": "https://github.com/lipemat/js-boilerplate/issues"
12
+ },
13
+ "homepage": "https://github.com/lipemat/js-boilerplate#readme",
8
14
  "repository": {
9
15
  "type": "git",
10
16
  "url": "git+https://github.com/lipemat/js-boilerplate.git"
11
17
  },
18
+ "sideEffects": false,
12
19
  "keywords": [
13
20
  "react",
14
21
  "boilerplate",
@@ -25,9 +32,9 @@
25
32
  "bin": {
26
33
  "lipemat-js-boilerplate": "bin/lipemat-js-boilerplate.js"
27
34
  },
28
- "author": "Mat Lipe",
29
- "license": "MIT",
30
- "sideEffects": false,
35
+ "scripts": {
36
+ "test": "lipemat-js-boilerplate test --silent"
37
+ },
31
38
  "dependencies": {
32
39
  "@babel/core": "^7.4.3",
33
40
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
@@ -41,7 +48,7 @@
41
48
  "@lipemat/postcss-loader": "^3.1.2",
42
49
  "@lipemat/webpack-cleanup-plugin": "^1.0.0",
43
50
  "@types/lipemat__js-boilerplate": "lipemat/types-js-boilerplate#semver:^1.3.0",
44
- "@wojtekmaj/enzyme-adapter-react-17": "^0.6.6",
51
+ "@wojtekmaj/enzyme-adapter-react-17": "^0.6.7",
45
52
  "@wordpress/browserslist-config": "^4.1.0",
46
53
  "are-you-es5": "^2.1.1",
47
54
  "babel-jest": "^24.7.1",
@@ -67,7 +74,6 @@
67
74
  "postcss-nested": "^4.1.2",
68
75
  "postcss-preset-env": "^6.6.0",
69
76
  "postcss-scss": "^2.0.0",
70
- "prop-types": "^15.7.2",
71
77
  "react": "^17.0.1",
72
78
  "react-dom": "^17.0.1",
73
79
  "react-hot-loader": "^4.8.3",
@@ -82,9 +88,5 @@
82
88
  "webpack-dev-server": "^4.7.2",
83
89
  "webpack-subresource-integrity": "^1.5.2"
84
90
  },
85
- "bugs": {
86
- "url": "https://github.com/lipemat/js-boilerplate/issues"
87
- },
88
- "homepage": "https://github.com/lipemat/js-boilerplate#readme",
89
91
  "packageManager": "yarn@3.2.0"
90
92
  }