@fougere/cli 0.12.5-alpha.0 → 0.13.0-alpha.0
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/.fougere/scan.generated.d.ts +3 -0
- package/dist/.fougere/scan.generated.d.ts.map +1 -0
- package/dist/.fougere/scan.generated.js +140 -0
- package/dist/.fougere/scan.generated.js.map +1 -0
- package/dist/app/commands/BuildCommand.d.ts +18 -0
- package/dist/app/commands/BuildCommand.d.ts.map +1 -0
- package/dist/app/commands/BuildCommand.js +35 -0
- package/dist/app/commands/BuildCommand.js.map +1 -0
- package/dist/app/commands/CallCommand.d.ts +16 -0
- package/dist/app/commands/CallCommand.d.ts.map +1 -0
- package/dist/app/commands/CallCommand.js +73 -0
- package/dist/app/commands/CallCommand.js.map +1 -0
- package/dist/app/commands/CheckCommand.d.ts +11 -0
- package/dist/app/commands/CheckCommand.d.ts.map +1 -0
- package/dist/app/commands/CheckCommand.js +59 -0
- package/dist/app/commands/CheckCommand.js.map +1 -0
- package/dist/app/commands/CompletionCommand.d.ts +7 -0
- package/dist/app/commands/CompletionCommand.d.ts.map +1 -0
- package/dist/app/commands/CompletionCommand.js +23 -0
- package/dist/app/commands/CompletionCommand.js.map +1 -0
- package/dist/app/commands/DevtoolsCommand.d.ts +20 -0
- package/dist/app/commands/DevtoolsCommand.d.ts.map +1 -0
- package/dist/app/commands/DevtoolsCommand.js +79 -0
- package/dist/app/commands/DevtoolsCommand.js.map +1 -0
- package/dist/app/commands/ExplainCommand.d.ts +18 -0
- package/dist/app/commands/ExplainCommand.d.ts.map +1 -0
- package/dist/app/commands/ExplainCommand.js +111 -0
- package/dist/app/commands/ExplainCommand.js.map +1 -0
- package/dist/app/commands/FreezeCommand.d.ts +21 -0
- package/dist/app/commands/FreezeCommand.d.ts.map +1 -0
- package/dist/app/commands/FreezeCommand.js +102 -0
- package/dist/app/commands/FreezeCommand.js.map +1 -0
- package/dist/app/commands/GrantCommand.d.ts +18 -0
- package/dist/app/commands/GrantCommand.d.ts.map +1 -0
- package/dist/app/commands/GrantCommand.js +39 -0
- package/dist/app/commands/GrantCommand.js.map +1 -0
- package/dist/app/commands/GraphCommand.d.ts +11 -0
- package/dist/app/commands/GraphCommand.d.ts.map +1 -0
- package/dist/app/commands/GraphCommand.js +72 -0
- package/dist/app/commands/GraphCommand.js.map +1 -0
- package/dist/app/commands/KeysCommand.d.ts +22 -0
- package/dist/app/commands/KeysCommand.d.ts.map +1 -0
- package/dist/app/commands/KeysCommand.js +50 -0
- package/dist/app/commands/KeysCommand.js.map +1 -0
- package/dist/app/commands/LoadCommand.d.ts +19 -0
- package/dist/app/commands/LoadCommand.d.ts.map +1 -0
- package/dist/app/commands/LoadCommand.js +37 -0
- package/dist/app/commands/LoadCommand.js.map +1 -0
- package/dist/app/commands/MigrateCommand.d.ts +17 -0
- package/dist/app/commands/MigrateCommand.d.ts.map +1 -0
- package/dist/app/commands/MigrateCommand.js +47 -0
- package/dist/app/commands/MigrateCommand.js.map +1 -0
- package/dist/app/commands/NewCommand.d.ts +24 -0
- package/dist/app/commands/NewCommand.d.ts.map +1 -0
- package/dist/app/commands/NewCommand.js +108 -0
- package/dist/app/commands/NewCommand.js.map +1 -0
- package/dist/app/commands/ServeCommand.d.ts +17 -0
- package/dist/app/commands/ServeCommand.d.ts.map +1 -0
- package/dist/app/commands/ServeCommand.js +92 -0
- package/dist/app/commands/ServeCommand.js.map +1 -0
- package/dist/app/commands/grant-material.d.ts +5 -0
- package/dist/app/commands/grant-material.d.ts.map +1 -0
- package/{app/commands/grant-material.ts → dist/app/commands/grant-material.js} +2 -2
- package/dist/app/commands/grant-material.js.map +1 -0
- package/dist/fronds/analysis/entities/Build.d.ts +10 -0
- package/dist/fronds/analysis/entities/Build.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Build.js +9 -0
- package/dist/fronds/analysis/entities/Build.js.map +1 -0
- package/dist/fronds/analysis/entities/Check.d.ts +8 -0
- package/dist/fronds/analysis/entities/Check.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Check.js +7 -0
- package/dist/fronds/analysis/entities/Check.js.map +1 -0
- package/dist/fronds/analysis/entities/Devtools.d.ts +10 -0
- package/dist/fronds/analysis/entities/Devtools.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Devtools.js +9 -0
- package/dist/fronds/analysis/entities/Devtools.js.map +1 -0
- package/dist/fronds/analysis/entities/Explain.d.ts +11 -0
- package/dist/fronds/analysis/entities/Explain.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Explain.js +10 -0
- package/dist/fronds/analysis/entities/Explain.js.map +1 -0
- package/dist/fronds/analysis/entities/Freeze.d.ts +10 -0
- package/dist/fronds/analysis/entities/Freeze.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Freeze.js +9 -0
- package/dist/fronds/analysis/entities/Freeze.js.map +1 -0
- package/dist/fronds/analysis/entities/Graph.d.ts +9 -0
- package/dist/fronds/analysis/entities/Graph.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Graph.js +8 -0
- package/dist/fronds/analysis/entities/Graph.js.map +1 -0
- package/dist/fronds/analysis/entities/Load.d.ts +10 -0
- package/dist/fronds/analysis/entities/Load.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Load.js +9 -0
- package/dist/fronds/analysis/entities/Load.js.map +1 -0
- package/dist/fronds/analysis/entities/Migrate.d.ts +10 -0
- package/dist/fronds/analysis/entities/Migrate.d.ts.map +1 -0
- package/dist/fronds/analysis/entities/Migrate.js +9 -0
- package/dist/fronds/analysis/entities/Migrate.js.map +1 -0
- package/dist/fronds/analysis/handlers/BuildHandler.d.ts +50 -0
- package/dist/fronds/analysis/handlers/BuildHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/BuildHandler.js +63 -0
- package/dist/fronds/analysis/handlers/BuildHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/CheckHandler.d.ts +30 -0
- package/dist/fronds/analysis/handlers/CheckHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/CheckHandler.js +196 -0
- package/dist/fronds/analysis/handlers/CheckHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/DevtoolsHandler.d.ts +45 -0
- package/dist/fronds/analysis/handlers/DevtoolsHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/DevtoolsHandler.js +61 -0
- package/dist/fronds/analysis/handlers/DevtoolsHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/ExplainHandler.d.ts +99 -0
- package/dist/fronds/analysis/handlers/ExplainHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/ExplainHandler.js +157 -0
- package/dist/fronds/analysis/handlers/ExplainHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/FreezeHandler.d.ts +55 -0
- package/dist/fronds/analysis/handlers/FreezeHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/FreezeHandler.js +145 -0
- package/dist/fronds/analysis/handlers/FreezeHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/GraphHandler.d.ts +23 -0
- package/dist/fronds/analysis/handlers/GraphHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/GraphHandler.js +23 -0
- package/dist/fronds/analysis/handlers/GraphHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/LoadHandler.d.ts +26 -0
- package/dist/fronds/analysis/handlers/LoadHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/LoadHandler.js +35 -0
- package/dist/fronds/analysis/handlers/LoadHandler.js.map +1 -0
- package/dist/fronds/analysis/handlers/MigrateHandler.d.ts +34 -0
- package/dist/fronds/analysis/handlers/MigrateHandler.d.ts.map +1 -0
- package/dist/fronds/analysis/handlers/MigrateHandler.js +92 -0
- package/dist/fronds/analysis/handlers/MigrateHandler.js.map +1 -0
- package/dist/fronds/analysis/services/ProjectScan.d.ts +22 -0
- package/dist/fronds/analysis/services/ProjectScan.d.ts.map +1 -0
- package/dist/fronds/analysis/services/ProjectScan.js +48 -0
- package/dist/fronds/analysis/services/ProjectScan.js.map +1 -0
- package/dist/fronds/analysis/versions.d.ts +21 -0
- package/dist/fronds/analysis/versions.d.ts.map +1 -0
- package/dist/fronds/analysis/versions.js +48 -0
- package/dist/fronds/analysis/versions.js.map +1 -0
- package/dist/fronds/scaffold/entities/BuildFrond.d.ts +7 -0
- package/dist/fronds/scaffold/entities/BuildFrond.d.ts.map +1 -0
- package/dist/fronds/scaffold/entities/BuildFrond.js +6 -0
- package/dist/fronds/scaffold/entities/BuildFrond.js.map +1 -0
- package/dist/fronds/scaffold/entities/Call.d.ts +8 -0
- package/dist/fronds/scaffold/entities/Call.d.ts.map +1 -0
- package/{fronds/scaffold/entities/Call.ts → dist/fronds/scaffold/entities/Call.js} +4 -3
- package/dist/fronds/scaffold/entities/Call.js.map +1 -0
- package/dist/fronds/scaffold/entities/Completion.d.ts +7 -0
- package/dist/fronds/scaffold/entities/Completion.d.ts.map +1 -0
- package/dist/fronds/scaffold/entities/Completion.js +6 -0
- package/dist/fronds/scaffold/entities/Completion.js.map +1 -0
- package/dist/fronds/scaffold/entities/Grant.d.ts +8 -0
- package/dist/fronds/scaffold/entities/Grant.d.ts.map +1 -0
- package/{fronds/scaffold/entities/Grant.ts → dist/fronds/scaffold/entities/Grant.js} +4 -3
- package/dist/fronds/scaffold/entities/Grant.js.map +1 -0
- package/dist/fronds/scaffold/entities/Keys.d.ts +6 -0
- package/dist/fronds/scaffold/entities/Keys.d.ts.map +1 -0
- package/{fronds/scaffold/entities/Keys.ts → dist/fronds/scaffold/entities/Keys.js} +3 -2
- package/dist/fronds/scaffold/entities/Keys.js.map +1 -0
- package/dist/fronds/scaffold/entities/New.d.ts +19 -0
- package/dist/fronds/scaffold/entities/New.d.ts.map +1 -0
- package/dist/fronds/scaffold/entities/New.js +18 -0
- package/dist/fronds/scaffold/entities/New.js.map +1 -0
- package/dist/fronds/scaffold/entities/Serve.d.ts +10 -0
- package/dist/fronds/scaffold/entities/Serve.d.ts.map +1 -0
- package/dist/fronds/scaffold/entities/Serve.js +9 -0
- package/dist/fronds/scaffold/entities/Serve.js.map +1 -0
- package/dist/fronds/scaffold/entities/Sync.d.ts +8 -0
- package/dist/fronds/scaffold/entities/Sync.d.ts.map +1 -0
- package/dist/fronds/scaffold/entities/Sync.js +7 -0
- package/dist/fronds/scaffold/entities/Sync.js.map +1 -0
- package/dist/fronds/scaffold/handlers/BuildFrondHandler.d.ts +11 -0
- package/dist/fronds/scaffold/handlers/BuildFrondHandler.d.ts.map +1 -0
- package/dist/fronds/scaffold/handlers/BuildFrondHandler.js +82 -0
- package/dist/fronds/scaffold/handlers/BuildFrondHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/CallHandler.d.ts +10 -0
- package/dist/fronds/scaffold/handlers/CallHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/CallHandler.ts → dist/fronds/scaffold/handlers/CallHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/CallHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/CompletionHandler.d.ts +9 -0
- package/dist/fronds/scaffold/handlers/CompletionHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/CompletionHandler.ts → dist/fronds/scaffold/handlers/CompletionHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/CompletionHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/GrantHandler.d.ts +9 -0
- package/dist/fronds/scaffold/handlers/GrantHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/GrantHandler.ts → dist/fronds/scaffold/handlers/GrantHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/GrantHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/KeysHandler.d.ts +9 -0
- package/dist/fronds/scaffold/handlers/KeysHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/KeysHandler.ts → dist/fronds/scaffold/handlers/KeysHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/KeysHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/NewHandler.d.ts +9 -0
- package/dist/fronds/scaffold/handlers/NewHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/NewHandler.ts → dist/fronds/scaffold/handlers/NewHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/NewHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/ServeHandler.d.ts +10 -0
- package/dist/fronds/scaffold/handlers/ServeHandler.d.ts.map +1 -0
- package/{fronds/scaffold/handlers/ServeHandler.ts → dist/fronds/scaffold/handlers/ServeHandler.js} +3 -2
- package/dist/fronds/scaffold/handlers/ServeHandler.js.map +1 -0
- package/dist/fronds/scaffold/handlers/SyncHandler.d.ts +18 -0
- package/dist/fronds/scaffold/handlers/SyncHandler.d.ts.map +1 -0
- package/dist/fronds/scaffold/handlers/SyncHandler.js +327 -0
- package/dist/fronds/scaffold/handlers/SyncHandler.js.map +1 -0
- package/dist/fronds/scaffold/services/ProjectWriter.d.ts +54 -0
- package/dist/fronds/scaffold/services/ProjectWriter.d.ts.map +1 -0
- package/dist/fronds/scaffold/services/ProjectWriter.js +315 -0
- package/dist/fronds/scaffold/services/ProjectWriter.js.map +1 -0
- package/dist/src/bin.d.ts.map +1 -0
- package/dist/src/bin.js +11 -0
- package/dist/src/bin.js.map +1 -0
- package/dist/src/bridge.d.ts.map +1 -0
- package/dist/src/bridge.js.map +1 -0
- package/dist/src/completion.d.ts.map +1 -0
- package/dist/src/completion.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/loader.d.ts.map +1 -0
- package/dist/src/loader.js.map +1 -0
- package/dist/src/machine.d.ts.map +1 -0
- package/dist/src/machine.js.map +1 -0
- package/dist/src/main.d.ts +2 -0
- package/dist/src/main.d.ts.map +1 -0
- package/dist/src/main.js +19 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/runner.d.ts.map +1 -0
- package/dist/{runner.js → src/runner.js} +22 -22
- package/dist/src/runner.js.map +1 -0
- package/dist/src/theme.d.ts.map +1 -0
- package/dist/src/theme.js.map +1 -0
- package/dist/src/typescript/EntityTypes.d.ts.map +1 -0
- package/dist/src/typescript/EntityTypes.js.map +1 -0
- package/dist/src/typescript/FacadeTypes.d.ts.map +1 -0
- package/dist/src/typescript/FacadeTypes.js.map +1 -0
- package/dist/src/typescript/syntax.d.ts.map +1 -0
- package/dist/src/typescript/syntax.js.map +1 -0
- package/dist/{ui.d.ts → src/ui.d.ts} +0 -1
- package/dist/src/ui.d.ts.map +1 -0
- package/dist/{ui.js → src/ui.js} +24 -22
- package/dist/src/ui.js.map +1 -0
- package/package.json +25 -29
- package/templates/frond/fronds/tsconfig.json +17 -0
- package/templates/workspace/fronds/tsconfig.json +2 -4
- package/templates/workspace/package.json +1 -1
- package/templates/workspace/pnpm-workspace.yaml +5 -3
- package/app/commands/BuildCommand.ts +0 -43
- package/app/commands/CallCommand.ts +0 -70
- package/app/commands/CheckCommand.ts +0 -70
- package/app/commands/CompletionCommand.ts +0 -24
- package/app/commands/DevtoolsCommand.ts +0 -92
- package/app/commands/ExplainCommand.ts +0 -136
- package/app/commands/FreezeCommand.ts +0 -119
- package/app/commands/GrantCommand.ts +0 -46
- package/app/commands/GraphCommand.ts +0 -91
- package/app/commands/KeysCommand.ts +0 -57
- package/app/commands/LoadCommand.ts +0 -46
- package/app/commands/MigrateCommand.ts +0 -61
- package/app/commands/NewCommand.ts +0 -137
- package/app/commands/ServeCommand.ts +0 -108
- package/dist/bin.d.ts.map +0 -1
- package/dist/bin.js +0 -64
- package/dist/bin.js.map +0 -1
- package/dist/bridge.d.ts.map +0 -1
- package/dist/bridge.js.map +0 -1
- package/dist/completion.d.ts.map +0 -1
- package/dist/completion.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/loader.d.ts.map +0 -1
- package/dist/loader.js.map +0 -1
- package/dist/machine.d.ts.map +0 -1
- package/dist/machine.js.map +0 -1
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js.map +0 -1
- package/dist/theme.d.ts.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/typescript/EntityTypes.d.ts.map +0 -1
- package/dist/typescript/EntityTypes.js.map +0 -1
- package/dist/typescript/FacadeTypes.d.ts.map +0 -1
- package/dist/typescript/FacadeTypes.js.map +0 -1
- package/dist/typescript/syntax.d.ts.map +0 -1
- package/dist/typescript/syntax.js.map +0 -1
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js.map +0 -1
- package/fronds/analysis/entities/Build.ts +0 -8
- package/fronds/analysis/entities/Check.ts +0 -6
- package/fronds/analysis/entities/Devtools.ts +0 -8
- package/fronds/analysis/entities/Explain.ts +0 -9
- package/fronds/analysis/entities/Freeze.ts +0 -8
- package/fronds/analysis/entities/Graph.ts +0 -7
- package/fronds/analysis/entities/Load.ts +0 -8
- package/fronds/analysis/entities/Migrate.ts +0 -8
- package/fronds/analysis/handlers/BuildHandler.ts +0 -87
- package/fronds/analysis/handlers/CheckHandler.ts +0 -217
- package/fronds/analysis/handlers/DevtoolsHandler.ts +0 -97
- package/fronds/analysis/handlers/ExplainHandler.ts +0 -263
- package/fronds/analysis/handlers/FreezeHandler.ts +0 -183
- package/fronds/analysis/handlers/GraphHandler.ts +0 -38
- package/fronds/analysis/handlers/LoadHandler.ts +0 -44
- package/fronds/analysis/handlers/MigrateHandler.ts +0 -110
- package/fronds/analysis/services/ProjectScan.ts +0 -55
- package/fronds/analysis/versions.ts +0 -59
- package/fronds/scaffold/entities/BuildFrond.ts +0 -5
- package/fronds/scaffold/entities/Completion.ts +0 -5
- package/fronds/scaffold/entities/New.ts +0 -19
- package/fronds/scaffold/entities/Serve.ts +0 -8
- package/fronds/scaffold/entities/Sync.ts +0 -6
- package/fronds/scaffold/handlers/BuildFrondHandler.ts +0 -96
- package/fronds/scaffold/handlers/SyncHandler.ts +0 -376
- package/fronds/scaffold/services/ProjectWriter.ts +0 -339
- package/fronds/shims.d.ts +0 -9
- package/src/bin.ts +0 -77
- package/src/bridge.ts +0 -118
- package/src/completion.ts +0 -145
- package/src/index.ts +0 -1
- package/src/loader.ts +0 -28
- package/src/machine.ts +0 -17
- package/src/runner.ts +0 -152
- package/src/theme.ts +0 -19
- package/src/typescript/EntityTypes.ts +0 -92
- package/src/typescript/FacadeTypes.ts +0 -50
- package/src/typescript/syntax.ts +0 -11
- package/src/ui.ts +0 -142
- package/templates/flat/AGENTS.md +0 -14
- package/templates/flat/CLAUDE.md +0 -87
- package/templates/flat/_gitignore +0 -6
- package/templates/flat/app/app.vue +0 -25
- package/templates/flat/app/pages/index.vue +0 -7
- package/templates/flat/fougere.config.ts +0 -7
- package/templates/flat/nuxt.config.ts +0 -4
- package/templates/flat/package.json +0 -24
- package/templates/flat/pnpm-workspace.yaml +0 -6
- package/templates/flat/tsconfig.frond.json +0 -25
- package/templates/flat/tsconfig.json +0 -3
- /package/dist/{bin.d.ts → src/bin.d.ts} +0 -0
- /package/dist/{bridge.d.ts → src/bridge.d.ts} +0 -0
- /package/dist/{bridge.js → src/bridge.js} +0 -0
- /package/dist/{completion.d.ts → src/completion.d.ts} +0 -0
- /package/dist/{completion.js → src/completion.js} +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{index.js → src/index.js} +0 -0
- /package/dist/{loader.d.ts → src/loader.d.ts} +0 -0
- /package/dist/{loader.js → src/loader.js} +0 -0
- /package/dist/{machine.d.ts → src/machine.d.ts} +0 -0
- /package/dist/{machine.js → src/machine.js} +0 -0
- /package/dist/{runner.d.ts → src/runner.d.ts} +0 -0
- /package/dist/{theme.d.ts → src/theme.d.ts} +0 -0
- /package/dist/{theme.js → src/theme.js} +0 -0
- /package/dist/{typescript → src/typescript}/EntityTypes.d.ts +0 -0
- /package/dist/{typescript → src/typescript}/EntityTypes.js +0 -0
- /package/dist/{typescript → src/typescript}/FacadeTypes.d.ts +0 -0
- /package/dist/{typescript → src/typescript}/FacadeTypes.js +0 -0
- /package/dist/{typescript → src/typescript}/syntax.d.ts +0 -0
- /package/dist/{typescript → src/typescript}/syntax.js +0 -0
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { cpSync, existsSync, mkdirSync, renameSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { type Conventions, DEFAULT_CONVENTIONS, frondPackage } from '@fougere/core';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The monorepo's `packages/`, found by its workspace marker rather than counted
|
|
10
|
-
* in `..` from this file. Counting encoded how deep the CLI itself sat, so the
|
|
11
|
-
* day `cli/` moved into a family, `--local` linked four packages instead of
|
|
12
|
-
* twenty-one — silently, because the scan below simply found less.
|
|
13
|
-
*
|
|
14
|
-
* Returns undefined outside the monorepo, which is every installed copy.
|
|
15
|
-
*/
|
|
16
|
-
function monorepoPackages(): string | undefined {
|
|
17
|
-
let d = fileURLToPath(new URL('.', import.meta.url));
|
|
18
|
-
while (d !== dirname(d)) {
|
|
19
|
-
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return join(d, 'packages');
|
|
20
|
-
d = dirname(d);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Scaffolds from real template files (create-vite pattern: stdlib copy, no
|
|
28
|
-
* token engine). The workspace model composes at every scale:
|
|
29
|
-
* - a workspace shell (`workspace/`),
|
|
30
|
-
* - fronds added from `fronds/<template>` (business hexagons),
|
|
31
|
-
* - apps added from `apps/<template>` (consumers: nuxt, cli).
|
|
32
|
-
* The only per-piece edits are the package names.
|
|
33
|
-
*/
|
|
34
|
-
const TEMPLATES = fileURLToPath(new URL('../../../templates/', import.meta.url));
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Where a HOST keeps its starter, or nothing when it ships none.
|
|
38
|
-
*
|
|
39
|
-
* The package that owns the wiring owns the files: `@fougere/nuxt` knows what a
|
|
40
|
-
* `nuxt.config.ts` must say, and a copy of it here would be that knowledge written twice —
|
|
41
|
-
* which is how `templates/apps/` came to hold one host while six were published.
|
|
42
|
-
*
|
|
43
|
-
* Two ways to reach them, and the first is the monorepo's: a host is on disk there, and in
|
|
44
|
-
* every process that installed one for its own reasons.
|
|
45
|
-
*/
|
|
46
|
-
function starterOf(pkg: string): string | undefined {
|
|
47
|
-
return carried(pkg) ?? fetched(pkg);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Resolved from the main entry and walked up to the manifest, because a host does not export
|
|
52
|
-
* its own `package.json` and has no reason to.
|
|
53
|
-
*
|
|
54
|
-
* `import.meta.resolve` and not `createRequire().resolve`: a host's `exports` states only the
|
|
55
|
-
* `import` condition, so the CJS resolver answers `ERR_PACKAGE_PATH_NOT_EXPORTED` for every
|
|
56
|
-
* one of them.
|
|
57
|
-
*/
|
|
58
|
-
function carried(pkg: string): string | undefined {
|
|
59
|
-
let dir: string;
|
|
60
|
-
try {
|
|
61
|
-
dir = dirname(fileURLToPath(import.meta.resolve(pkg)));
|
|
62
|
-
} catch { return undefined; }
|
|
63
|
-
|
|
64
|
-
while (!existsSync(join(dir, 'package.json')) && dir !== dirname(dir)) dir = dirname(dir);
|
|
65
|
-
const template = join(dir, 'template');
|
|
66
|
-
|
|
67
|
-
return existsSync(template) ? template : undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The starter of a host this process does not carry, read out of its published tarball.
|
|
72
|
-
*
|
|
73
|
-
* A host is no longer a `dependencies` entry: what is wanted of it is a directory of files, and
|
|
74
|
-
* npm answers a dependency by installing the whole tree behind it — `next` brought 300 MB and
|
|
75
|
-
* `nuxt` its own, so that 28 files weighing 112 KB could be copied. A tarball is 27 to 388 KB,
|
|
76
|
-
* and the peers it names are the scaffolded app's to install, never this CLI's.
|
|
77
|
-
*
|
|
78
|
-
* Pinned to `scaffoldVersion()` for the reason `pinVersions` states, and extracted under that
|
|
79
|
-
* version, so a second call reuses what the first unpacked and a released CLI never reads the
|
|
80
|
-
* starter of another one.
|
|
81
|
-
*/
|
|
82
|
-
function fetched(pkg: string): string | undefined {
|
|
83
|
-
const dir = join(tmpdir(), 'fougere-starter', `${pkg.replace('/', '-')}@${scaffoldVersion()}`);
|
|
84
|
-
const template = join(dir, 'package', 'template');
|
|
85
|
-
if (existsSync(template)) return template;
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
mkdirSync(dir, { recursive: true });
|
|
89
|
-
const tarball = execFileSync('npm', ['pack', `${pkg}@${scaffoldVersion()}`, '--pack-destination', dir, '--silent'],
|
|
90
|
-
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
91
|
-
execFileSync('tar', ['-xzf', join(dir, tarball), '-C', dir, 'package/template'], { stdio: 'ignore' });
|
|
92
|
-
} catch { return undefined; }
|
|
93
|
-
|
|
94
|
-
return existsSync(template) ? template : undefined;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The hosts this CLI can scaffold: the `@fougere/*` packages it is developed against.
|
|
99
|
-
*
|
|
100
|
-
* The dependency list IS the registry — nothing to declare, and a host added to the family
|
|
101
|
-
* appears here the day the CLI names it. It names them under `devDependencies`, because what
|
|
102
|
-
* it wants of a host is a directory of files rather than a module to load, and `dependencies`
|
|
103
|
-
* is what had `npm create fougere` install Next.js and Nuxt to copy 28 files.
|
|
104
|
-
*
|
|
105
|
-
* The NAMES are read here and the FILES only where an app is written, so offering the list
|
|
106
|
-
* costs nothing: resolving all six would fetch six tarballs to print six words.
|
|
107
|
-
*/
|
|
108
|
-
function hosts(): string[] {
|
|
109
|
-
const manifest = JSON.parse(readFileSync(fileURLToPath(new URL('../../../package.json', import.meta.url)), 'utf8')) as
|
|
110
|
-
{ devDependencies?: Record<string, string> };
|
|
111
|
-
|
|
112
|
-
return Object.keys(manifest.devDependencies ?? {})
|
|
113
|
-
.filter((pkg) => pkg.startsWith('@fougere/'))
|
|
114
|
-
.map((pkg) => pkg.slice('@fougere/'.length));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** The version that scaffolds is the version the templates were written for. */
|
|
118
|
-
const scaffoldVersion = (): string =>
|
|
119
|
-
(JSON.parse(readFileSync(fileURLToPath(new URL('../../../package.json', import.meta.url)), 'utf8')) as
|
|
120
|
-
{ version: string }).version;
|
|
121
|
-
|
|
122
|
-
// npm strips a literal .gitignore from published packages — it ships as
|
|
123
|
-
// _gitignore and the name is restored on copy.
|
|
124
|
-
function restoreGitignore(dir: string): void {
|
|
125
|
-
const gi = join(dir, '_gitignore');
|
|
126
|
-
if (existsSync(gi)) renameSync(gi, join(dir, '.gitignore'));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function setPackageName(dir: string, name: string): void {
|
|
130
|
-
const pkgPath = join(dir, 'package.json');
|
|
131
|
-
if (!existsSync(pkgPath)) return;
|
|
132
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name: string };
|
|
133
|
-
pkg.name = name;
|
|
134
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export default class ProjectWriter {
|
|
138
|
-
/** The workspace shell — fougere.config, pnpm-workspace (fronds/* apps/*), package.json. */
|
|
139
|
-
createWorkspace(dir: string, name: string): { path: string } {
|
|
140
|
-
cpSync(join(TEMPLATES, 'workspace'), dir, { recursive: true });
|
|
141
|
-
restoreGitignore(dir);
|
|
142
|
-
setPackageName(dir, name);
|
|
143
|
-
|
|
144
|
-
return { path: dir };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* The flat shell — one Nuxt app whose root carries the convention, so no `fronds/`
|
|
149
|
-
* and no workspace. `templates/flat/` is that shell; what separates the two shapes is
|
|
150
|
-
* only where the domain lands.
|
|
151
|
-
*/
|
|
152
|
-
createFlat(dir: string, name: string): { path: string } {
|
|
153
|
-
cpSync(join(TEMPLATES, 'flat'), dir, { recursive: true });
|
|
154
|
-
restoreGitignore(dir);
|
|
155
|
-
setPackageName(dir, name);
|
|
156
|
-
|
|
157
|
-
return { path: dir };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Put a frond template's directories at the project root. Only the directories: at the
|
|
162
|
-
* root the app's own `package.json` is the frond's, and `@fronds/<name>` comes from the
|
|
163
|
-
* directory through the Nuxt module's alias, so the template's package would only
|
|
164
|
-
* duplicate it under a second name.
|
|
165
|
-
*/
|
|
166
|
-
addRootFrond(dir: string, template: string): { path: string } {
|
|
167
|
-
const src = join(TEMPLATES, 'fronds', template);
|
|
168
|
-
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
169
|
-
if (!entry.isDirectory()) continue;
|
|
170
|
-
cpSync(join(src, entry.name), join(dir, entry.name), { recursive: true });
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return { path: dir };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** Add a frond (business hexagon) under fronds/<name>. */
|
|
177
|
-
addFrond(wsDir: string, template: string, name: string, conventions: Conventions = DEFAULT_CONVENTIONS): { path: string } {
|
|
178
|
-
const dest = join(wsDir, conventions.fronds, name);
|
|
179
|
-
cpSync(join(TEMPLATES, 'fronds', template), dest, { recursive: true });
|
|
180
|
-
// Only the import name. Carrying the convention is what makes a frond — the scan
|
|
181
|
-
// reads directories. `fougere.frond` IS read now (`scanner.ts`, `frondNameOf`), but
|
|
182
|
-
// it renames the contract, which a freshly scaffolded frond has no reason to do.
|
|
183
|
-
const pkgPath = join(dest, 'package.json');
|
|
184
|
-
if (existsSync(pkgPath)) {
|
|
185
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name: string };
|
|
186
|
-
pkg.name = frondPackage(name, conventions);
|
|
187
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return { path: dest };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/** Add an app (consumer) under apps/<name>, from the host package that owns its wiring. */
|
|
194
|
-
addApp(wsDir: string, template: string, name: string): { path: string } {
|
|
195
|
-
const dest = join(wsDir, 'apps', name);
|
|
196
|
-
const starter = hosts().includes(template) ? starterOf(`@fougere/${template}`) : undefined;
|
|
197
|
-
if (!starter) throw new Error(`No host ships a starter for '${template}'. Served: ${hosts().join(', ')}.`);
|
|
198
|
-
|
|
199
|
-
cpSync(starter, dest, { recursive: true });
|
|
200
|
-
restoreGitignore(dest);
|
|
201
|
-
setPackageName(dest, name);
|
|
202
|
-
|
|
203
|
-
return { path: dest };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* What can be scaffolded, of a kind.
|
|
208
|
-
*
|
|
209
|
-
* A FROND comes from this package: it is Fougere's own vocabulary, entities and handlers,
|
|
210
|
-
* and no other package owns it. An APP comes from its HOST — the registry is the hosts this
|
|
211
|
-
* CLI depends on, so `fougere new` offers what is published rather than what was copied here.
|
|
212
|
-
*/
|
|
213
|
-
listTemplates(kind: 'fronds' | 'apps'): string[] {
|
|
214
|
-
if (kind === 'apps') return hosts().sort();
|
|
215
|
-
|
|
216
|
-
const dir = join(TEMPLATES, kind);
|
|
217
|
-
if (!existsSync(dir)) return [];
|
|
218
|
-
|
|
219
|
-
return readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Every app depends on every frond of the workspace — stated once composition is done,
|
|
224
|
-
* because that is when the names exist.
|
|
225
|
-
*
|
|
226
|
-
* A template cannot carry it: the frond is named at composition time (`blog:catalog`),
|
|
227
|
-
* so a dependency written into `templates/apps/nuxt` would name the template instead
|
|
228
|
-
* and resolve to nothing. Which is what happened — the generated app imported
|
|
229
|
-
* `@fronds/blog` whatever you had called it, and did not start.
|
|
230
|
-
*
|
|
231
|
-
* `fronds/` and `apps/` are the registry, like `listTemplates`: nothing to declare.
|
|
232
|
-
*/
|
|
233
|
-
linkFronds(wsDir: string, conventions: Conventions = DEFAULT_CONVENTIONS): void {
|
|
234
|
-
const dirs = (kind: string): string[] => {
|
|
235
|
-
const dir = join(wsDir, kind);
|
|
236
|
-
if (!existsSync(dir)) return [];
|
|
237
|
-
|
|
238
|
-
return readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const fronds = dirs(conventions.fronds);
|
|
242
|
-
if (fronds.length === 0) return;
|
|
243
|
-
|
|
244
|
-
for (const app of dirs('apps')) {
|
|
245
|
-
const pkgPath = join(wsDir, 'apps', app, 'package.json');
|
|
246
|
-
if (!existsSync(pkgPath)) continue;
|
|
247
|
-
|
|
248
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { dependencies?: Record<string, string> };
|
|
249
|
-
pkg.dependencies ??= {};
|
|
250
|
-
for (const frond of fronds) pkg.dependencies[frondPackage(frond, conventions)] = 'workspace:*';
|
|
251
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Every `@fougere/*` dependency, pinned to the version that scaffolded it.
|
|
257
|
-
*
|
|
258
|
-
* The templates say `latest`, which reads as "whatever is current" and is not: pnpm
|
|
259
|
-
* answers from a metadata cache, and a fresh project installed 0.6 while the registry
|
|
260
|
-
* said 0.7 — measured. A version is also what makes an install reproducible, which
|
|
261
|
-
* `latest` never was.
|
|
262
|
-
*
|
|
263
|
-
* Read off this CLI's own package, because the scaffold and the packages it names ship
|
|
264
|
-
* together: the version that wrote the file is the one it was written for.
|
|
265
|
-
*/
|
|
266
|
-
pinVersions(wsDir: string, conventions: Conventions = DEFAULT_CONVENTIONS): void {
|
|
267
|
-
const version = scaffoldVersion();
|
|
268
|
-
const manifests = [
|
|
269
|
-
join(wsDir, 'package.json'),
|
|
270
|
-
...['apps', conventions.fronds].flatMap((kind) => {
|
|
271
|
-
const dir = join(wsDir, kind);
|
|
272
|
-
if (!existsSync(dir)) return [];
|
|
273
|
-
|
|
274
|
-
return readdirSync(dir, { withFileTypes: true })
|
|
275
|
-
.filter((e) => e.isDirectory())
|
|
276
|
-
.map((e) => join(dir, e.name, 'package.json'));
|
|
277
|
-
}),
|
|
278
|
-
];
|
|
279
|
-
|
|
280
|
-
for (const path of manifests) {
|
|
281
|
-
if (!existsSync(path)) continue;
|
|
282
|
-
const pkg = JSON.parse(readFileSync(path, 'utf8')) as { dependencies?: Record<string, string> };
|
|
283
|
-
let moved = false;
|
|
284
|
-
for (const [name, range] of Object.entries(pkg.dependencies ?? {})) {
|
|
285
|
-
if (!name.startsWith('@fougere/') || range !== 'latest') continue;
|
|
286
|
-
pkg.dependencies![name] = version;
|
|
287
|
-
moved = true;
|
|
288
|
-
}
|
|
289
|
-
if (moved) writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n');
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Dev mode: rewrite every `@fougere/*` dependency in the workspace to a
|
|
295
|
-
* `link:` into this monorepo, so `pnpm install` resolves offline (the
|
|
296
|
-
* packages aren't on npm yet). No-op once the packages are published.
|
|
297
|
-
*/
|
|
298
|
-
linkLocal(wsDir: string): void {
|
|
299
|
-
const packages = monorepoPackages();
|
|
300
|
-
if (!packages) return;
|
|
301
|
-
// Read off the monorepo rather than listed here: a hand-kept map knew the seven
|
|
302
|
-
// packages the default templates use, so the first step beyond the default — a
|
|
303
|
-
// GraphQL surface, auth — added a dependency it had never heard of, which stayed
|
|
304
|
-
// on `latest` and broke the install. `@fougere/nuxt` lives in `app/nuxt/` and
|
|
305
|
-
// `@fougere/transport-http` in `transport/http/`, which is exactly why the name is
|
|
306
|
-
// read from each package.json instead of guessed from its directory.
|
|
307
|
-
const dirOf = new Map<string, string>();
|
|
308
|
-
const scan = (dir: string, depth = 0): void => {
|
|
309
|
-
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
310
|
-
if (!e.isDirectory() || e.name === 'node_modules') continue;
|
|
311
|
-
const sub = join(dir, e.name);
|
|
312
|
-
const pkgPath = join(sub, 'package.json');
|
|
313
|
-
if (existsSync(pkgPath)) {
|
|
314
|
-
const { name } = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string };
|
|
315
|
-
if (name?.startsWith('@fougere/')) dirOf.set(name, sub);
|
|
316
|
-
} else if (depth === 0) {
|
|
317
|
-
scan(sub, depth + 1);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
scan(packages);
|
|
322
|
-
const walk = (d: string): void => {
|
|
323
|
-
for (const e of readdirSync(d, { withFileTypes: true })) {
|
|
324
|
-
if (e.name === 'node_modules') continue;
|
|
325
|
-
const f = join(d, e.name);
|
|
326
|
-
if (e.isDirectory()) { walk(f); continue; }
|
|
327
|
-
if (e.name !== 'package.json') continue;
|
|
328
|
-
const pkg = JSON.parse(readFileSync(f, 'utf8')) as { dependencies?: Record<string, string> };
|
|
329
|
-
let changed = false;
|
|
330
|
-
for (const dep of Object.keys(pkg.dependencies ?? {})) {
|
|
331
|
-
const local = dirOf.get(dep);
|
|
332
|
-
if (local) { pkg.dependencies![dep] = `link:${local}`; changed = true; }
|
|
333
|
-
}
|
|
334
|
-
if (changed) writeFileSync(f, JSON.stringify(pkg, null, 2) + '\n');
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
walk(wsDir);
|
|
338
|
-
}
|
|
339
|
-
}
|
package/fronds/shims.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// `safe-regex` ships no types, and `@types/safe-regex` describes its version 1 while the
|
|
2
|
-
// package here is version 2. The exported signature did not move between the two, so the
|
|
3
|
-
// shim states it rather than pinning a types package a major behind.
|
|
4
|
-
declare module 'safe-regex' {
|
|
5
|
-
export default function safeRegex(
|
|
6
|
-
pattern: string | RegExp,
|
|
7
|
-
options?: { limit?: number },
|
|
8
|
-
): boolean;
|
|
9
|
-
}
|
package/src/bin.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/** fougere CLI — a Fougere app powered by citty. */
|
|
3
|
-
import { createApp, setLogLevel, envLevel, type ScanResult } from '@fougere/core';
|
|
4
|
-
import { scanProject } from '@fougere/compiler';
|
|
5
|
-
import { frondDirsOf, DEFAULT_CONVENTIONS } from '@fougere/core';
|
|
6
|
-
import { getModuleLoader } from '@fougere/core/node';
|
|
7
|
-
import { readdir, stat } from 'node:fs/promises';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import { createContainer } from '@fougere/container';
|
|
10
|
-
import { ui } from './ui.js';
|
|
11
|
-
import { run } from './runner.js';
|
|
12
|
-
import { installLoader } from './loader.js';
|
|
13
|
-
|
|
14
|
-
await installLoader(process.cwd());
|
|
15
|
-
|
|
16
|
-
const cliRoot = new URL('..', import.meta.url).pathname;
|
|
17
|
-
const container = createContainer();
|
|
18
|
-
const terminal = ui();
|
|
19
|
-
container.registerValue('ui', terminal);
|
|
20
|
-
container.registerValue('cwd', process.cwd());
|
|
21
|
-
|
|
22
|
-
// The CLI is a Fougere app — silence its boot chatter unless explicitly asked. The
|
|
23
|
-
// threshold is SET, not only announced: a static import evaluates the logger module,
|
|
24
|
-
// its env read included, before this line runs.
|
|
25
|
-
process.env.FOUGERE_LOG_LEVEL ??= 'warn';
|
|
26
|
-
setLogLevel(envLevel() ?? 'warn');
|
|
27
|
-
|
|
28
|
-
/** The newest declaration under `fronds/`, or 0 when there is none to compare against. */
|
|
29
|
-
async function newestDeclaration(root: string): Promise<number> {
|
|
30
|
-
const frondsDir = join(root, DEFAULT_CONVENTIONS.fronds);
|
|
31
|
-
const names = await readdir(frondsDir, { withFileTypes: true }).catch(() => []);
|
|
32
|
-
const dirs = names.filter((entry) => entry.isDirectory())
|
|
33
|
-
.flatMap((entry) => [
|
|
34
|
-
join(frondsDir, entry.name),
|
|
35
|
-
...frondDirsOf(DEFAULT_CONVENTIONS).map((dir) => join(frondsDir, entry.name, dir)),
|
|
36
|
-
]);
|
|
37
|
-
|
|
38
|
-
const times = await Promise.all(dirs.map(async (dir) => {
|
|
39
|
-
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
40
|
-
const stats = await Promise.all(entries
|
|
41
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith('.ts'))
|
|
42
|
-
.map((entry) => stat(join(dir, entry.name)).then((s) => s.mtimeMs).catch(() => 0)));
|
|
43
|
-
|
|
44
|
-
return Math.max(0, ...stats);
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
return Math.max(0, ...times);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The CLI is a Fougere app, so it reads its own written-down scan like any deployment — producing
|
|
52
|
-
* the description reads the project, consuming it does not.
|
|
53
|
-
*/
|
|
54
|
-
async function scanOf(root: string): Promise<ScanResult> {
|
|
55
|
-
const written = join(root, '.fougere/scan.generated.ts');
|
|
56
|
-
const writtenAt = await stat(written).then((s) => s.mtimeMs).catch(() => 0);
|
|
57
|
-
if (writtenAt > 0 && writtenAt >= await newestDeclaration(root)) {
|
|
58
|
-
return ((await getModuleLoader()(written)) as unknown as { scan: ScanResult }).scan;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// The only slow phase, and it announced nothing: the boot states it at `info`, which the
|
|
62
|
-
// threshold above lowers to `warn`. The terminal says it instead, and a pipe keeps its
|
|
63
|
-
// output parsable.
|
|
64
|
-
const spin = process.stdout.isTTY ? terminal.spinner('reading fronds') : undefined;
|
|
65
|
-
const scan = await scanProject(root);
|
|
66
|
-
spin?.stop(`${scan.fronds.length} frond(s)`);
|
|
67
|
-
|
|
68
|
-
return scan;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const scan = await scanOf(cliRoot);
|
|
72
|
-
|
|
73
|
-
const app = await createApp({ scan, createContainer: () => container });
|
|
74
|
-
|
|
75
|
-
container.registerValue('app', app);
|
|
76
|
-
|
|
77
|
-
await run(app);
|
package/src/bridge.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { Lifecycle, Role } from '@fougere/schema';
|
|
2
|
-
/** Entity → citty bridge. */
|
|
3
|
-
import type { Fields } from '@fougere/schema';
|
|
4
|
-
import { Shapes, Visibility, type ShapeType } from '@fougere/schema';
|
|
5
|
-
import type { ArgsDef, ArgDef } from 'citty';
|
|
6
|
-
|
|
7
|
-
function toKebab(name: string): string {
|
|
8
|
-
return name.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase());
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* What a caller supplies: the fields the axes admit, or the PRIMARY when they admit nothing.
|
|
13
|
-
*
|
|
14
|
-
* `Visibility.input` answers who may WRITE a field, and a primary is the server's — right for a
|
|
15
|
-
* form, wrong for an operation whose whole input is `Product.pick('id')`. That contract asks the
|
|
16
|
-
* caller to NAME a row, and the axes leave it with no argument at all: `product:archive abc-9`
|
|
17
|
-
* answered `Unexpected argument`.
|
|
18
|
-
*
|
|
19
|
-
* Only when nothing else remains, so `create` over a full entity is untouched — its input holds
|
|
20
|
-
* twelve writable fields and the primary stays the server's.
|
|
21
|
-
*/
|
|
22
|
-
function suppliedIn(fields: Fields): Fields {
|
|
23
|
-
const written = Visibility.of(fields).input;
|
|
24
|
-
if (Object.keys(written).length > 0) return written;
|
|
25
|
-
|
|
26
|
-
return Object.fromEntries(
|
|
27
|
-
Object.entries(fields).filter(([, field]) => Role.of(field).isPrimary()),
|
|
28
|
-
) as Fields;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Convert an Entity's fields into citty args definition. */
|
|
32
|
-
export function entityToArgs(fields: Fields): ArgsDef {
|
|
33
|
-
const args: ArgsDef = {};
|
|
34
|
-
let positionalIndex = 0;
|
|
35
|
-
|
|
36
|
-
// The CLI additionally skips ALL relations: a ref is not a flag — supplying related rows is
|
|
37
|
-
// not a CLI gesture.
|
|
38
|
-
for (const [key, field] of Object.entries(suppliedIn(fields))) {
|
|
39
|
-
if (Role.of(field).isRelation()) continue;
|
|
40
|
-
|
|
41
|
-
// A `default(v)` travels as the create rule `{ value }` — citty shows it.
|
|
42
|
-
const defaultValue = Lifecycle.of(field).literal?.value;
|
|
43
|
-
const { base: shape, nullable } = Shapes.of(field.shape);
|
|
44
|
-
const type = Shapes.typeOf(field.shape);
|
|
45
|
-
// Naming a row is required by definition: a generator fills a primary the server writes,
|
|
46
|
-
// never one a caller hands in to designate.
|
|
47
|
-
const designates = Role.of(field).isPrimary();
|
|
48
|
-
const common = {
|
|
49
|
-
description: field.shape?.description,
|
|
50
|
-
required: designates || (!nullable && Lifecycle.of(field).requiredAtCreate()),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// A closed set is citty's `enum`: the shape already names the legal values, so the
|
|
54
|
-
// refusal and the `--help` listing come from the declaration rather than a check
|
|
55
|
-
// written beside it.
|
|
56
|
-
const options = shape && 'enum' in shape && shape.enum?.length
|
|
57
|
-
? shape.enum.filter((value) => value !== null).map(String)
|
|
58
|
-
: undefined;
|
|
59
|
-
// First required field becomes positional — but never a boolean, a closed set, or a
|
|
60
|
-
// date-time, which stay named flags.
|
|
61
|
-
const positional = positionalIndex === 0
|
|
62
|
-
&& common.required
|
|
63
|
-
&& key !== 'force'
|
|
64
|
-
&& options === undefined
|
|
65
|
-
&& type !== 'boolean'
|
|
66
|
-
&& type !== 'date';
|
|
67
|
-
if (positional) positionalIndex++;
|
|
68
|
-
|
|
69
|
-
args[toKebab(key) === key ? key : toKebab(key)] = argFor(
|
|
70
|
-
type,
|
|
71
|
-
common,
|
|
72
|
-
defaultValue,
|
|
73
|
-
options,
|
|
74
|
-
positional,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return args;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Which types carry a declared default onto the CLI. A `boolean` is answered above, with
|
|
83
|
-
* its own default; an `object` and an `array` are named and bare.
|
|
84
|
-
*/
|
|
85
|
-
const CARRIES_DEFAULT: Record<ShapeType, boolean> = {
|
|
86
|
-
number: true,
|
|
87
|
-
integer: true,
|
|
88
|
-
text: true,
|
|
89
|
-
date: true,
|
|
90
|
-
choice: true,
|
|
91
|
-
boolean: false,
|
|
92
|
-
object: false,
|
|
93
|
-
array: false,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/** One arg, built WITH its `type`. */
|
|
97
|
-
function argFor(
|
|
98
|
-
type: ShapeType | undefined,
|
|
99
|
-
common: { description?: string; required: boolean },
|
|
100
|
-
defaultValue: unknown,
|
|
101
|
-
options: string[] | undefined,
|
|
102
|
-
positional: boolean,
|
|
103
|
-
): ArgDef {
|
|
104
|
-
if (type === 'boolean') {
|
|
105
|
-
return defaultValue === undefined
|
|
106
|
-
? { ...common, type: 'boolean' }
|
|
107
|
-
: { ...common, type: 'boolean', default: defaultValue as boolean };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const withDefault = type && CARRIES_DEFAULT[type] && defaultValue !== undefined
|
|
111
|
-
? { default: String(defaultValue) }
|
|
112
|
-
: {};
|
|
113
|
-
|
|
114
|
-
if (options) return { ...common, ...withDefault, type: 'enum', options };
|
|
115
|
-
if (positional) return { ...common, ...withDefault, type: 'positional' };
|
|
116
|
-
|
|
117
|
-
return { ...common, ...withDefault, type: 'string' };
|
|
118
|
-
}
|
package/src/completion.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/** Shell completion generator — outputs a script for bash/zsh. */
|
|
2
|
-
import type { App } from '@fougere/core';
|
|
3
|
-
import { entityToArgs } from './bridge.js';
|
|
4
|
-
|
|
5
|
-
function toKebab(name: string): string {
|
|
6
|
-
return name.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase()).replace(/^-/, '');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** What a positional names, said by the field's own name — no table to keep in step. */
|
|
10
|
-
const NAMES: Record<string, 'operations' | 'fronds' | undefined> = {
|
|
11
|
-
operation: 'operations',
|
|
12
|
-
frond: 'fronds',
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
interface CommandMeta {
|
|
16
|
-
name: string;
|
|
17
|
-
flags: string[];
|
|
18
|
-
names?: 'operations' | 'fronds';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function extractCommandMeta(app: App): CommandMeta[] {
|
|
22
|
-
const commands: CommandMeta[] = [];
|
|
23
|
-
|
|
24
|
-
for (const frond of app.fronds) {
|
|
25
|
-
const handlerMap = new Map(frond.handlers.map((h) => [h.address, h]));
|
|
26
|
-
|
|
27
|
-
for (const entity of frond.entities) {
|
|
28
|
-
const handler = handlerMap.get(entity.name);
|
|
29
|
-
if (!handler) continue;
|
|
30
|
-
|
|
31
|
-
let facade: Record<string, Function>;
|
|
32
|
-
try { facade = app.resolve(handler.name); } catch { continue; }
|
|
33
|
-
if (typeof facade.execute !== 'function') continue;
|
|
34
|
-
|
|
35
|
-
// The same function the runner builds citty's args from, so the positional and the
|
|
36
|
-
// flags are the ones the command actually has.
|
|
37
|
-
const args = Object.entries(entityToArgs(entity.entityClass.getFields())) as
|
|
38
|
-
[string, { type?: string }][];
|
|
39
|
-
const positional = args.find(([, def]) => def.type === 'positional')?.[0];
|
|
40
|
-
|
|
41
|
-
commands.push({
|
|
42
|
-
name: toKebab(entity.name),
|
|
43
|
-
flags: args.filter(([, def]) => def.type !== 'positional').map(([key]) => `--${key}`),
|
|
44
|
-
...(positional && NAMES[positional] ? { names: NAMES[positional]! } : {}),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return commands;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function generateZshCompletion(app: App, binName = 'fougere'): string {
|
|
53
|
-
const commands = extractCommandMeta(app);
|
|
54
|
-
|
|
55
|
-
const valueCases = commands
|
|
56
|
-
.filter((cmd) => cmd.names)
|
|
57
|
-
.map((cmd) => ` ${cmd.name}) _${binName}_names ${cmd.names} ;;`)
|
|
58
|
-
.join('\n');
|
|
59
|
-
|
|
60
|
-
const flagCases = commands
|
|
61
|
-
.map((cmd) => ` ${cmd.name}) flags="${cmd.flags.join(' ')}" ;;`)
|
|
62
|
-
.join('\n');
|
|
63
|
-
|
|
64
|
-
return `# Auto-generated by @fougere/cli
|
|
65
|
-
|
|
66
|
-
# The project answers; a stale list in this file would not.
|
|
67
|
-
_${binName}_names() {
|
|
68
|
-
local -a values
|
|
69
|
-
values=(\${(f)"$(${binName} explain --names $1 2>/dev/null)"})
|
|
70
|
-
(( \${#values} )) && compadd -- \${values}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
_${binName}() {
|
|
74
|
-
local -a commands flags
|
|
75
|
-
commands=(${commands.map((c) => `'${c.name}'`).join(' ')})
|
|
76
|
-
|
|
77
|
-
if (( CURRENT == 2 )); then
|
|
78
|
-
_describe 'command' commands
|
|
79
|
-
return
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
local cmd=\${words[2]}
|
|
83
|
-
|
|
84
|
-
if [[ "\${words[CURRENT]}" != --* ]]; then
|
|
85
|
-
case "$cmd" in
|
|
86
|
-
${valueCases}
|
|
87
|
-
esac
|
|
88
|
-
return
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
case "$cmd" in
|
|
92
|
-
${flagCases}
|
|
93
|
-
*) flags="" ;;
|
|
94
|
-
esac
|
|
95
|
-
_values 'flags' \${(s: :)flags}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
compdef _${binName} ${binName}
|
|
99
|
-
`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function generateBashCompletion(app: App, binName = 'fougere'): string {
|
|
103
|
-
const commands = extractCommandMeta(app);
|
|
104
|
-
const cmdNames = commands.map((c) => c.name).join(' ');
|
|
105
|
-
|
|
106
|
-
const valueCases = commands
|
|
107
|
-
.filter((cmd) => cmd.names)
|
|
108
|
-
.map((cmd) => ` ${cmd.name}) names="${cmd.names}" ;;`)
|
|
109
|
-
.join('\n');
|
|
110
|
-
|
|
111
|
-
const flagCases = commands
|
|
112
|
-
.map((cmd) => ` ${cmd.name}) COMPREPLY=( $(compgen -W "${cmd.flags.join(' ')}" -- "\${cur}") ) ;;`)
|
|
113
|
-
.join('\n');
|
|
114
|
-
|
|
115
|
-
return `# Auto-generated by @fougere/cli
|
|
116
|
-
_${binName}_completions() {
|
|
117
|
-
local cur cmd names
|
|
118
|
-
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
119
|
-
cmd="\${COMP_WORDS[1]}"
|
|
120
|
-
|
|
121
|
-
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
122
|
-
COMPREPLY=( $(compgen -W "${cmdNames}" -- "\${cur}") )
|
|
123
|
-
return
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
if [[ "\${cur}" != --* ]]; then
|
|
127
|
-
names=""
|
|
128
|
-
case "$cmd" in
|
|
129
|
-
${valueCases}
|
|
130
|
-
esac
|
|
131
|
-
if [[ -n "\${names}" ]]; then
|
|
132
|
-
# The project answers; a stale list in this file would not.
|
|
133
|
-
COMPREPLY=( $(compgen -W "$(${binName} explain --names "\${names}" 2>/dev/null | tr '\\n' ' ')" -- "\${cur}") )
|
|
134
|
-
return
|
|
135
|
-
fi
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
case "$cmd" in
|
|
139
|
-
${flagCases}
|
|
140
|
-
esac
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
complete -F _${binName}_completions ${binName}
|
|
144
|
-
`;
|
|
145
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { run } from './runner.js';
|