@gem-sdk/hash-class-names 1.0.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/cjs/index.js +111 -0
- package/dist/esm/index.js +109 -0
- package/dist/types/index.d.ts +15 -0
- package/package.json +33 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var parse5 = require('parse5');
|
|
4
|
+
|
|
5
|
+
const hashClassNames = (html, css, options) => {
|
|
6
|
+
const documentFragment = parse5.parseFragment(html);
|
|
7
|
+
const jsonHTML = documentFragment.childNodes;
|
|
8
|
+
if (jsonHTML?.length) {
|
|
9
|
+
const classes = {};
|
|
10
|
+
const hashClasses = {};
|
|
11
|
+
// Find & Obfuscate class in html
|
|
12
|
+
loopNode(jsonHTML, (node) => {
|
|
13
|
+
if (node?.attrs?.length) {
|
|
14
|
+
const attrClass = node.attrs.find((item) => item.name == 'class');
|
|
15
|
+
if (attrClass?.value) {
|
|
16
|
+
const nodeClasses = attrClass.value.split(' ');
|
|
17
|
+
if (nodeClasses?.length) {
|
|
18
|
+
for (let i = 0; i < nodeClasses.length; i++) {
|
|
19
|
+
const nodeClass = nodeClasses[i]?.trim() || '';
|
|
20
|
+
if (options?.ignoreClasses?.includes(nodeClass)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (nodeClass) {
|
|
24
|
+
const data = classes[nodeClass];
|
|
25
|
+
if (!data) {
|
|
26
|
+
// eslint-disable-next-line no-constant-condition
|
|
27
|
+
while (true) {
|
|
28
|
+
const newClass = `a${ID()}`;
|
|
29
|
+
if (!hashClasses[newClass]) {
|
|
30
|
+
hashClasses[newClass] = true; // flag
|
|
31
|
+
// Cache
|
|
32
|
+
classes[nodeClass] = {
|
|
33
|
+
hash: newClass,
|
|
34
|
+
};
|
|
35
|
+
// replace
|
|
36
|
+
attrClass.value = attrClass.value.replace(nodeClass, newClass);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
attrClass.value = attrClass.value.replace(nodeClass, data.hash);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
let newHTML = '';
|
|
51
|
+
for (let i = 0; i < jsonHTML.length; i++) {
|
|
52
|
+
const node = jsonHTML[i];
|
|
53
|
+
if (node) {
|
|
54
|
+
newHTML += parse5.serializeOuter(node);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Replace class in css
|
|
58
|
+
const orderClasses = [];
|
|
59
|
+
for (const oldClass in classes) {
|
|
60
|
+
if (Object.prototype.hasOwnProperty.call(classes, oldClass)) {
|
|
61
|
+
const data = classes[oldClass];
|
|
62
|
+
if (data?.hash) {
|
|
63
|
+
orderClasses.push({
|
|
64
|
+
oldClass: oldClass,
|
|
65
|
+
newClass: data.hash,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
orderClasses.sort((a, b) => {
|
|
71
|
+
if (a.oldClass.includes(b.oldClass)) {
|
|
72
|
+
return -1;
|
|
73
|
+
}
|
|
74
|
+
return 1;
|
|
75
|
+
});
|
|
76
|
+
let newCSS = css;
|
|
77
|
+
for (let i = 0; i < orderClasses.length; i++) {
|
|
78
|
+
const data = orderClasses[i];
|
|
79
|
+
newCSS = newCSS.replaceAll(`.${data?.oldClass}`, `.${data?.newClass}`);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
html: newHTML,
|
|
83
|
+
css: newCSS,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
html,
|
|
88
|
+
css,
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
const loopNode = (childNodes, callback) => {
|
|
92
|
+
if (childNodes?.length) {
|
|
93
|
+
for (let i = 0; i < childNodes.length; i++) {
|
|
94
|
+
const childNode = childNodes[i];
|
|
95
|
+
if (childNode) {
|
|
96
|
+
callback(childNode);
|
|
97
|
+
if (childNode.childNodes?.length) {
|
|
98
|
+
loopNode(childNode.childNodes, callback);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const ID = function () {
|
|
105
|
+
// Math.random should be unique because of its seeding algorithm.
|
|
106
|
+
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
|
|
107
|
+
// after the decimal.
|
|
108
|
+
return Math.random().toString(36).substr(2, 5);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
exports.hashClassNames = hashClassNames;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { parseFragment, serializeOuter } from 'parse5';
|
|
2
|
+
|
|
3
|
+
const hashClassNames = (html, css, options) => {
|
|
4
|
+
const documentFragment = parseFragment(html);
|
|
5
|
+
const jsonHTML = documentFragment.childNodes;
|
|
6
|
+
if (jsonHTML?.length) {
|
|
7
|
+
const classes = {};
|
|
8
|
+
const hashClasses = {};
|
|
9
|
+
// Find & Obfuscate class in html
|
|
10
|
+
loopNode(jsonHTML, (node) => {
|
|
11
|
+
if (node?.attrs?.length) {
|
|
12
|
+
const attrClass = node.attrs.find((item) => item.name == 'class');
|
|
13
|
+
if (attrClass?.value) {
|
|
14
|
+
const nodeClasses = attrClass.value.split(' ');
|
|
15
|
+
if (nodeClasses?.length) {
|
|
16
|
+
for (let i = 0; i < nodeClasses.length; i++) {
|
|
17
|
+
const nodeClass = nodeClasses[i]?.trim() || '';
|
|
18
|
+
if (options?.ignoreClasses?.includes(nodeClass)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (nodeClass) {
|
|
22
|
+
const data = classes[nodeClass];
|
|
23
|
+
if (!data) {
|
|
24
|
+
// eslint-disable-next-line no-constant-condition
|
|
25
|
+
while (true) {
|
|
26
|
+
const newClass = `a${ID()}`;
|
|
27
|
+
if (!hashClasses[newClass]) {
|
|
28
|
+
hashClasses[newClass] = true; // flag
|
|
29
|
+
// Cache
|
|
30
|
+
classes[nodeClass] = {
|
|
31
|
+
hash: newClass,
|
|
32
|
+
};
|
|
33
|
+
// replace
|
|
34
|
+
attrClass.value = attrClass.value.replace(nodeClass, newClass);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
attrClass.value = attrClass.value.replace(nodeClass, data.hash);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
let newHTML = '';
|
|
49
|
+
for (let i = 0; i < jsonHTML.length; i++) {
|
|
50
|
+
const node = jsonHTML[i];
|
|
51
|
+
if (node) {
|
|
52
|
+
newHTML += serializeOuter(node);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Replace class in css
|
|
56
|
+
const orderClasses = [];
|
|
57
|
+
for (const oldClass in classes) {
|
|
58
|
+
if (Object.prototype.hasOwnProperty.call(classes, oldClass)) {
|
|
59
|
+
const data = classes[oldClass];
|
|
60
|
+
if (data?.hash) {
|
|
61
|
+
orderClasses.push({
|
|
62
|
+
oldClass: oldClass,
|
|
63
|
+
newClass: data.hash,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
orderClasses.sort((a, b) => {
|
|
69
|
+
if (a.oldClass.includes(b.oldClass)) {
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
return 1;
|
|
73
|
+
});
|
|
74
|
+
let newCSS = css;
|
|
75
|
+
for (let i = 0; i < orderClasses.length; i++) {
|
|
76
|
+
const data = orderClasses[i];
|
|
77
|
+
newCSS = newCSS.replaceAll(`.${data?.oldClass}`, `.${data?.newClass}`);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
html: newHTML,
|
|
81
|
+
css: newCSS,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
html,
|
|
86
|
+
css,
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const loopNode = (childNodes, callback) => {
|
|
90
|
+
if (childNodes?.length) {
|
|
91
|
+
for (let i = 0; i < childNodes.length; i++) {
|
|
92
|
+
const childNode = childNodes[i];
|
|
93
|
+
if (childNode) {
|
|
94
|
+
callback(childNode);
|
|
95
|
+
if (childNode.childNodes?.length) {
|
|
96
|
+
loopNode(childNode.childNodes, callback);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const ID = function () {
|
|
103
|
+
// Math.random should be unique because of its seeding algorithm.
|
|
104
|
+
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
|
|
105
|
+
// after the decimal.
|
|
106
|
+
return Math.random().toString(36).substr(2, 5);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export { hashClassNames };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type Node = {
|
|
2
|
+
attrs?: {
|
|
3
|
+
name: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}[];
|
|
6
|
+
childNodes?: Node[];
|
|
7
|
+
};
|
|
8
|
+
declare const hashClassNames: (html: string, css: string, options?: {
|
|
9
|
+
ignoreClasses?: string[];
|
|
10
|
+
}) => {
|
|
11
|
+
html: string;
|
|
12
|
+
css: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { Node, hashClassNames };
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gem-sdk/hash-class-names",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"cleanup": "rimraf es dist lib",
|
|
8
|
+
"prebuild": "yarn cleanup",
|
|
9
|
+
"pre:publish": "node ./../../helpers/convert-publish.js -p",
|
|
10
|
+
"post:publish": "node ./../../helpers/convert-publish.js",
|
|
11
|
+
"watch": "rollup -c ./../../helpers/rollup.config.mjs -w",
|
|
12
|
+
"build": "rollup -c ./../../helpers/rollup.config.mjs --environment NODE_ENV:production",
|
|
13
|
+
"lint": "eslint ./src --ext .tsx,.ts",
|
|
14
|
+
"type-check": "yarn tsc --noEmit",
|
|
15
|
+
"test": "jest -c ./../../helpers/jest.config.ts"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"parse5": "^7.1.2"
|
|
19
|
+
},
|
|
20
|
+
"module": "dist/esm/index.js",
|
|
21
|
+
"types": "dist/types/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
"./package.json": "./package.json",
|
|
24
|
+
".": {
|
|
25
|
+
"import": "./dist/esm/index.js",
|
|
26
|
+
"require": "./dist/cjs/index.js",
|
|
27
|
+
"types": "./dist/types/index.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
]
|
|
33
|
+
}
|