minify-css-idents 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of minify-css-idents might be problematic. Click here for more details.
- package/LICENSE.txt +21 -0
- package/README.md +206 -0
- package/dist/IdentGenerator.d.ts +66 -0
- package/dist/IdentGenerator.js +201 -0
- package/dist/MinifyCssIdentsError.d.ts +27 -0
- package/dist/MinifyCssIdentsError.js +38 -0
- package/dist/MinifyCssIdentsPlugin.d.ts +94 -0
- package/dist/MinifyCssIdentsPlugin.js +172 -0
- package/dist/css-loader.d.ts +25 -0
- package/dist/css-loader.js +29 -0
- package/dist/utils.d.ts +32 -0
- package/dist/utils.js +102 -0
- package/package.json +76 -0
package/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
# Minify CSS Identifiers
|
2
|
+
|
3
|
+
![CI Tests status](https://github.com/adrien-febvay/minify-css-idents/actions/workflows/ci-tests.yml/badge.svg)
|
4
|
+
|
5
|
+
Webpack plug-in using [css-loader](https://www.npmjs.com/package/css-loader) to shorten identifiers and make CSS files lighter.
|
6
|
+
|
7
|
+
For maximum efficiency, also use a CSS minifier like [css-minimizer-webpack-plugin/](https://webpack.js.org/plugins/css-minimizer-webpack-plugin/).
|
8
|
+
|
9
|
+
## Setup
|
10
|
+
|
11
|
+
### Installation
|
12
|
+
|
13
|
+
```sh
|
14
|
+
npm install --save-dev minify-css-idents
|
15
|
+
```
|
16
|
+
|
17
|
+
### Webpack configuration
|
18
|
+
|
19
|
+
This is the typical configuration that should be compatible all use cases.
|
20
|
+
|
21
|
+
Just replace the `css-loader` with `minify-css-idents/css-loader`, ie:
|
22
|
+
|
23
|
+
```js
|
24
|
+
module.exports = {
|
25
|
+
module: {
|
26
|
+
rules: [
|
27
|
+
{
|
28
|
+
test: /\.css$/,
|
29
|
+
use: [
|
30
|
+
"style-loader",
|
31
|
+
{
|
32
|
+
loader: "minify-css-idents/css-loader",
|
33
|
+
options: {
|
34
|
+
// Your usual css-loader configuration here,
|
35
|
+
// to setup how to build unminified CSS identifiers
|
36
|
+
// consistently accross all build steps
|
37
|
+
modules: {
|
38
|
+
localIdentContext: 'common-path-for-all-build-steps',
|
39
|
+
localIdentName: '[path]___[name]__[local]',
|
40
|
+
}
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"postcss-loader"
|
44
|
+
]
|
45
|
+
}
|
46
|
+
]
|
47
|
+
}
|
48
|
+
};
|
49
|
+
```
|
50
|
+
|
51
|
+
Then add the minifier to the plugins:
|
52
|
+
|
53
|
+
```js
|
54
|
+
const MinifyCssIdentsPlugin = require("minify-css-idents");
|
55
|
+
module.exports = {
|
56
|
+
plugins: [
|
57
|
+
new MinifyCssIdentsPlugin({
|
58
|
+
exclude: ["global-identifiers-here"],
|
59
|
+
inputMap: "path-to-prior/idents-map.json",
|
60
|
+
outputMap: "path-to-new/idents-map.json",
|
61
|
+
})
|
62
|
+
]
|
63
|
+
};
|
64
|
+
```
|
65
|
+
|
66
|
+
## Options
|
67
|
+
|
68
|
+
Available options to specify in the instanciation of `MinifyCssIdentsPlugin`:
|
69
|
+
|
70
|
+
```js
|
71
|
+
new MinifyCssIdentsPlugin({
|
72
|
+
enabled: true,
|
73
|
+
exclude: ["some-ident", "some-ident-prefix-*"],
|
74
|
+
inputMap: "path-to-prior/idents.map.json",
|
75
|
+
mapIndent: 2,
|
76
|
+
outputMap: "path-to-new/idents.map.json",
|
77
|
+
startIdent: "some-minified-ident-to-start-with",
|
78
|
+
});
|
79
|
+
```
|
80
|
+
|
81
|
+
### options.enabled
|
82
|
+
|
83
|
+
Default value: Webpack's [optimization.minimize](https://webpack.js.org/configuration/optimization/#optimizationminimize) option value when set, otherwise `true` when [mode](https://webpack.js.org/configuration/mode/) is set to "production" or omitted and `false` in any other mode.
|
84
|
+
|
85
|
+
Enables/disables the minification of CSS identifiers.
|
86
|
+
|
87
|
+
### options.exclude
|
88
|
+
|
89
|
+
Default value: `["ad*", "app", "root"]`
|
90
|
+
|
91
|
+
Identifiers of identifier prefixes the minifier should not generate. You should put there all global identifiers your project uses that could match a minified one.
|
92
|
+
|
93
|
+
A global identifier is one that wouldn't get changed by `css-loaded`, either because it is wrapped by `:global()`, or because the CSS is not processed by [css-loader](https://www.npmjs.com/package/css-loader) to begin with (typically the stylesheet of an external module in which classnames are hard-coded).
|
94
|
+
|
95
|
+
You may also add there identifiers that may be problematics, like any identifier beginning with "ad".
|
96
|
+
|
97
|
+
Also, note that a global identifier/prefix longer than 10 characters, not beginning with a letter or having characters others than letters and digits cannot match a minified identifier. It is then not necessary to specify it in this option and it would be ignored anyway.
|
98
|
+
|
99
|
+
### options.inputMap
|
100
|
+
|
101
|
+
Default value: `null`
|
102
|
+
|
103
|
+
Pathname to the identifier map file of the previous build step, relative to Webpack's context path.
|
104
|
+
|
105
|
+
If your project has several build steps, loading the previously emitted map is needed in order to keep the identifiers consistent.
|
106
|
+
|
107
|
+
### options.mapIndent
|
108
|
+
|
109
|
+
Default value: `2`
|
110
|
+
|
111
|
+
The indentation size to use in the identifier map file. Set it to `0` if you want a minimal file without spaces and line returns.
|
112
|
+
|
113
|
+
### options.outputMap
|
114
|
+
|
115
|
+
Default value: `null`
|
116
|
+
|
117
|
+
Pathname to the identifier map file to emit, relative to Webpack's output path.
|
118
|
+
|
119
|
+
If your project has several build steps, emitting a map for the next build step is needed in order to keep the identifiers consistent.
|
120
|
+
|
121
|
+
### options.startIdent
|
122
|
+
|
123
|
+
Default value: `null`
|
124
|
+
|
125
|
+
Identifier to start the generation with.
|
126
|
+
|
127
|
+
Please note that this identifier will be skipped if it matches a value in the "exclude" option, and ignored if it is not valid.
|
128
|
+
|
129
|
+
## Alternative syntax
|
130
|
+
|
131
|
+
Should `minify-css-idents/css-loader` not work properly or should your configuration not allow to use it, you may rely on the `MinifyCssIdentsPlugin.getLocalIdent` function, ie:
|
132
|
+
|
133
|
+
```js
|
134
|
+
const MinifyCssIdentsPlugin = require("minify-css-idents");
|
135
|
+
module.exports = {
|
136
|
+
module: {
|
137
|
+
rules: [
|
138
|
+
{
|
139
|
+
test: /\.css$/,
|
140
|
+
use: [
|
141
|
+
"style-loader",
|
142
|
+
{
|
143
|
+
loader: "css-loader",
|
144
|
+
options: {
|
145
|
+
modules: {
|
146
|
+
getLocalIdent: MinifyCssIdentsPlugin.getLocalIdent
|
147
|
+
}
|
148
|
+
}
|
149
|
+
},
|
150
|
+
"postcss-loader"
|
151
|
+
]
|
152
|
+
}
|
153
|
+
]
|
154
|
+
}
|
155
|
+
};
|
156
|
+
```
|
157
|
+
|
158
|
+
If you already rely on a custom [getLocalIdent](https://webpack.js.org/loaders/css-loader/#getlocalident) function to generate unminified CSS identifiers, you may specify it:
|
159
|
+
|
160
|
+
```js
|
161
|
+
modules: {
|
162
|
+
getLocalIdent: MinifyCssIdentsPlugin.getLocalIdent(your_former_getLocalIdent_here)
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
## How the package works and additional notes
|
167
|
+
|
168
|
+
### About the loader
|
169
|
+
|
170
|
+
The `minify-css-idents/css-loader` wraps [css-loader](https://www.npmjs.com/package/css-loader) in order to override its [getLocalIdent](https://webpack.js.org/loaders/css-loader/#getlocalident) option, which allows to specify a function to generate CSS identifiers.
|
171
|
+
|
172
|
+
### About CSS identifiers generation
|
173
|
+
|
174
|
+
A minified identifier is a positive integer number representation in base 36 not beginning with a digit. Because of JavaScript's integer limitations (see [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)), they are limited to 10 characters. It matches the regular expression `/^[a-z][0-9a-z]{0,9}$/i`.
|
175
|
+
|
176
|
+
In simpler terms, a minified identifier is a letter eventually followed by up to 9 letters and digits.
|
177
|
+
|
178
|
+
Before generating a minified identifier, the `MinifyCssIdentsPlugin.getLocalIdent` function generates an unminified one just as [css-loader](https://www.npmjs.com/package/css-loader) would, using the [getLocalIdent](https://webpack.js.org/loaders/css-loader/#getlocalident) function specified in the loader options, or the default one provided with [css-loader](https://www.npmjs.com/package/css-loader).
|
179
|
+
|
180
|
+
### About the plugin
|
181
|
+
|
182
|
+
When `MinifyCssIdentsPlugin` is registered in Webpack's plug-ins, it has the opportunity to emit and/or load an identifier map file.
|
183
|
+
This feature is critical to keep the identifiers consistent across build steps.
|
184
|
+
|
185
|
+
It uses the `beforeCompile` hook of Webpack's compiler to load the prior map, then the `compilation` and `afterProcessAssets` hooks to emit the new map.
|
186
|
+
|
187
|
+
When `MinifyCssIdentsPlugin` is omitted, it will instanciate automatically with its default options. However, it might not be able to detect the value of Webpack's [optimization.minimize](https://webpack.js.org/configuration/optimization/#optimizationminimize) option in the future, as the way of accessing the compiler's options from a loader is deprecated.
|
188
|
+
|
189
|
+
### About the "exclude" option
|
190
|
+
|
191
|
+
It does not accept regular expressions for two reasons:
|
192
|
+
1. Lack of efficiency: Every generated identifier would be matched with every provided RegExp. By only accepting string identifiers and prefixes, the identifier generator can instead plan in advance for which identifiers it must avoid and do so very efficiently.
|
193
|
+
2. Probably useless: Because of the format of minified identifiers, there shouldn't be a lot of exclusions to specify to begin with. Handling regular expressions therefore seems like an overkill.
|
194
|
+
|
195
|
+
Such a feature could be developed on request, but at the moment it just seems unecessary.
|
196
|
+
|
197
|
+
## Credits
|
198
|
+
|
199
|
+
### Author
|
200
|
+
|
201
|
+
Adrien Febvay https://github.com/adrien-febvay
|
202
|
+
|
203
|
+
### Special thanks
|
204
|
+
|
205
|
+
Gajus Kuizinas https://github.com/gajus <br>
|
206
|
+
For writing an article about [Reducing CSS bundle size 70% by cutting the class names and using scope isolation](https://medium.com/free-code-camp/reducing-css-bundle-size-70-by-cutting-the-class-names-and-using-scope-isolation-625440de600b).
|
@@ -0,0 +1,66 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
import { MinifyCssIdentsError } from './MinifyCssIdentsError';
|
25
|
+
import { Falsy } from './utils';
|
26
|
+
declare class IdentGenerator {
|
27
|
+
readonly options: IdentGenerator.Options.Sanitized;
|
28
|
+
protected readonly excludeRanges: [Range, ...Range[]];
|
29
|
+
protected currExcludeRange: Range;
|
30
|
+
protected currIdentIndex: number;
|
31
|
+
identMap: IdentGenerator.Map;
|
32
|
+
constructor(options?: IdentGenerator.Options | null);
|
33
|
+
get lastIdent(): string;
|
34
|
+
protected addExcludeRange(newRange: Range): void;
|
35
|
+
generateIdent(key: string): string;
|
36
|
+
importMap(map: IdentGenerator.Map): void;
|
37
|
+
loadMap(filename: string, ignoreNoEnt?: boolean): void;
|
38
|
+
protected nextExcludeRange(): Range;
|
39
|
+
stringifyMap(indent?: number): string;
|
40
|
+
static readonly Error: typeof MinifyCssIdentsError;
|
41
|
+
static readonly identRx: RegExp;
|
42
|
+
protected static implicitInstance?: IdentGenerator;
|
43
|
+
static generateIdent(key: string): string;
|
44
|
+
static parseIdent(ident: string): number;
|
45
|
+
static sanitizeExclusions(excludeOption: Falsy<readonly Falsy<string>[]>): string[] | null;
|
46
|
+
}
|
47
|
+
declare namespace IdentGenerator {
|
48
|
+
type Error = MinifyCssIdentsError;
|
49
|
+
type Map = {
|
50
|
+
[Key in string]?: string;
|
51
|
+
};
|
52
|
+
interface Options {
|
53
|
+
readonly exclude?: Falsy<readonly Falsy<string>[]>;
|
54
|
+
readonly mapIndent?: Falsy<number>;
|
55
|
+
readonly startIdent?: Falsy<string>;
|
56
|
+
}
|
57
|
+
namespace Options {
|
58
|
+
interface Sanitized {
|
59
|
+
readonly exclude: readonly string[];
|
60
|
+
readonly mapIndent: number;
|
61
|
+
readonly startIdent: string | null;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
type Range = readonly [startIndex: number, endIndex: number, repeat?: boolean];
|
66
|
+
export = IdentGenerator;
|
@@ -0,0 +1,201 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
"use strict";
|
25
|
+
const fs_1 = require("fs");
|
26
|
+
const MinifyCssIdentsError_1 = require("./MinifyCssIdentsError");
|
27
|
+
const utils_1 = require("./utils");
|
28
|
+
const MAX_IDENT_INDEX = 3656158440062975;
|
29
|
+
const MAX_REPEATABLE_RANGE_INDEX = 101559956668415;
|
30
|
+
const noRange = [Infinity, Infinity];
|
31
|
+
class IdentGenerator {
|
32
|
+
constructor(options) {
|
33
|
+
var _a;
|
34
|
+
this.excludeRanges = [[1, 10, true], noRange];
|
35
|
+
this.currExcludeRange = noRange;
|
36
|
+
this.identMap = {};
|
37
|
+
if ((options === null || options === void 0 ? void 0 : options.exclude) && options.exclude.filter((ident) => /^\*|\*./.test(ident || '')).length) {
|
38
|
+
const details = 'The * wildchar can only be used at the end of an identifier';
|
39
|
+
throw new MinifyCssIdentsError_1.MinifyCssIdentsError('Invalid "exclude" option', details);
|
40
|
+
}
|
41
|
+
this.options = Object.freeze({
|
42
|
+
exclude: (_a = IdentGenerator.sanitizeExclusions(options === null || options === void 0 ? void 0 : options.exclude)) !== null && _a !== void 0 ? _a : ['ad*', 'app', 'root'],
|
43
|
+
mapIndent: (options === null || options === void 0 ? void 0 : options.mapIndent) || 2,
|
44
|
+
startIdent: (options === null || options === void 0 ? void 0 : options.startIdent) || null,
|
45
|
+
});
|
46
|
+
this.currIdentIndex = IdentGenerator.parseIdent((options === null || options === void 0 ? void 0 : options.startIdent) || '') - 1 || 0;
|
47
|
+
for (const item of this.options.exclude) {
|
48
|
+
const isPrefix = item.slice(-1) === '*';
|
49
|
+
const ident = isPrefix ? item.slice(0, -1) : item;
|
50
|
+
const startIndex = parseInt(ident, 36);
|
51
|
+
this.addExcludeRange([startIndex, startIndex + 1, isPrefix]);
|
52
|
+
}
|
53
|
+
this.nextExcludeRange();
|
54
|
+
IdentGenerator.implicitInstance = this;
|
55
|
+
}
|
56
|
+
get lastIdent() {
|
57
|
+
return this.currIdentIndex.toString(36);
|
58
|
+
}
|
59
|
+
addExcludeRange(newRange) {
|
60
|
+
const { excludeRanges } = this;
|
61
|
+
const [newStartIndex] = newRange;
|
62
|
+
let rangeIndex = 0;
|
63
|
+
for (const [startIndex] of excludeRanges) {
|
64
|
+
if (newStartIndex < startIndex) {
|
65
|
+
break;
|
66
|
+
}
|
67
|
+
else {
|
68
|
+
rangeIndex += 1;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
excludeRanges.splice(rangeIndex, 0, newRange);
|
72
|
+
}
|
73
|
+
generateIdent(key) {
|
74
|
+
let identIndex = this.currIdentIndex;
|
75
|
+
if (this.identMap[key]) {
|
76
|
+
return this.identMap[key];
|
77
|
+
}
|
78
|
+
else if (identIndex >= MAX_IDENT_INDEX) {
|
79
|
+
return key;
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
identIndex += 1;
|
83
|
+
for (let [start, end] = this.currExcludeRange; identIndex >= start; [start, end] = this.nextExcludeRange()) {
|
84
|
+
identIndex = end > identIndex ? end : identIndex;
|
85
|
+
}
|
86
|
+
this.currIdentIndex = identIndex;
|
87
|
+
return (this.identMap[key] = this.lastIdent);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
importMap(map) {
|
91
|
+
let maxIdent = this.lastIdent;
|
92
|
+
for (const key in map) {
|
93
|
+
const ident = map[key];
|
94
|
+
if (typeof ident === 'string') {
|
95
|
+
if ((ident.length > maxIdent.length || ident > maxIdent) && IdentGenerator.identRx.test(ident)) {
|
96
|
+
maxIdent = ident;
|
97
|
+
}
|
98
|
+
this.identMap[key] = ident;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
this.currIdentIndex = parseInt(maxIdent, 36);
|
102
|
+
}
|
103
|
+
loadMap(filename, ignoreNoEnt) {
|
104
|
+
const mapBytes = readMap(filename, ignoreNoEnt);
|
105
|
+
if (mapBytes !== null) {
|
106
|
+
this.importMap(parseMap(mapBytes, filename));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
nextExcludeRange() {
|
110
|
+
this.currExcludeRange = this.excludeRanges[0];
|
111
|
+
this.excludeRanges.shift();
|
112
|
+
const [startIndex, endIndex, repeat] = this.currExcludeRange;
|
113
|
+
if (repeat && startIndex < MAX_REPEATABLE_RANGE_INDEX) {
|
114
|
+
this.addExcludeRange([startIndex * 36, endIndex * 36, true]);
|
115
|
+
}
|
116
|
+
return this.currExcludeRange;
|
117
|
+
}
|
118
|
+
stringifyMap(indent = this.options.mapIndent) {
|
119
|
+
return `${JSON.stringify(this.identMap, null, indent)}\n`;
|
120
|
+
}
|
121
|
+
static generateIdent(key) {
|
122
|
+
var _a;
|
123
|
+
(_a = IdentGenerator.implicitInstance) !== null && _a !== void 0 ? _a : (IdentGenerator.implicitInstance = new IdentGenerator());
|
124
|
+
return IdentGenerator.implicitInstance.generateIdent(key);
|
125
|
+
}
|
126
|
+
static parseIdent(ident) {
|
127
|
+
return this.identRx.test(ident) ? parseInt(ident, 36) : NaN;
|
128
|
+
}
|
129
|
+
static sanitizeExclusions(excludeOption) {
|
130
|
+
if (excludeOption) {
|
131
|
+
return excludeOption
|
132
|
+
.filter(utils_1.isTruthy)
|
133
|
+
.filter((ident) => this.identRx.test(ident))
|
134
|
+
.map((ident) => ident.toLowerCase())
|
135
|
+
.sort((a, b) => {
|
136
|
+
const aPrfx = a.slice(-1) === '*';
|
137
|
+
const bPrfx = b.slice(-1) === '*';
|
138
|
+
const aId = aPrfx ? a.slice(0, -1) : a;
|
139
|
+
const bId = bPrfx ? b.slice(0, -1) : b;
|
140
|
+
return aId.length - bId.length || (aId > bId ? 1 : aId < bId ? -1 : Number(bPrfx) - Number(aPrfx));
|
141
|
+
})
|
142
|
+
.filter((ident, index, idents) => {
|
143
|
+
for (const otherIdent of idents.slice(0, index)) {
|
144
|
+
if (otherIdent.slice(-1) === '*' ? ident.startsWith(otherIdent.slice(0, -1)) : ident === otherIdent) {
|
145
|
+
return false;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
return true;
|
149
|
+
});
|
150
|
+
}
|
151
|
+
else {
|
152
|
+
return null;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
IdentGenerator.Error = MinifyCssIdentsError_1.MinifyCssIdentsError;
|
157
|
+
IdentGenerator.identRx = /^[a-z][^\W_]{0,9}\*?$/i;
|
158
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
159
|
+
const loadMap = IdentGenerator.prototype.loadMap;
|
160
|
+
function parseMap(bytes, filename) {
|
161
|
+
var _a;
|
162
|
+
let data;
|
163
|
+
try {
|
164
|
+
data = JSON.parse(bytes);
|
165
|
+
}
|
166
|
+
catch (cause) {
|
167
|
+
throw new MinifyCssIdentsError_1.MinifyCssIdentsError(`Failure to parse ${filename}`, cause, loadMap);
|
168
|
+
}
|
169
|
+
const causes = [];
|
170
|
+
if (!(0, utils_1.isDictLike)(data)) {
|
171
|
+
causes.push(`Expected string dictionary, got ${(0, utils_1.type)(data)}`);
|
172
|
+
}
|
173
|
+
else {
|
174
|
+
for (const key in data) {
|
175
|
+
if (typeof data[key] !== 'string') {
|
176
|
+
(_a = causes[0]) !== null && _a !== void 0 ? _a : (causes[0] = `Expected string dictionary, but:`);
|
177
|
+
causes.push(` - Item ${JSON.stringify(key)} is ${(0, utils_1.type)(data[key])}`);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
if (causes.length) {
|
182
|
+
throw new MinifyCssIdentsError_1.MinifyCssIdentsError(`Invalid CSS identifier map in ${filename}`, causes.join('\n'), loadMap);
|
183
|
+
}
|
184
|
+
else {
|
185
|
+
return data;
|
186
|
+
}
|
187
|
+
}
|
188
|
+
function readMap(filename, ignoreNoEnt) {
|
189
|
+
try {
|
190
|
+
return (0, fs_1.readFileSync)(filename, 'utf-8');
|
191
|
+
}
|
192
|
+
catch (cause) {
|
193
|
+
if (ignoreNoEnt && (0, utils_1.isError)(cause) && cause.code === 'ENOENT') {
|
194
|
+
return null;
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
throw new MinifyCssIdentsError_1.MinifyCssIdentsError(`Failure to read ${filename}`, cause, loadMap);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
module.exports = IdentGenerator;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
export declare class MinifyCssIdentsError extends Error {
|
25
|
+
constructor(message: string, cause?: unknown, capture?: (this: unknown, ...args: any[]) => void);
|
26
|
+
static message(message: string, cause?: unknown): string;
|
27
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
"use strict";
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.MinifyCssIdentsError = void 0;
|
27
|
+
class MinifyCssIdentsError extends Error {
|
28
|
+
constructor(message, cause, capture) {
|
29
|
+
super(MinifyCssIdentsError.message(message, cause));
|
30
|
+
if (capture) {
|
31
|
+
Error.captureStackTrace(this, capture);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
static message(message, cause) {
|
35
|
+
return `${message}\n ${String(cause).replace(/\n/g, '\n ')}`;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
exports.MinifyCssIdentsError = MinifyCssIdentsError;
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
import type { Compiler, LoaderContext as LegacyContext, LoaderDefinition } from 'webpack';
|
25
|
+
import { Module } from 'webpack';
|
26
|
+
import { MinifyCssIdentsError } from './MinifyCssIdentsError';
|
27
|
+
import { Falsy } from './utils';
|
28
|
+
import IdentGeneratorImport from './IdentGenerator';
|
29
|
+
declare class MinifyCssIdentsPlugin extends Module {
|
30
|
+
readonly options: MinifyCssIdentsPlugin.Options.Sanitized;
|
31
|
+
protected readonly identGenerator: IdentGeneratorImport;
|
32
|
+
protected applied: boolean;
|
33
|
+
protected enabled: boolean | null;
|
34
|
+
constructor(options?: MinifyCssIdentsPlugin.Options | null);
|
35
|
+
get cssLoader(): LoaderDefinition;
|
36
|
+
get getLocalIdent(): {
|
37
|
+
(this: unknown, priorGetLocalIdent?: MinifyCssIdentsPlugin.GetLocalIdentFn | undefined): GetLocalIdentFn;
|
38
|
+
(this: unknown, context: MinifyCssIdentsPlugin.LoaderContext, localIdentName: string, localName: string, options: object): string;
|
39
|
+
};
|
40
|
+
apply(compiler: Compiler): void;
|
41
|
+
static readonly Error: typeof MinifyCssIdentsError;
|
42
|
+
static readonly IdentGenerator: typeof IdentGeneratorImport;
|
43
|
+
protected static implicitInstance?: MinifyCssIdentsPlugin;
|
44
|
+
static readonly symbol: unique symbol;
|
45
|
+
static readonly defaultGetLocalIdent: typeof defaultGetLocalIdent;
|
46
|
+
protected static createCssLoader(plugin?: MinifyCssIdentsPlugin): LoaderDefinition;
|
47
|
+
static get cssLoader(): LoaderDefinition;
|
48
|
+
protected static getInstance(context: MinifyCssIdentsPlugin.LoaderContext): MinifyCssIdentsPlugin;
|
49
|
+
static get getLocalIdent(): {
|
50
|
+
(this: unknown, priorGetLocalIdent?: MinifyCssIdentsPlugin.GetLocalIdentFn | undefined): GetLocalIdentFn;
|
51
|
+
(this: unknown, context: MinifyCssIdentsPlugin.LoaderContext, localIdentName: string, localName: string, options: object): string;
|
52
|
+
};
|
53
|
+
}
|
54
|
+
declare function defaultGetLocalIdent(this: unknown, ...args: Parameters<GetLocalIdentFn>): string;
|
55
|
+
declare namespace MinifyCssIdentsPlugin {
|
56
|
+
type Error = MinifyCssIdentsError;
|
57
|
+
interface GetLocalIdentFn {
|
58
|
+
(this: unknown, context: LoaderContext, localIdentName: string, localName: string, options: object): string;
|
59
|
+
}
|
60
|
+
namespace GetLocalIdentFn {
|
61
|
+
interface Extended extends GetLocalIdentFn {
|
62
|
+
(priorGetLocalIdent?: GetLocalIdentFn): GetLocalIdentFn;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
type IdentGenerator = IdentGeneratorImport;
|
66
|
+
namespace IdentGenerator {
|
67
|
+
type Error = IdentGeneratorImport.Error;
|
68
|
+
type Map = IdentGeneratorImport.Map;
|
69
|
+
type Options = IdentGeneratorImport.Options;
|
70
|
+
namespace Options {
|
71
|
+
type Sanitized = IdentGeneratorImport.Options.Sanitized;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
interface LoaderContext extends LegacyContext<NodeJS.Dict<unknown>> {
|
75
|
+
[MinifyCssIdentsPlugin.symbol]?: MinifyCssIdentsPlugin;
|
76
|
+
}
|
77
|
+
interface Options extends IdentGenerator.Options {
|
78
|
+
enabled?: Falsy<boolean>;
|
79
|
+
inputMap?: Falsy<string>;
|
80
|
+
outputMap?: Falsy<string>;
|
81
|
+
}
|
82
|
+
namespace Options {
|
83
|
+
interface Sanitized extends IdentGenerator.Options.Sanitized {
|
84
|
+
enabled: boolean | null;
|
85
|
+
inputMap: string | null;
|
86
|
+
outputMap: string | null;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
type GetLocalIdentFn = MinifyCssIdentsPlugin.GetLocalIdentFn;
|
91
|
+
declare namespace GetLocalIdentFn {
|
92
|
+
type Extended = MinifyCssIdentsPlugin.GetLocalIdentFn.Extended;
|
93
|
+
}
|
94
|
+
export = MinifyCssIdentsPlugin;
|
@@ -0,0 +1,172 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
"use strict";
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
26
|
+
if (k2 === undefined) k2 = k;
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
30
|
+
}
|
31
|
+
Object.defineProperty(o, k2, desc);
|
32
|
+
}) : (function(o, m, k, k2) {
|
33
|
+
if (k2 === undefined) k2 = k;
|
34
|
+
o[k2] = m[k];
|
35
|
+
}));
|
36
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
37
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
38
|
+
}) : function(o, v) {
|
39
|
+
o["default"] = v;
|
40
|
+
});
|
41
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
42
|
+
if (mod && mod.__esModule) return mod;
|
43
|
+
var result = {};
|
44
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
45
|
+
__setModuleDefault(result, mod);
|
46
|
+
return result;
|
47
|
+
};
|
48
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
49
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
50
|
+
};
|
51
|
+
const css_loader_1 = __importStar(require("css-loader"));
|
52
|
+
const path_1 = require("path");
|
53
|
+
const webpack_1 = require("webpack");
|
54
|
+
const MinifyCssIdentsError_1 = require("./MinifyCssIdentsError");
|
55
|
+
const utils_1 = require("./utils");
|
56
|
+
const IdentGenerator_1 = __importDefault(require("./IdentGenerator"));
|
57
|
+
class MinifyCssIdentsPlugin extends webpack_1.Module {
|
58
|
+
constructor(options) {
|
59
|
+
super('css/minify-ident');
|
60
|
+
this.applied = false;
|
61
|
+
this.identGenerator = new IdentGenerator_1.default(options);
|
62
|
+
this.options = Object.freeze(Object.assign({ enabled: (options === null || options === void 0 ? void 0 : options.enabled) == null ? null : Boolean(options.enabled), inputMap: (options === null || options === void 0 ? void 0 : options.inputMap) || null, outputMap: (options === null || options === void 0 ? void 0 : options.outputMap) || null }, this.identGenerator.options));
|
63
|
+
this.enabled = this.options.enabled;
|
64
|
+
MinifyCssIdentsPlugin.implicitInstance = this;
|
65
|
+
}
|
66
|
+
get cssLoader() {
|
67
|
+
return MinifyCssIdentsPlugin.createCssLoader(this);
|
68
|
+
}
|
69
|
+
get getLocalIdent() {
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
71
|
+
const plugin = this;
|
72
|
+
let priorGetLocalIdent = defaultGetLocalIdent;
|
73
|
+
function getLocalIdent(...args) {
|
74
|
+
var _a, _b, _c, _d;
|
75
|
+
if (args[0] === void 0 || typeof args[0] === 'function') {
|
76
|
+
priorGetLocalIdent = (_a = args[0]) !== null && _a !== void 0 ? _a : priorGetLocalIdent;
|
77
|
+
return getLocalIdent;
|
78
|
+
}
|
79
|
+
else {
|
80
|
+
const [context, ...otherArgs] = args;
|
81
|
+
(_b = plugin.enabled) !== null && _b !== void 0 ? _b : (plugin.enabled = (_d = (_c = context._compiler) === null || _c === void 0 ? void 0 : _c.options.optimization.minimize) !== null && _d !== void 0 ? _d : context.mode === 'production');
|
82
|
+
const priorLocalIdent = priorGetLocalIdent.call(this, context, ...otherArgs);
|
83
|
+
return plugin.enabled ? plugin.identGenerator.generateIdent(priorLocalIdent) : priorLocalIdent;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return getLocalIdent;
|
87
|
+
}
|
88
|
+
apply(compiler) {
|
89
|
+
var _a;
|
90
|
+
if (!this.applied) {
|
91
|
+
const { name } = MinifyCssIdentsPlugin;
|
92
|
+
const { outputMap, enabled, inputMap } = this.options;
|
93
|
+
this.enabled = (_a = enabled !== null && enabled !== void 0 ? enabled : compiler.options.optimization.minimize) !== null && _a !== void 0 ? _a : compiler.options.mode === 'production';
|
94
|
+
if (this.enabled && inputMap) {
|
95
|
+
const resolvedSourceMap = (0, path_1.isAbsolute)(inputMap) ? inputMap : (0, path_1.join)(compiler.context, inputMap);
|
96
|
+
compiler.hooks.beforeCompile.tap(name, () => this.identGenerator.loadMap(resolvedSourceMap));
|
97
|
+
}
|
98
|
+
compiler.hooks.compilation.tap(name, (compilation) => {
|
99
|
+
compiler.webpack.NormalModule.getCompilationHooks(compilation).loader.tap(name, (context) => {
|
100
|
+
context[MinifyCssIdentsPlugin.symbol] = this;
|
101
|
+
});
|
102
|
+
if (this.enabled && outputMap) {
|
103
|
+
const stage = webpack_1.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE;
|
104
|
+
compilation.hooks.afterProcessAssets.tap({ stage, name }, () => {
|
105
|
+
const relativeEmitMap = (0, path_1.isAbsolute)(outputMap) ? (0, path_1.relative)(compiler.outputPath, outputMap) : outputMap;
|
106
|
+
compilation.emitAsset(relativeEmitMap, new webpack_1.sources.RawSource(this.identGenerator.stringifyMap()));
|
107
|
+
});
|
108
|
+
}
|
109
|
+
});
|
110
|
+
this.applied = true;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
static createCssLoader(plugin) {
|
114
|
+
let minifyCssIdentsPlugin = plugin;
|
115
|
+
let options;
|
116
|
+
function cssLoader(...args) {
|
117
|
+
const legacyGetOptions = this.getOptions.bind(this);
|
118
|
+
function getOptions(schema = {}) {
|
119
|
+
var _a;
|
120
|
+
if (!options) {
|
121
|
+
options = legacyGetOptions(schema);
|
122
|
+
(_a = options.modules) !== null && _a !== void 0 ? _a : (options.modules = {});
|
123
|
+
if ((0, utils_1.isDictLike)(options.modules)) {
|
124
|
+
const { getLocalIdent } = options.modules;
|
125
|
+
minifyCssIdentsPlugin !== null && minifyCssIdentsPlugin !== void 0 ? minifyCssIdentsPlugin : (minifyCssIdentsPlugin = MinifyCssIdentsPlugin.getInstance(this));
|
126
|
+
options.modules.getLocalIdent = MinifyCssIdentsPlugin.getLocalIdent(getLocalIdent instanceof Function ? getLocalIdent : void 0);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return options;
|
130
|
+
}
|
131
|
+
return css_loader_1.default.apply(Object.assign(Object.assign({}, this), { getOptions }), args);
|
132
|
+
}
|
133
|
+
return Object.assign(cssLoader, Object.assign({}, css_loader_1.default));
|
134
|
+
}
|
135
|
+
static get cssLoader() {
|
136
|
+
return MinifyCssIdentsPlugin.createCssLoader();
|
137
|
+
}
|
138
|
+
static getInstance(context) {
|
139
|
+
var _a, _b;
|
140
|
+
return (_b = (_a = context[this.symbol]) !== null && _a !== void 0 ? _a : this.implicitInstance) !== null && _b !== void 0 ? _b : new this();
|
141
|
+
}
|
142
|
+
static get getLocalIdent() {
|
143
|
+
let minifyCssIdentsPlugin;
|
144
|
+
let priorGetLocalIdent = defaultGetLocalIdent;
|
145
|
+
function getLocalIdent(...args) {
|
146
|
+
var _a;
|
147
|
+
if (args[0] === void 0 || typeof args[0] === 'function') {
|
148
|
+
priorGetLocalIdent = (_a = args[0]) !== null && _a !== void 0 ? _a : priorGetLocalIdent;
|
149
|
+
return getLocalIdent;
|
150
|
+
}
|
151
|
+
else {
|
152
|
+
const [context, ...otherArgs] = args;
|
153
|
+
minifyCssIdentsPlugin !== null && minifyCssIdentsPlugin !== void 0 ? minifyCssIdentsPlugin : (minifyCssIdentsPlugin = MinifyCssIdentsPlugin.getInstance(context));
|
154
|
+
return minifyCssIdentsPlugin.getLocalIdent(priorGetLocalIdent).call(this, context, ...otherArgs);
|
155
|
+
}
|
156
|
+
}
|
157
|
+
return getLocalIdent;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
MinifyCssIdentsPlugin.Error = MinifyCssIdentsError_1.MinifyCssIdentsError;
|
161
|
+
MinifyCssIdentsPlugin.IdentGenerator = IdentGenerator_1.default;
|
162
|
+
MinifyCssIdentsPlugin.symbol = Symbol(MinifyCssIdentsPlugin.name);
|
163
|
+
MinifyCssIdentsPlugin.defaultGetLocalIdent = defaultGetLocalIdent;
|
164
|
+
function defaultGetLocalIdent(...args) {
|
165
|
+
const [, , localName] = args;
|
166
|
+
const defaultLocalIdent = css_loader_1.defaultGetLocalIdent.apply(this, args);
|
167
|
+
// For some reason, defaultGetLocalIdent does not get all the job done
|
168
|
+
// and does not replace [local] in the ident template nor escape the resulting ident.
|
169
|
+
const resolvedLocalIdent = defaultLocalIdent.replace(/\[local]/gi, (0, utils_1.escape)(localName));
|
170
|
+
return (0, utils_1.escapeLocalIdent)(resolvedLocalIdent);
|
171
|
+
}
|
172
|
+
module.exports = MinifyCssIdentsPlugin;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
declare const _default: import("webpack").LoaderDefinition;
|
25
|
+
export = _default;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
"use strict";
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
const MinifyCssIdentsPlugin_1 = __importDefault(require("./MinifyCssIdentsPlugin"));
|
29
|
+
module.exports = MinifyCssIdentsPlugin_1.default.cssLoader;
|
package/dist/utils.d.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
export declare function escape(str: string): string;
|
25
|
+
export declare function escapeLocalIdent(localident: string): string;
|
26
|
+
export declare function isDictLike(value: unknown): value is NodeJS.Dict<unknown>;
|
27
|
+
export type Falsy<Type = never> = Type | undefined | null | false | 0 | '';
|
28
|
+
export declare function isTruthy<Type>(value: Falsy<Type>): value is Type;
|
29
|
+
export declare function isError(value: unknown): value is Error & {
|
30
|
+
code: unknown;
|
31
|
+
};
|
32
|
+
export declare function type(value: unknown): string;
|
package/dist/utils.js
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
/*! *****************************************************************************
|
2
|
+
MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2024 Adrien Febvay. All rights reserved.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
***************************************************************************** */
|
24
|
+
"use strict";
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.escape = escape;
|
27
|
+
exports.escapeLocalIdent = escapeLocalIdent;
|
28
|
+
exports.isDictLike = isDictLike;
|
29
|
+
exports.isTruthy = isTruthy;
|
30
|
+
exports.isError = isError;
|
31
|
+
exports.type = type;
|
32
|
+
// This function has been extracted from css-loader/dist/utils.js
|
33
|
+
const regexSingleEscape = /[ -,./:-@[\]^`{-~]/;
|
34
|
+
const regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
|
35
|
+
/* istanbul ignore next @preserve */
|
36
|
+
function escape(str) {
|
37
|
+
let output = '';
|
38
|
+
for (let counter = 0; counter < str.length; counter += 1) {
|
39
|
+
const character = str.charAt(counter);
|
40
|
+
// eslint-disable-next-line no-control-regex
|
41
|
+
if (/[\t\n\f\r\x0B]/.test(character)) {
|
42
|
+
output += `\\${character.charCodeAt(0).toString(16).toUpperCase()} `;
|
43
|
+
}
|
44
|
+
else if (character === '\\' || regexSingleEscape.test(character)) {
|
45
|
+
output += `\\${character}`;
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
output += character;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
const firstChar = str.charAt(0);
|
52
|
+
if (/^-[-\d]/.test(output)) {
|
53
|
+
output = `\\${output}`;
|
54
|
+
}
|
55
|
+
else if (/\d/.test(firstChar)) {
|
56
|
+
output = `\\3${firstChar} ${output.slice(1)}`;
|
57
|
+
}
|
58
|
+
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
|
59
|
+
// since they’re redundant. Note that this is only possible if the escape
|
60
|
+
// sequence isn’t preceded by an odd number of backslashes.
|
61
|
+
return output.replace(regexExcessiveSpaces, ($0, $1 = '', $2) => {
|
62
|
+
if ($1.length % 2) {
|
63
|
+
// It’s not safe to remove the space, so don’t.
|
64
|
+
return $0;
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
// Strip the space.
|
68
|
+
return $1 + $2;
|
69
|
+
}
|
70
|
+
});
|
71
|
+
}
|
72
|
+
// This function has been extracted from css-loader/dist/utils.js
|
73
|
+
// eslint-disable-next-line no-control-regex
|
74
|
+
const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g;
|
75
|
+
const filenameReservedRegex = /[<>:"/\\|?*]/g;
|
76
|
+
/* istanbul ignore next @preserve */
|
77
|
+
function escapeLocalIdent(localident) {
|
78
|
+
return escape(localident
|
79
|
+
.replace(/^((-?[0-9])|--)/, '_$1')
|
80
|
+
.replace(filenameReservedRegex, '-')
|
81
|
+
.replace(reControlChars, '-')
|
82
|
+
.replace(/\./g, '-'));
|
83
|
+
}
|
84
|
+
function isDictLike(value) {
|
85
|
+
return value ? typeof value === 'object' : false;
|
86
|
+
}
|
87
|
+
function isTruthy(value) {
|
88
|
+
return Boolean(value);
|
89
|
+
}
|
90
|
+
function isError(value) {
|
91
|
+
return value instanceof Error;
|
92
|
+
}
|
93
|
+
function type(value) {
|
94
|
+
if (value == null) {
|
95
|
+
return String(value);
|
96
|
+
}
|
97
|
+
else {
|
98
|
+
const type = value instanceof Array ? 'array' : typeof value;
|
99
|
+
const article = /[aeiou]/.test(type.slice(0, 1)) ? 'an' : 'a';
|
100
|
+
return `${article} ${type}`;
|
101
|
+
}
|
102
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
{
|
2
|
+
"name": "minify-css-idents",
|
3
|
+
"version": "1.1.0",
|
4
|
+
"description": "Minify CSS identifiers in order to emit smaller CSS files",
|
5
|
+
"author": "Adrien Febvay <adrien.febvay@gmail.com> (https://github.com/adrien-febvay)",
|
6
|
+
"license": "MIT",
|
7
|
+
"scripts": {
|
8
|
+
"eslint": "eslint src/**/*.ts",
|
9
|
+
"eslint-fix": "eslint **/*/*.ts --fix",
|
10
|
+
"test": "jest --coverage --runInBand --verbose",
|
11
|
+
"build": "node bin/build tsconfig.build.json",
|
12
|
+
"preversion": "changelog check && npm test && npm run build",
|
13
|
+
"version": "changelog update && git add CHANGELOG.md"
|
14
|
+
},
|
15
|
+
"repository": {
|
16
|
+
"type": "git",
|
17
|
+
"url": "git+https://github.com/adrien-febvay/minify-css-idents.git"
|
18
|
+
},
|
19
|
+
"bugs": {
|
20
|
+
"url": "https://github.com/adrien-febvay/minify-css-idents/issues",
|
21
|
+
"email": "adrien.febvay@gmail.com"
|
22
|
+
},
|
23
|
+
"homepage": "https://github.com/adrien-febvay/minify-css-idents#readme",
|
24
|
+
"keywords": [
|
25
|
+
"webpack",
|
26
|
+
"minify",
|
27
|
+
"minimize",
|
28
|
+
"css",
|
29
|
+
"ident",
|
30
|
+
"identifier",
|
31
|
+
"classname",
|
32
|
+
"optimization",
|
33
|
+
"web"
|
34
|
+
],
|
35
|
+
"files": [
|
36
|
+
"dist/*"
|
37
|
+
],
|
38
|
+
"exports": {
|
39
|
+
".": "./dist/MinifyCssIdentsPlugin.js",
|
40
|
+
"./IdentGenerator": "./dist/IdentGenerator.js",
|
41
|
+
"./css-loader": "./dist/css-loader.js"
|
42
|
+
},
|
43
|
+
"devDependencies": {
|
44
|
+
"@babel/core": "^7.25.8",
|
45
|
+
"@babel/preset-env": "^7.25.8",
|
46
|
+
"@types/jest": "^29.5.13",
|
47
|
+
"@types/node": "^22.5.5",
|
48
|
+
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
49
|
+
"@typescript-eslint/parser": "^8.8.0",
|
50
|
+
"babel-loader": "^9.2.1",
|
51
|
+
"changelog-safeguard": "^1.0.1",
|
52
|
+
"css-loader": "^7.1.2",
|
53
|
+
"eslint": "^8.57.0",
|
54
|
+
"eslint-config-prettier": "^9.1.0",
|
55
|
+
"eslint-plugin-import": "^2.30.0",
|
56
|
+
"eslint-plugin-prettier": "^5.2.1",
|
57
|
+
"eslint-plugin-promise": "^7.1.0",
|
58
|
+
"jest": "^29.7.0",
|
59
|
+
"jest-runner-eslint": "^2.2.0",
|
60
|
+
"mini-css-extract-plugin": "^2.9.1",
|
61
|
+
"postcss-loader": "^8.1.1",
|
62
|
+
"prettier": "^3.3.3",
|
63
|
+
"rimraf": "^6.0.1",
|
64
|
+
"sass": "^1.81.0",
|
65
|
+
"sass-loader": "^16.0.3",
|
66
|
+
"style-loader": "^4.0.0",
|
67
|
+
"ts-jest": "^29.2.5",
|
68
|
+
"typescript": "^5.5.4",
|
69
|
+
"webpack": "^5.95.0",
|
70
|
+
"webpack-cli": "^5.1.4"
|
71
|
+
},
|
72
|
+
"peerDependencies": {
|
73
|
+
"css-loader": ">= 7.0.0",
|
74
|
+
"webpack": ">= 5.0.0"
|
75
|
+
}
|
76
|
+
}
|