@timeax/scaffold 0.0.2 → 0.0.4
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/.vscode/settings.json +12 -0
- package/dist/ast.cjs +438 -0
- package/dist/ast.cjs.map +1 -0
- package/dist/ast.d.cts +152 -0
- package/dist/ast.d.ts +152 -0
- package/dist/ast.mjs +433 -0
- package/dist/ast.mjs.map +1 -0
- package/dist/index.cjs +59 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.mjs +57 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -3
- package/readme.md +285 -81
- package/src/ast/format.ts +261 -0
- package/src/ast/index.ts +2 -0
- package/src/ast/parser.ts +593 -0
- package/src/core/config-loader.ts +4 -3
- package/src/core/init-scaffold.ts +8 -3
- package/src/core/structure-txt.ts +221 -174
- package/src/index.ts +3 -2
- package/src/schema/config.ts +10 -1
- package/src/schema/index.ts +1 -0
- package/test/format-roundtrip.spec.ts +20 -0
- package/test/format.spec.ts +104 -0
- package/test/parser-diagnostics.spec.ts +86 -0
- package/test/parser-tree.spec.ts +102 -0
- package/tsup.config.ts +61 -43
- package/vitest.config.ts +9 -0
- package/dist/cli.cjs +0 -1141
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.mjs +0 -1130
- package/dist/cli.mjs.map +0 -1
package/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Scaffold
|
|
1
|
+
# Scaffold – `@timeax/scaffold`
|
|
2
2
|
|
|
3
3
|
A tiny, opinionated scaffolding tool that keeps your project structure in sync with a **declarative tree** (like `structure.txt`) – Prisma‑style.
|
|
4
4
|
|
|
@@ -8,26 +8,30 @@ A tiny, opinionated scaffolding tool that keeps your project structure in sync w
|
|
|
8
8
|
* Reverse‑engineer existing projects into `*.txt` structures.
|
|
9
9
|
* Watch for changes and re‑apply automatically.
|
|
10
10
|
|
|
11
|
+
> **Supported structure files:** `.tss`, `.stx`, `structure.txt` (and any `.txt` inside `.scaffold/`).
|
|
12
|
+
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
## Features
|
|
14
16
|
|
|
15
|
-
* **Prisma‑style scaffold directory**: all config and
|
|
17
|
+
* **Prisma‑style scaffold directory**: all config and structures live under a hidden root, **`.scaffold/`**, by default.
|
|
16
18
|
* **Config‑driven groups**: declare multiple roots (e.g. `app`, `frontend`) with their own structure files.
|
|
17
19
|
* **Plain‑text structure files**: strict, easy‑to‑read tree syntax with indentation and annotations.
|
|
18
20
|
* **Safe apply**:
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* Creates missing files/directories.
|
|
23
|
+
* Tracks what it created in a cache.
|
|
24
|
+
* Only auto‑deletes files it previously created.
|
|
25
|
+
* Interactive delete for “large” files.
|
|
24
26
|
* **Hooks**:
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
* Regular hooks around file create/delete.
|
|
29
|
+
* Stub hooks around content generation.
|
|
28
30
|
* **Stubs**: programmatic content generators for files (e.g. React pages, controllers, etc.).
|
|
29
|
-
* **Watch mode**: watch
|
|
30
|
-
* **Scanner**: generate
|
|
31
|
+
* **Watch mode**: watch `.scaffold/` for changes and re‑run automatically.
|
|
32
|
+
* **Scanner**: generate `*.tss`/`structure.txt` from an existing codebase.
|
|
33
|
+
* **AST + formatter**: loose/strict parser with diagnostics, plus a smart formatter that can *fix* simple indentation mistakes.
|
|
34
|
+
* **VS Code extension**: syntax highlighting, formatting, diagnostics, folding, hover info, “go to file”, and code actions.
|
|
31
35
|
|
|
32
36
|
---
|
|
33
37
|
|
|
@@ -57,7 +61,7 @@ pnpm scaffold init
|
|
|
57
61
|
This will create:
|
|
58
62
|
|
|
59
63
|
```txt
|
|
60
|
-
scaffold/
|
|
64
|
+
.scaffold/
|
|
61
65
|
config.ts # main ScaffoldConfig
|
|
62
66
|
structure.txt # example structure (single-root mode)
|
|
63
67
|
```
|
|
@@ -65,7 +69,7 @@ scaffold/
|
|
|
65
69
|
If you want a different directory name:
|
|
66
70
|
|
|
67
71
|
```bash
|
|
68
|
-
scaffold init --dir tools
|
|
72
|
+
scaffold init --dir tools/.scaffold
|
|
69
73
|
```
|
|
70
74
|
|
|
71
75
|
> Use `--force` to overwrite existing config/structure files.
|
|
@@ -74,7 +78,7 @@ scaffold init --dir tools/scaffold
|
|
|
74
78
|
|
|
75
79
|
### 2. Define your structure
|
|
76
80
|
|
|
77
|
-
By default,
|
|
81
|
+
By default, `.scaffold/structure.txt` is used in single‑root mode.
|
|
78
82
|
|
|
79
83
|
Example:
|
|
80
84
|
|
|
@@ -98,12 +102,13 @@ README.md
|
|
|
98
102
|
|
|
99
103
|
**Rules:**
|
|
100
104
|
|
|
101
|
-
* Indent with **2 spaces per level** (
|
|
105
|
+
* Indent with **2 spaces per level** by default (configurable via `indentStep`).
|
|
102
106
|
* Directories **must** end with `/`.
|
|
103
107
|
* Files **must not** end with `/`.
|
|
104
|
-
* You **cannot indent under a file** (files cannot have children).
|
|
105
|
-
* You can’t “skip” levels (no jumping from depth 0 to depth 2 in one go).
|
|
106
|
-
* Lines starting with `#` are comments.
|
|
108
|
+
* You **cannot indent under a file** (files cannot have children) – in strict mode this is an error, in loose mode you get a diagnostic.
|
|
109
|
+
* You can’t “skip” levels (no jumping from depth 0 straight to depth 2 in one go).
|
|
110
|
+
* Lines starting with `#` or `//` are treated as comments.
|
|
111
|
+
* Inline comments are supported: `index.ts # comment`, `index.ts // comment`.
|
|
107
112
|
|
|
108
113
|
#### Annotations
|
|
109
114
|
|
|
@@ -126,18 +131,23 @@ These map onto the `StructureEntry` fields in TypeScript.
|
|
|
126
131
|
|
|
127
132
|
---
|
|
128
133
|
|
|
129
|
-
|
|
134
|
+
## Config: groups, base, and indent
|
|
130
135
|
|
|
131
|
-
In
|
|
136
|
+
In `.scaffold/config.ts` you can enable grouped mode and control the base root + indent step:
|
|
132
137
|
|
|
133
138
|
```ts
|
|
134
139
|
import type { ScaffoldConfig } from '@timeax/scaffold';
|
|
135
140
|
|
|
136
141
|
const config: ScaffoldConfig = {
|
|
137
|
-
|
|
142
|
+
// Project root (defaults to cwd if omitted)
|
|
143
|
+
base: '.',
|
|
144
|
+
|
|
145
|
+
// Indent step in spaces (must match your `.tss`/`structure.txt`)
|
|
146
|
+
indentStep: 2,
|
|
138
147
|
|
|
148
|
+
// Optional: grouped mode
|
|
139
149
|
groups: [
|
|
140
|
-
{ name: 'app',
|
|
150
|
+
{ name: 'app', root: 'app', structureFile: 'app.txt' },
|
|
141
151
|
{ name: 'frontend', root: 'resources/js', structureFile: 'frontend.txt' },
|
|
142
152
|
],
|
|
143
153
|
|
|
@@ -148,14 +158,14 @@ const config: ScaffoldConfig = {
|
|
|
148
158
|
export default config;
|
|
149
159
|
```
|
|
150
160
|
|
|
151
|
-
Then create per‑group structure files in
|
|
161
|
+
Then create per‑group structure files in `.scaffold/`:
|
|
152
162
|
|
|
153
163
|
```txt
|
|
154
|
-
# scaffold/app.txt
|
|
164
|
+
# .scaffold/app.txt
|
|
155
165
|
App/Services/
|
|
156
166
|
UserService.php
|
|
157
167
|
|
|
158
|
-
# scaffold/frontend.txt
|
|
168
|
+
# .scaffold/frontend.txt
|
|
159
169
|
src/
|
|
160
170
|
index.tsx
|
|
161
171
|
pages/
|
|
@@ -166,26 +176,26 @@ src/
|
|
|
166
176
|
|
|
167
177
|
---
|
|
168
178
|
|
|
169
|
-
|
|
179
|
+
## Running scaffold
|
|
170
180
|
|
|
171
181
|
```bash
|
|
172
182
|
# single run
|
|
173
183
|
scaffold
|
|
174
184
|
|
|
175
185
|
# or with explicit scaffold dir / config
|
|
176
|
-
scaffold --dir scaffold --config scaffold/config.ts
|
|
186
|
+
scaffold --dir .scaffold --config .scaffold/config.ts
|
|
177
187
|
```
|
|
178
188
|
|
|
179
189
|
What happens:
|
|
180
190
|
|
|
181
|
-
* Config is loaded from
|
|
191
|
+
* Config is loaded from `.scaffold/config.*` (Prisma‑style resolution).
|
|
182
192
|
* Structure(s) are resolved (grouped or single‑root).
|
|
183
193
|
* Files/directories missing on disk are created.
|
|
184
|
-
* New files are registered in `.scaffold-cache.json`
|
|
185
|
-
* Any previously created files that are no longer in the structure are candidates for deletion
|
|
194
|
+
* New files are registered in a cache file (default: `.scaffold-cache.json` under project root).
|
|
195
|
+
* Any previously created files that are no longer in the structure are candidates for deletion:
|
|
186
196
|
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
* Small files are deleted automatically.
|
|
198
|
+
* Large files (configurable threshold) trigger an interactive prompt.
|
|
189
199
|
|
|
190
200
|
### Watch mode
|
|
191
201
|
|
|
@@ -195,8 +205,8 @@ scaffold --watch
|
|
|
195
205
|
|
|
196
206
|
* Watches:
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
* `.scaffold/config.*`
|
|
209
|
+
* `.scaffold/*.txt` / `.scaffold/*.tss` / `.scaffold/*.stx`
|
|
200
210
|
* Debounces rapid edits.
|
|
201
211
|
* Prevents overlapping runs.
|
|
202
212
|
|
|
@@ -213,11 +223,13 @@ scaffold [options]
|
|
|
213
223
|
Options:
|
|
214
224
|
|
|
215
225
|
* `-c, --config <path>` – override config file path.
|
|
216
|
-
* `-d, --dir <path>` – override scaffold directory (default:
|
|
226
|
+
* `-d, --dir <path>` – override scaffold directory (default: `./.scaffold`).
|
|
217
227
|
* `-w, --watch` – watch scaffold directory for changes.
|
|
218
228
|
* `--quiet` – silence logs.
|
|
219
229
|
* `--debug` – verbose debug logs.
|
|
220
230
|
|
|
231
|
+
---
|
|
232
|
+
|
|
221
233
|
### `scaffold init`
|
|
222
234
|
|
|
223
235
|
Initialize the scaffold directory + config + structure.
|
|
@@ -228,42 +240,44 @@ scaffold init [options]
|
|
|
228
240
|
|
|
229
241
|
Options:
|
|
230
242
|
|
|
231
|
-
* `-d, --dir <path>` – scaffold directory (default:
|
|
243
|
+
* `-d, --dir <path>` – scaffold directory (default: `./.scaffold`, inherited from root options).
|
|
232
244
|
* `--force` – overwrite existing `config.ts` / `structure.txt`.
|
|
233
245
|
|
|
246
|
+
---
|
|
247
|
+
|
|
234
248
|
### `scaffold scan`
|
|
235
249
|
|
|
236
|
-
Generate
|
|
250
|
+
Generate `*.tss`/`structure.txt`‑style definitions from an existing project.
|
|
237
251
|
|
|
238
252
|
Two modes:
|
|
239
253
|
|
|
240
|
-
1.
|
|
254
|
+
#### 1. Config‑aware mode (default if no `--root` / `--out`)
|
|
241
255
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
256
|
+
```bash
|
|
257
|
+
scaffold scan
|
|
258
|
+
scaffold scan --from-config
|
|
259
|
+
scaffold scan --from-config --groups app frontend
|
|
260
|
+
```
|
|
247
261
|
|
|
248
|
-
|
|
249
|
-
|
|
262
|
+
* Loads `.scaffold/config.ts`.
|
|
263
|
+
* For each `group` in config:
|
|
250
264
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
265
|
+
* Scans `group.root` on disk.
|
|
266
|
+
* Writes to `.scaffold/<group.structureFile || group.name + '.txt'>`.
|
|
267
|
+
* `--groups` filters which groups to scan.
|
|
254
268
|
|
|
255
|
-
2.
|
|
269
|
+
#### 2. Manual mode (single root)
|
|
256
270
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
271
|
+
```bash
|
|
272
|
+
scaffold scan -r src
|
|
273
|
+
scaffold scan -r src -o .scaffold/src.txt
|
|
274
|
+
```
|
|
261
275
|
|
|
262
|
-
|
|
276
|
+
Options:
|
|
263
277
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
278
|
+
* `-r, --root <path>` – directory to scan.
|
|
279
|
+
* `-o, --out <path>` – output file (otherwise prints to stdout).
|
|
280
|
+
* `--ignore <patterns...>` – extra globs to ignore (in addition to defaults like `node_modules/**`, `.git/**`, etc.).
|
|
267
281
|
|
|
268
282
|
---
|
|
269
283
|
|
|
@@ -277,15 +291,15 @@ scaffold structures
|
|
|
277
291
|
|
|
278
292
|
What it does:
|
|
279
293
|
|
|
280
|
-
* Loads
|
|
294
|
+
* Loads `.scaffold/config.*`.
|
|
281
295
|
* Determines which structure files are expected:
|
|
282
296
|
|
|
283
|
-
|
|
284
|
-
|
|
297
|
+
* **Grouped mode** (`config.groups` defined): each group gets `group.structureFile || \`${group.name}.txt``.
|
|
298
|
+
* **Single-root mode** (no groups): uses `config.structureFile || 'structure.txt'`.
|
|
285
299
|
* For each expected structure file:
|
|
286
300
|
|
|
287
|
-
|
|
288
|
-
|
|
301
|
+
* If it **already exists** → it is left untouched.
|
|
302
|
+
* If it is **missing** → it is created with a small header comment.
|
|
289
303
|
|
|
290
304
|
Examples:
|
|
291
305
|
|
|
@@ -296,15 +310,17 @@ Examples:
|
|
|
296
310
|
# { name: 'frontend', root: 'resources/js', structureFile: 'frontend.txt' },
|
|
297
311
|
# ]
|
|
298
312
|
scaffold structures
|
|
299
|
-
# => ensures scaffold/app.txt and scaffold/frontend.txt exist
|
|
313
|
+
# => ensures .scaffold/app.txt and .scaffold/frontend.txt exist
|
|
300
314
|
|
|
301
315
|
# With single-root config:
|
|
302
316
|
# structureFile: 'structure.txt'
|
|
303
317
|
scaffold structures
|
|
304
|
-
# => ensures scaffold/structure.txt exists
|
|
318
|
+
# => ensures .scaffold/structure.txt exists
|
|
305
319
|
```
|
|
306
320
|
|
|
307
|
-
This is useful right after setting up or editing
|
|
321
|
+
This is useful right after setting up or editing `.scaffold/config.ts` so that all declared structure files are present and ready to edit.
|
|
322
|
+
|
|
323
|
+
---
|
|
308
324
|
|
|
309
325
|
## TypeScript API
|
|
310
326
|
|
|
@@ -315,8 +331,8 @@ import { runOnce } from '@timeax/scaffold';
|
|
|
315
331
|
|
|
316
332
|
await runOnce(process.cwd(), {
|
|
317
333
|
// optional overrides
|
|
318
|
-
configPath: 'scaffold/config.ts',
|
|
319
|
-
scaffoldDir: 'scaffold',
|
|
334
|
+
configPath: '.scaffold/config.ts',
|
|
335
|
+
scaffoldDir: '.scaffold',
|
|
320
336
|
});
|
|
321
337
|
```
|
|
322
338
|
|
|
@@ -337,7 +353,7 @@ const results = await scanProjectFromConfig(process.cwd(), {
|
|
|
337
353
|
groups: ['app', 'frontend'],
|
|
338
354
|
});
|
|
339
355
|
|
|
340
|
-
// write group structure files to scaffold/
|
|
356
|
+
// write group structure files to .scaffold/
|
|
341
357
|
await writeScannedStructuresFromConfig(process.cwd(), {
|
|
342
358
|
groups: ['app'],
|
|
343
359
|
});
|
|
@@ -345,7 +361,100 @@ await writeScannedStructuresFromConfig(process.cwd(), {
|
|
|
345
361
|
|
|
346
362
|
---
|
|
347
363
|
|
|
348
|
-
##
|
|
364
|
+
## AST & Formatter
|
|
365
|
+
|
|
366
|
+
`@timeax/scaffold` exposes an AST parser and formatter from a dedicated subpath:
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import { parseStructureAst, formatStructureText } from '@timeax/scaffold/ast';
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### `parseStructureAst(text, options)`
|
|
373
|
+
|
|
374
|
+
Parses a structure file into a loose or strict AST with diagnostics:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
const ast = parseStructureAst(text, {
|
|
378
|
+
indentStep: 2, // must match your structure files
|
|
379
|
+
mode: 'loose', // 'loose' | 'strict'
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Return shape (simplified):
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
interface StructureAstNode {
|
|
387
|
+
type: 'dir' | 'file';
|
|
388
|
+
name: string;
|
|
389
|
+
path?: string; // normalized POSIX path (no trailing slash for files)
|
|
390
|
+
line?: number; // 1-based source line
|
|
391
|
+
indentLevel?: number; // 0,1,2,...
|
|
392
|
+
stub?: string;
|
|
393
|
+
include?: string[];
|
|
394
|
+
exclude?: string[];
|
|
395
|
+
children?: StructureAstNode[];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
interface StructureDiagnostic {
|
|
399
|
+
code:
|
|
400
|
+
| 'indent-misaligned'
|
|
401
|
+
| 'indent-skip-level'
|
|
402
|
+
| 'child-of-file-loose'
|
|
403
|
+
| 'path-colon'
|
|
404
|
+
| 'unknown';
|
|
405
|
+
message: string;
|
|
406
|
+
line: number; // 1-based
|
|
407
|
+
severity: 'info' | 'warning' | 'error';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
interface StructureAst {
|
|
411
|
+
rootNodes: StructureAstNode[];
|
|
412
|
+
indentStep: number;
|
|
413
|
+
mode: 'loose' | 'strict';
|
|
414
|
+
diagnostics: StructureDiagnostic[];
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Loose mode** tries to recover from small mistakes (over‑indent, under‑indent) and reports them as diagnostics instead of throwing.
|
|
419
|
+
|
|
420
|
+
**Strict mode** is closer to the CLI parser and may reject invalid indentation entirely.
|
|
421
|
+
|
|
422
|
+
Typical diagnostics:
|
|
423
|
+
|
|
424
|
+
* `indent-misaligned` – indent is not a multiple of `indentStep`.
|
|
425
|
+
* `indent-skip-level` – you jumped more than one level at once.
|
|
426
|
+
* `child-of-file-loose` – a line is indented under a file.
|
|
427
|
+
* `path-colon` – path token contains a colon (`:`), which is reserved for annotations.
|
|
428
|
+
|
|
429
|
+
### `formatStructureText(text, options)`
|
|
430
|
+
|
|
431
|
+
Smart formatter that:
|
|
432
|
+
|
|
433
|
+
* Normalizes line endings and trailing whitespace.
|
|
434
|
+
* Re‑indents entries to canonical multiples of `indentStep`.
|
|
435
|
+
* Fixes common over‑indent/under‑indent issues in **loose mode**.
|
|
436
|
+
* Preserves:
|
|
437
|
+
|
|
438
|
+
* Blank lines.
|
|
439
|
+
* Full‑line comments (`#`, `//`).
|
|
440
|
+
* Inline comments and annotations (keeps them attached to their entries).
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
const { text: formatted, ast, diagnostics } = formatStructureText(input, {
|
|
444
|
+
indentStep: 2,
|
|
445
|
+
mode: 'loose', // 'loose' is recommended for editor integrations
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`formatStructureText` reuses the same AST model and diagnostics, so you can:
|
|
450
|
+
|
|
451
|
+
* Run it in an editor (e.g. VS Code) for formatting.
|
|
452
|
+
* Show the diagnostics in a side panel or gutter.
|
|
453
|
+
* Still feed the formatted text back into the strict CLI parser later.
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Hooks & Stubs (high‑level overview)
|
|
349
458
|
|
|
350
459
|
### Regular hooks
|
|
351
460
|
|
|
@@ -386,6 +495,7 @@ Each receives a `HookContext` with fields like:
|
|
|
386
495
|
* `absolutePath`
|
|
387
496
|
* `isDirectory`
|
|
388
497
|
* `stubName?`
|
|
498
|
+
* `group?`
|
|
389
499
|
|
|
390
500
|
### Stubs
|
|
391
501
|
|
|
@@ -401,7 +511,9 @@ const config: ScaffoldConfig = {
|
|
|
401
511
|
name: 'page',
|
|
402
512
|
async getContent(ctx) {
|
|
403
513
|
const name = ctx.targetPath.split('/').pop();
|
|
404
|
-
return `export default function ${name}() {
|
|
514
|
+
return `export default function ${name}() {
|
|
515
|
+
return <div>${name}</div>;
|
|
516
|
+
}`;
|
|
405
517
|
},
|
|
406
518
|
hooks: {
|
|
407
519
|
preStub: [
|
|
@@ -412,13 +524,14 @@ const config: ScaffoldConfig = {
|
|
|
412
524
|
},
|
|
413
525
|
},
|
|
414
526
|
],
|
|
527
|
+
postStub: [],
|
|
415
528
|
},
|
|
416
529
|
},
|
|
417
530
|
},
|
|
418
531
|
};
|
|
419
532
|
```
|
|
420
533
|
|
|
421
|
-
In
|
|
534
|
+
In a structure file:
|
|
422
535
|
|
|
423
536
|
```txt
|
|
424
537
|
src/
|
|
@@ -431,33 +544,124 @@ Any file in `pages/` without an explicit stub inherits `@stub:page` from the par
|
|
|
431
544
|
|
|
432
545
|
---
|
|
433
546
|
|
|
434
|
-
## Cache &
|
|
547
|
+
## Cache & Safety
|
|
435
548
|
|
|
436
549
|
* Cache file (default): `.scaffold-cache.json` under project root (configurable via `cacheFile`).
|
|
437
550
|
* Every file created by scaffold is recorded with:
|
|
438
551
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
552
|
+
* project‑relative path
|
|
553
|
+
* created time
|
|
554
|
+
* size at creation
|
|
555
|
+
* stub name (if any)
|
|
556
|
+
* group metadata
|
|
444
557
|
* On each run, scaffold compares the **desired structure** vs. **cached entries**:
|
|
445
558
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
559
|
+
* If a cached file is no longer in the structure and still exists → deletion candidate.
|
|
560
|
+
* If its size exceeds `sizePromptThreshold` (configurable) and the CLI is interactive → prompt the user.
|
|
561
|
+
* If the user chooses “keep”, the file is left on disk and removed from the cache (user now owns it).
|
|
449
562
|
|
|
450
563
|
This keeps scaffolding **idempotent** and avoids reckless deletes.
|
|
451
564
|
|
|
452
565
|
---
|
|
453
566
|
|
|
567
|
+
## VS Code Extension
|
|
568
|
+
|
|
569
|
+
There is a companion VS Code extension that makes editing scaffold files much nicer.
|
|
570
|
+
|
|
571
|
+
### Language & files
|
|
572
|
+
|
|
573
|
+
* Registers a `scaffold-structure` language.
|
|
574
|
+
* Treats as scaffold structure files:
|
|
575
|
+
|
|
576
|
+
* `.tss`
|
|
577
|
+
* `.stx`
|
|
578
|
+
* `structure.txt`
|
|
579
|
+
* Any `.txt` inside `.scaffold/` (configurable in the extension’s `package.json`).
|
|
580
|
+
|
|
581
|
+
### Syntax highlighting
|
|
582
|
+
|
|
583
|
+
* Tree‑like syntax with clear highlighting for:
|
|
584
|
+
|
|
585
|
+
* Directories vs files.
|
|
586
|
+
* Annotations (`@stub:`, `@include:`, `@exclude:`).
|
|
587
|
+
* Comments and inline comments.
|
|
588
|
+
|
|
589
|
+
### Formatting
|
|
590
|
+
|
|
591
|
+
* Command: **“Scaffold: Format structure”** (`timeax-scaffold.formatStructure`).
|
|
592
|
+
* Uses `formatStructureText` from `@timeax/scaffold/ast`:
|
|
593
|
+
|
|
594
|
+
* Normalizes indentation to `indentStep`.
|
|
595
|
+
* Fixes simple over/under‑indents in loose mode.
|
|
596
|
+
* Preserves blank lines and comments.
|
|
597
|
+
|
|
598
|
+
You can wire this as the default formatter for `scaffold-structure` files via your VS Code settings.
|
|
599
|
+
|
|
600
|
+
### Sorting
|
|
601
|
+
|
|
602
|
+
* Command: **“Scaffold: Sort entries”** (`timeax-scaffold.sortEntries`).
|
|
603
|
+
* Sorts non‑comment lines lexicographically while preserving comment/blank line positions.
|
|
604
|
+
|
|
605
|
+
### Diagnostics
|
|
606
|
+
|
|
607
|
+
* Live diagnostics (squiggles) using `parseStructureAst`:
|
|
608
|
+
|
|
609
|
+
* `indent-misaligned`, `indent-skip-level`, `child-of-file-loose`, `path-colon`, etc.
|
|
610
|
+
* Diagnostics update on open and on change.
|
|
611
|
+
|
|
612
|
+
### Folding
|
|
613
|
+
|
|
614
|
+
* Folding regions for directories based on AST:
|
|
615
|
+
|
|
616
|
+
* Collapse an entire subtree under a dir.
|
|
617
|
+
|
|
618
|
+
### Hover
|
|
619
|
+
|
|
620
|
+
* Hovering an entry shows:
|
|
621
|
+
|
|
622
|
+
* Kind (dir/file).
|
|
623
|
+
* Effective `path`.
|
|
624
|
+
* Stub / include / exclude.
|
|
625
|
+
* Resolved absolute path based on `base` + group root.
|
|
626
|
+
|
|
627
|
+
### “Go to file”
|
|
628
|
+
|
|
629
|
+
* Command: **“Scaffold: Go to file”** (`timeax-scaffold.openTargetFile`).
|
|
630
|
+
* On a file line:
|
|
631
|
+
|
|
632
|
+
* Resolves the project base (from `.scaffold/config.*`, `base`, and group `root`).
|
|
633
|
+
* Opens the target file if it exists.
|
|
634
|
+
* If it doesn’t exist, you can create it on the spot.
|
|
635
|
+
|
|
636
|
+
### Code actions
|
|
637
|
+
|
|
638
|
+
Source actions exposed in the light‑bulb menu for structure files:
|
|
639
|
+
|
|
640
|
+
* **“Scaffold: Ensure structure files exist (scaffold structures)”**
|
|
641
|
+
|
|
642
|
+
* Runs `npx scaffold structures` in a workspace terminal.
|
|
643
|
+
* **“Scaffold: Apply structure to project (scaffold)”**
|
|
644
|
+
|
|
645
|
+
* Runs `npx scaffold` in a workspace terminal.
|
|
646
|
+
|
|
647
|
+
### Status bar integration
|
|
648
|
+
|
|
649
|
+
* Status bar item (left side) shows current scaffold context:
|
|
650
|
+
|
|
651
|
+
* `Scaffold: frontend (resources/js)` when editing `.scaffold/frontend.txt`.
|
|
652
|
+
* `Scaffold: single root` when in single‑root mode.
|
|
653
|
+
* Tooltip shows the resolved base root path.
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
454
657
|
## Roadmap / Ideas
|
|
455
658
|
|
|
456
659
|
Some things this package is intentionally designed to grow into:
|
|
457
660
|
|
|
458
|
-
* Richer annotations in `*.
|
|
459
|
-
* Stub groups (one logical stub creating multiple files).
|
|
661
|
+
* Richer annotations in `*.tss` (e.g. per‑entry hooks, metadata aliases).
|
|
662
|
+
* Stub groups (one logical stub creating multiple files at once).
|
|
460
663
|
* Built‑in templates for common stacks (Laravel + Inertia, Next.js, etc.).
|
|
461
664
|
* Better diff/dry‑run UX (show what will change without touching disk).
|
|
665
|
+
* Deeper editor integrations (per‑group commands, quick‑fixes for diagnostics, etc.).
|
|
462
666
|
|
|
463
667
|
PRs and ideas are welcome ✨
|