@cassida/compiler 0.1.0 → 0.1.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/dist/hasher.d.ts +25 -0
- package/dist/hasher.d.ts.map +1 -1
- package/dist/hasher.js +96 -3
- package/dist/hasher.js.map +1 -1
- package/package.json +8 -3
package/dist/hasher.d.ts
CHANGED
|
@@ -4,5 +4,30 @@ export interface HashOptions {
|
|
|
4
4
|
readonly prefix?: string;
|
|
5
5
|
readonly length?: number;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Build-time class-name hasher.
|
|
9
|
+
*
|
|
10
|
+
* Uses MurmurHash3 (x86, 32-bit) — a non-cryptographic hash with good
|
|
11
|
+
* distribution and low collision rate over ASCII inputs.
|
|
12
|
+
*
|
|
13
|
+
* Why not `node:crypto`? It pulls Node-only APIs into modules that
|
|
14
|
+
* eventually transit through bundlers. When the bundler thinks a
|
|
15
|
+
* downstream module *might* still reach `cas()` at runtime (e.g. when
|
|
16
|
+
* tree-shake is conservative), it traces the import graph into
|
|
17
|
+
* `hasher.ts` and chokes on `node:crypto`'s missing `createHash`
|
|
18
|
+
* export in browser-stub mode. A self-contained JS implementation
|
|
19
|
+
* avoids that whole class of build-time failures and ships zero
|
|
20
|
+
* dependencies.
|
|
21
|
+
*
|
|
22
|
+
* Hash strength is non-cryptographic by design — collisions are
|
|
23
|
+
* detected at build time by the emitter (`CssEmitter.add` throws on
|
|
24
|
+
* a class name with two distinct canonical bags), so a chance
|
|
25
|
+
* collision surfaces as a clear error, not a silent miscompile.
|
|
26
|
+
*
|
|
27
|
+
* For lengths > 8 hex chars, additional 32-bit rounds with
|
|
28
|
+
* incrementing seed are concatenated until the requested length is
|
|
29
|
+
* met. This preserves the existing API (length 4..40) without
|
|
30
|
+
* forcing a bigger algorithm or dual-package complexity.
|
|
31
|
+
*/
|
|
7
32
|
export declare function hash(canonical: string, options?: HashOptions): string;
|
|
8
33
|
//# sourceMappingURL=hasher.d.ts.map
|
package/dist/hasher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasher.d.ts","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hasher.d.ts","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAgBzE"}
|
package/dist/hasher.js
CHANGED
|
@@ -1,10 +1,103 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
export const DEFAULT_PREFIX = 'cas-';
|
|
3
2
|
export const DEFAULT_LENGTH = 8;
|
|
3
|
+
/**
|
|
4
|
+
* Build-time class-name hasher.
|
|
5
|
+
*
|
|
6
|
+
* Uses MurmurHash3 (x86, 32-bit) — a non-cryptographic hash with good
|
|
7
|
+
* distribution and low collision rate over ASCII inputs.
|
|
8
|
+
*
|
|
9
|
+
* Why not `node:crypto`? It pulls Node-only APIs into modules that
|
|
10
|
+
* eventually transit through bundlers. When the bundler thinks a
|
|
11
|
+
* downstream module *might* still reach `cas()` at runtime (e.g. when
|
|
12
|
+
* tree-shake is conservative), it traces the import graph into
|
|
13
|
+
* `hasher.ts` and chokes on `node:crypto`'s missing `createHash`
|
|
14
|
+
* export in browser-stub mode. A self-contained JS implementation
|
|
15
|
+
* avoids that whole class of build-time failures and ships zero
|
|
16
|
+
* dependencies.
|
|
17
|
+
*
|
|
18
|
+
* Hash strength is non-cryptographic by design — collisions are
|
|
19
|
+
* detected at build time by the emitter (`CssEmitter.add` throws on
|
|
20
|
+
* a class name with two distinct canonical bags), so a chance
|
|
21
|
+
* collision surfaces as a clear error, not a silent miscompile.
|
|
22
|
+
*
|
|
23
|
+
* For lengths > 8 hex chars, additional 32-bit rounds with
|
|
24
|
+
* incrementing seed are concatenated until the requested length is
|
|
25
|
+
* met. This preserves the existing API (length 4..40) without
|
|
26
|
+
* forcing a bigger algorithm or dual-package complexity.
|
|
27
|
+
*/
|
|
4
28
|
export function hash(canonical, options = {}) {
|
|
5
29
|
const prefix = options.prefix ?? DEFAULT_PREFIX;
|
|
6
30
|
const length = options.length ?? DEFAULT_LENGTH;
|
|
7
|
-
|
|
8
|
-
|
|
31
|
+
// Encode once outside the round loop. For length > 8 we run multiple
|
|
32
|
+
// 32-bit rounds with incrementing seeds, but the input bytes don't
|
|
33
|
+
// change — re-encoding per round is pure waste and grows linear in
|
|
34
|
+
// the canonical-bag size for every extra hex char requested.
|
|
35
|
+
const bytes = utf8Bytes(canonical);
|
|
36
|
+
let hex = '';
|
|
37
|
+
let seed = 0;
|
|
38
|
+
while (hex.length < length) {
|
|
39
|
+
hex += murmur3_32(bytes, seed).toString(16).padStart(8, '0');
|
|
40
|
+
seed++;
|
|
41
|
+
}
|
|
42
|
+
return prefix + hex.slice(0, length);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* MurmurHash3 x86 32-bit. Public-domain algorithm by Austin Appleby.
|
|
46
|
+
*
|
|
47
|
+
* Takes a pre-encoded UTF-8 byte sequence so the caller can amortize
|
|
48
|
+
* encoding across multiple seeded rounds. All arithmetic is kept in
|
|
49
|
+
* unsigned 32-bit territory via `>>> 0` and `Math.imul`, both of
|
|
50
|
+
* which V8 / SpiderMonkey JIT fast-path. Returns a non-negative
|
|
51
|
+
* 32-bit integer.
|
|
52
|
+
*/
|
|
53
|
+
function murmur3_32(bytes, seed = 0) {
|
|
54
|
+
const len = bytes.length;
|
|
55
|
+
const nblocks = Math.floor(len / 4);
|
|
56
|
+
const c1 = 0xcc9e2d51;
|
|
57
|
+
const c2 = 0x1b873593;
|
|
58
|
+
let h1 = seed >>> 0;
|
|
59
|
+
for (let i = 0; i < nblocks; i++) {
|
|
60
|
+
const o = i * 4;
|
|
61
|
+
let k1 = (bytes[o] |
|
|
62
|
+
(bytes[o + 1] << 8) |
|
|
63
|
+
(bytes[o + 2] << 16) |
|
|
64
|
+
(bytes[o + 3] << 24)) >>>
|
|
65
|
+
0;
|
|
66
|
+
k1 = Math.imul(k1, c1) >>> 0;
|
|
67
|
+
k1 = ((k1 << 15) | (k1 >>> 17)) >>> 0;
|
|
68
|
+
k1 = Math.imul(k1, c2) >>> 0;
|
|
69
|
+
h1 = (h1 ^ k1) >>> 0;
|
|
70
|
+
h1 = ((h1 << 13) | (h1 >>> 19)) >>> 0;
|
|
71
|
+
h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;
|
|
72
|
+
}
|
|
73
|
+
// tail
|
|
74
|
+
let k1 = 0;
|
|
75
|
+
const tailStart = nblocks * 4;
|
|
76
|
+
const rem = len & 3;
|
|
77
|
+
if (rem >= 3)
|
|
78
|
+
k1 ^= bytes[tailStart + 2] << 16;
|
|
79
|
+
if (rem >= 2)
|
|
80
|
+
k1 ^= bytes[tailStart + 1] << 8;
|
|
81
|
+
if (rem >= 1) {
|
|
82
|
+
k1 ^= bytes[tailStart];
|
|
83
|
+
k1 = Math.imul(k1, c1) >>> 0;
|
|
84
|
+
k1 = ((k1 << 15) | (k1 >>> 17)) >>> 0;
|
|
85
|
+
k1 = Math.imul(k1, c2) >>> 0;
|
|
86
|
+
h1 = (h1 ^ k1) >>> 0;
|
|
87
|
+
}
|
|
88
|
+
// finalization
|
|
89
|
+
h1 = (h1 ^ len) >>> 0;
|
|
90
|
+
h1 = (h1 ^ (h1 >>> 16)) >>> 0;
|
|
91
|
+
h1 = Math.imul(h1, 0x85ebca6b) >>> 0;
|
|
92
|
+
h1 = (h1 ^ (h1 >>> 13)) >>> 0;
|
|
93
|
+
h1 = Math.imul(h1, 0xc2b2ae35) >>> 0;
|
|
94
|
+
h1 = (h1 ^ (h1 >>> 16)) >>> 0;
|
|
95
|
+
return h1 >>> 0;
|
|
96
|
+
}
|
|
97
|
+
// Module-level encoder. `TextEncoder` is stateless once constructed,
|
|
98
|
+
// so reusing one instance avoids per-hash allocation.
|
|
99
|
+
const utf8Encoder = new TextEncoder();
|
|
100
|
+
function utf8Bytes(s) {
|
|
101
|
+
return utf8Encoder.encode(s);
|
|
9
102
|
}
|
|
10
103
|
//# sourceMappingURL=hasher.js.map
|
package/dist/hasher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasher.js","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"hasher.js","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cassida/compiler",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Cassida build-time CSS resolver: registry, canonicalizer, hasher, emitter.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"type": "module",
|
|
7
8
|
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
8
10
|
"types": "./dist/index.d.ts",
|
|
9
11
|
"exports": {
|
|
10
12
|
".": {
|
|
11
13
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.js"
|
|
13
|
-
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./config.schema.json": "./config.schema.json",
|
|
18
|
+
"./package.json": "./package.json"
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
16
21
|
"dist",
|