Skip to content

Commit d3a3bef

Browse files
Linting fixes
1 parent 4fb8a7e commit d3a3bef

9 files changed

Lines changed: 106 additions & 161 deletions

File tree

.vscodeignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ test-fixtures/**
66
out/test/**
77
node_modules/**
88
!node_modules/node-sqlite3-wasm/**
9-
scripts/**
9+
tools/**
1010
.too_many_cooks/**
1111
.claude/**
1212
.github/**

CONTRIBUTING.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Contributing to CommandTree
2+
3+
## Prerequisites
4+
5+
- Node.js (LTS)
6+
- VS Code
7+
8+
## Setup
9+
10+
```bash
11+
npm install
12+
```
13+
14+
## CI Gate
15+
16+
Before submitting a pull request, you **must** run:
17+
18+
```bash
19+
make ci
20+
```
21+
22+
This runs formatting, linting, building, testing (with coverage check), and packaging. All steps must pass. Pull requests that fail `make ci` will not be merged.
23+
24+
## Make Targets
25+
26+
| Target | Description |
27+
|--------|-------------|
28+
| `make format` | Format source with Prettier |
29+
| `make lint` | Lint with ESLint |
30+
| `make build` | Compile TypeScript |
31+
| `make test` | Run unit tests, e2e tests with coverage, and coverage threshold check |
32+
| `make package` | Build VSIX package |
33+
| `make ci` | Run all of the above in sequence |
34+
35+
## Coverage
36+
37+
Tests enforce a 90% coverage threshold on lines, functions, branches, and statements. The coverage check runs automatically as part of `make test`.

Claude.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# CLAUDE.md - CommandTree Extension
22

3+
⚠️ CRITICAL: **Reduce token usage.** Check file size before loading. Write less. Delete fluff and dead code. Alert user when context is loaded with pointless files. ⚠️
4+
35
## Too Many Cooks
46

57
You are working with many other agents. Make sure there is effective cooperation

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ package: build
1515
test: build
1616
npm run test:unit
1717
npx vscode-test --coverage
18+
node tools/check-coverage.mjs
1819

1920
test-exclude-ci: build
2021
npm run test:unit
2122
npx vscode-test --coverage --grep @exclude-ci --invert
23+
node tools/check-coverage.mjs
2224

2325
ci: format lint build test package

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ Open a workspace and the CommandTree panel appears in the sidebar. All discovere
8383
| `commandtree.excludePatterns` | Glob patterns to exclude from discovery | `**/node_modules/**`, `**/.git/**`, etc. |
8484
| `commandtree.sortOrder` | Sort commands by `folder`, `name`, or `type` | `folder` |
8585

86+
## Contributing
87+
88+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines. All pull requests must pass `make ci` before merging.
89+
8690
## License
8791

8892
[MIT](LICENSE)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@
382382
"test:unit": "mocha out/test/unit/**/*.test.js",
383383
"test:e2e": "vscode-test",
384384
"test:coverage": "vscode-test --coverage",
385-
"coverage:check": "node scripts/check-coverage.mjs",
385+
"coverage:check": "node tools/check-coverage.mjs",
386386
"clean": "rm -rf node_modules out *.vsix coverage || true",
387387
"package": "npm run compile && vsce package",
388388
"uninstall": "code --uninstall-extension nimblesite.commandtree || true",

scripts/convert-icon.py

Lines changed: 0 additions & 105 deletions
This file was deleted.

src/discovery/parsers/miseParser.ts

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,111 +6,116 @@ export interface MiseTask {
66
params: ParamDef[];
77
}
88

