@arcote.tech/arc-cli 0.3.0 → 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/dist/index.js +36 -60
- package/package.json +1 -1
- package/src/utils/build.ts +46 -125
- package/src/utils/config.ts +18 -31
package/dist/index.js
CHANGED
|
@@ -11202,7 +11202,7 @@ import { dirname as dirname2 } from "path";
|
|
|
11202
11202
|
|
|
11203
11203
|
// src/utils/build.ts
|
|
11204
11204
|
import { spawn } from "child_process";
|
|
11205
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
11205
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
11206
11206
|
import { dirname, join as join2 } from "path";
|
|
11207
11207
|
|
|
11208
11208
|
// src/utils/config.ts
|
|
@@ -16541,27 +16541,17 @@ function getContextsFromConfig(config, configDir) {
|
|
|
16541
16541
|
}
|
|
16542
16542
|
function generateBaseTypes(config, configDir) {
|
|
16543
16543
|
const { clients } = config;
|
|
16544
|
-
|
|
16545
|
-
if (!existsSync(arcDir)) {
|
|
16546
|
-
mkdirSync(arcDir, { recursive: true });
|
|
16547
|
-
}
|
|
16548
|
-
let typesDefs = `declare global {
|
|
16549
|
-
`;
|
|
16544
|
+
let typesDefs = "";
|
|
16550
16545
|
clients.forEach((client) => {
|
|
16551
16546
|
const normalizedClient = normalizeClientName(client);
|
|
16552
|
-
typesDefs += `
|
|
16547
|
+
typesDefs += `declare const ${normalizedClient}: boolean;
|
|
16553
16548
|
`;
|
|
16554
|
-
typesDefs += `
|
|
16549
|
+
typesDefs += `declare const NOT_ON_${normalizedClient}: boolean;
|
|
16555
16550
|
`;
|
|
16556
|
-
typesDefs += `
|
|
16551
|
+
typesDefs += `declare const ONLY_${normalizedClient}: boolean;
|
|
16557
16552
|
`;
|
|
16558
16553
|
});
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
export {};
|
|
16562
|
-
`;
|
|
16563
|
-
writeFileSync(join(arcDir, "types.ts"), typesDefs);
|
|
16564
|
-
writeFileSync(join(configDir, "arc.types.ts"), typesDefs);
|
|
16554
|
+
writeFileSync(join(configDir, "arc.d.ts"), typesDefs);
|
|
16565
16555
|
}
|
|
16566
16556
|
function generateClientTypes(config, configDir, client) {
|
|
16567
16557
|
const { clients } = config;
|
|
@@ -16570,23 +16560,18 @@ function generateClientTypes(config, configDir, client) {
|
|
|
16570
16560
|
if (!existsSync(clientTypesDir)) {
|
|
16571
16561
|
mkdirSync(clientTypesDir, { recursive: true });
|
|
16572
16562
|
}
|
|
16573
|
-
let typesDefs =
|
|
16574
|
-
`;
|
|
16563
|
+
let typesDefs = "";
|
|
16575
16564
|
clients.forEach((c) => {
|
|
16576
16565
|
const normalizedC = normalizeClientName(c);
|
|
16577
16566
|
const isCurrentClient = normalizeClientName(client) === normalizedC;
|
|
16578
|
-
typesDefs += `
|
|
16567
|
+
typesDefs += `declare const ${normalizedC}: ${isCurrentClient ? "true" : "false"};
|
|
16579
16568
|
`;
|
|
16580
|
-
typesDefs += `
|
|
16569
|
+
typesDefs += `declare const NOT_ON_${normalizedC}: ${isCurrentClient ? "false" : "true"};
|
|
16581
16570
|
`;
|
|
16582
|
-
typesDefs += `
|
|
16571
|
+
typesDefs += `declare const ONLY_${normalizedC}: ${isCurrentClient ? "true" : "false"};
|
|
16583
16572
|
`;
|
|
16584
16573
|
});
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
export {};
|
|
16588
|
-
`;
|
|
16589
|
-
const typesPath = join(clientTypesDir, `${normalizeClientName(client).toLowerCase()}.ts`);
|
|
16574
|
+
const typesPath = join(clientTypesDir, `${normalizeClientName(client).toLowerCase()}.d.ts`);
|
|
16590
16575
|
writeFileSync(typesPath, typesDefs);
|
|
16591
16576
|
return typesPath;
|
|
16592
16577
|
}
|
|
@@ -16657,7 +16642,7 @@ async function buildContextBundle(configPath, config, context, client, watch = f
|
|
|
16657
16642
|
const externals = getExternals(config, configDir, client);
|
|
16658
16643
|
const externalArgs = externals.map((dep) => `--external=${dep}`).join(" ");
|
|
16659
16644
|
const buildTarget = client === "browser" ? "browser" : "bun";
|
|
16660
|
-
const outDirPath = join2(configDir, config.outDir,
|
|
16645
|
+
const outDirPath = join2(configDir, config.outDir, client.toLowerCase(), context.name);
|
|
16661
16646
|
const command = `bun build ${context.fullPath} --target=${buildTarget} --outdir=${outDirPath} ${defineArgs} ${externalArgs}${watch ? " --watch" : ""}`;
|
|
16662
16647
|
return new Promise((resolve, reject) => {
|
|
16663
16648
|
const proc2 = spawn(command, { shell: true, cwd: configDir });
|
|
@@ -16670,27 +16655,29 @@ async function buildContextBundle(configPath, config, context, client, watch = f
|
|
|
16670
16655
|
errorOutput += data.toString();
|
|
16671
16656
|
});
|
|
16672
16657
|
proc2.on("close", (code) => {
|
|
16673
|
-
if (code !== 0 && !watch)
|
|
16658
|
+
if (code !== 0 && !watch)
|
|
16674
16659
|
reject(new Error(`Build failed: ${errorOutput || output}`));
|
|
16675
|
-
|
|
16660
|
+
else if (!watch)
|
|
16676
16661
|
resolve();
|
|
16677
|
-
}
|
|
16678
16662
|
});
|
|
16679
16663
|
});
|
|
16680
16664
|
}
|
|
16681
16665
|
async function buildContextDeclarations(configPath, config, context, client) {
|
|
16682
16666
|
const configDir = dirname(configPath);
|
|
16683
16667
|
generateClientTypes(config, configDir, client);
|
|
16684
|
-
const outDir = join2(configDir, config.outDir,
|
|
16685
|
-
const
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16668
|
+
const outDir = join2(configDir, config.outDir, client.toLowerCase());
|
|
16669
|
+
const arcTypesPath = join2(configDir, "arc.d.ts");
|
|
16670
|
+
const files = existsSync2(arcTypesPath) ? [context.fullPath, arcTypesPath] : [context.fullPath];
|
|
16671
|
+
let result = await runTsgo(files, outDir, configDir);
|
|
16672
|
+
if (result === null) {
|
|
16673
|
+
result = await runTsc(files, outDir, configDir);
|
|
16674
|
+
}
|
|
16675
|
+
return result;
|
|
16690
16676
|
}
|
|
16691
|
-
async function runTsgo(
|
|
16677
|
+
async function runTsgo(files, outDir, cwd) {
|
|
16678
|
+
const fileArgs = files.map((f) => `"${f}"`).join(" ");
|
|
16679
|
+
const command = `npx tsgo ${fileArgs} --declaration --emitDeclarationOnly --outDir "${outDir}" --rootDir "${cwd}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext --ignoreConfig`;
|
|
16692
16680
|
return new Promise((resolve) => {
|
|
16693
|
-
const command = `npx tsgo --declaration --emitDeclarationOnly --outDir "${outDir}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext --ignoreConfig "${entryFile}"`;
|
|
16694
16681
|
const proc2 = spawn(command, { shell: true, cwd });
|
|
16695
16682
|
let output = "";
|
|
16696
16683
|
let errorOutput = "";
|
|
@@ -16700,26 +16687,21 @@ async function runTsgo(entryFile, outDir, cwd) {
|
|
|
16700
16687
|
proc2.stderr.on("data", (data) => {
|
|
16701
16688
|
errorOutput += data.toString();
|
|
16702
16689
|
});
|
|
16703
|
-
proc2.on("error", () =>
|
|
16704
|
-
resolve(null);
|
|
16705
|
-
});
|
|
16690
|
+
proc2.on("error", () => resolve(null));
|
|
16706
16691
|
proc2.on("close", (code) => {
|
|
16707
16692
|
if (errorOutput.includes("not found") || errorOutput.includes("ENOENT") || errorOutput.includes("Cannot find")) {
|
|
16708
16693
|
resolve(null);
|
|
16709
16694
|
return;
|
|
16710
16695
|
}
|
|
16711
|
-
const
|
|
16712
|
-
|
|
16713
|
-
resolve({
|
|
16714
|
-
success: code === 0 && errors.length === 0,
|
|
16715
|
-
errors
|
|
16716
|
-
});
|
|
16696
|
+
const errors = parseTypeScriptErrors(output + errorOutput, cwd);
|
|
16697
|
+
resolve({ success: code === 0 && errors.length === 0, errors });
|
|
16717
16698
|
});
|
|
16718
16699
|
});
|
|
16719
16700
|
}
|
|
16720
|
-
async function runTsc(
|
|
16701
|
+
async function runTsc(files, outDir, cwd) {
|
|
16702
|
+
const fileArgs = files.map((f) => `"${f}"`).join(" ");
|
|
16703
|
+
const command = `npx tsc ${fileArgs} --declaration --emitDeclarationOnly --outDir "${outDir}" --rootDir "${cwd}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext`;
|
|
16721
16704
|
return new Promise((resolve) => {
|
|
16722
|
-
const command = `npx tsc --declaration --emitDeclarationOnly --outDir "${outDir}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext "${entryFile}"`;
|
|
16723
16705
|
const proc2 = spawn(command, { shell: true, cwd });
|
|
16724
16706
|
let output = "";
|
|
16725
16707
|
let errorOutput = "";
|
|
@@ -16730,27 +16712,21 @@ async function runTsc(entryFile, outDir, cwd) {
|
|
|
16730
16712
|
errorOutput += data.toString();
|
|
16731
16713
|
});
|
|
16732
16714
|
proc2.on("close", (code) => {
|
|
16733
|
-
const
|
|
16734
|
-
|
|
16735
|
-
resolve({
|
|
16736
|
-
success: code === 0 && errors.length === 0,
|
|
16737
|
-
errors
|
|
16738
|
-
});
|
|
16715
|
+
const errors = parseTypeScriptErrors(output + errorOutput, cwd);
|
|
16716
|
+
resolve({ success: code === 0 && errors.length === 0, errors });
|
|
16739
16717
|
});
|
|
16740
16718
|
});
|
|
16741
16719
|
}
|
|
16742
16720
|
function parseTypeScriptErrors(output, cwd) {
|
|
16743
16721
|
const errors = [];
|
|
16744
|
-
const
|
|
16745
|
-
`)
|
|
16746
|
-
for (const line of lines) {
|
|
16722
|
+
for (const line of output.split(`
|
|
16723
|
+
`)) {
|
|
16747
16724
|
const match2 = line.match(/^(.+?)(?:\((\d+),(\d+)\)|:(\d+):(\d+))\s*[-:]\s*error\s+TS\d+:\s*(.+)$/);
|
|
16748
16725
|
if (match2) {
|
|
16749
16726
|
const file = match2[1].replace(cwd + "/", "");
|
|
16750
16727
|
const lineNum = match2[2] || match2[4];
|
|
16751
16728
|
const col = match2[3] || match2[5];
|
|
16752
|
-
|
|
16753
|
-
errors.push(`${file}:${lineNum}:${col} - ${message}`);
|
|
16729
|
+
errors.push(`${file}:${lineNum}:${col} - ${match2[6]}`);
|
|
16754
16730
|
} else if (line.includes("error TS")) {
|
|
16755
16731
|
errors.push(line.trim());
|
|
16756
16732
|
}
|
package/package.json
CHANGED
package/src/utils/build.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
-
import { readFileSync } from "fs";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
4
|
import type { ArcConfig, ContextInfo } from "./config";
|
|
5
5
|
import { generateClientTypes } from "./config";
|
|
@@ -23,9 +23,6 @@ export interface BuildTask {
|
|
|
23
23
|
watch: boolean;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* Read package.json and extract peer dependencies
|
|
28
|
-
*/
|
|
29
26
|
function getPeerDependencies(configDir: string): string[] {
|
|
30
27
|
try {
|
|
31
28
|
const packageJsonPath = join(configDir, "package.json");
|
|
@@ -36,9 +33,6 @@ function getPeerDependencies(configDir: string): string[] {
|
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
/**
|
|
40
|
-
* Get external dependencies for a specific client
|
|
41
|
-
*/
|
|
42
36
|
function getExternals(
|
|
43
37
|
config: ArcConfig,
|
|
44
38
|
configDir: string,
|
|
@@ -46,27 +40,20 @@ function getExternals(
|
|
|
46
40
|
): string[] {
|
|
47
41
|
const peerDeps = getPeerDependencies(configDir);
|
|
48
42
|
const externals = new Set<string>(peerDeps);
|
|
49
|
-
|
|
50
43
|
if (config.externals?.common) {
|
|
51
44
|
config.externals.common.forEach((ext) => externals.add(ext));
|
|
52
45
|
}
|
|
53
|
-
|
|
54
46
|
const clientExternals =
|
|
55
47
|
config.externals?.[client as keyof typeof config.externals];
|
|
56
48
|
if (Array.isArray(clientExternals)) {
|
|
57
49
|
clientExternals.forEach((ext) => externals.add(ext));
|
|
58
50
|
}
|
|
59
|
-
|
|
60
51
|
return Array.from(externals);
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
/**
|
|
64
|
-
* Build a single context for a specific client
|
|
65
|
-
*/
|
|
66
54
|
export async function buildContext(task: BuildTask): Promise<BuildResult> {
|
|
67
55
|
const startTime = Date.now();
|
|
68
56
|
const { configPath, config, context, client, watch } = task;
|
|
69
|
-
|
|
70
57
|
const result: BuildResult = {
|
|
71
58
|
success: false,
|
|
72
59
|
context: context.name,
|
|
@@ -77,11 +64,8 @@ export async function buildContext(task: BuildTask): Promise<BuildResult> {
|
|
|
77
64
|
};
|
|
78
65
|
|
|
79
66
|
try {
|
|
80
|
-
// Build the JavaScript bundle
|
|
81
67
|
await buildContextBundle(configPath, config, context, client, watch);
|
|
82
68
|
result.jsBuilt = true;
|
|
83
|
-
|
|
84
|
-
// Build declarations
|
|
85
69
|
if (!watch) {
|
|
86
70
|
const declResult = await buildContextDeclarations(
|
|
87
71
|
configPath,
|
|
@@ -92,7 +76,6 @@ export async function buildContext(task: BuildTask): Promise<BuildResult> {
|
|
|
92
76
|
result.declarationsBuilt = declResult.success;
|
|
93
77
|
result.declarationErrors = declResult.errors;
|
|
94
78
|
}
|
|
95
|
-
|
|
96
79
|
result.success = result.jsBuilt;
|
|
97
80
|
result.duration = Date.now() - startTime;
|
|
98
81
|
return result;
|
|
@@ -103,9 +86,6 @@ export async function buildContext(task: BuildTask): Promise<BuildResult> {
|
|
|
103
86
|
}
|
|
104
87
|
}
|
|
105
88
|
|
|
106
|
-
/**
|
|
107
|
-
* Build JavaScript bundle for a context
|
|
108
|
-
*/
|
|
109
89
|
export async function buildContextBundle(
|
|
110
90
|
configPath: string,
|
|
111
91
|
config: ArcConfig,
|
|
@@ -114,54 +94,42 @@ export async function buildContextBundle(
|
|
|
114
94
|
watch: boolean = false,
|
|
115
95
|
): Promise<void> {
|
|
116
96
|
const configDir = dirname(configPath);
|
|
117
|
-
|
|
118
97
|
const defineValues: Record<string, string> = {};
|
|
119
|
-
|
|
120
98
|
for (const c of config.clients) {
|
|
121
99
|
const normalizedC = c.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
122
100
|
defineValues[normalizedC] = c === client ? "true" : "false";
|
|
123
101
|
defineValues[`NOT_ON_${normalizedC}`] = c === client ? "false" : "true";
|
|
124
102
|
defineValues[`ONLY_${normalizedC}`] = c === client ? "true" : "false";
|
|
125
103
|
}
|
|
126
|
-
|
|
127
104
|
const defineArgs = Object.entries(defineValues)
|
|
128
105
|
.map(([key, value]) => `--define="${key}=${value}"`)
|
|
129
106
|
.join(" ");
|
|
130
|
-
|
|
131
107
|
const externals = getExternals(config, configDir, client);
|
|
132
108
|
const externalArgs = externals.map((dep) => `--external=${dep}`).join(" ");
|
|
133
|
-
|
|
134
109
|
const buildTarget = client === "browser" ? "browser" : "bun";
|
|
135
|
-
|
|
110
|
+
// JS output: dist/{client}/{context}/ (matches TypeScript declaration output)
|
|
136
111
|
const outDirPath = join(
|
|
137
112
|
configDir,
|
|
138
113
|
config.outDir,
|
|
139
|
-
context.name,
|
|
140
114
|
client.toLowerCase(),
|
|
115
|
+
context.name,
|
|
141
116
|
);
|
|
142
|
-
|
|
143
117
|
const command = `bun build ${context.fullPath} --target=${buildTarget} --outdir=${outDirPath} ${defineArgs} ${externalArgs}${watch ? " --watch" : ""}`;
|
|
144
118
|
|
|
145
119
|
return new Promise((resolve, reject) => {
|
|
146
120
|
const proc = spawn(command, { shell: true, cwd: configDir });
|
|
147
|
-
|
|
148
121
|
let output = "";
|
|
149
122
|
let errorOutput = "";
|
|
150
|
-
|
|
151
|
-
proc.stdout.on("data", (data) => {
|
|
123
|
+
proc.stdout.on("data", (data: Buffer) => {
|
|
152
124
|
output += data.toString();
|
|
153
125
|
});
|
|
154
|
-
|
|
155
|
-
proc.stderr.on("data", (data) => {
|
|
126
|
+
proc.stderr.on("data", (data: Buffer) => {
|
|
156
127
|
errorOutput += data.toString();
|
|
157
128
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (code !== 0 && !watch) {
|
|
129
|
+
proc.on("close", (code: number) => {
|
|
130
|
+
if (code !== 0 && !watch)
|
|
161
131
|
reject(new Error(`Build failed: ${errorOutput || output}`));
|
|
162
|
-
|
|
163
|
-
resolve();
|
|
164
|
-
}
|
|
132
|
+
else if (!watch) resolve();
|
|
165
133
|
});
|
|
166
134
|
});
|
|
167
135
|
}
|
|
@@ -172,8 +140,8 @@ interface DeclarationResult {
|
|
|
172
140
|
}
|
|
173
141
|
|
|
174
142
|
/**
|
|
175
|
-
* Build declarations
|
|
176
|
-
*
|
|
143
|
+
* Build declarations.
|
|
144
|
+
* Output: dist/{client}/{context}/ (matches JS output and TypeScript's natural output)
|
|
177
145
|
*/
|
|
178
146
|
export async function buildContextDeclarations(
|
|
179
147
|
configPath: string,
|
|
@@ -182,61 +150,45 @@ export async function buildContextDeclarations(
|
|
|
182
150
|
client: string,
|
|
183
151
|
): Promise<DeclarationResult> {
|
|
184
152
|
const configDir = dirname(configPath);
|
|
185
|
-
|
|
186
|
-
// Generate client types
|
|
187
153
|
generateClientTypes(config, configDir, client);
|
|
188
154
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
config.outDir,
|
|
192
|
-
context.name,
|
|
193
|
-
client.toLowerCase(),
|
|
194
|
-
);
|
|
155
|
+
// Output to dist/{client}/ - TypeScript will add {context}/ based on source structure
|
|
156
|
+
const outDir = join(configDir, config.outDir, client.toLowerCase());
|
|
195
157
|
|
|
196
|
-
//
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
158
|
+
// Include arc.d.ts for global constants
|
|
159
|
+
const arcTypesPath = join(configDir, "arc.d.ts");
|
|
160
|
+
const files = existsSync(arcTypesPath)
|
|
161
|
+
? [context.fullPath, arcTypesPath]
|
|
162
|
+
: [context.fullPath];
|
|
201
163
|
|
|
202
|
-
//
|
|
203
|
-
|
|
164
|
+
// Try tsgo, fallback to tsc - use configDir as rootDir
|
|
165
|
+
let result = await runTsgo(files, outDir, configDir);
|
|
166
|
+
if (result === null) {
|
|
167
|
+
result = await runTsc(files, outDir, configDir);
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
204
170
|
}
|
|
205
171
|
|
|
206
|
-
/**
|
|
207
|
-
* Run tsgo CLI for declaration generation
|
|
208
|
-
* Returns null if tsgo is not available
|
|
209
|
-
*/
|
|
210
172
|
async function runTsgo(
|
|
211
|
-
|
|
173
|
+
files: string[],
|
|
212
174
|
outDir: string,
|
|
213
175
|
cwd: string,
|
|
214
176
|
): Promise<DeclarationResult | null> {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// --ignoreConfig to skip tsconfig.json when files are specified on command line
|
|
218
|
-
const command = `npx tsgo --declaration --emitDeclarationOnly --outDir "${outDir}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext --ignoreConfig "${entryFile}"`;
|
|
177
|
+
const fileArgs = files.map((f) => `"${f}"`).join(" ");
|
|
178
|
+
const command = `npx tsgo ${fileArgs} --declaration --emitDeclarationOnly --outDir "${outDir}" --rootDir "${cwd}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext --ignoreConfig`;
|
|
219
179
|
|
|
180
|
+
return new Promise((resolve) => {
|
|
220
181
|
const proc = spawn(command, { shell: true, cwd });
|
|
221
|
-
|
|
222
182
|
let output = "";
|
|
223
183
|
let errorOutput = "";
|
|
224
|
-
|
|
225
|
-
proc.stdout.on("data", (data) => {
|
|
184
|
+
proc.stdout.on("data", (data: Buffer) => {
|
|
226
185
|
output += data.toString();
|
|
227
186
|
});
|
|
228
|
-
|
|
229
|
-
proc.stderr.on("data", (data) => {
|
|
187
|
+
proc.stderr.on("data", (data: Buffer) => {
|
|
230
188
|
errorOutput += data.toString();
|
|
231
189
|
});
|
|
232
|
-
|
|
233
|
-
proc.on("
|
|
234
|
-
// tsgo not available
|
|
235
|
-
resolve(null);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
proc.on("close", (code) => {
|
|
239
|
-
// Check if tsgo was not found
|
|
190
|
+
proc.on("error", () => resolve(null));
|
|
191
|
+
proc.on("close", (code: number) => {
|
|
240
192
|
if (
|
|
241
193
|
errorOutput.includes("not found") ||
|
|
242
194
|
errorOutput.includes("ENOENT") ||
|
|
@@ -245,64 +197,40 @@ async function runTsgo(
|
|
|
245
197
|
resolve(null);
|
|
246
198
|
return;
|
|
247
199
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const errors = parseTypeScriptErrors(allOutput, cwd);
|
|
251
|
-
|
|
252
|
-
resolve({
|
|
253
|
-
success: code === 0 && errors.length === 0,
|
|
254
|
-
errors,
|
|
255
|
-
});
|
|
200
|
+
const errors = parseTypeScriptErrors(output + errorOutput, cwd);
|
|
201
|
+
resolve({ success: code === 0 && errors.length === 0, errors });
|
|
256
202
|
});
|
|
257
203
|
});
|
|
258
204
|
}
|
|
259
205
|
|
|
260
|
-
/**
|
|
261
|
-
* Run tsc CLI for declaration generation (fallback)
|
|
262
|
-
*/
|
|
263
206
|
async function runTsc(
|
|
264
|
-
|
|
207
|
+
files: string[],
|
|
265
208
|
outDir: string,
|
|
266
209
|
cwd: string,
|
|
267
210
|
): Promise<DeclarationResult> {
|
|
268
|
-
|
|
269
|
-
|
|
211
|
+
const fileArgs = files.map((f) => `"${f}"`).join(" ");
|
|
212
|
+
const command = `npx tsc ${fileArgs} --declaration --emitDeclarationOnly --outDir "${outDir}" --rootDir "${cwd}" --skipLibCheck --moduleResolution bundler --module esnext --target esnext`;
|
|
270
213
|
|
|
214
|
+
return new Promise((resolve) => {
|
|
271
215
|
const proc = spawn(command, { shell: true, cwd });
|
|
272
|
-
|
|
273
216
|
let output = "";
|
|
274
217
|
let errorOutput = "";
|
|
275
|
-
|
|
276
|
-
proc.stdout.on("data", (data) => {
|
|
218
|
+
proc.stdout.on("data", (data: Buffer) => {
|
|
277
219
|
output += data.toString();
|
|
278
220
|
});
|
|
279
|
-
|
|
280
|
-
proc.stderr.on("data", (data) => {
|
|
221
|
+
proc.stderr.on("data", (data: Buffer) => {
|
|
281
222
|
errorOutput += data.toString();
|
|
282
223
|
});
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const errors = parseTypeScriptErrors(allOutput, cwd);
|
|
287
|
-
|
|
288
|
-
resolve({
|
|
289
|
-
success: code === 0 && errors.length === 0,
|
|
290
|
-
errors,
|
|
291
|
-
});
|
|
224
|
+
proc.on("close", (code: number) => {
|
|
225
|
+
const errors = parseTypeScriptErrors(output + errorOutput, cwd);
|
|
226
|
+
resolve({ success: code === 0 && errors.length === 0, errors });
|
|
292
227
|
});
|
|
293
228
|
});
|
|
294
229
|
}
|
|
295
230
|
|
|
296
|
-
/**
|
|
297
|
-
* Parse TypeScript CLI error output into structured errors
|
|
298
|
-
*/
|
|
299
231
|
function parseTypeScriptErrors(output: string, cwd: string): string[] {
|
|
300
232
|
const errors: string[] = [];
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
for (const line of lines) {
|
|
304
|
-
// Match TypeScript error format: file(line,col): error TS1234: message
|
|
305
|
-
// or: file:line:col - error TS1234: message
|
|
233
|
+
for (const line of output.split("\n")) {
|
|
306
234
|
const match = line.match(
|
|
307
235
|
/^(.+?)(?:\((\d+),(\d+)\)|:(\d+):(\d+))\s*[-:]\s*error\s+TS\d+:\s*(.+)$/,
|
|
308
236
|
);
|
|
@@ -310,33 +238,28 @@ function parseTypeScriptErrors(output: string, cwd: string): string[] {
|
|
|
310
238
|
const file = match[1].replace(cwd + "/", "");
|
|
311
239
|
const lineNum = match[2] || match[4];
|
|
312
240
|
const col = match[3] || match[5];
|
|
313
|
-
|
|
314
|
-
errors.push(`${file}:${lineNum}:${col} - ${message}`);
|
|
241
|
+
errors.push(`${file}:${lineNum}:${col} - ${match[6]}`);
|
|
315
242
|
} else if (line.includes("error TS")) {
|
|
316
|
-
// Catch any other error format
|
|
317
243
|
errors.push(line.trim());
|
|
318
244
|
}
|
|
319
245
|
}
|
|
320
|
-
|
|
321
246
|
return errors;
|
|
322
247
|
}
|
|
323
248
|
|
|
324
|
-
// Legacy
|
|
249
|
+
// Legacy
|
|
325
250
|
export async function buildClient(
|
|
326
251
|
configPath: string,
|
|
327
252
|
config: ArcConfig,
|
|
328
253
|
client: string,
|
|
329
|
-
watch
|
|
254
|
+
watch = false,
|
|
330
255
|
): Promise<void> {
|
|
331
256
|
const configDir = dirname(configPath);
|
|
332
|
-
|
|
333
257
|
if (config.file) {
|
|
334
258
|
const context: ContextInfo = {
|
|
335
259
|
name: "main",
|
|
336
260
|
entryFile: config.file,
|
|
337
261
|
fullPath: join(configDir, config.file),
|
|
338
262
|
};
|
|
339
|
-
|
|
340
263
|
await buildContextBundle(configPath, config, context, client, watch);
|
|
341
264
|
}
|
|
342
265
|
}
|
|
@@ -347,14 +270,12 @@ export async function buildDeclarations(
|
|
|
347
270
|
client: string,
|
|
348
271
|
): Promise<void> {
|
|
349
272
|
const configDir = dirname(configPath);
|
|
350
|
-
|
|
351
273
|
if (config.file) {
|
|
352
274
|
const context: ContextInfo = {
|
|
353
275
|
name: "main",
|
|
354
276
|
entryFile: config.file,
|
|
355
277
|
fullPath: join(configDir, config.file),
|
|
356
278
|
};
|
|
357
|
-
|
|
358
279
|
await buildContextDeclarations(configPath, config, context, client);
|
|
359
280
|
}
|
|
360
281
|
}
|
package/src/utils/config.ts
CHANGED
|
@@ -113,40 +113,29 @@ export function getContextsFromConfig(
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Generate base types file for TypeScript intellisense
|
|
116
|
-
* This creates a file with all constants defined as boolean type
|
|
116
|
+
* This creates a .d.ts file with all constants defined as boolean type
|
|
117
117
|
*/
|
|
118
118
|
export function generateBaseTypes(config: ArcConfig, configDir: string): void {
|
|
119
119
|
const { clients } = config;
|
|
120
120
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
if (!existsSync(arcDir)) {
|
|
124
|
-
mkdirSync(arcDir, { recursive: true });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Generate types.ts file with boolean declarations for IDE support
|
|
128
|
-
let typesDefs = `declare global {\n`;
|
|
121
|
+
// Generate ambient declarations (no export {} so they're truly global)
|
|
122
|
+
let typesDefs = "";
|
|
129
123
|
|
|
130
124
|
clients.forEach((client) => {
|
|
131
125
|
const normalizedClient = normalizeClientName(client);
|
|
132
126
|
|
|
133
|
-
typesDefs += `
|
|
134
|
-
typesDefs += `
|
|
135
|
-
typesDefs += `
|
|
127
|
+
typesDefs += `declare const ${normalizedClient}: boolean;\n`;
|
|
128
|
+
typesDefs += `declare const NOT_ON_${normalizedClient}: boolean;\n`;
|
|
129
|
+
typesDefs += `declare const ONLY_${normalizedClient}: boolean;\n`;
|
|
136
130
|
});
|
|
137
131
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
writeFileSync(join(arcDir, "types.ts"), typesDefs);
|
|
141
|
-
|
|
142
|
-
// Also generate arc.types.ts in root for backward compatibility
|
|
143
|
-
// Only generate at root level - contexts should reference the root file
|
|
144
|
-
writeFileSync(join(configDir, "arc.types.ts"), typesDefs);
|
|
132
|
+
// Write as .d.ts file in the config directory for proper TypeScript pickup
|
|
133
|
+
writeFileSync(join(configDir, "arc.d.ts"), typesDefs);
|
|
145
134
|
}
|
|
146
135
|
|
|
147
136
|
/**
|
|
148
137
|
* Generate client-specific types file for a build
|
|
149
|
-
* This creates a file with concrete true/false values based on the current client
|
|
138
|
+
* This creates a .d.ts file with concrete true/false values based on the current client
|
|
150
139
|
*/
|
|
151
140
|
export function generateClientTypes(
|
|
152
141
|
config: ArcConfig,
|
|
@@ -154,33 +143,31 @@ export function generateClientTypes(
|
|
|
154
143
|
client: string,
|
|
155
144
|
): string {
|
|
156
145
|
const { clients } = config;
|
|
157
|
-
const arcDir = join(configDir, ".arc");
|
|
158
146
|
|
|
159
|
-
// Create client-
|
|
147
|
+
// Create .arc/client-types directory
|
|
148
|
+
const arcDir = join(configDir, ".arc");
|
|
160
149
|
const clientTypesDir = join(arcDir, "client-types");
|
|
161
150
|
if (!existsSync(clientTypesDir)) {
|
|
162
151
|
mkdirSync(clientTypesDir, { recursive: true });
|
|
163
152
|
}
|
|
164
153
|
|
|
165
|
-
// Generate client-specific
|
|
166
|
-
let typesDefs =
|
|
154
|
+
// Generate client-specific ambient declarations
|
|
155
|
+
let typesDefs = "";
|
|
167
156
|
|
|
168
157
|
clients.forEach((c) => {
|
|
169
158
|
const normalizedC = normalizeClientName(c);
|
|
170
159
|
const isCurrentClient = normalizeClientName(client) === normalizedC;
|
|
171
160
|
|
|
172
161
|
// Set concrete values based on the current client
|
|
173
|
-
typesDefs += `
|
|
174
|
-
typesDefs += `
|
|
175
|
-
typesDefs += `
|
|
162
|
+
typesDefs += `declare const ${normalizedC}: ${isCurrentClient ? "true" : "false"};\n`;
|
|
163
|
+
typesDefs += `declare const NOT_ON_${normalizedC}: ${isCurrentClient ? "false" : "true"};\n`;
|
|
164
|
+
typesDefs += `declare const ONLY_${normalizedC}: ${isCurrentClient ? "true" : "false"};\n`;
|
|
176
165
|
});
|
|
177
166
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// Write to a client-specific file
|
|
167
|
+
// Write as .d.ts file
|
|
181
168
|
const typesPath = join(
|
|
182
169
|
clientTypesDir,
|
|
183
|
-
`${normalizeClientName(client).toLowerCase()}.ts`,
|
|
170
|
+
`${normalizeClientName(client).toLowerCase()}.d.ts`,
|
|
184
171
|
);
|
|
185
172
|
writeFileSync(typesPath, typesDefs);
|
|
186
173
|
|