tangled
alpha
login
or
join now
danabra.mov
/
typelex
56
fork
atom
An experimental TypeSpec syntax for Lexicon
56
fork
atom
overview
issues
1
pulls
2
pipelines
nits
danabra.mov
5 months ago
d6fda094
b90f9277
+51
-36
2 changed files
expand all
collapse all
unified
split
packages
cli
src
cli.ts
commands
init.ts
+17
-1
packages/cli/src/cli.ts
···
19
19
});
20
20
},
21
21
async (argv) => {
22
22
-
await initCommand(argv.setup);
22
22
+
// Extract any unknown flags to pass through to package manager
23
23
+
const flags: string[] = [];
24
24
+
const knownFlags = new Set(["setup", "_", "$0"]);
25
25
+
26
26
+
for (const [key, value] of Object.entries(argv)) {
27
27
+
if (!knownFlags.has(key)) {
28
28
+
// Single letter = short flag, multiple letters = long flag
29
29
+
const prefix = key.length === 1 ? "-" : "--";
30
30
+
if (typeof value === "boolean" && value) {
31
31
+
flags.push(`${prefix}${key}`);
32
32
+
} else if (value !== false && value !== undefined) {
33
33
+
flags.push(`${prefix}${key}`, String(value));
34
34
+
}
35
35
+
}
36
36
+
}
37
37
+
38
38
+
await initCommand(argv.setup, flags);
23
39
}
24
40
)
25
41
.command(
+34
-35
packages/cli/src/commands/init.ts
···
4
4
import { createInterface } from "readline";
5
5
import pc from "picocolors";
6
6
7
7
-
// Gradient colors matching website (approximated with ANSI 256 colors)
8
8
-
// Darker variant for better readability on white terminals
9
7
function gradientText(text: string): string {
10
10
-
// Approximating: #4a9eff -> #7a8ef7 -> #ff85c1 -> #9b7ef7
11
11
-
// Using darker ANSI 256 color codes for a blue->purple->pink gradient
12
8
const colors = [
13
13
-
'\x1b[38;5;33m', // darker blue
14
14
-
'\x1b[38;5;69m', // blue-purple
15
15
-
'\x1b[38;5;99m', // purple
16
16
-
'\x1b[38;5;133m', // purple-pink
17
17
-
'\x1b[38;5;170m', // pink
18
18
-
'\x1b[38;5;170m', // pink
19
19
-
'\x1b[38;5;133m', // purple-pink
9
9
+
'\x1b[38;5;33m',
10
10
+
'\x1b[38;5;69m',
11
11
+
'\x1b[38;5;99m',
12
12
+
'\x1b[38;5;133m',
13
13
+
'\x1b[38;5;170m',
14
14
+
'\x1b[38;5;170m',
15
15
+
'\x1b[38;5;133m',
20
16
];
21
17
const reset = '\x1b[0m';
22
18
···
60
56
});
61
57
}
62
58
63
63
-
/**
64
64
-
* Initialize command - installs packages and hands off to local version
65
65
-
* This is what gets called by npx
66
66
-
*/
67
67
-
export async function initCommand(isSetup: boolean = false): Promise<void> {
68
68
-
const cwd = process.cwd();
59
59
+
export async function initCommand(isSetup: boolean = false, flags: string[] = []): Promise<void> {
60
60
+
const originalCwd = process.cwd();
61
61
+
62
62
+
// Find nearest package.json upward
63
63
+
let projectRoot = originalCwd;
64
64
+
let dir = originalCwd;
65
65
+
while (dir !== resolve(dir, "..")) {
66
66
+
try {
67
67
+
await access(resolve(dir, "package.json"));
68
68
+
projectRoot = dir;
69
69
+
break;
70
70
+
} catch {
71
71
+
dir = resolve(dir, "..");
72
72
+
}
73
73
+
}
69
74
70
70
-
// If this is the second pass (after handoff), run setup
71
75
if (isSetup) {
72
76
return initSetup();
73
77
}
74
78
75
79
console.log(`Adding ${gradientText("typelex")}...\n`);
76
80
77
77
-
// Detect package manager: walk up from cwd
81
81
+
// Detect package manager
78
82
let packageManager = "npm";
79
79
-
let dir = cwd;
83
83
+
dir = projectRoot;
80
84
while (dir !== resolve(dir, "..") && packageManager === "npm") {
81
85
try {
82
86
await access(resolve(dir, "pnpm-lock.yaml"));
···
95
99
dir = resolve(dir, "..");
96
100
}
97
101
98
98
-
// Install dependencies (always use latest)
102
102
+
// Install dependencies
99
103
await new Promise<void>((resolvePromise, reject) => {
100
104
const args = packageManager === "npm"
101
105
? ["install", "--save-dev", "@typelex/cli@latest", "@typelex/emitter@latest"]
102
106
: ["add", "-D", "@typelex/cli@latest", "@typelex/emitter@latest"];
103
107
108
108
+
// Add any additional flags
109
109
+
args.push(...flags);
110
110
+
104
111
const install = spawn(packageManager, args, {
105
105
-
cwd,
112
112
+
cwd: projectRoot,
106
113
stdio: "inherit",
107
114
});
108
115
···
122
129
});
123
130
});
124
131
125
125
-
// Hand off to locally installed version
126
126
-
// Find where node_modules actually is (could be at workspace root with pnpm)
127
127
-
let nodeModulesDir = resolve(cwd, "node_modules");
128
128
-
let searchDir = cwd;
129
129
-
130
130
-
// Search upward for node_modules with typelex installed
132
132
+
// Find node_modules
133
133
+
let nodeModulesDir = resolve(projectRoot, "node_modules");
134
134
+
let searchDir = projectRoot;
131
135
while (searchDir !== resolve(searchDir, "..")) {
132
136
try {
133
137
const candidatePath = resolve(searchDir, "node_modules/.bin/typelex");
···
135
139
nodeModulesDir = resolve(searchDir, "node_modules");
136
140
break;
137
141
} catch {
138
138
-
// Not found, try parent
142
142
+
searchDir = resolve(searchDir, "..");
139
143
}
140
140
-
searchDir = resolve(searchDir, "..");
141
144
}
142
145
143
146
return new Promise((resolvePromise, reject) => {
144
147
const localCli = resolve(nodeModulesDir, ".bin/typelex");
145
148
const setup = spawn(localCli, ["init", "--setup"], {
146
146
-
cwd,
149
149
+
cwd: projectRoot,
147
150
stdio: "inherit",
148
151
});
149
152
···
162
165
});
163
166
}
164
167
165
165
-
/**
166
166
-
* Setup function - called after packages are installed
167
167
-
* This runs from the locally installed version
168
168
-
*/
169
168
export async function initSetup(): Promise<void> {
170
169
const cwd = process.cwd();
171
170
const typelexDir = resolve(cwd, "typelex");