@jk2908/cxx 0.2.4 → 0.3.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/README.md +18 -2
- package/dist/build.d.ts +46 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +314 -0
- package/dist/build.js.map +13 -0
- package/dist/index.d.ts +3 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -188
- package/dist/index.js.map +4 -7
- package/dist/logger.d.ts +9 -11
- package/dist/logger.d.ts.map +1 -1
- package/dist/lru.d.ts +2 -2
- package/dist/next/cxx-loader.cjs +249 -152
- package/dist/next/cxx-loader.cjs.map +9 -9
- package/dist/next/index.d.ts +32 -11
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +278 -135
- package/dist/next/index.js.map +7 -7
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/vite/index.d.ts +14 -6
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +281 -129
- package/dist/vite/index.js.map +8 -8
- package/package.json +83 -75
- package/src/build.ts +373 -0
- package/src/index.ts +24 -210
- package/src/logger.ts +14 -22
- package/src/lru.ts +2 -2
- package/src/next/cxx-loader.js +1 -5
- package/src/next/index.ts +143 -100
- package/src/types.ts +5 -4
- package/src/utils.ts +72 -7
- package/src/vite/index.ts +110 -79
package/dist/index.js
CHANGED
|
@@ -1,195 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { transform } from "lightningcss";
|
|
6
|
-
|
|
7
|
-
// src/config.ts
|
|
8
|
-
var NAME = "cxx";
|
|
9
|
-
var PKG_NAME = `@jk2908/${NAME}`;
|
|
10
|
-
var GENERATED_DIR = `.${NAME}`;
|
|
11
|
-
var AUTOGEN_MSG = `// auto-generated by ${NAME}`;
|
|
12
|
-
|
|
13
|
-
// src/lru.ts
|
|
14
|
-
var CACHE_MAX_SIZE = 100;
|
|
15
|
-
|
|
16
|
-
class LruCache {
|
|
17
|
-
#cache = new Map;
|
|
18
|
-
#maxSize;
|
|
19
|
-
constructor(maxSize = CACHE_MAX_SIZE) {
|
|
20
|
-
this.#maxSize = maxSize;
|
|
21
|
-
}
|
|
22
|
-
get size() {
|
|
23
|
-
return this.#cache.size;
|
|
24
|
-
}
|
|
25
|
-
get(key) {
|
|
26
|
-
const cached = this.#cache.get(key);
|
|
27
|
-
if (this.#cache.has(key))
|
|
28
|
-
this.set(key, cached);
|
|
29
|
-
return cached;
|
|
30
|
-
}
|
|
31
|
-
set(key, value) {
|
|
32
|
-
this.#cache.delete(key);
|
|
33
|
-
if (this.#cache.size >= this.#maxSize) {
|
|
34
|
-
const lru = this.#cache.keys().next().value;
|
|
35
|
-
if (lru !== undefined)
|
|
36
|
-
this.#cache.delete(lru);
|
|
37
|
-
}
|
|
38
|
-
this.#cache.set(key, value);
|
|
39
|
-
}
|
|
40
|
-
delete(key) {
|
|
41
|
-
return this.#cache.delete(key);
|
|
42
|
-
}
|
|
43
|
-
clear() {
|
|
44
|
-
return this.#cache.clear();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// src/utils.ts
|
|
49
|
-
function capitalise(str) {
|
|
50
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
51
|
-
}
|
|
52
|
-
function pascalise(str) {
|
|
53
|
-
return str.split(/[ _-]+/).map(capitalise).join("");
|
|
54
|
-
}
|
|
55
|
-
function debounce(fn, wait) {
|
|
56
|
-
let timeoutId = null;
|
|
57
|
-
return (...args) => {
|
|
58
|
-
if (timeoutId) {
|
|
59
|
-
clearTimeout(timeoutId);
|
|
60
|
-
}
|
|
61
|
-
timeoutId = setTimeout(() => {
|
|
62
|
-
fn.apply(null, args);
|
|
63
|
-
}, wait);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
66
3
|
|
|
67
4
|
// src/index.ts
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
function isENOENT(err) {
|
|
71
|
-
return err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
72
|
-
}
|
|
73
|
-
async function maybeWrite(filePath, content) {
|
|
74
|
-
const cached = fileCache.get(filePath);
|
|
75
|
-
if (cached !== content) {
|
|
76
|
-
await fs.writeFile(filePath, content);
|
|
77
|
-
fileCache.set(filePath, content);
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
if (await fs.readFile(filePath, "utf-8") === content) {
|
|
82
|
-
fileCache.set(filePath, content);
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
} catch (err) {
|
|
86
|
-
if (!isENOENT(err))
|
|
87
|
-
throw err;
|
|
88
|
-
}
|
|
89
|
-
await fs.writeFile(filePath, content);
|
|
90
|
-
fileCache.set(filePath, content);
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
var regex = /(?:const|var|let)\s*\[(\w+|)\s*,?\s*(\w+|)\s*,?\s*(\w+|)\s*\]\s*=\s*cxx(?:\s*`([\s\S]*?)`|\s*\.\s*tag(?:\s*<[^>]+>)?\s*\(\s*(['"])(.*?)\5\s*\)\s*`([\s\S]*?)`)/gm;
|
|
94
|
-
function hashCss(code) {
|
|
95
|
-
return `cxx-${createHash("sha256").update(code).digest("base64url").slice(0, 12)}`;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
class TagDuplicateError extends Error {
|
|
99
|
-
constructor(tag) {
|
|
100
|
-
super(`Tag ${tag} has already been seen. Tags must be unique across your application`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function collect(source, id, config) {
|
|
104
|
-
const tags = new Map;
|
|
105
|
-
const cached = collectCache.get(id);
|
|
106
|
-
if (cached?.source === source)
|
|
107
|
-
return cached;
|
|
108
|
-
const template = source.replace(regex, (_match, varOne, varTwo, varThree, plainCss, _quote, tag, taggedCss) => {
|
|
109
|
-
const css = plainCss ?? taggedCss;
|
|
110
|
-
const { code, exports = {} } = transform({
|
|
111
|
-
minify: true,
|
|
112
|
-
cssModules: true,
|
|
113
|
-
filename: id,
|
|
114
|
-
code: new TextEncoder().encode(css)
|
|
115
|
-
});
|
|
116
|
-
const href = hashCss(code);
|
|
117
|
-
const styles = Object.fromEntries(Object.entries(exports).map(([k, v]) => [k, v.name]));
|
|
118
|
-
if (tag) {
|
|
119
|
-
const suffix = typeof config.typeSuffix === "string" ? config.typeSuffix : config.typeSuffix === false ? "" : "Classes";
|
|
120
|
-
const tagWithSuffix = pascalise(`${tag}${suffix}`);
|
|
121
|
-
if (tags.has(tagWithSuffix))
|
|
122
|
-
throw new TagDuplicateError(tagWithSuffix);
|
|
123
|
-
tags.set(tagWithSuffix, Object.keys(styles));
|
|
124
|
-
}
|
|
125
|
-
return [
|
|
126
|
-
varOne && `const ${varOne} = \`${code}\``,
|
|
127
|
-
varTwo && `const ${varTwo} = ${JSON.stringify(styles)}`,
|
|
128
|
-
varThree && `const ${varThree} = \`${href}\``
|
|
129
|
-
].filter(Boolean).join(`
|
|
130
|
-
`);
|
|
131
|
-
});
|
|
132
|
-
collectCache.set(id, { source, template, tags });
|
|
133
|
-
return {
|
|
134
|
-
template,
|
|
135
|
-
tags
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
async function writeTypes(tags) {
|
|
139
|
-
const filePath = path.join(GENERATED_DIR, "index.d.ts");
|
|
140
|
-
if (!tags.size) {
|
|
141
|
-
try {
|
|
142
|
-
await fs.rm(filePath, { force: true });
|
|
143
|
-
fileCache.delete(filePath);
|
|
144
|
-
} catch (err) {
|
|
145
|
-
if (!isENOENT(err))
|
|
146
|
-
throw err;
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
|
151
|
-
await maybeWrite(filePath, `${AUTOGEN_MSG}
|
|
152
|
-
|
|
153
|
-
import '${PKG_NAME}'
|
|
154
|
-
|
|
155
|
-
declare module '${PKG_NAME}' {
|
|
156
|
-
${tagsToType(tags)}
|
|
157
|
-
}
|
|
158
|
-
`);
|
|
159
|
-
}
|
|
160
|
-
function tagsToType(tags) {
|
|
161
|
-
return [...tags].map(([tag, classes]) => `
|
|
162
|
-
export type ${tag} = ${classes.length > 0 ? classes.toSorted((a, b) => a.length - b.length).map((c) => `'${c}'`).join(" | ") : "never"}
|
|
163
|
-
`).join(`
|
|
164
|
-
`);
|
|
165
|
-
}
|
|
166
|
-
function flattenTags(tagsByFile) {
|
|
167
|
-
const tags = new Map;
|
|
168
|
-
for (const fileTags of tagsByFile.values()) {
|
|
169
|
-
for (const [name, classes] of fileTags) {
|
|
170
|
-
if (tags.has(name))
|
|
171
|
-
throw new TagDuplicateError(name);
|
|
172
|
-
tags.set(name, classes);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return tags;
|
|
5
|
+
function untransformed() {
|
|
6
|
+
throw new Error("cxx template was not transformed. Make sure the cxx Vite plugin or Next integration is configured and applies to this file.");
|
|
176
7
|
}
|
|
177
|
-
var cxx = Object.assign((_) =>
|
|
178
|
-
tag: (_) => (_strings) =>
|
|
179
|
-
"",
|
|
180
|
-
{},
|
|
181
|
-
""
|
|
182
|
-
]
|
|
8
|
+
var cxx = Object.assign((_) => untransformed(), {
|
|
9
|
+
tag: (_) => (_strings) => untransformed()
|
|
183
10
|
});
|
|
184
11
|
export {
|
|
185
|
-
|
|
186
|
-
tagsToType,
|
|
187
|
-
maybeWrite,
|
|
188
|
-
isENOENT,
|
|
189
|
-
flattenTags,
|
|
190
|
-
cxx,
|
|
191
|
-
collect,
|
|
192
|
-
TagDuplicateError
|
|
12
|
+
cxx
|
|
193
13
|
};
|
|
194
14
|
|
|
195
|
-
//# debugId=
|
|
15
|
+
//# debugId=3CD7511904F6E92464756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import
|
|
6
|
-
"export const NAME = 'cxx'\nexport const PKG_NAME = `@jk2908/${NAME}`\nexport const GENERATED_DIR = `.${NAME}`\nexport const AUTOGEN_MSG = `// auto-generated by ${NAME}`\n",
|
|
7
|
-
"export const CACHE_MAX_SIZE = 100\n\nexport class LruCache<T> {\n\t#cache: Map<string, T> = new Map()\n\t#maxSize: number\n\n\tconstructor(maxSize = CACHE_MAX_SIZE) {\n\t\tthis.#maxSize = maxSize\n\t}\n\n\tget size() {\n\t\treturn this.#cache.size\n\t}\n\n\t/**\n\t * Retrieve a cached value and promote it to most-recently-used so it won't\n\t * be evicted while still actively referenced\n\t */\n\tget(key: string) {\n\t\tconst cached = this.#cache.get(key)\n\t\tif (this.#cache.has(key)) this.set(key, cached as T)\n\n\t\treturn cached\n\t}\n\n\t/**\n\t * Promote an existing cache entry to most-recently-used by deleting and\n\t * re-inserting it, which moves it to the end of the Map's iteration\n\t * order. If the cache is at capacity, evict the least recently used\n\t * entry (front) before inserting\n\t */\n\tset(key: string, value: T) {\n\t\t// drop any existing entry\n\t\tthis.#cache.delete(key)\n\n\t\tif (this.#cache.size >= this.#maxSize) {\n\t\t\tconst lru = this.#cache.keys().next().value\n\t\t\tif (lru !== undefined) this.#cache.delete(lru)\n\t\t}\n\n\t\tthis.#cache.set(key, value)\n\t}\n\n\tdelete(key: string) {\n\t\treturn this.#cache.delete(key)\n\t}\n\n\tclear() {\n\t\treturn this.#cache.clear()\n\t}\n}\n",
|
|
8
|
-
"export function capitalise(str: string) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function pascalise(str: string) {\n\treturn str\n\t\t.split(/[ _-]+/)\n\t\t.map(capitalise)\n\t\t.join('')\n}\n\nexport function debounce<T extends unknown[]>(fn: (...args: T) => void, wait: number) {\n\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\treturn (...args: T) => {\n\t\tif (timeoutId) {\n\t\t\tclearTimeout(timeoutId)\n\t\t}\n\n\t\ttimeoutId = setTimeout(() => {\n\t\t\tfn.apply(null, args)\n\t\t}, wait)\n\t}\n}\n"
|
|
5
|
+
"import type { Cxx, Result } from './types.js'\n\nexport type { Cxx, Result, Tag } from './types.js'\n\n/**\n * Hit when a `cxx` template reaches runtime, which means the build transform did\n * not run. Throws so the problem is obvious instead of rendering empty styles.\n *\n * @example\n * ```ts\n * // no cxx plugin configured\n * const [css, styles, href] = cxx`.a { color: red; }`\n * // Error: cxx template was not transformed ...\n * ```\n */\nfunction untransformed(): never {\n\tthrow new Error(\n\t\t'cxx template was not transformed. Make sure the cxx Vite plugin or Next integration is configured and applies to this file.',\n\t)\n}\n\n/**\n * Build-time template tag placeholder used by the transform to emit CSS, classes and href values.\n */\nexport const cxx: Cxx = Object.assign(\n\t(_: TemplateStringsArray): Result => untransformed(),\n\t{\n\t\ttag:\n\t\t\t<ClassName extends string = string>(_: string) =>\n\t\t\t(_strings: TemplateStringsArray): Result<ClassName> =>\n\t\t\t\tuntransformed(),\n\t},\n)\n"
|
|
9
6
|
],
|
|
10
|
-
"mappings": "
|
|
11
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;AAeA,SAAS,aAAa,GAAU;AAAA,EAC/B,MAAM,IAAI,MACT,6HACD;AAAA;AAMM,IAAM,MAAW,OAAO,OAC9B,CAAC,MAAoC,cAAc,GACnD;AAAA,EACC,KACC,CAAoC,MACpC,CAAC,aACA,cAAc;AACjB,CACD;",
|
|
8
|
+
"debugId": "3CD7511904F6E92464756E2164756E21",
|
|
12
9
|
"names": []
|
|
13
10
|
}
|
package/dist/logger.d.ts
CHANGED
|
@@ -7,46 +7,44 @@ declare const LEVELS: {
|
|
|
7
7
|
};
|
|
8
8
|
export type LogLevel = keyof typeof LEVELS;
|
|
9
9
|
/**
|
|
10
|
-
* Log messages with different severity levels
|
|
10
|
+
* Log messages with different severity levels.
|
|
11
11
|
*/
|
|
12
12
|
export declare class Logger {
|
|
13
13
|
#private;
|
|
14
14
|
name?: string | undefined;
|
|
15
15
|
constructor(level?: LogLevel, name?: string | undefined);
|
|
16
|
-
static set defaultLevel(level: LogLevel);
|
|
17
|
-
static get defaultLevel(): LogLevel;
|
|
18
16
|
/**
|
|
19
|
-
* Convert a value to an Error instance
|
|
17
|
+
* Convert a value to an Error instance.
|
|
20
18
|
*/
|
|
21
19
|
static toError(err: unknown): Error;
|
|
22
20
|
/**
|
|
23
|
-
* Stringify the error for logging
|
|
21
|
+
* Stringify the error for logging.
|
|
24
22
|
*/
|
|
25
23
|
static print(err: unknown): string;
|
|
26
24
|
set level(level: LogLevel);
|
|
27
25
|
get level(): LogLevel;
|
|
28
26
|
/**
|
|
29
|
-
* Log a message with a specific level
|
|
27
|
+
* Log a message with a specific level.
|
|
30
28
|
*/
|
|
31
29
|
log(level: LogLevel, message: string, error?: Error): void;
|
|
32
30
|
/**
|
|
33
|
-
* Log a debug message
|
|
31
|
+
* Log a debug message.
|
|
34
32
|
*/
|
|
35
33
|
debug(...messages: string[]): void;
|
|
36
34
|
/**
|
|
37
|
-
* Log an info message
|
|
35
|
+
* Log an info message.
|
|
38
36
|
*/
|
|
39
37
|
info(...messages: string[]): void;
|
|
40
38
|
/**
|
|
41
|
-
* Log a warning message
|
|
39
|
+
* Log a warning message.
|
|
42
40
|
*/
|
|
43
41
|
warn(...messages: string[]): void;
|
|
44
42
|
/**
|
|
45
|
-
* Log an error message
|
|
43
|
+
* Log an error message.
|
|
46
44
|
*/
|
|
47
45
|
error(message: string, error?: unknown): void;
|
|
48
46
|
/**
|
|
49
|
-
* Log a fatal error message
|
|
47
|
+
* Log a fatal error message.
|
|
50
48
|
*/
|
|
51
49
|
fatal(message: string, error?: unknown): void;
|
|
52
50
|
}
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,MAAM;;;;;;CAMF,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,MAAM;;;;;;CAMF,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,MAAM,CAAA;AAiB1C;;GAEG;AACH,qBAAa,MAAM;;IAKV,IAAI,CAAC,EAAE,MAAM;gBADpB,KAAK,CAAC,EAAE,QAAQ,EACT,IAAI,CAAC,EAAE,MAAM,YAAA;IAKrB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO;IAI3B;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO;IAoBzB,IAAI,KAAK,CAAC,KAAK,EAAE,QAAQ,EAExB;IAED,IAAI,KAAK,IAJQ,QAAQ,CAMxB;IAED;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;IA6BnD;;OAEG;IACH,KAAK,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE;IAI3B;;OAEG;IACH,IAAI,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE;IAI1B;;OAEG;IACH,IAAI,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE;IAI1B;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAItC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAGtC"}
|
package/dist/lru.d.ts
CHANGED
|
@@ -5,14 +5,14 @@ export declare class LruCache<T> {
|
|
|
5
5
|
get size(): number;
|
|
6
6
|
/**
|
|
7
7
|
* Retrieve a cached value and promote it to most-recently-used so it won't
|
|
8
|
-
* be evicted while still actively referenced
|
|
8
|
+
* be evicted while still actively referenced.
|
|
9
9
|
*/
|
|
10
10
|
get(key: string): T | undefined;
|
|
11
11
|
/**
|
|
12
12
|
* Promote an existing cache entry to most-recently-used by deleting and
|
|
13
13
|
* re-inserting it, which moves it to the end of the Map's iteration
|
|
14
14
|
* order. If the cache is at capacity, evict the least recently used
|
|
15
|
-
* entry (front) before inserting
|
|
15
|
+
* entry (front) before inserting.
|
|
16
16
|
*/
|
|
17
17
|
set(key: string, value: T): void;
|
|
18
18
|
delete(key: string): boolean;
|