@arcote.tech/arc-cli 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/README.md +67 -0
- package/dist/fsevents-hj42pnne.node +0 -0
- package/dist/index.js +180038 -0
- package/package.json +29 -0
- package/src/commands/build.ts +68 -0
- package/src/commands/dev.ts +112 -0
- package/src/index.ts +30 -0
- package/src/utils/build.ts +146 -0
- package/src/utils/config.ts +141 -0
- package/tsconfig.json +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arcote.tech/arc-cli",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "CLI tool for Arc framework",
|
|
5
|
+
"module": "index.ts",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"arc": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "bun build --target=node ./src/index.ts --outdir=dist && chmod +x dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"commander": "^11.1.0",
|
|
16
|
+
"chokidar": "^3.5.3",
|
|
17
|
+
"glob": "^10.3.10",
|
|
18
|
+
"find-up": "^7.0.0",
|
|
19
|
+
"typescript": "^5.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/bun": "latest",
|
|
23
|
+
"@types/node": "^20.10.5",
|
|
24
|
+
"typescript": "^5.2.2"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"typescript": "^5.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { findUpSync } from "find-up";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import { buildClient, buildDeclarations } from "../utils/build";
|
|
4
|
+
import {
|
|
5
|
+
findArcConfigs,
|
|
6
|
+
generateBaseTypes,
|
|
7
|
+
loadArcConfig,
|
|
8
|
+
} from "../utils/config";
|
|
9
|
+
|
|
10
|
+
export async function build(): Promise<void> {
|
|
11
|
+
try {
|
|
12
|
+
// Find the package.json from the current directory
|
|
13
|
+
const packageJsonPath = findUpSync("package.json", { cwd: process.cwd() });
|
|
14
|
+
|
|
15
|
+
if (!packageJsonPath) {
|
|
16
|
+
console.error("No package.json found");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const packageDir = dirname(packageJsonPath);
|
|
21
|
+
console.log(`Found package.json at: ${packageJsonPath}`);
|
|
22
|
+
|
|
23
|
+
// Find all arc.config.json files
|
|
24
|
+
const configPaths = await findArcConfigs(packageDir);
|
|
25
|
+
console.log(`Found ${configPaths.length} arc.config.json files`);
|
|
26
|
+
|
|
27
|
+
if (configPaths.length === 0) {
|
|
28
|
+
console.error("No arc.config.json files found");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Process each config
|
|
33
|
+
for (const configPath of configPaths) {
|
|
34
|
+
console.log(`Processing config: ${configPath}`);
|
|
35
|
+
|
|
36
|
+
// Load the config
|
|
37
|
+
const config = await loadArcConfig(configPath);
|
|
38
|
+
const configDir = dirname(configPath);
|
|
39
|
+
|
|
40
|
+
// Generate base types file for IDE support
|
|
41
|
+
generateBaseTypes(config, configDir);
|
|
42
|
+
console.log(`Generated base types for IDE support`);
|
|
43
|
+
|
|
44
|
+
// Build each client
|
|
45
|
+
for (const client of config.clients) {
|
|
46
|
+
try {
|
|
47
|
+
// Build the client (without watch mode)
|
|
48
|
+
await buildClient(configPath, config, client, false);
|
|
49
|
+
console.log(`Built ${client} client successfully`);
|
|
50
|
+
|
|
51
|
+
// Build declarations
|
|
52
|
+
await buildDeclarations(configPath, config, client);
|
|
53
|
+
console.log(`Built declarations for ${client} successfully`);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error(
|
|
56
|
+
`Error building ${client}: ${err instanceof Error ? err.message : String(err)}`,
|
|
57
|
+
);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log("Build completed successfully.");
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error("Error in build command:", err);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import chokidar from "chokidar";
|
|
2
|
+
import { findUpSync } from "find-up";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { buildClient, buildDeclarations } from "../utils/build";
|
|
5
|
+
import {
|
|
6
|
+
findArcConfigs,
|
|
7
|
+
generateBaseTypes,
|
|
8
|
+
loadArcConfig,
|
|
9
|
+
} from "../utils/config";
|
|
10
|
+
|
|
11
|
+
export async function dev(): Promise<void> {
|
|
12
|
+
try {
|
|
13
|
+
// Find the package.json from the current directory
|
|
14
|
+
const packageJsonPath = findUpSync("package.json", { cwd: process.cwd() });
|
|
15
|
+
|
|
16
|
+
if (!packageJsonPath) {
|
|
17
|
+
console.error("No package.json found");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const packageDir = dirname(packageJsonPath);
|
|
22
|
+
console.log(`Found package.json at: ${packageJsonPath}`);
|
|
23
|
+
|
|
24
|
+
// Find all arc.config.json files
|
|
25
|
+
const configPaths = await findArcConfigs(packageDir);
|
|
26
|
+
console.log(`Found ${configPaths.length} arc.config.json files`);
|
|
27
|
+
|
|
28
|
+
if (configPaths.length === 0) {
|
|
29
|
+
console.error("No arc.config.json files found");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Process each config
|
|
34
|
+
for (const configPath of configPaths) {
|
|
35
|
+
console.log(`Processing config: ${configPath}`);
|
|
36
|
+
|
|
37
|
+
// Load the config
|
|
38
|
+
const config = await loadArcConfig(configPath);
|
|
39
|
+
const configDir = dirname(configPath);
|
|
40
|
+
|
|
41
|
+
// Generate base types file for IDE support
|
|
42
|
+
generateBaseTypes(config, configDir);
|
|
43
|
+
|
|
44
|
+
console.log(`Generated base types for IDE support`);
|
|
45
|
+
|
|
46
|
+
// Set up source file watchers
|
|
47
|
+
const sourceWatcher = chokidar.watch(
|
|
48
|
+
[
|
|
49
|
+
join(configDir, "**/*.ts"),
|
|
50
|
+
join(configDir, "**/*.tsx"),
|
|
51
|
+
join(configDir, "**/*.js"),
|
|
52
|
+
join(configDir, "**/*.jsx"),
|
|
53
|
+
],
|
|
54
|
+
{
|
|
55
|
+
ignored: [
|
|
56
|
+
"**/node_modules/**",
|
|
57
|
+
`**/${config.outDir}/**`, // Exclude the output directory
|
|
58
|
+
"**/.arc/client-types/**", // Exclude generated client types
|
|
59
|
+
"**/dist/**", // Exclude any dist directories
|
|
60
|
+
"**/*.d.ts", // Exclude declaration files
|
|
61
|
+
],
|
|
62
|
+
persistent: true,
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Start watchers for each client
|
|
67
|
+
for (const client of config.clients) {
|
|
68
|
+
try {
|
|
69
|
+
// Start the client build in watch mode
|
|
70
|
+
buildClient(configPath, config, client, true).catch((err) =>
|
|
71
|
+
console.error(
|
|
72
|
+
`Error building ${client}: ${err instanceof Error ? err.message : String(err)}`,
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
await buildDeclarations(configPath, config, client);
|
|
76
|
+
|
|
77
|
+
// Set up a handler for source file changes
|
|
78
|
+
sourceWatcher.on("change", async (path) => {
|
|
79
|
+
console.log(`Source file changed: ${path}`);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Build declarations when source files change
|
|
83
|
+
console.log(`Rebuilding declarations for ${client}...`);
|
|
84
|
+
await buildDeclarations(configPath, config, client);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error(
|
|
87
|
+
`Error building declarations for ${client}: ${err instanceof Error ? err.message : String(err)}`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error(
|
|
93
|
+
`Error setting up build for ${client}: ${err instanceof Error ? err.message : String(err)}`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(`Watching for changes in ${configDir}...`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log("Development mode started. Press Ctrl+C to stop.");
|
|
102
|
+
|
|
103
|
+
// Keep the process running
|
|
104
|
+
process.on("SIGINT", () => {
|
|
105
|
+
console.log("Shutting down dev mode...");
|
|
106
|
+
process.exit(0);
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error("Error in dev command:", err);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { build } from "./commands/build";
|
|
5
|
+
import { dev } from "./commands/dev";
|
|
6
|
+
|
|
7
|
+
// Create the program
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
// Setup program information
|
|
11
|
+
program.name("arc").description("CLI tool for Arc framework").version("0.0.1");
|
|
12
|
+
|
|
13
|
+
// Register commands
|
|
14
|
+
program
|
|
15
|
+
.command("dev")
|
|
16
|
+
.description("Run development mode for Arc framework")
|
|
17
|
+
.action(dev);
|
|
18
|
+
|
|
19
|
+
program
|
|
20
|
+
.command("build")
|
|
21
|
+
.description("Build all clients and declarations")
|
|
22
|
+
.action(build);
|
|
23
|
+
|
|
24
|
+
// Parse command line arguments
|
|
25
|
+
program.parse(process.argv);
|
|
26
|
+
|
|
27
|
+
// If no arguments, show help
|
|
28
|
+
if (process.argv.length === 2) {
|
|
29
|
+
program.help();
|
|
30
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
|
+
import * as ts from "typescript";
|
|
4
|
+
import type { ArcConfig } from "./config";
|
|
5
|
+
import { generateClientTypes } from "./config";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build a package using Bun for a specific client
|
|
9
|
+
*/
|
|
10
|
+
export async function buildClient(
|
|
11
|
+
configPath: string,
|
|
12
|
+
config: ArcConfig,
|
|
13
|
+
client: string,
|
|
14
|
+
watch: boolean = false,
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
const configDir = dirname(configPath);
|
|
17
|
+
const { file, outDir } = config;
|
|
18
|
+
const normalizedClient = client.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
19
|
+
|
|
20
|
+
// Prepare the define values for this client
|
|
21
|
+
const defineValues: Record<string, string> = {};
|
|
22
|
+
|
|
23
|
+
// Set the current client to true and all others to false
|
|
24
|
+
for (const c of config.clients) {
|
|
25
|
+
const normalizedC = c.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
26
|
+
|
|
27
|
+
// Set client flags
|
|
28
|
+
defineValues[normalizedC] = c === client ? "true" : "false";
|
|
29
|
+
defineValues[`NOT_ON_${normalizedC}`] = c === client ? "false" : "true";
|
|
30
|
+
defineValues[`ONLY_${normalizedC}`] = c === client ? "true" : "false";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create the define argument string
|
|
34
|
+
const defineArgs = Object.entries(defineValues)
|
|
35
|
+
.map(([key, value]) => `--define="${key}=${value}"`)
|
|
36
|
+
.join(" ");
|
|
37
|
+
|
|
38
|
+
// Construct the bun build command
|
|
39
|
+
const filePath = join(configDir, file);
|
|
40
|
+
const outFilePath = join(configDir, outDir, client.toLowerCase(), "index.js");
|
|
41
|
+
|
|
42
|
+
const command = `bun build ${filePath} --outfile=${outFilePath} ${defineArgs}${watch ? " --watch" : ""}`;
|
|
43
|
+
|
|
44
|
+
console.log(`Building ${client} client...`);
|
|
45
|
+
console.log(command);
|
|
46
|
+
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const process = spawn(command, { shell: true, cwd: configDir });
|
|
49
|
+
|
|
50
|
+
process.stdout.on("data", (data) => {
|
|
51
|
+
console.log(`[${client}] ${data.toString().trim()}`);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
process.stderr.on("data", (data) => {
|
|
55
|
+
console.error(`[${client} ERROR] ${data.toString().trim()}`);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
process.on("close", (code) => {
|
|
59
|
+
if (code !== 0 && !watch) {
|
|
60
|
+
reject(new Error(`Build for ${client} failed with code ${code}`));
|
|
61
|
+
} else if (!watch) {
|
|
62
|
+
resolve();
|
|
63
|
+
}
|
|
64
|
+
// Don't resolve for watch mode, it keeps running
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build declarations using TypeScript Compiler API
|
|
71
|
+
*/
|
|
72
|
+
export async function buildDeclarations(
|
|
73
|
+
configPath: string,
|
|
74
|
+
config: ArcConfig,
|
|
75
|
+
client: string,
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
const configDir = dirname(configPath);
|
|
78
|
+
const { file } = config;
|
|
79
|
+
const filePath = join(configDir, file);
|
|
80
|
+
|
|
81
|
+
// Generate the client-specific types file and get its path
|
|
82
|
+
const clientTypesPath = generateClientTypes(config, configDir, client);
|
|
83
|
+
|
|
84
|
+
console.log(`Building ${client} declarations...`);
|
|
85
|
+
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
try {
|
|
88
|
+
// TypeScript compiler options for declaration files
|
|
89
|
+
const compilerOptions: ts.CompilerOptions = {
|
|
90
|
+
declaration: true,
|
|
91
|
+
emitDeclarationOnly: true,
|
|
92
|
+
outDir: join(configDir, config.outDir, client.toLowerCase()),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Create the program with the client-specific types
|
|
96
|
+
const program = ts.createProgram(
|
|
97
|
+
[filePath, clientTypesPath],
|
|
98
|
+
compilerOptions,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Emit the declarations
|
|
102
|
+
const emitResult = program.emit();
|
|
103
|
+
|
|
104
|
+
// Report any errors
|
|
105
|
+
const diagnostics = ts
|
|
106
|
+
.getPreEmitDiagnostics(program)
|
|
107
|
+
.concat(emitResult.diagnostics);
|
|
108
|
+
|
|
109
|
+
if (diagnostics.length > 0) {
|
|
110
|
+
let errorMessage = "";
|
|
111
|
+
diagnostics.forEach((diagnostic) => {
|
|
112
|
+
if (diagnostic.file) {
|
|
113
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
114
|
+
diagnostic.file,
|
|
115
|
+
diagnostic.start!,
|
|
116
|
+
);
|
|
117
|
+
const message = ts.flattenDiagnosticMessageText(
|
|
118
|
+
diagnostic.messageText,
|
|
119
|
+
"\n",
|
|
120
|
+
);
|
|
121
|
+
errorMessage += `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}\n`;
|
|
122
|
+
} else {
|
|
123
|
+
errorMessage += `${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}\n`;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (emitResult.emitSkipped) {
|
|
128
|
+
reject(
|
|
129
|
+
new Error(
|
|
130
|
+
`Declaration build for ${client} failed:\n${errorMessage}`,
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
} else {
|
|
134
|
+
// console.warn(
|
|
135
|
+
// `Declaration build for ${client} had warnings:\n${errorMessage}`,
|
|
136
|
+
// );
|
|
137
|
+
resolve();
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
resolve();
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
export interface ArcConfig {
|
|
6
|
+
file: string;
|
|
7
|
+
outDir: string;
|
|
8
|
+
clients: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Find arc.config.json files in the workspace
|
|
13
|
+
*/
|
|
14
|
+
export async function findArcConfigs(packagePath: string): Promise<string[]> {
|
|
15
|
+
// Check if we're in a monorepo
|
|
16
|
+
const packageJson = JSON.parse(
|
|
17
|
+
readFileSync(join(packagePath, "package.json"), "utf-8"),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// If workspaces field exists, we're in a monorepo
|
|
21
|
+
if (packageJson.workspaces) {
|
|
22
|
+
const workspacePatterns = Array.isArray(packageJson.workspaces)
|
|
23
|
+
? packageJson.workspaces
|
|
24
|
+
: packageJson.workspaces.packages || [];
|
|
25
|
+
|
|
26
|
+
// Get all directory paths from workspace patterns
|
|
27
|
+
const workspaceDirs = await glob(workspacePatterns, {
|
|
28
|
+
cwd: packagePath,
|
|
29
|
+
absolute: true,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Find all arc.config.json files in workspace directories
|
|
33
|
+
const configFiles: string[] = [];
|
|
34
|
+
|
|
35
|
+
for (const dir of workspaceDirs) {
|
|
36
|
+
const configsInDir = await glob("**/arc.config.json", {
|
|
37
|
+
cwd: dir,
|
|
38
|
+
absolute: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
configFiles.push(...configsInDir);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return configFiles;
|
|
45
|
+
} else {
|
|
46
|
+
// Not a monorepo, just find arc.config.json files in the package
|
|
47
|
+
return await glob("**/arc.config.json", {
|
|
48
|
+
cwd: packagePath,
|
|
49
|
+
absolute: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load and parse an arc.config.json file
|
|
56
|
+
*/
|
|
57
|
+
export async function loadArcConfig(configPath: string): Promise<ArcConfig> {
|
|
58
|
+
// Read and parse the JSON config file
|
|
59
|
+
const configContent = readFileSync(configPath, "utf-8");
|
|
60
|
+
const config: ArcConfig = JSON.parse(configContent);
|
|
61
|
+
return config;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Generate base types file for TypeScript intellisense
|
|
66
|
+
* This creates a file with all constants defined as boolean type
|
|
67
|
+
*/
|
|
68
|
+
export function generateBaseTypes(config: ArcConfig, configDir: string): void {
|
|
69
|
+
const { clients } = config;
|
|
70
|
+
|
|
71
|
+
// Create .arc directory if it doesn't exist
|
|
72
|
+
const arcDir = join(configDir, ".arc");
|
|
73
|
+
if (!existsSync(arcDir)) {
|
|
74
|
+
mkdirSync(arcDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Generate types.ts file with boolean declarations for IDE support
|
|
78
|
+
let typesDefs = `declare global {\n`;
|
|
79
|
+
|
|
80
|
+
clients.forEach((client) => {
|
|
81
|
+
const normalizedClient = normalizeClientName(client);
|
|
82
|
+
|
|
83
|
+
typesDefs += ` const ${normalizedClient}: boolean;\n`;
|
|
84
|
+
typesDefs += ` const NOT_ON_${normalizedClient}: boolean;\n`;
|
|
85
|
+
typesDefs += ` const ONLY_${normalizedClient}: boolean;\n`;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
typesDefs += `}\n\nexport {};\n`;
|
|
89
|
+
|
|
90
|
+
writeFileSync(join(arcDir, "types.ts"), typesDefs);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Generate client-specific types file for a build
|
|
95
|
+
* This creates a file with concrete true/false values based on the current client
|
|
96
|
+
*/
|
|
97
|
+
export function generateClientTypes(
|
|
98
|
+
config: ArcConfig,
|
|
99
|
+
configDir: string,
|
|
100
|
+
client: string,
|
|
101
|
+
): string {
|
|
102
|
+
const { clients } = config;
|
|
103
|
+
const arcDir = join(configDir, ".arc");
|
|
104
|
+
|
|
105
|
+
// Create client-specific types directory
|
|
106
|
+
const clientTypesDir = join(arcDir, "client-types");
|
|
107
|
+
if (!existsSync(clientTypesDir)) {
|
|
108
|
+
mkdirSync(clientTypesDir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Generate client-specific types file
|
|
112
|
+
let typesDefs = `declare global {\n`;
|
|
113
|
+
|
|
114
|
+
clients.forEach((c) => {
|
|
115
|
+
const normalizedC = normalizeClientName(c);
|
|
116
|
+
const isCurrentClient = normalizeClientName(client) === normalizedC;
|
|
117
|
+
|
|
118
|
+
// Set concrete values based on the current client
|
|
119
|
+
typesDefs += ` const ${normalizedC}: ${isCurrentClient ? "true" : "false"};\n`;
|
|
120
|
+
typesDefs += ` const NOT_ON_${normalizedC}: ${isCurrentClient ? "false" : "true"};\n`;
|
|
121
|
+
typesDefs += ` const ONLY_${normalizedC}: ${isCurrentClient ? "true" : "false"};\n`;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
typesDefs += `}\n\nexport {};\n`;
|
|
125
|
+
|
|
126
|
+
// Write to a client-specific file
|
|
127
|
+
const typesPath = join(
|
|
128
|
+
clientTypesDir,
|
|
129
|
+
`${normalizeClientName(client).toLowerCase()}.ts`,
|
|
130
|
+
);
|
|
131
|
+
writeFileSync(typesPath, typesDefs);
|
|
132
|
+
|
|
133
|
+
return typesPath;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Normalize client name to a valid identifier
|
|
138
|
+
*/
|
|
139
|
+
export function normalizeClientName(client: string): string {
|
|
140
|
+
return client.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
141
|
+
}
|