@jk2908/cxx 0.2.6 → 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 +13 -4
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +180 -54
- package/dist/build.js.map +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +3 -3
- package/dist/logger.d.ts +0 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/next/cxx-loader.cjs +214 -132
- package/dist/next/cxx-loader.cjs.map +7 -7
- package/dist/next/index.d.ts +32 -11
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +272 -123
- package/dist/next/index.js.map +5 -5
- 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 +11 -3
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +273 -115
- package/dist/vite/index.js.map +6 -6
- package/package.json +83 -79
- package/src/build.ts +258 -93
- package/src/index.ts +26 -9
- package/src/logger.ts +5 -13
- 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 +109 -78
package/dist/next/index.d.ts
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
import type { NextConfig } from 'next';
|
|
2
2
|
import type { Logger } from '../logger.js';
|
|
3
|
-
import type { PluginConfig
|
|
3
|
+
import type { PluginConfig } from '../types.js';
|
|
4
4
|
/**
|
|
5
|
-
* Transform one module and, in development, register it with the shared watcher state
|
|
5
|
+
* Transform one module and, in development, register it with the shared watcher state.
|
|
6
6
|
*/
|
|
7
7
|
export declare function processFile(source: string, filePath: string, pluginConfig: PluginConfig, logger: Logger): {
|
|
8
8
|
source: string;
|
|
9
|
+
config: string;
|
|
9
10
|
template: string;
|
|
10
|
-
tags: Tags;
|
|
11
|
-
|
|
12
|
-
template: string;
|
|
13
|
-
tags: Tags;
|
|
11
|
+
tags: import("../types.js").Tags;
|
|
12
|
+
map: import("magic-string").SourceMap | null;
|
|
14
13
|
};
|
|
15
|
-
export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginConfig):
|
|
14
|
+
export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginConfig): {
|
|
16
15
|
turbopack: {
|
|
17
16
|
rules: {
|
|
18
17
|
"*.{tsx,jsx,ts,js}": ({
|
|
19
18
|
loader: string;
|
|
20
19
|
options: {
|
|
21
|
-
pluginConfig:
|
|
20
|
+
pluginConfig: {
|
|
21
|
+
watch: {
|
|
22
|
+
root: string;
|
|
23
|
+
ignore?: string[];
|
|
24
|
+
};
|
|
25
|
+
typeSuffix?: string | false;
|
|
26
|
+
};
|
|
22
27
|
};
|
|
23
28
|
} | import("next/dist/server/config-shared.js").TurbopackRuleConfigItem | import("next/dist/server/config-shared.js").TurbopackLoaderItem)[] | {
|
|
24
29
|
loaders: ({
|
|
25
30
|
loader: string;
|
|
26
31
|
options: {
|
|
27
|
-
pluginConfig:
|
|
32
|
+
pluginConfig: {
|
|
33
|
+
watch: {
|
|
34
|
+
root: string;
|
|
35
|
+
ignore?: string[];
|
|
36
|
+
};
|
|
37
|
+
typeSuffix?: string | false;
|
|
38
|
+
};
|
|
28
39
|
};
|
|
29
40
|
} | import("next/dist/server/config-shared.js").TurbopackLoaderItem)[];
|
|
30
41
|
as?: string;
|
|
@@ -41,6 +52,12 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
41
52
|
title?: string | RegExp;
|
|
42
53
|
description?: string | RegExp;
|
|
43
54
|
}>;
|
|
55
|
+
chunkLoadingGlobal?: string;
|
|
56
|
+
};
|
|
57
|
+
webpack(config: unknown, context: unknown): {
|
|
58
|
+
module?: {
|
|
59
|
+
rules?: unknown[];
|
|
60
|
+
};
|
|
44
61
|
};
|
|
45
62
|
allowedDevOrigins?: string[];
|
|
46
63
|
exportPathMap?: (defaultMap: import("next/dist/server/config-shared.js").ExportPathMap, ctx: {
|
|
@@ -65,7 +82,6 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
65
82
|
};
|
|
66
83
|
redirects?: () => Promise<import("next/dist/lib/load-custom-routes.js").Redirect[]> | import("next/dist/lib/load-custom-routes.js").Redirect[];
|
|
67
84
|
excludeDefaultMomentLocales?: boolean;
|
|
68
|
-
webpack?: import("next/dist/server/config-shared.js").NextJsWebpackConfig | null;
|
|
69
85
|
trailingSlash?: boolean;
|
|
70
86
|
env?: Record<string, string | undefined>;
|
|
71
87
|
distDir?: string;
|
|
@@ -84,6 +100,7 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
84
100
|
generateBuildId?: () => string | null | Promise<string | null>;
|
|
85
101
|
generateEtags?: boolean;
|
|
86
102
|
pageExtensions?: string[];
|
|
103
|
+
instrumentationClientInject?: string[];
|
|
87
104
|
compress?: boolean;
|
|
88
105
|
poweredByHeader?: boolean;
|
|
89
106
|
images?: import("next/dist/shared/lib/image-config.js").ImageConfig;
|
|
@@ -95,6 +112,7 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
95
112
|
pagesBufferLength?: number;
|
|
96
113
|
};
|
|
97
114
|
deploymentId?: string;
|
|
115
|
+
supportsImmutableAssets?: boolean;
|
|
98
116
|
basePath?: string;
|
|
99
117
|
sassOptions?: {
|
|
100
118
|
implementation?: string;
|
|
@@ -148,6 +166,7 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
148
166
|
logging?: import("next/dist/server/config-shared.js").LoggingConfig | false;
|
|
149
167
|
enablePrerenderSourceMaps?: boolean;
|
|
150
168
|
cacheComponents?: boolean;
|
|
169
|
+
partialPrefetching?: boolean | "unstable_eager";
|
|
151
170
|
cacheLife?: {
|
|
152
171
|
[profile: string]: {
|
|
153
172
|
stale?: number;
|
|
@@ -156,15 +175,17 @@ export declare function withCxx(nextConfig?: NextConfig, pluginConfig?: PluginCo
|
|
|
156
175
|
};
|
|
157
176
|
};
|
|
158
177
|
expireTime?: number;
|
|
178
|
+
agentRules?: boolean;
|
|
159
179
|
experimental?: import("next/dist/server/config-shared.js").ExperimentalConfig;
|
|
160
180
|
bundlePagesRouterDependencies?: boolean;
|
|
161
181
|
serverExternalPackages?: string[];
|
|
162
182
|
outputFileTracingRoot?: string;
|
|
163
183
|
outputFileTracingExcludes?: Record<string, string[]>;
|
|
164
184
|
outputFileTracingIncludes?: Record<string, string[]>;
|
|
185
|
+
outputHashSalt?: string;
|
|
165
186
|
watchOptions?: {
|
|
166
187
|
pollIntervalMs?: number;
|
|
167
188
|
};
|
|
168
189
|
htmlLimitedBots?: RegExp;
|
|
169
|
-
}
|
|
190
|
+
};
|
|
170
191
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/next/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAMtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAqI/C;;GAEG;AACH,wBAAgB,WAAW,CAC1B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM;;;;;;EAgBd;AAID,wBAAgB,OAAO,CAAC,UAAU,GAAE,UAAe,EAAE,YAAY,GAAE,YAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDkpE,CAAC;uBAAsC,CAAC;;;;oBApB5vE,OAAO,WAAW,OAAO;iBAI9B;YAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE;;;;;;;;;;;;;;;mBAgBg05C,CAAC;kBAA+B,CAAC;gBAA6B,CAAC;;mBAAuD,CAAC;kBAA+B,CAAC;gBAA6B,CAAC;;;;;;;;;;;;eAA8lF,CAAC;cAAwB,CAAC;cAAwB,CAAC;;;;;;;;;;;;;gBAAkxE,CAAC;;;sBAAie,CAAC;yBAA4H,CAAC;;;;;;sBAAuyB,CAAC;;;;;;;;;iBAA4+C,CAAC;;;;;6BAA+sB,CAAC;sBAAoC,CAAC;;aAAoC,CAAC;;6BAA0D,CAAC;oBAA8B,CAAC;0BAAkE,CAAC;;qBAA2C,CAAC;mBAAiC,CAAC;;wBAA+C,CAAC;eAAmD,CAAC;iBAA4C,CAAC;2BAAyC,CAAC;;cAA6L,CAAC;oBAAyP,CAAC;iCAA8S,CAAC;;;;;;;;;;;;yBAAm0D,CAAC;6BAAwC,CAAC;;;;;;;;iBAAgxD,CAAC;sBAAgC,CAAC;kBAA4B,CAAC;;;;;;;;;;;;;sBAA+vE,CAAC;;;EADjp5D"}
|
package/dist/next/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/build.ts
|
|
2
5
|
import { createHash } from "node:crypto";
|
|
3
6
|
import fs from "node:fs/promises";
|
|
4
7
|
import path from "node:path";
|
|
5
8
|
import { transform } from "lightningcss";
|
|
9
|
+
import MagicString from "magic-string";
|
|
6
10
|
|
|
7
11
|
// src/config.ts
|
|
8
12
|
var NAME = "cxx";
|
|
@@ -52,31 +56,73 @@ function capitalise(str) {
|
|
|
52
56
|
function pascalise(str) {
|
|
53
57
|
return str.split(/[ _-]+/).map(capitalise).join("");
|
|
54
58
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
function createBatcher(wait, flush) {
|
|
60
|
+
const pending = new Map;
|
|
61
|
+
let timer = null;
|
|
62
|
+
let running = false;
|
|
63
|
+
async function drain() {
|
|
64
|
+
if (running)
|
|
65
|
+
return;
|
|
66
|
+
running = true;
|
|
67
|
+
try {
|
|
68
|
+
while (pending.size > 0) {
|
|
69
|
+
const batch = new Map(pending);
|
|
70
|
+
pending.clear();
|
|
71
|
+
await flush(batch);
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
running = false;
|
|
60
75
|
}
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
}
|
|
77
|
+
function schedule() {
|
|
78
|
+
if (timer)
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
timer = setTimeout(() => {
|
|
81
|
+
timer = null;
|
|
82
|
+
drain();
|
|
63
83
|
}, wait);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
add(key, value) {
|
|
87
|
+
pending.set(key, value);
|
|
88
|
+
schedule();
|
|
89
|
+
},
|
|
90
|
+
flush() {
|
|
91
|
+
if (timer) {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
timer = null;
|
|
94
|
+
}
|
|
95
|
+
return drain();
|
|
96
|
+
}
|
|
64
97
|
};
|
|
65
98
|
}
|
|
66
99
|
|
|
67
100
|
// src/build.ts
|
|
101
|
+
var decoder = new TextDecoder;
|
|
68
102
|
var collectCache = new LruCache;
|
|
69
103
|
var fileCache = new LruCache;
|
|
104
|
+
var writeChain = Promise.resolve();
|
|
70
105
|
function isENOENT(err) {
|
|
71
106
|
return err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
72
107
|
}
|
|
108
|
+
async function writeFileAtomic(filePath, content) {
|
|
109
|
+
const tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
110
|
+
await fs.writeFile(tmp, content);
|
|
111
|
+
await fs.rename(tmp, filePath);
|
|
112
|
+
}
|
|
113
|
+
function enqueueWrite(task) {
|
|
114
|
+
const run = writeChain.then(task, task);
|
|
115
|
+
writeChain = run.then(() => {
|
|
116
|
+
return;
|
|
117
|
+
}, () => {
|
|
118
|
+
return;
|
|
119
|
+
});
|
|
120
|
+
return run;
|
|
121
|
+
}
|
|
73
122
|
async function maybeWrite(filePath, content) {
|
|
74
123
|
const cached = fileCache.get(filePath);
|
|
75
|
-
if (cached
|
|
76
|
-
|
|
77
|
-
fileCache.set(filePath, content);
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
124
|
+
if (cached === content)
|
|
125
|
+
return false;
|
|
80
126
|
try {
|
|
81
127
|
if (await fs.readFile(filePath, "utf-8") === content) {
|
|
82
128
|
fileCache.set(filePath, content);
|
|
@@ -86,11 +132,12 @@ async function maybeWrite(filePath, content) {
|
|
|
86
132
|
if (!isENOENT(err))
|
|
87
133
|
throw err;
|
|
88
134
|
}
|
|
89
|
-
await
|
|
135
|
+
await writeFileAtomic(filePath, content);
|
|
90
136
|
fileCache.set(filePath, content);
|
|
91
137
|
return true;
|
|
92
138
|
}
|
|
93
|
-
var regex = /(?:const|var|let)\s*\[(\w
|
|
139
|
+
var regex = /((?:export\s+)?)(?:const|var|let)\s*\[(\w*)\s*,?\s*(\w*)\s*,?\s*(\w*)\s*\]\s*=\s*cxx(?:\s*`([\s\S]*?)`|\s*\.\s*tag(?:\s*<[^>]+>)?\s*\(\s*(['"])(.*?)\6\s*\)\s*`([\s\S]*?)`)/gm;
|
|
140
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
94
141
|
function hashCss(code) {
|
|
95
142
|
return `cxx-${createHash("sha256").update(code).digest("base64url").slice(0, 12)}`;
|
|
96
143
|
}
|
|
@@ -101,12 +148,26 @@ class DuplicateTagError extends Error {
|
|
|
101
148
|
super(`Tag ${tag} has already been seen. Tags must be unique across your application`);
|
|
102
149
|
}
|
|
103
150
|
}
|
|
151
|
+
|
|
152
|
+
class InvalidTagError extends Error {
|
|
153
|
+
name = "InvalidTagError";
|
|
154
|
+
constructor(tag) {
|
|
155
|
+
super(`Tag "${tag}" does not map to a valid TypeScript identifier. ` + `Use letters, numbers, spaces, "_" or "-"`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
104
158
|
function collect(source, id, config) {
|
|
105
|
-
const
|
|
159
|
+
const configKey = JSON.stringify(config);
|
|
106
160
|
const cached = collectCache.get(id);
|
|
107
|
-
if (cached?.source === source)
|
|
161
|
+
if (cached?.source === source && cached.config === configKey)
|
|
108
162
|
return cached;
|
|
109
|
-
const
|
|
163
|
+
const tags = new Map;
|
|
164
|
+
const magic = new MagicString(source);
|
|
165
|
+
let matched = false;
|
|
166
|
+
regex.lastIndex = 0;
|
|
167
|
+
let match;
|
|
168
|
+
while (match = regex.exec(source)) {
|
|
169
|
+
matched = true;
|
|
170
|
+
const [, exp, varOne, varTwo, varThree, plainCss, , tag, taggedCss] = match;
|
|
110
171
|
const css = plainCss ?? taggedCss;
|
|
111
172
|
const { code, exports = {} } = transform({
|
|
112
173
|
minify: true,
|
|
@@ -119,49 +180,112 @@ function collect(source, id, config) {
|
|
|
119
180
|
if (tag) {
|
|
120
181
|
const suffix = typeof config.typeSuffix === "string" ? config.typeSuffix : config.typeSuffix === false ? "" : "Classes";
|
|
121
182
|
const tagWithSuffix = pascalise(`${tag}${suffix}`);
|
|
183
|
+
if (!IDENTIFIER.test(tagWithSuffix))
|
|
184
|
+
throw new InvalidTagError(tag);
|
|
122
185
|
if (tags.has(tagWithSuffix))
|
|
123
186
|
throw new DuplicateTagError(tagWithSuffix);
|
|
124
187
|
tags.set(tagWithSuffix, Object.keys(styles));
|
|
125
188
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
189
|
+
const statements = [];
|
|
190
|
+
if (varOne) {
|
|
191
|
+
statements.push(`${exp}const ${varOne} = ${JSON.stringify(decoder.decode(code))}`);
|
|
192
|
+
}
|
|
193
|
+
if (varTwo) {
|
|
194
|
+
statements.push(`${exp}const ${varTwo} = ${JSON.stringify(styles)}`);
|
|
195
|
+
}
|
|
196
|
+
if (varThree) {
|
|
197
|
+
statements.push(`${exp}const ${varThree} = ${JSON.stringify(href)}`);
|
|
198
|
+
}
|
|
199
|
+
magic.overwrite(match.index, match.index + match[0].length, statements.join(`
|
|
200
|
+
`));
|
|
201
|
+
}
|
|
202
|
+
const template = magic.toString();
|
|
203
|
+
const map = matched ? magic.generateMap({ source: id, includeContent: true, hires: true }) : null;
|
|
204
|
+
const result = { source, config: configKey, template, tags, map };
|
|
205
|
+
collectCache.set(id, result);
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
function renderTypes(tags) {
|
|
209
|
+
return [
|
|
210
|
+
AUTOGEN_MSG,
|
|
211
|
+
"",
|
|
212
|
+
`import '${PKG_NAME}'`,
|
|
213
|
+
"",
|
|
214
|
+
`declare module '${PKG_NAME}' {`,
|
|
215
|
+
tagsToType(tags),
|
|
216
|
+
"}",
|
|
217
|
+
""
|
|
218
|
+
].join(`
|
|
131
219
|
`);
|
|
132
|
-
});
|
|
133
|
-
collectCache.set(id, { source, template, tags });
|
|
134
|
-
return {
|
|
135
|
-
template,
|
|
136
|
-
tags
|
|
137
|
-
};
|
|
138
220
|
}
|
|
139
|
-
async function
|
|
221
|
+
async function writeRenderedTypes(tags) {
|
|
140
222
|
const filePath = path.join(GENERATED_DIR, "index.d.ts");
|
|
141
223
|
if (!tags.size) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
fileCache.delete(filePath);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
if (!isENOENT(err))
|
|
147
|
-
throw err;
|
|
148
|
-
}
|
|
224
|
+
await fs.rm(filePath, { force: true });
|
|
225
|
+
fileCache.delete(filePath);
|
|
149
226
|
return;
|
|
150
227
|
}
|
|
151
228
|
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
|
152
|
-
await maybeWrite(filePath,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
229
|
+
await maybeWrite(filePath, renderTypes(tags));
|
|
230
|
+
}
|
|
231
|
+
function writeTypes(tags) {
|
|
232
|
+
return enqueueWrite(() => writeRenderedTypes(tags));
|
|
233
|
+
}
|
|
234
|
+
var PARTIAL_DIR = path.join(GENERATED_DIR, "tags");
|
|
235
|
+
function partialPath(filePath) {
|
|
236
|
+
return path.join(PARTIAL_DIR, `${createHash("sha1").update(filePath).digest("hex")}.json`);
|
|
237
|
+
}
|
|
238
|
+
async function readPartials() {
|
|
239
|
+
let entries;
|
|
240
|
+
try {
|
|
241
|
+
entries = await fs.readdir(PARTIAL_DIR);
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (isENOENT(err))
|
|
244
|
+
return new Map;
|
|
245
|
+
throw err;
|
|
246
|
+
}
|
|
247
|
+
const tags = new Map;
|
|
248
|
+
for (const entry of entries) {
|
|
249
|
+
if (!entry.endsWith(".json"))
|
|
250
|
+
continue;
|
|
251
|
+
const partial = path.join(PARTIAL_DIR, entry);
|
|
252
|
+
let parsed;
|
|
253
|
+
try {
|
|
254
|
+
parsed = JSON.parse(await fs.readFile(partial, "utf-8"));
|
|
255
|
+
} catch {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
await fs.access(parsed.file);
|
|
260
|
+
} catch {
|
|
261
|
+
await fs.rm(partial, { force: true });
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
for (const [name, classes] of Object.entries(parsed.tags)) {
|
|
265
|
+
if (tags.has(name))
|
|
266
|
+
throw new DuplicateTagError(name);
|
|
267
|
+
tags.set(name, classes);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return tags;
|
|
271
|
+
}
|
|
272
|
+
function writeTypesForFile(filePath, tags) {
|
|
273
|
+
return enqueueWrite(async () => {
|
|
274
|
+
await fs.mkdir(PARTIAL_DIR, { recursive: true });
|
|
275
|
+
const partial = partialPath(filePath);
|
|
276
|
+
if (!tags.size) {
|
|
277
|
+
await fs.rm(partial, { force: true });
|
|
278
|
+
} else {
|
|
279
|
+
await writeFileAtomic(partial, JSON.stringify({ file: filePath, tags: Object.fromEntries(tags) }));
|
|
280
|
+
}
|
|
281
|
+
await writeRenderedTypes(await readPartials());
|
|
282
|
+
});
|
|
160
283
|
}
|
|
161
284
|
function tagsToType(tags) {
|
|
162
|
-
return [...tags].map(([tag, classes]) =>
|
|
163
|
-
|
|
164
|
-
|
|
285
|
+
return [...tags].map(([tag, classes]) => {
|
|
286
|
+
const union = classes.length > 0 ? classes.toSorted((a, b) => a.length - b.length).map((c) => `'${c}'`).join(" | ") : "never";
|
|
287
|
+
return ` export type ${tag} = ${union}`;
|
|
288
|
+
}).join(`
|
|
165
289
|
`);
|
|
166
290
|
}
|
|
167
291
|
function flattenTags(tagsByFile) {
|
|
@@ -180,106 +304,119 @@ function flattenTags(tagsByFile) {
|
|
|
180
304
|
import fs2 from "node:fs/promises";
|
|
181
305
|
import path2 from "node:path";
|
|
182
306
|
import { fileURLToPath } from "node:url";
|
|
183
|
-
import watcher from "@parcel/watcher";
|
|
184
307
|
var nextDir = path2.dirname(fileURLToPath(import.meta.url));
|
|
185
308
|
var loader = path2.join(nextDir, "cxx-loader.cjs");
|
|
186
|
-
var tagsByFile = new Map;
|
|
187
309
|
var watchedFiles = new Map;
|
|
188
|
-
var
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
310
|
+
var subscription = null;
|
|
311
|
+
var subscriptionPromise = null;
|
|
312
|
+
var cleanupRegistered = false;
|
|
313
|
+
var watcherLogger = null;
|
|
314
|
+
var DEFAULT_IGNORE = [
|
|
315
|
+
"**/node_modules/**",
|
|
316
|
+
"**/.next/**",
|
|
317
|
+
`**/${GENERATED_DIR}/**`,
|
|
318
|
+
"**/.git/**"
|
|
319
|
+
];
|
|
320
|
+
async function onEvent(event, filePath) {
|
|
321
|
+
const watched = watchedFiles.get(filePath);
|
|
322
|
+
if (!watched)
|
|
192
323
|
return;
|
|
193
|
-
const { pluginConfig, logger } =
|
|
194
|
-
const hadTags = tagsByFile.has(filePath);
|
|
324
|
+
const { pluginConfig, logger } = watched;
|
|
195
325
|
if (event === "delete") {
|
|
196
|
-
|
|
197
|
-
if (!hadTags)
|
|
198
|
-
return;
|
|
199
|
-
await writeTypes(flattenTags(tagsByFile));
|
|
326
|
+
await writeTypesForFile(filePath, new Map);
|
|
200
327
|
logger.info(`updated types from ${filePath}`);
|
|
201
328
|
return;
|
|
202
329
|
}
|
|
330
|
+
let source;
|
|
203
331
|
try {
|
|
204
|
-
|
|
205
|
-
const { tags } = collect(source, filePath, pluginConfig);
|
|
206
|
-
const hasTags = tags.size > 0;
|
|
207
|
-
if (hasTags) {
|
|
208
|
-
tagsByFile.set(filePath, tags);
|
|
209
|
-
} else {
|
|
210
|
-
tagsByFile.delete(filePath);
|
|
211
|
-
}
|
|
212
|
-
if (!hadTags && !hasTags)
|
|
213
|
-
return;
|
|
214
|
-
await writeTypes(flattenTags(tagsByFile));
|
|
215
|
-
logger.info(`updated types from ${filePath}`);
|
|
332
|
+
source = await fs2.readFile(filePath, "utf-8");
|
|
216
333
|
} catch (err) {
|
|
217
334
|
if (!isENOENT(err))
|
|
218
335
|
throw err;
|
|
219
|
-
|
|
220
|
-
return;
|
|
221
|
-
tagsByFile.delete(filePath);
|
|
222
|
-
await writeTypes(flattenTags(tagsByFile));
|
|
336
|
+
await writeTypesForFile(filePath, new Map);
|
|
223
337
|
logger.info(`updated types from ${filePath}`);
|
|
338
|
+
return;
|
|
224
339
|
}
|
|
340
|
+
const { tags } = collect(source, filePath, pluginConfig);
|
|
341
|
+
await writeTypesForFile(filePath, tags);
|
|
342
|
+
logger.info(`updated types from ${filePath}`);
|
|
343
|
+
}
|
|
344
|
+
function ensureWatcher(pluginConfig, logger) {
|
|
345
|
+
watcherLogger = logger;
|
|
346
|
+
if (subscriptionPromise)
|
|
347
|
+
return;
|
|
348
|
+
const root = pluginConfig.watch?.root ?? process.cwd();
|
|
349
|
+
const ignore = [...DEFAULT_IGNORE, ...pluginConfig.watch?.ignore ?? []];
|
|
350
|
+
subscriptionPromise = (async () => {
|
|
351
|
+
const { subscribe } = await import("@parcel/watcher");
|
|
352
|
+
subscription = await subscribe(root, (watchErr, events) => {
|
|
353
|
+
if (watchErr) {
|
|
354
|
+
watcherLogger?.error(`failed to watch ${root}`, watchErr);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
for (const event of events) {
|
|
358
|
+
const filePath = path2.resolve(event.path);
|
|
359
|
+
if (!watchedFiles.has(filePath))
|
|
360
|
+
continue;
|
|
361
|
+
onEvent(event.type, filePath).catch((err) => {
|
|
362
|
+
watcherLogger?.error(`failed to update types from ${filePath}`, err);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}, { ignore });
|
|
366
|
+
registerCleanup();
|
|
367
|
+
})().catch((err) => {
|
|
368
|
+
watcherLogger?.error("failed to start cxx watcher", err);
|
|
369
|
+
subscriptionPromise = null;
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
async function cleanup() {
|
|
373
|
+
const active = subscription;
|
|
374
|
+
subscription = null;
|
|
375
|
+
subscriptionPromise = null;
|
|
376
|
+
watchedFiles.clear();
|
|
377
|
+
if (active)
|
|
378
|
+
await active.unsubscribe();
|
|
379
|
+
}
|
|
380
|
+
async function shutdown(signal) {
|
|
381
|
+
try {
|
|
382
|
+
await cleanup();
|
|
383
|
+
} finally {
|
|
384
|
+
process.kill(process.pid, signal);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function registerCleanup() {
|
|
388
|
+
if (cleanupRegistered)
|
|
389
|
+
return;
|
|
390
|
+
cleanupRegistered = true;
|
|
391
|
+
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
392
|
+
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
225
393
|
}
|
|
226
394
|
function processFile(source, filePath, pluginConfig, logger) {
|
|
227
395
|
const resolvedFilePath = path2.resolve(filePath);
|
|
228
|
-
|
|
229
|
-
let subscription = subscriptionsByDir.get(directoryPath);
|
|
230
|
-
if (true) {
|
|
396
|
+
if (process.env["NODE_ENV"] !== "production") {
|
|
231
397
|
watchedFiles.set(resolvedFilePath, { pluginConfig, logger });
|
|
232
|
-
|
|
233
|
-
subscription = watcher.subscribe(directoryPath, async (err, events) => {
|
|
234
|
-
if (err) {
|
|
235
|
-
logger.error(`failed to update types from ${directoryPath}`, err);
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
for (const event of events) {
|
|
239
|
-
const eventFilePath = path2.resolve(event.path);
|
|
240
|
-
if (!watchedFiles.has(eventFilePath))
|
|
241
|
-
continue;
|
|
242
|
-
try {
|
|
243
|
-
await rebuildFile(eventFilePath, event.type);
|
|
244
|
-
} catch (watchErr) {
|
|
245
|
-
logger.error(`failed to update types from ${eventFilePath}`, watchErr);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
subscriptionsByDir.set(directoryPath, subscription);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
const result = collect(source, filePath, pluginConfig);
|
|
253
|
-
if (result.tags.size > 0) {
|
|
254
|
-
tagsByFile.set(filePath, result.tags);
|
|
255
|
-
} else {
|
|
256
|
-
tagsByFile.delete(filePath);
|
|
398
|
+
ensureWatcher(pluginConfig, logger);
|
|
257
399
|
}
|
|
258
|
-
|
|
400
|
+
const result = collect(source, resolvedFilePath, pluginConfig);
|
|
401
|
+
writeTypesForFile(resolvedFilePath, result.tags).catch((err) => {
|
|
402
|
+
logger.error(`failed to write types for ${resolvedFilePath}`, err);
|
|
403
|
+
});
|
|
259
404
|
return result;
|
|
260
405
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
await (await subPromise).unsubscribe();
|
|
265
|
-
}));
|
|
266
|
-
subscriptionsByDir.clear();
|
|
267
|
-
}
|
|
268
|
-
process.once("SIGINT", () => {
|
|
269
|
-
cleanup().finally(() => process.exit(130));
|
|
270
|
-
});
|
|
271
|
-
process.once("SIGTERM", () => {
|
|
272
|
-
cleanup().finally(() => process.exit(143));
|
|
273
|
-
});
|
|
274
|
-
async function withCxx(nextConfig = {}, pluginConfig = {}) {
|
|
275
|
-
const TURBOPACK_GLOB = "*.{tsx,jsx,ts,js}";
|
|
406
|
+
var TURBOPACK_GLOB = "*.{tsx,jsx,ts,js}";
|
|
407
|
+
function withCxx(nextConfig = {}, pluginConfig = {}) {
|
|
408
|
+
const watchRoot = pluginConfig.watch?.root ?? nextConfig.turbopack?.root ?? process.cwd();
|
|
276
409
|
const loaderItem = {
|
|
277
410
|
loader,
|
|
278
411
|
options: {
|
|
279
|
-
pluginConfig
|
|
412
|
+
pluginConfig: {
|
|
413
|
+
...pluginConfig,
|
|
414
|
+
watch: { ...pluginConfig.watch, root: watchRoot }
|
|
415
|
+
}
|
|
280
416
|
}
|
|
281
417
|
};
|
|
282
418
|
const currentRule = nextConfig.turbopack?.rules?.[TURBOPACK_GLOB];
|
|
419
|
+
const userWebpack = nextConfig.webpack;
|
|
283
420
|
return {
|
|
284
421
|
...nextConfig,
|
|
285
422
|
turbopack: {
|
|
@@ -291,12 +428,24 @@ async function withCxx(nextConfig = {}, pluginConfig = {}) {
|
|
|
291
428
|
loaders: [...currentRule.loaders ?? [], loaderItem]
|
|
292
429
|
} : { loaders: [loaderItem] }
|
|
293
430
|
}
|
|
431
|
+
},
|
|
432
|
+
webpack(config, context) {
|
|
433
|
+
const next = userWebpack ? userWebpack(config, context) : config;
|
|
434
|
+
next.module ??= {};
|
|
435
|
+
next.module.rules ??= [];
|
|
436
|
+
next.module.rules.push({
|
|
437
|
+
test: /\.[jt]sx?$/,
|
|
438
|
+
exclude: /node_modules/,
|
|
439
|
+
enforce: "pre",
|
|
440
|
+
use: [loaderItem]
|
|
441
|
+
});
|
|
442
|
+
return next;
|
|
294
443
|
}
|
|
295
444
|
};
|
|
296
445
|
}
|
|
297
446
|
export {
|
|
298
|
-
|
|
299
|
-
|
|
447
|
+
processFile,
|
|
448
|
+
withCxx
|
|
300
449
|
};
|
|
301
450
|
|
|
302
|
-
//# debugId=
|
|
451
|
+
//# debugId=A4FD970DD20B088B64756E2164756E21
|