9+
function parseTomlTaskHeader(trimmed: string): string | undefined {
10+
const match = /^\[tasks\.([^\]]+)\]$/.exec(trimmed);
11+
return match?.[1];
12+
}
13+
14+
function parseTomlDescription(trimmed: string): string | undefined {
15+
const match = /^description\s*=\s*"([^"]*)"/.exec(trimmed);
16+
return match?.[1];
17+
}
18+
19+
function finishTask(tasks: MiseTask[], current: MiseTask | null): void {
20+
if (current !== null) {
21+
tasks.push(current);
22+
}
23+
}
24+
925
/**
1026
* Parses TOML format mise configuration.
1127
*/
1228
export function parseMiseToml(content: string): MiseTask[] {
1329
const tasks: MiseTask[] = [];
14-
1530
const lines = content.split("\n");
1631
let currentTask: MiseTask | null = null;
1732

1833
for (const line of lines) {
1934
const trimmed = line.trim();
2035

21-
// [tasks.name] sections are self-identifying — no [tasks] preamble needed
2236
if (trimmed.startsWith("[tasks.")) {
23-
if (currentTask !== null) {
24-
tasks.push(currentTask);
25-
currentTask = null;
26-
}
27-
28-
const match = /^\[tasks\.([^\]]+)\]$/.exec(trimmed);
29-
if (match !== null && match[1] !== undefined) {
30-
currentTask = {
31-
name: match[1],
32-
params: [],
33-
};
34-
}
37+
finishTask(tasks, currentTask);
38+
const name = parseTomlTaskHeader(trimmed);
39+
currentTask = name !== undefined ? { name, params: [] } : null;
3540
continue;
3641
}
3742

38-
// Any other section header ends the current task
3943
if (trimmed.startsWith("[")) {
40-
if (currentTask !== null) {
41-
tasks.push(currentTask);
42-
currentTask = null;
43-
}
44+
finishTask(tasks, currentTask);
45+
currentTask = null;
4446
continue;
4547
}
4648

47-
// Extract description from current task
4849
if (currentTask !== null && trimmed.startsWith("description")) {
49-
const descMatch = /^description\s*=\s*"([^"]*)"/.exec(trimmed);
50-
if (descMatch !== null && descMatch[1] !== undefined) {
51-
currentTask.description = descMatch[1];
50+
const desc = parseTomlDescription(trimmed);
51+
if (desc !== undefined) {
52+
currentTask.description = desc;
5253
}
5354
}
5455
}
5556

56-
if (currentTask !== null) {
57-
tasks.push(currentTask);
57+
finishTask(tasks, currentTask);
58+
return tasks;
59+
}
60+
61+
function parseYamlTaskName(line: string): string | undefined {
62+
const match = /^\s+([^:]+):\s*$/.exec(line);
63+
return match?.[1]?.trim();
64+
}
65+
66+
function parseYamlDescription(line: string): string | undefined {
67+
const match = /^\s+description:\s*["]?([^"]*)["]?\s*$/.exec(line);
68+
return match?.[1];
69+
}
70+
71+
function isSkippableLine(trimmed: string): boolean {
72+
return trimmed === "" || trimmed.startsWith("#");
73+
}
74+
75+
function processYamlTaskLine(tasks: MiseTask[], line: string, indent: number): void {
76+
if (indent === 2 && !line.trim().startsWith("-") && line.includes(":")) {
77+
const name = parseYamlTaskName(line);
78+
if (name !== undefined) {
79+
tasks.push({ name, params: [] });
80+
}
81+
return;
5882
}
5983

60-
return tasks;
84+
if (indent > 2 && line.includes("description:")) {
85+
const desc = parseYamlDescription(line);
86+
const lastTask = tasks[tasks.length - 1];
87+
if (desc !== undefined && lastTask !== undefined) {
88+
lastTask.description = desc;
89+
}
90+
}
6191
}
6292

6393
/**
6494
* Parses YAML format mise configuration.
6595
*/
6696
export function parseMiseYaml(content: string): MiseTask[] {
6797
const tasks: MiseTask[] = [];
68-
6998
const lines = content.split("\n");
7099
let inTasks = false;
71100

72101
for (const line of lines) {
73-
// Skip empty lines and comments
74-
if (line.trim() === "" || line.trim().startsWith("#")) {
102+
if (isSkippableLine(line.trim())) {
75103
continue;
76104
}
77105

78-
// Get indent level
79106
const indent = line.search(/\S/);
80107

81-
// Check for "tasks:" at root level
82108
if (indent === 0 && line.trim() === "tasks:") {
83109
inTasks = true;
84110
continue;
85111
}
86112

87-
// Exit tasks section if we hit another root-level key
88-
if (inTasks && indent === 0 && !line.trim().startsWith("tasks:")) {
113+
if (inTasks && indent === 0) {
89114
inTasks = false;
90115
}
91116

92117
if (inTasks && indent > 0) {
93-
// Task name line (immediate child of tasks)
94-
if (indent === 2 && !line.trim().startsWith("-") && line.includes(":")) {
95-
const match = /^\s+([^:]+):\s*$/.exec(line);
96-
if (match !== null && match[1] !== undefined) {
97-
tasks.push({
98-
name: match[1].trim(),
99-
params: [],
100-
});
101-
}
102-
}
103-
104-
// Description line (child of task)
105-
if (indent > 2 && line.includes("description:")) {
106-
const descMatch = /^\s+description:\s*["]?([^"]*)["]?\s*$/.exec(line);
107-
if (descMatch !== null && descMatch[1] !== undefined && tasks.length > 0) {
108-
const lastTask = tasks[tasks.length - 1];
109-
if (lastTask !== undefined) {
110-
lastTask.description = descMatch[1];
111-
}
112-
}
113-
}
118+
processYamlTaskLine(tasks, line, indent);
114119
}
115120
}
116121

0 commit comments

Comments
 (0)