css-shuffle 1.0.1
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/.github/workflows/npm.yml +22 -0
- package/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/astro.d.ts +3 -0
- package/dist/astro.d.ts.map +1 -0
- package/dist/astro.js +16 -0
- package/dist/css-shuffle.d.ts +15 -0
- package/dist/css-shuffle.d.ts.map +1 -0
- package/dist/css-shuffle.js +160 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/renamer.d.ts +8 -0
- package/dist/renamer.d.ts.map +1 -0
- package/dist/renamer.js +32 -0
- package/package.json +35 -0
- package/tsconfig.json +44 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20.x'
|
|
17
|
+
registry-url: 'https://registry.npmjs.org'
|
|
18
|
+
- run: npm ci
|
|
19
|
+
- run: npm run build
|
|
20
|
+
- run: npm publish --provenance --access public
|
|
21
|
+
env:
|
|
22
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Oskar Karpiński
|
|
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,99 @@
|
|
|
1
|
+
# CSS Shuffle
|
|
2
|
+
|
|
3
|
+
**CSS Shuffle** is a tool for obfuscating CSS and HTML files by randomizing all CSS class names, IDs, and CSS custom properties (variables).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Obfuscates all CSS class names, IDs, and custom properties (variables)
|
|
10
|
+
- Updates references in HTML (`class`, `id`, and inline style attributes)
|
|
11
|
+
- Handles both external CSS files and inline `<style>` tags in HTML
|
|
12
|
+
- Outputs a mapping file for reference
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install css-shuffle
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Astro
|
|
27
|
+
|
|
28
|
+
`astro.config.mjs`
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// ...
|
|
32
|
+
import { astro as cssShuffle } from 'css-shuffle'
|
|
33
|
+
|
|
34
|
+
export default defineConfig({
|
|
35
|
+
// ...
|
|
36
|
+
integrations: [
|
|
37
|
+
// ...
|
|
38
|
+
cssShuffle()
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Custom
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { CSSShuffle } from "css-shuffle";
|
|
47
|
+
|
|
48
|
+
const cssShuffler = new CSSShuffle();
|
|
49
|
+
await cssShuffler.obfuscate("./input-directory", "./output-directory");
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- `input-directory`: Path to your source files (HTML and CSS)
|
|
53
|
+
- `output-directory`: Path where the obfuscated website files will be written
|
|
54
|
+
|
|
55
|
+
**Example:**
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
await cssShuffler.obfuscate("./public", "./dist");
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## How It Works
|
|
64
|
+
|
|
65
|
+
1. **Copies** all files from the input directory to the output directory.
|
|
66
|
+
2. **Obfuscates** all CSS class names, IDs, and variables in CSS files and inline `<style>` tags.
|
|
67
|
+
3. **Replaces** all references in HTML (`class`, `id`, and inline style attributes).
|
|
68
|
+
4. **Outputs** the obfuscated files and a mapping (see below).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Mapping
|
|
73
|
+
|
|
74
|
+
You can get the mapping of original to obfuscated names:
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
console.log(cssShuffler.getMappingJSON());
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Requirements
|
|
83
|
+
|
|
84
|
+
- Node.js
|
|
85
|
+
- npm, yarn or something else
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
**Note:**
|
|
96
|
+
This tool is intended for code obfuscation and not for security. Use responsibly!
|
|
97
|
+
|
|
98
|
+
After obfuscation, **please thoroughly check your obfuscated website for any bugs or issues**.
|
|
99
|
+
If you notice anything not working as expected, or if you find a bug caused by the obfuscation process, **please create an issue** in the repository with details and, if possible, steps to reproduce.
|
package/dist/astro.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.d.ts","sourceRoot":"","sources":["../src/astro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAK9C,MAAM,CAAC,OAAO,UAAU,qBAAqB,IAAI,gBAAgB,CAgBhE"}
|
package/dist/astro.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import { CSSShuffle } from './css-shuffle.js';
|
|
3
|
+
export default function cssShuffleIntegration() {
|
|
4
|
+
return {
|
|
5
|
+
name: "css-shuffle",
|
|
6
|
+
hooks: {
|
|
7
|
+
"astro:build:done": async ({ dir }) => {
|
|
8
|
+
const dist = fileURLToPath(dir);
|
|
9
|
+
const cssShuffler = new CSSShuffle();
|
|
10
|
+
await cssShuffler.obfuscate(dist);
|
|
11
|
+
cssShuffler.printStatsTable();
|
|
12
|
+
cssShuffler.saveMappingJSON(`${dist}/../mapping.json`);
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class CSSShuffle {
|
|
2
|
+
private renamer;
|
|
3
|
+
private readonly stats;
|
|
4
|
+
private obfuscateName;
|
|
5
|
+
private getObfuscateName;
|
|
6
|
+
getMapping(): Map<string, string>;
|
|
7
|
+
getMappingJSON(): string;
|
|
8
|
+
saveMappingJSON(path: string): void;
|
|
9
|
+
obfuscateCSS(css: string): Promise<string>;
|
|
10
|
+
private obfuscateCSSInHtml;
|
|
11
|
+
private replaceNamesInHtml;
|
|
12
|
+
obfuscate(input: string, dist?: string): Promise<void>;
|
|
13
|
+
printStatsTable(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=css-shuffle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-shuffle.d.ts","sourceRoot":"","sources":["../src/css-shuffle.ts"],"names":[],"mappings":"AAWA,qBAAa,UAAU;IACnB,OAAO,CAAC,OAAO,CAAiB;IAIhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4D;IAElF,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IAIxB,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjC,cAAc,IAAI,MAAM;IAIxB,eAAe,CAAC,IAAI,EAAE,MAAM;IAMtB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA2BhD,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IA4BpB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IA0E5C,eAAe;CAclB"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { globby } from "globby";
|
|
3
|
+
import * as cheerio from "cheerio";
|
|
4
|
+
import { Table } from "console-table-printer";
|
|
5
|
+
import prettyBytes from "pretty-bytes";
|
|
6
|
+
import postcss, { Root } from "postcss";
|
|
7
|
+
import selectorParser from "postcss-selector-parser";
|
|
8
|
+
import valueParser from "postcss-value-parser";
|
|
9
|
+
import { Renamer } from "./renamer.js";
|
|
10
|
+
export class CSSShuffle {
|
|
11
|
+
renamer = new Renamer();
|
|
12
|
+
// private readonly stats = new Table();
|
|
13
|
+
stats = new Map();
|
|
14
|
+
obfuscateName(originalName) {
|
|
15
|
+
return this.renamer.rename(originalName);
|
|
16
|
+
}
|
|
17
|
+
getObfuscateName(key) {
|
|
18
|
+
return this.renamer.get(key);
|
|
19
|
+
}
|
|
20
|
+
getMapping() {
|
|
21
|
+
return this.renamer.renames;
|
|
22
|
+
}
|
|
23
|
+
getMappingJSON() {
|
|
24
|
+
return JSON.stringify(Object.fromEntries(this.getMapping()), null, 2);
|
|
25
|
+
}
|
|
26
|
+
saveMappingJSON(path) {
|
|
27
|
+
const mapping = this.getMappingJSON();
|
|
28
|
+
fs.writeFileSync(path, mapping);
|
|
29
|
+
}
|
|
30
|
+
async obfuscateCSS(css) {
|
|
31
|
+
return await postcss([
|
|
32
|
+
(root) => {
|
|
33
|
+
root.walkRules(rule => {
|
|
34
|
+
rule.selector = selectorParser(selectors => {
|
|
35
|
+
selectors.walkClasses(node => { node.value = this.obfuscateName(node.value); });
|
|
36
|
+
selectors.walkIds(node => { node.value = this.obfuscateName(node.value); });
|
|
37
|
+
}).processSync(rule.selector);
|
|
38
|
+
});
|
|
39
|
+
root.walkDecls(decl => {
|
|
40
|
+
if (decl.prop.startsWith("--")) {
|
|
41
|
+
decl.prop = `--${this.obfuscateName(decl.prop.substring(2))}`;
|
|
42
|
+
}
|
|
43
|
+
const parsedValue = valueParser(decl.value);
|
|
44
|
+
parsedValue.walk(node => {
|
|
45
|
+
if (node.type === 'function' && node.value === 'var' && node.nodes[0]) {
|
|
46
|
+
node.nodes[0].value = `--${this.obfuscateName(node.nodes[0].value.substring(2))}`;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
decl.value = parsedValue.toString();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
]).process(css, { from: undefined }).then(result => result.css);
|
|
53
|
+
}
|
|
54
|
+
obfuscateCSSInHtml(html) {
|
|
55
|
+
const styleTagRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
|
|
56
|
+
return html.replace(styleTagRegex, (_, p1) => {
|
|
57
|
+
let styleContent = p1;
|
|
58
|
+
styleContent = this.obfuscateCSS(styleContent);
|
|
59
|
+
return `<style>${styleContent}</style>`;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
replaceNamesInHtml(html) {
|
|
63
|
+
const $ = cheerio.load(html);
|
|
64
|
+
$('[class]').each((_, e) => {
|
|
65
|
+
const classes = $(e).attr('class').split(/\s+/).filter(Boolean);
|
|
66
|
+
const newClasses = classes.map(cls => this.getObfuscateName(cls) || cls);
|
|
67
|
+
$(e).attr('class', newClasses.join(' '));
|
|
68
|
+
});
|
|
69
|
+
$('[id]').each((_, e) => {
|
|
70
|
+
const id = $(e).attr('id');
|
|
71
|
+
$(e).attr('id', this.getObfuscateName(id));
|
|
72
|
+
});
|
|
73
|
+
$('[for]').each((_, e) => {
|
|
74
|
+
const id = $(e).attr('for');
|
|
75
|
+
$(e).attr('for', this.getObfuscateName(id));
|
|
76
|
+
});
|
|
77
|
+
$('a[href^="#"]').each((_, e) => {
|
|
78
|
+
const href = $(e).attr('href');
|
|
79
|
+
const target = href.slice(1);
|
|
80
|
+
$(e).attr('href', '#' + this.getObfuscateName(target));
|
|
81
|
+
});
|
|
82
|
+
return $.html();
|
|
83
|
+
}
|
|
84
|
+
async obfuscate(input, dist) {
|
|
85
|
+
if (dist == undefined) {
|
|
86
|
+
dist = input;
|
|
87
|
+
}
|
|
88
|
+
if (input != dist) {
|
|
89
|
+
// copy files from input dir to output dir
|
|
90
|
+
if (fs.existsSync(dist)) {
|
|
91
|
+
fs.rmSync(dist, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
fs.mkdirSync(dist, { recursive: true });
|
|
94
|
+
fs.cpSync(input, dist, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
const htmlFiles = await globby(['**/*.html'], { cwd: dist, absolute: true });
|
|
97
|
+
const cssFiles = await globby(['**/*.css'], { cwd: dist, absolute: true });
|
|
98
|
+
// Obfuscate CSS files
|
|
99
|
+
for (const cssFile of cssFiles) {
|
|
100
|
+
const cssContent = fs.readFileSync(cssFile, 'utf-8');
|
|
101
|
+
const obfuscatedCss = await this.obfuscateCSS(cssContent);
|
|
102
|
+
fs.writeFileSync(cssFile, obfuscatedCss, 'utf-8');
|
|
103
|
+
const oldSize = cssContent.length;
|
|
104
|
+
const newSize = obfuscatedCss.length;
|
|
105
|
+
if (oldSize != newSize) {
|
|
106
|
+
const fileName = cssFile.replace(dist, '');
|
|
107
|
+
this.stats.set(fileName, {
|
|
108
|
+
orginalSize: oldSize,
|
|
109
|
+
newSize: newSize
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Obfuscate CSS in <style> tag in HTML files
|
|
114
|
+
for (const htmlFile of htmlFiles) {
|
|
115
|
+
const htmlContent = fs.readFileSync(htmlFile, 'utf-8');
|
|
116
|
+
let obfuscatedHtmlContent = this.obfuscateCSSInHtml(htmlContent);
|
|
117
|
+
fs.writeFileSync(htmlFile, obfuscatedHtmlContent, 'utf-8');
|
|
118
|
+
const oldSize = htmlContent.length;
|
|
119
|
+
const newSize = obfuscatedHtmlContent.length;
|
|
120
|
+
if (oldSize != newSize) {
|
|
121
|
+
const fileName = htmlFile.replace(dist, '');
|
|
122
|
+
this.stats.set(fileName, {
|
|
123
|
+
orginalSize: oldSize,
|
|
124
|
+
newSize: newSize
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Export export obfuscated names to HTML
|
|
129
|
+
for (const htmlFile of htmlFiles) {
|
|
130
|
+
const htmlContent = fs.readFileSync(htmlFile, 'utf-8');
|
|
131
|
+
let newHtmlContent = this.replaceNamesInHtml(htmlContent);
|
|
132
|
+
fs.writeFileSync(htmlFile, newHtmlContent, 'utf-8');
|
|
133
|
+
let orginalSize = htmlContent.length;
|
|
134
|
+
const newSize = newHtmlContent.length;
|
|
135
|
+
if (orginalSize != newSize) {
|
|
136
|
+
const fileName = htmlFile.replace(dist, '');
|
|
137
|
+
// this file maybe already obfuscated so get the really orginal file size
|
|
138
|
+
const fileStats = this.stats.get(fileName);
|
|
139
|
+
if (fileStats != undefined)
|
|
140
|
+
orginalSize = fileStats.orginalSize;
|
|
141
|
+
this.stats.set(fileName, {
|
|
142
|
+
orginalSize: orginalSize,
|
|
143
|
+
newSize: newSize
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
printStatsTable() {
|
|
149
|
+
const table = new Table();
|
|
150
|
+
this.stats.forEach((stats, file) => {
|
|
151
|
+
table.addRow({
|
|
152
|
+
File: file,
|
|
153
|
+
'Original Size': prettyBytes(stats.orginalSize),
|
|
154
|
+
'New Size': prettyBytes(stats.newSize),
|
|
155
|
+
Reduced: `${(((stats.orginalSize - stats.newSize) / stats.orginalSize) * 100) | 0}%`,
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
table.printTable();
|
|
159
|
+
}
|
|
160
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renamer.d.ts","sourceRoot":"","sources":["../src/renamer.ts"],"names":[],"mappings":"AAGA,qBAAa,OAAO;IAChB,OAAO,CAAC,SAAS,CAAK;IAEtB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,sBAA6B;IAE7C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAyB3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAK3B"}
|
package/dist/renamer.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const START_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
2
|
+
const NEXT_CHARS = START_CHARS + '0123456789';
|
|
3
|
+
export class Renamer {
|
|
4
|
+
nextIndex = 0;
|
|
5
|
+
/** Map of original names to their new obfuscated names */
|
|
6
|
+
renames = new Map();
|
|
7
|
+
rename(key) {
|
|
8
|
+
if (this.renames.has(key)) {
|
|
9
|
+
return this.renames.get(key);
|
|
10
|
+
}
|
|
11
|
+
let index = this.nextIndex;
|
|
12
|
+
let name = '';
|
|
13
|
+
// First character
|
|
14
|
+
name = START_CHARS[index % START_CHARS.length] + name;
|
|
15
|
+
index = Math.floor(index / START_CHARS.length);
|
|
16
|
+
// Subsequent characters
|
|
17
|
+
while (index > 0) {
|
|
18
|
+
index--; // Adjust for 0-based index
|
|
19
|
+
name = NEXT_CHARS[index % NEXT_CHARS.length] + name;
|
|
20
|
+
index = Math.floor(index / NEXT_CHARS.length);
|
|
21
|
+
}
|
|
22
|
+
this.renames.set(key, name);
|
|
23
|
+
this.nextIndex++;
|
|
24
|
+
return name;
|
|
25
|
+
}
|
|
26
|
+
get(key) {
|
|
27
|
+
let value = this.renames.get(key);
|
|
28
|
+
if (value == undefined)
|
|
29
|
+
return key;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "css-shuffle",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Tool for obfuscating and randomizing all CSS classes and ID names in your HTML, CSS files.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/M3DZIK/css-shuffle.git"
|
|
13
|
+
},
|
|
14
|
+
"author": "Oskar Karpiński",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/M3DZIK/css-shuffle/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/M3DZIK/css-shuffle#readme",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"cheerio": "^1.1.2",
|
|
22
|
+
"console-table-printer": "^2.14.6",
|
|
23
|
+
"globby": "^14.1.0",
|
|
24
|
+
"postcss": "^8.5.6",
|
|
25
|
+
"postcss-selector-parser": "^7.1.0",
|
|
26
|
+
"postcss-value-parser": "^4.2.0",
|
|
27
|
+
"pretty-bytes": "^7.0.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/css-tree": "^2.3.10",
|
|
31
|
+
"@types/node": "^24.3.0",
|
|
32
|
+
"astro": "^5.13.3",
|
|
33
|
+
"typescript": "^5.9.2"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
// "types": [],
|
|
13
|
+
// For nodejs:
|
|
14
|
+
// "lib": ["esnext"],
|
|
15
|
+
"types": ["node"],
|
|
16
|
+
// and npm install -D @types/node
|
|
17
|
+
|
|
18
|
+
// Other Outputs
|
|
19
|
+
// "sourceMap": true,
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"declarationMap": true,
|
|
22
|
+
|
|
23
|
+
// Stricter Typechecking Options
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
// "exactOptionalPropertyTypes": true,
|
|
26
|
+
|
|
27
|
+
// Style Options
|
|
28
|
+
// "noImplicitReturns": true,
|
|
29
|
+
// "noImplicitOverride": true,
|
|
30
|
+
// "noUnusedLocals": true,
|
|
31
|
+
// "noUnusedParameters": true,
|
|
32
|
+
// "noFallthroughCasesInSwitch": true,
|
|
33
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
+
|
|
35
|
+
// Recommended Options
|
|
36
|
+
"strict": false,
|
|
37
|
+
// "jsx": "react-jsx",
|
|
38
|
+
"verbatimModuleSyntax": true,
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|