classnames-minifier 0.1.0 → 0.1.2-canary.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.
- package/dist/ClassnamesMinifier.d.ts +20 -0
- package/dist/ClassnamesMinifier.js +39 -0
- package/dist/lib/ConverterMinified.d.ts +29 -0
- package/dist/lib/ConverterMinified.js +136 -0
- package/dist/lib/classnames-minifier-postloader.d.ts +5 -0
- package/dist/lib/classnames-minifier-postloader.js +18 -0
- package/dist/lib/classnames-minifier-preloader.d.ts +5 -0
- package/dist/lib/classnames-minifier-preloader.js +17 -0
- package/dist/lib/constants/configuration.d.ts +6 -0
- package/dist/lib/constants/configuration.js +9 -0
- package/dist/lib/types/plugin.d.ts +6 -0
- package/dist/lib/types/plugin.js +2 -0
- package/dist/lib/validateConfig.d.ts +3 -0
- package/dist/lib/validateConfig.js +27 -0
- package/dist/lib/validateDist.d.ts +3 -0
- package/dist/lib/validateDist.js +51 -0
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Config } from './lib/types/plugin';
|
|
2
|
+
import ConverterMinified from './lib/ConverterMinified';
|
|
3
|
+
declare class ClassnamesMinifier {
|
|
4
|
+
converterMinified: ConverterMinified;
|
|
5
|
+
constructor(config: Config);
|
|
6
|
+
get getLocalIdent(): ({ resourcePath }: import("webpack").LoaderContext<any>, _localIdent: string, origName: string) => string;
|
|
7
|
+
get preLoader(): {
|
|
8
|
+
loader: string;
|
|
9
|
+
options: {
|
|
10
|
+
classnamesMinifier: ConverterMinified;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
get postLoader(): {
|
|
14
|
+
loader: string;
|
|
15
|
+
options: {
|
|
16
|
+
classnamesMinifier: ConverterMinified;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export default ClassnamesMinifier;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const validateConfig_1 = __importDefault(require("./lib/validateConfig"));
|
|
8
|
+
const ConverterMinified_1 = __importDefault(require("./lib/ConverterMinified"));
|
|
9
|
+
const validateDist_1 = __importDefault(require("./lib/validateDist"));
|
|
10
|
+
class ClassnamesMinifier {
|
|
11
|
+
constructor(config) {
|
|
12
|
+
(0, validateConfig_1.default)(config);
|
|
13
|
+
if (config.cacheDir) {
|
|
14
|
+
(0, validateDist_1.default)(config);
|
|
15
|
+
}
|
|
16
|
+
this.converterMinified = new ConverterMinified_1.default(config);
|
|
17
|
+
}
|
|
18
|
+
get getLocalIdent() {
|
|
19
|
+
return this.converterMinified.getLocalIdent.bind(this.converterMinified);
|
|
20
|
+
}
|
|
21
|
+
get preLoader() {
|
|
22
|
+
return {
|
|
23
|
+
loader: path_1.default.join(__dirname, './lib/classnames-minifier-preloader.js'),
|
|
24
|
+
options: {
|
|
25
|
+
classnamesMinifier: this.converterMinified,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
get postLoader() {
|
|
30
|
+
return {
|
|
31
|
+
loader: path_1.default.join(__dirname, './lib/classnames-minifier-postloader.js'),
|
|
32
|
+
options: {
|
|
33
|
+
classnamesMinifier: this.converterMinified,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
;
|
|
39
|
+
exports.default = ClassnamesMinifier;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { LoaderContext } from 'webpack/types';
|
|
2
|
+
import type { Config } from './types/plugin';
|
|
3
|
+
type CacheType = {
|
|
4
|
+
[resourcePath: string]: {
|
|
5
|
+
cachePath: string;
|
|
6
|
+
matchings: {
|
|
7
|
+
[origClass: string]: string;
|
|
8
|
+
};
|
|
9
|
+
type: 'new' | 'updated' | 'old';
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
declare class ConverterMinified {
|
|
13
|
+
private cacheDir?;
|
|
14
|
+
private prefix;
|
|
15
|
+
private reservedNames;
|
|
16
|
+
dirtyСache: CacheType;
|
|
17
|
+
private symbols;
|
|
18
|
+
private freeClasses;
|
|
19
|
+
lastIndex: number;
|
|
20
|
+
private nextLoopEndsWith;
|
|
21
|
+
private currentLoopLength;
|
|
22
|
+
private nameMap;
|
|
23
|
+
constructor({ cacheDir, prefix, reservedNames }: Config);
|
|
24
|
+
private recycleCache;
|
|
25
|
+
private generateClassName;
|
|
26
|
+
private getTargetClassName;
|
|
27
|
+
getLocalIdent({ resourcePath }: LoaderContext<any>, _localIdent: string, origName: string): string;
|
|
28
|
+
}
|
|
29
|
+
export default ConverterMinified;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class ConverterMinified {
|
|
10
|
+
constructor({ cacheDir, prefix = '', reservedNames = [] }) {
|
|
11
|
+
this.dirtyСache = {};
|
|
12
|
+
this.symbols = [
|
|
13
|
+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
14
|
+
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
15
|
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
|
16
|
+
];
|
|
17
|
+
this.freeClasses = [];
|
|
18
|
+
this.lastIndex = 0;
|
|
19
|
+
this.nextLoopEndsWith = 26;
|
|
20
|
+
this.currentLoopLength = 0;
|
|
21
|
+
this.nameMap = [0];
|
|
22
|
+
this.recycleCache = (cacheDir) => {
|
|
23
|
+
this.cacheDir = cacheDir;
|
|
24
|
+
if (!(0, fs_1.existsSync)(cacheDir))
|
|
25
|
+
(0, fs_1.mkdirSync)(cacheDir, { recursive: true });
|
|
26
|
+
const cachedFiles = (0, fs_1.readdirSync)(cacheDir);
|
|
27
|
+
if (cachedFiles.length) {
|
|
28
|
+
console.log('classnames-minifier: Restoring pairs of classes...');
|
|
29
|
+
}
|
|
30
|
+
const usedClassNames = [];
|
|
31
|
+
const dirtyСache = {};
|
|
32
|
+
let prevLastIndex = 0;
|
|
33
|
+
cachedFiles.forEach((file) => {
|
|
34
|
+
const filePath = path_1.default.join(cacheDir, file);
|
|
35
|
+
const dirtyCacheFile = (0, fs_1.readFileSync)(filePath, { encoding: 'utf8' });
|
|
36
|
+
const [resourcePath, lastIndex, ...classnames] = dirtyCacheFile.split(',');
|
|
37
|
+
if (lastIndex && +lastIndex > prevLastIndex)
|
|
38
|
+
prevLastIndex = +lastIndex;
|
|
39
|
+
if ((0, fs_1.existsSync)(resourcePath)) {
|
|
40
|
+
const cachedMatchings = classnames.reduce((acc, cur) => {
|
|
41
|
+
const [origClass, newClass] = cur.split('=');
|
|
42
|
+
acc[origClass] = newClass;
|
|
43
|
+
if (!usedClassNames.includes(newClass)) {
|
|
44
|
+
usedClassNames.push(newClass);
|
|
45
|
+
}
|
|
46
|
+
return acc;
|
|
47
|
+
}, {});
|
|
48
|
+
dirtyСache[resourcePath] = {
|
|
49
|
+
cachePath: filePath,
|
|
50
|
+
matchings: cachedMatchings,
|
|
51
|
+
type: 'old',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
(0, fs_1.rmSync)(filePath);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
let unfoundClassNamesLength = usedClassNames.length;
|
|
59
|
+
for (let i = 0; i <= prevLastIndex; i++) {
|
|
60
|
+
const newClass = this.generateClassName();
|
|
61
|
+
this.lastIndex += 1;
|
|
62
|
+
const usedClassNameIndex = usedClassNames.indexOf(newClass);
|
|
63
|
+
if (usedClassNameIndex !== -1) {
|
|
64
|
+
unfoundClassNamesLength -= 1;
|
|
65
|
+
usedClassNames.splice(usedClassNameIndex, 1);
|
|
66
|
+
}
|
|
67
|
+
else if (!this.reservedNames.includes(newClass)) {
|
|
68
|
+
this.freeClasses.push(newClass);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (cachedFiles.length) {
|
|
72
|
+
console.log('classnames-minifier: Pairs restored');
|
|
73
|
+
}
|
|
74
|
+
this.dirtyСache = dirtyСache;
|
|
75
|
+
};
|
|
76
|
+
this.prefix = prefix;
|
|
77
|
+
this.reservedNames = reservedNames;
|
|
78
|
+
if (cacheDir)
|
|
79
|
+
this.recycleCache(path_1.default.join(cacheDir, 'ncm'));
|
|
80
|
+
}
|
|
81
|
+
generateClassName() {
|
|
82
|
+
const symbolsCount = 62;
|
|
83
|
+
if (this.lastIndex >= this.nextLoopEndsWith) {
|
|
84
|
+
if (this.nextLoopEndsWith === 26)
|
|
85
|
+
this.nextLoopEndsWith = 62 * symbolsCount;
|
|
86
|
+
else
|
|
87
|
+
this.nextLoopEndsWith = this.nextLoopEndsWith * symbolsCount;
|
|
88
|
+
this.nameMap.push(0);
|
|
89
|
+
this.currentLoopLength += 1;
|
|
90
|
+
}
|
|
91
|
+
const currentClassname = this.prefix + this.nameMap.map((e) => this.symbols[e]).join('');
|
|
92
|
+
for (let i = this.currentLoopLength; i >= 0; i--) {
|
|
93
|
+
if (this.nameMap[i] === symbolsCount - 1 || (i === 0 && this.nameMap[i] === 25)) {
|
|
94
|
+
this.nameMap[i] = 0;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.nameMap[i] += 1;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return currentClassname;
|
|
102
|
+
}
|
|
103
|
+
getTargetClassName(origName) {
|
|
104
|
+
let targetClassName;
|
|
105
|
+
if (this.freeClasses.length) {
|
|
106
|
+
targetClassName = this.freeClasses.shift();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
targetClassName = this.generateClassName();
|
|
110
|
+
}
|
|
111
|
+
if (this.reservedNames.includes(targetClassName)) {
|
|
112
|
+
targetClassName = this.getTargetClassName(origName);
|
|
113
|
+
this.lastIndex += 1;
|
|
114
|
+
}
|
|
115
|
+
return targetClassName;
|
|
116
|
+
}
|
|
117
|
+
getLocalIdent({ resourcePath }, _localIdent, origName) {
|
|
118
|
+
if (!this.dirtyСache[resourcePath]) {
|
|
119
|
+
this.dirtyСache[resourcePath] = {
|
|
120
|
+
cachePath: this.cacheDir ? path_1.default.join(this.cacheDir, (0, uuid_1.v4)()) : '',
|
|
121
|
+
matchings: {},
|
|
122
|
+
type: 'new',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const currentCache = this.dirtyСache[resourcePath];
|
|
126
|
+
if (currentCache.matchings[origName])
|
|
127
|
+
return currentCache.matchings[origName];
|
|
128
|
+
let targetClassName = this.getTargetClassName(origName);
|
|
129
|
+
currentCache.matchings[origName] = targetClassName;
|
|
130
|
+
currentCache.type = 'updated';
|
|
131
|
+
this.lastIndex += 1;
|
|
132
|
+
return targetClassName;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
;
|
|
136
|
+
exports.default = ConverterMinified;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
function default_1(source, map, meta) {
|
|
8
|
+
const options = this.getOptions();
|
|
9
|
+
const classnamesMinifier = options.classnamesMinifier;
|
|
10
|
+
Object.entries(classnamesMinifier.dirtyСache).forEach(([resourcePath, data]) => {
|
|
11
|
+
if (data.type !== 'old') {
|
|
12
|
+
fs_1.default.writeFileSync(data.cachePath, `${resourcePath},${classnamesMinifier.lastIndex},${Object.entries(data.matchings).map(([key, value]) => (`${key}=${value}`)).join(',')}`);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
this.callback(null, source, map, meta);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
exports.default = default_1;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function default_1(source, map, meta) {
|
|
4
|
+
const options = this.getOptions();
|
|
5
|
+
const classnamesMinifier = options.classnamesMinifier;
|
|
6
|
+
const maybeClassesList = source.match(/\.-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g);
|
|
7
|
+
const cache = classnamesMinifier.dirtyСache[this.resourcePath];
|
|
8
|
+
/**
|
|
9
|
+
* if some class has ceased to be used since the last time the file was loaded, we remove it from the cache
|
|
10
|
+
*/
|
|
11
|
+
if (cache && cache.matchings) {
|
|
12
|
+
cache.matchings = maybeClassesList ? Object.fromEntries(Object.entries(cache.matchings).filter(([key]) => maybeClassesList === null || maybeClassesList === void 0 ? void 0 : maybeClassesList.includes(`.${key}`))) : {};
|
|
13
|
+
}
|
|
14
|
+
this.callback(null, source, map, meta);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
exports.default = default_1;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Just a version of the code whose change means that the logic has a critical update
|
|
3
|
+
* and minifying the previous version is not compatible with the current one,
|
|
4
|
+
* which would mean that we should clean dist folder
|
|
5
|
+
*/
|
|
6
|
+
export declare const CODE_VERSION = "rabbit";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CODE_VERSION = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Just a version of the code whose change means that the logic has a critical update
|
|
6
|
+
* and minifying the previous version is not compatible with the current one,
|
|
7
|
+
* which would mean that we should clean dist folder
|
|
8
|
+
*/
|
|
9
|
+
exports.CODE_VERSION = 'rabbit';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const validKeys = ['prefix', 'reservedNames', 'cacheDir', 'distDir'];
|
|
4
|
+
const validateIsObject = (config) => {
|
|
5
|
+
if (!config)
|
|
6
|
+
return false;
|
|
7
|
+
if (typeof config !== 'object' || Array.isArray(config)) {
|
|
8
|
+
console.error(`classnames-minifier: Invalid configuration. Expected object, received ${typeof config}. See https://github.com/vordgi/classnames-minifier#configuration`);
|
|
9
|
+
process.exit();
|
|
10
|
+
}
|
|
11
|
+
const isValidKeys = Object.keys(config).every(key => validKeys.includes(key));
|
|
12
|
+
if (!isValidKeys) {
|
|
13
|
+
console.error(`classnames-minifier: Invalid configuration. Valid keys are: ${validKeys.join(', ')}. See https://github.com/vordgi/classnames-minifier#configuration`);
|
|
14
|
+
process.exit();
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
const validateConfig = (config = {}) => {
|
|
19
|
+
if (!validateIsObject(config))
|
|
20
|
+
return {};
|
|
21
|
+
if (config.prefix && !config.prefix.match(/^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/)) {
|
|
22
|
+
console.error(`classnames-minifier: Invalid prefix. It should match following rule: "^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$". See https://github.com/vordgi/classnames-minifier#configuration`);
|
|
23
|
+
process.exit();
|
|
24
|
+
}
|
|
25
|
+
return config;
|
|
26
|
+
};
|
|
27
|
+
exports.default = validateConfig;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const configuration_1 = require("./constants/configuration");
|
|
9
|
+
const readManifest = (manifestPath) => {
|
|
10
|
+
try {
|
|
11
|
+
const prevData = fs_1.default.readFileSync(manifestPath, { encoding: 'utf-8' });
|
|
12
|
+
return JSON.parse(prevData);
|
|
13
|
+
}
|
|
14
|
+
catch (_a) {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const validateDist = (pluginOptions) => {
|
|
19
|
+
var _a, _b;
|
|
20
|
+
const { cacheDir, distDir, prefix, reservedNames } = pluginOptions;
|
|
21
|
+
if (!cacheDir || !distDir) {
|
|
22
|
+
console.log('classnames-minifier: Failed to check the dist folder because cacheDir or distDir is not specified');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const manifestDir = path_1.default.join(cacheDir, 'ncm-meta');
|
|
26
|
+
const manifestPath = path_1.default.join(manifestDir, 'manifest.json');
|
|
27
|
+
let isImpreciseDist = false;
|
|
28
|
+
if (fs_1.default.existsSync(manifestPath)) {
|
|
29
|
+
const prevData = readManifest(manifestPath);
|
|
30
|
+
if (prevData.prefix !== prefix
|
|
31
|
+
|| prevData.cacheDir !== cacheDir
|
|
32
|
+
|| prevData.distDir !== distDir
|
|
33
|
+
|| ((_a = prevData.reservedNames) === null || _a === void 0 ? void 0 : _a.length) !== (reservedNames === null || reservedNames === void 0 ? void 0 : reservedNames.length)
|
|
34
|
+
|| ((_b = prevData.reservedNames) === null || _b === void 0 ? void 0 : _b.some(name => !(reservedNames === null || reservedNames === void 0 ? void 0 : reservedNames.includes(name))))
|
|
35
|
+
|| prevData.version !== configuration_1.CODE_VERSION) {
|
|
36
|
+
isImpreciseDist = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
isImpreciseDist = true;
|
|
41
|
+
}
|
|
42
|
+
if (isImpreciseDist) {
|
|
43
|
+
console.log('classnames-minifier: Changes found in package configuration. Cleaning the dist folder...');
|
|
44
|
+
fs_1.default.rmSync(distDir, { recursive: true, force: true });
|
|
45
|
+
console.log('classnames-minifier: Changes found in package configuration. Dist folder cleared');
|
|
46
|
+
}
|
|
47
|
+
if (!fs_1.default.existsSync(manifestDir))
|
|
48
|
+
fs_1.default.mkdirSync(manifestDir, { recursive: true });
|
|
49
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(Object.assign(Object.assign({}, pluginOptions), { version: configuration_1.CODE_VERSION })), { encoding: 'utf-8' });
|
|
50
|
+
};
|
|
51
|
+
exports.default = validateDist;
|
package/package.json
CHANGED