depflow 3.0.0-dev.11 → 3.0.0-dev.12

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 CHANGED
@@ -1,236 +1,567 @@
1
- # DepFlow — Dependency Flow Manager
1
+ # DepFlow
2
2
 
3
- DepFlow is a focused dependency orchestration tool that lets projects consume Git repositories and NPM packages as managed dependencies. It simplifies building, extracting, and mapping artifacts into your application (for example, populating an `importmap` or TypeScript `paths`).
3
+ DepFlow turns Git repositories and NPM packages into managed dependencies of a project: it fetches
4
+ them into a single `.depflow` folder, runs a build pipeline over each one, and wires the resulting
5
+ artifacts into the project through path aliases. Those aliases are then written into a TypeScript
6
+ `tsconfig` and a browser `importmap`, and the built files can be rewritten to point either at the
7
+ local artifacts or at their CDN counterparts.
4
8
 
5
- Key goals:
6
- - Keep repository-sourced modules reproducible and buildable.
7
- - Provide automatic path/importmap resolution for browser and TypeScript workflows.
8
- - Support lightweight builder pipelines for extracted artifacts.
9
+ The configuration is a single **YAML** file, `depflow.yml` by default. JSON is supported as a
10
+ secondary format for tooling, and the two can be converted into each other from the CLI.
9
11
 
10
12
  ---
11
13
 
12
14
  ## Features
13
- - Git-based dependencies with optional build pipelines
14
- - NPM dependency extraction and local mirroring
15
- - Automatic `tsconfig` paths and browser `importmap` generation via `dep sync`
16
- - Flexible resolver aliases for local and CDN targets
17
- - Reproducible checkouts: every install lands on the tag the configuration asks for
15
+
16
+ - Git dependencies cloned at a pinned revision and rebuilt on demand.
17
+ - NPM dependencies installed into the flow folder and built the same way.
18
+ - Ordered build pipelines per dependency: run shell commands, extract files, transform content.
19
+ - A resolver that maps aliases to local and CDN targets.
20
+ - `tsconfig` `paths` and browser `importmap` generated from those aliases.
21
+ - Import rewriting of the built files, with a watch mode.
22
+ - Three run modes (`default`, `--verbose`, `--silent`) and optional decoration.
23
+ - An evidence trail: the complete output of every command is written under `.logs` in every mode.
24
+ - Named actions runnable with `dep run`.
25
+ - Configuration conversion between YAML and JSON.
18
26
 
19
27
  ---
20
28
 
21
29
  ## Installation
22
30
 
23
- Install globally with npm to use the CLI system-wide:
24
-
25
31
  ```bash
26
- npm install -g @netfeez/depflow
32
+ npm install -g depflow
27
33
  ```
28
34
 
29
- Alternatively, add it as a dev-dependency for project-specific usage.
35
+ Or add it as a project dev-dependency and invoke the `dep` binary from there.
30
36
 
31
37
  ---
32
38
 
33
39
  ## Quick Start
34
40
 
35
- 1. Create a configuration file, `depflow.yml` (or any other name, passed with `--flow`).
36
- 2. Run `dep install` to fetch and build all configured dependencies.
37
- 3. Run `dep sync` to update `tsconfig` paths and `importmap` (if configured).
41
+ ### Requirements
38
42
 
39
- CLI examples:
43
+ DepFlow is an ESM-only Node.js package (`"type": "module"`) and needs an LTS Node.js with native
44
+ ECMAScript module support. There is no CommonJS build. `git` and `npm` are used directly, so both
45
+ must be on `PATH` to install the corresponding kinds of dependency.
40
46
 
41
47
  ```bash
42
- # install the dependencies declared in depflow.yml
48
+ # 1. Create a configuration file (default name: depflow.yml)
49
+ # `dep add` creates it from the defaults and registers the first dependency.
50
+ dep add NetFeez/vizui
51
+
52
+ # 2. Fetch, build and extract every dependency, then synchronize the aliases
43
53
  dep install
44
- # --flow <file> to use a specific config instead
45
54
 
46
- # sync tsconfig/importmap from the configuration
47
- dep sync
55
+ # 3. Inspect what is declared and whether its files are in place
56
+ dep list
48
57
  ```
49
58
 
59
+ `dep install` runs `dep sync` on its own after fetching, so step 2 already writes the `tsconfig`
60
+ paths and the `importmap` when those files are configured.
61
+
50
62
  ---
51
63
 
52
64
  ## Configuration
53
65
 
54
- DepFlow uses a single configuration file describing where to fetch dependencies and how to build and expose them. The format follows the extension: `.yml` and `.yaml` are read and written as YAML, `.json` as JSON. Without `--flow`, the CLI reads `depflow.yml` from the current working directory.
55
-
56
- A YAML config is read as a document, so key order, indentation and the comments of the keys a save does not touch are preserved; a config created from scratch is written in block style, documented with a comment per key, and accompanied by an editor JSON Schema at `.depflow/schema.json`.
57
-
58
- The minimal structure:
59
-
60
- - `outDir` (string): project output root scanned by `rewrite-paths` (and by the watcher). Defaults to `dist`. Extraction targets are *not* relative to it, they are relative to the project root, see [Builder rules](#builder-rules).
61
- - `tsconfig` (string|null): optional path to TypeScript `tsconfig.json` to update `compilerOptions.paths`.
62
- - `importmap` (string|null): optional path to write a browser `importmap`.
63
- - `actions` (object): named pipelines runnable with `dep run <action>`.
64
- - `dependencies` (array): Git-based dependencies.
65
- - `npmDependencies` (array): NPM packages to extract files from.
66
-
67
- Each dependency supports `builder` steps (run commands, file extraction, content transformation) and `resolver` entries that map aliases to local or CDN targets.
68
-
69
- ### Example Configuration
70
-
71
- Shown as JSON, which the CLI reads and writes just as well as YAML whenever the file is named `.json`. The extraction targets are shown as absolute paths, which is the only form that survives being copied between machines: a relative one is resolved against the project root, the same as every other relative path of the configuration.
72
-
73
- ```json
74
- {
75
- "outDir": ".",
76
- "tsconfig": "tsconfig.web.json",
77
- "importmap": "public/importmap.json",
78
- "dependencies": [
79
- {
80
- "name": "NetFeez.Vizui",
81
- "repo": "https://github.com/NetFeez/Vizui.git",
82
- "tag": "v1.2.0",
83
- "builder": [
84
- {
85
- "run": [ "npm install", "npm run compile" ]
86
- },
87
- {
88
- "extract": {
89
- "build/**/*.js": { "to": "/abs/path/to/app/public/lib/vizui/", "map": "^build/" },
90
- "build/**/*.d.ts": { "to": "/abs/path/to/app/public/lib/vizui/", "map": "^build/" }
91
- }
92
- }
93
- ],
94
- "resolver": {
95
- "vizui": "public/lib/vizui/vizui.js",
96
- "vizui/*": "public/lib/vizui/*"
97
- }
98
- }
99
- ],
100
- "npmDependencies": [
101
- {
102
- "name": "@netfeez/common",
103
- "version": "latest",
104
- "builder": [
105
- {
106
- "extract": {
107
- "build/**/*.js": { "to": "/abs/path/to/app/public/lib/common/", "map": "^build/" },
108
- "build/**/*.d.ts": { "to": "/abs/path/to/app/public/lib/common/", "map": "^build/" }
109
- }
110
- }
111
- ],
112
- "resolver": {
113
- "@netfeez/common": "public/lib/common/index.js",
114
- "@netfeez/common/*": "public/lib/common/*"
115
- }
116
- }
117
- ]
118
- }
66
+ DepFlow reads a single configuration file. Its format is chosen by extension:
67
+
68
+ | Extension | Format | Notes |
69
+ |---|---|---|
70
+ | `.yml`, `.yaml` | YAML | The default. The document is preserved across saves. |
71
+ | `.json` | JSON | Secondary format, read and written just as well. |
72
+
73
+ Without `--flow`, the CLI reads `depflow.yml` from the current working directory. The directory that
74
+ holds the configuration file is the **project root**: every relative path of the configuration is
75
+ resolved against it.
76
+
77
+ A YAML config is handled as a document, so key order, indentation and the comments of keys a save
78
+ does not touch survive a round trip. A config created from scratch is written in block style with the
79
+ file header and one comment per key, taken from the schema descriptions, so a generated file
80
+ documents itself.
81
+
82
+ The YAML dialect DepFlow reads is block style: non-empty flow collections (`[ ... ]` and `{ ... }`)
83
+ are not supported and are reported as an error when the file is loaded. Write lists and maps as
84
+ indented blocks; the empty `{}` and `[]` the generated file uses are fine. Use JSON if a
85
+ flow-style document is a hard requirement, or let `dep yaml-to-json` produce one.
86
+
87
+ Whenever the config is saved, DepFlow also refreshes the editor JSON Schema at `.depflow/schema.json`
88
+ and points `$schema` at it, which gives validation and autocompletion in editors that understand JSON
89
+ Schema.
90
+
91
+ ### Generated configuration
92
+
93
+ A freshly generated `depflow.yml` looks like this:
94
+
95
+ ```yaml
96
+ # Depflow Configuration File
97
+ # You can use the Red Hat extension for JSON schema validation in VSCode: "$schema: .depflow/schema.json"
98
+
99
+
100
+ # Path to the JSON Schema describing the configuration. Used by editors and tools to provide validation, autocompletion and other features.
101
+ $schema: .depflow/schema.json
102
+ # Output directory for built files. Can be relative or absolute. Defaults to "dist".
103
+ outDir: dist
104
+ # Path to the tsconfig.json file. Can be relative or absolute. Defaults to "tsconfig.json".
105
+ tsconfig: null
106
+ # Path to the importmap.json file. Can be relative or absolute. Defaults to "importmap.json".
107
+ importmap: null
108
+ # Named build actions. Each action runs a pipeline of run, extract and transform steps.
109
+ actions: {}
110
+ # Mapping of dependency names to their resolution targets (local file or CDN). Paths are resolved relative to this folder.
111
+ resolver: {}
112
+ # Git dependencies to clone and build, each an object with a name and a repo.
113
+ dependencies: []
114
+ # NPM dependencies to install and build, each an object with a name and a version.
115
+ npmDependencies: []
116
+ ```
117
+
118
+ ### Top-level keys
119
+
120
+ | Key | Type | Default | Meaning |
121
+ |---|---|---|---|
122
+ | `$schema` | string | `.depflow/schema.json` | Path to the JSON Schema used by editors. Refreshed on every save. |
123
+ | `outDir` | string | `dist` | Output root scanned by `rewrite-paths` and its watcher. Relative or absolute. |
124
+ | `tsconfig` | string \| null | `null` | Path to a `tsconfig.json` whose `compilerOptions.paths` `sync` updates. When `null`, synchronization of the tsconfig is skipped. |
125
+ | `importmap` | string \| null | `null` | Path to an `importmap.json` that `sync` writes. When `null`, synchronization of the import map is skipped. |
126
+ | `actions` | object | `{}` | Named build pipelines runnable with `dep run <action>`. |
127
+ | `resolver` | object | `{}` | Aliases shared by the whole project, merged with each dependency's own `resolver`. |
128
+ | `dependencies` | array | `[]` | Git dependencies. |
129
+ | `npmDependencies` | array | `[]` | NPM dependencies. |
130
+
131
+ Streaming collections default to a fresh empty value on every load, so a processed document never
132
+ shares state with the schema.
133
+
134
+ ### Dependencies
135
+
136
+ A **git dependency** is cloned into `.depflow/<user>/<repo>` and rebuilt from its `tag` on every install:
137
+
138
+ ```yaml
139
+ dependencies:
140
+ - name: NetFeez/vizui
141
+ repo: https://github.com/NetFeez/vizui.git
142
+ tag: main
143
+ builder: []
144
+ resolver: {}
119
145
  ```
120
146
 
147
+ | Key | Type | Default | Meaning |
148
+ |---|---|---|---|
149
+ | `name` | string | — (required) | Identity of the dependency. See [Dependency identity](#dependency-identity). |
150
+ | `repo` | string | — (required) | Any value `git clone` accepts, always ending in `.git`. |
151
+ | `tag` | string | `main` | Tag, branch or commit the checkout is left on. |
152
+ | `builder` | array | `[]` | Build pipeline applied after cloning. |
153
+ | `resolver` | object | `{}` | Aliases contributed by this dependency. |
154
+
155
+ An **NPM dependency** is installed into `.depflow/node_modules/<name>` and built the same way:
156
+
157
+ ```yaml
158
+ npmDependencies:
159
+ - name: "@netfeez/common"
160
+ version: latest
161
+ builder: []
162
+ resolver: {}
163
+ ```
164
+
165
+ | Key | Type | Default | Meaning |
166
+ |---|---|---|---|
167
+ | `name` | string | — (required) | Package name, optionally scoped. |
168
+ | `version` | string | — (required) | Version or semver range to install. |
169
+ | `builder` | array | `[]` | Build pipeline applied after installing. |
170
+ | `resolver` | object | `{}` | Aliases contributed by this dependency. |
171
+
172
+ Git dependencies are installed before NPM dependencies.
173
+
121
174
  ### Dependency identity
122
175
 
123
- The `name` of a dependency is its identity, not a path: it is a single path segment, and it is also the
124
- name of its checkout folder inside `.depflow`. A name may not be a path, may not start with a dot, and may
125
- not be one of the names the flow folder reserves for itself (`schema.json` and `node_modules`).
176
+ The `name` of a dependency is an identity, not an arbitrary path:
177
+
178
+ - A git name is a `<user>/<repo>` pair or a **single path segment** (letters, digits, `.`, `_`, `-`),
179
+ and it is also the path of its checkout folder inside `.depflow`. It may not lead with
180
+ `schema.json` or `node_modules`, the two names the flow folder reserves for itself, and it is at
181
+ most one `/`.
182
+ - An NPM name is a package name, optionally scoped (`@scope/name`).
126
183
 
127
- The `repo` of a git dependency is any value `git clone` accepts: a URL with its scheme, an SSH address or a
128
- local path of a repository. It always carries the `.git` suffix, whichever transport it comes in. `tag` is the
129
- revision the checkout lands on after cloning and after every reinstall; it defaults to `main`.
184
+ The name of a git dependency can be derived from its repository only when that repository is a GitHub
185
+ one, where it becomes `<user>/<repo>` (for example `NetFeez/vizui`). For any other repository the
186
+ name has to be given explicitly to `dep add`.
130
187
 
131
- ### Builder rules
188
+ `dep add` accepts a GitHub repository written in any of its usual forms, canonicalizes it to the
189
+ repository git clones from, always ending in `.git`, and derives the name from it when no name is
190
+ given:
132
191
 
133
- A pipeline is an ordered list of steps, each of them exactly one of:
192
+ ```bash
193
+ dep add netfeez/vizui # https://github.com/netfeez/vizui.git, name netfeez/vizui
194
+ dep add https://github.com/netfeez/vizui # https://github.com/netfeez/vizui.git, name netfeez/vizui
195
+ dep add https://github.com/netfeez/vizui.git # https://github.com/netfeez/vizui.git, name netfeez/vizui
196
+ dep add git@github.com:/netfeez/vizui # git@github.com:netfeez/vizui.git, name netfeez/vizui
197
+ ```
134
198
 
135
- - `run`: a string or a list of shell commands executed inside the dependency checkout. It accepts
136
- `maxTimeMs` (deadline in milliseconds, `-1` for no deadline, defaults to `60000`) and `allowFails`
137
- (whether a failed command is tolerated, defaults to `false`).
138
- - `extract`: a mapping of source globs to extraction entries, or a destination folder as a shorthand for
139
- `**/*` → that folder. The globs are matched against the folder the pipeline works in (the dependency
140
- checkout, or the project itself for a `dep run` action) and an entry is a destination (`to`) plus,
141
- optionally, a `map` transformation applied to the destination path and a `transform` transformation
142
- applied to the content of the files. A relative `to` is resolved against the project root and an
143
- absolute one is used as it stands, so a pipeline reads from the dependency and deposits into the
144
- project. `map` runs against the *relative* path of the matched file, inside the destination.
145
- - `transform`: a `glob` plus a `search`/`replace` transformation applied in place to the matched files.
199
+ ### Build pipelines
146
200
 
147
- Every transformation (`map`, `transform`, and the in-place `transform` step) takes one of two forms, and
148
- they do not mean the same thing:
201
+ The `builder` of a dependency, and each entry of a named `action`, is an ordered list of steps. Every
202
+ step is an object carrying exactly one of `run`, `extract` or `transform`. A step that fails without
203
+ tolerating its failures stops the pipeline, and the steps after it are reported as steps that never
204
+ ran.
149
205
 
150
- - a **string** is a pattern to *remove*: `"^build/"` strips that prefix from the path of every matched
151
- file, globally;
152
- - an **object** `{ "search": ..., "flags": ..., "replace": ... }` is the only form that *substitutes*
153
- something: `search` is the pattern, `replace` what takes its place, and `flags` defaults to `g`.
206
+ **`run`** executes one shell command, or a list of them, in the pipeline's working directory, which is
207
+ the dependency checkout for an install and the project root for a `dep run` action:
208
+
209
+ ```yaml
210
+ builder:
211
+ - run: npm run build
212
+ - run:
213
+ - npm ci
214
+ - npm run compile
215
+ maxTimeMs: 120000
216
+ allowFails: false
217
+ ```
154
218
 
155
- ```json
156
- { "map": "^build/" }
157
- { "map": { "search": "^build/(.*)\\.js$", "replace": "$1.js" } }
219
+ | Key | Type | Default | Meaning |
220
+ |---|---|---|---|
221
+ | `run` | string \| string[] | — (required) | Command or commands to execute, in order. |
222
+ | `maxTimeMs` | number | `60000` | Deadline for the whole step in milliseconds. `-1` disables the limit. |
223
+ | `allowFails` | boolean | `false` | Whether a failed command is tolerated, so the step completes anyway. |
224
+
225
+ **`extract`** copies files matched by source globs from the working directory into a destination:
226
+
227
+ ```yaml
228
+ builder:
229
+ - extract:
230
+ "build/**/*.js":
231
+ to: dist/vizui
232
+ map: "^build/"
233
+ "build/**/*.d.ts":
234
+ to: dist/vizui
235
+ map: "^build/"
158
236
  ```
159
237
 
160
- An object whose `replace` is empty removes the matches exactly as the string form does.
238
+ The `extract` value is either a mapping of glob → entry, or a single string used as a shorthand for
239
+ extracting every file (`**/*`) into that folder. Each entry is:
240
+
241
+ | Key | Type | Meaning |
242
+ |---|---|---|
243
+ | `to` | string — required | Destination folder. A relative path is resolved against the project root; an absolute one is used as it stands. |
244
+ | `map` | transform | Transformation applied to the destination path of each file, relative to the working directory. |
245
+ | `transform` | transform | Transformation applied to the content of each file. |
246
+
247
+ **`transform`** applies a search/replace transformation in place to every file matched by a glob:
248
+
249
+ ```yaml
250
+ builder:
251
+ - transform:
252
+ glob: "build/**/*.js"
253
+ search: "process\\.env\\.NODE_ENV"
254
+ replace: "\"production\""
255
+ flags: g
256
+ ```
257
+
258
+ ### Transformations
259
+
260
+ `map`, the `transform` of an extraction entry and the in-place `transform` step all accept one of two
261
+ forms, and they do not mean the same thing:
262
+
263
+ - a **string** is a pattern whose matches are **removed**. `"^build/"` strips that prefix from every
264
+ matched path.
265
+ - an **object** is the only form that **substitutes**: `search` is the pattern, `replace` what takes
266
+ its place, and `flags` (default `g`) is applied to the regular expression. An object with an empty
267
+ or absent `replace` removes the matches, exactly as the string form does.
268
+
269
+ ```yaml
270
+ map: "^build/"
271
+ transform:
272
+ search: "^\\.\\/(.*)$"
273
+ replace: "$1"
274
+ flags: g
275
+ ```
161
276
 
162
277
  ### Resolver entries
163
278
 
164
- The `resolver` of a dependency, and the `resolver` of the configuration, are mappings of an alias to its
165
- target. The target is either a string path or an object with these keys:
279
+ The `resolver` of the project and the `resolver` of a dependency are mappings of an alias to its
280
+ target. The target is either a plain string path or an object:
281
+
282
+ ```yaml
283
+ resolver:
284
+ "@utils": src/utils
285
+ "@app/*": src/app
286
+ "@vizui":
287
+ local: dist/vizui/index.js
288
+ type: /abs/path/types/vizui.d.ts
289
+ cdn: https://cdn.example.com/vizui/index.js
290
+ ```
291
+
292
+ | Key | Type | Meaning |
293
+ |---|---|---|
294
+ | `local` | string — required | The path the alias resolves to, resolved against the project root. `sync` turns it into the `tsconfig` `paths` entry and the `importmap` entry, and `rewrite-paths` rewrites imports that point at it. With `--cdn`, an alias that also declares a `cdn` target uses it instead. |
295
+ | `type` | string | The target holding the type declarations. It becomes the **first** entry of the generated `paths` array, so the editor finds the `.d.ts`. Unlike `local`, it is not resolved against the project root, so it has to be an absolute path. |
296
+ | `cdn` | string | The URL that replaces `local` when `--cdn` is given. |
297
+
298
+ An alias ending in `/` or `/*` is a **wildcard** alias: `@app/*` also covers `@app/Button`. Dependency
299
+ resolvers are compiled before the project resolver, so a project entry with the same alias wins.
300
+
301
+ ### Named actions
302
+
303
+ `actions` maps a name to a list of `run`, `extract` and `transform` steps, run in the project root by
304
+ `dep run <name>`:
305
+
306
+ ```yaml
307
+ actions:
308
+ build:
309
+ - run: npm run build
310
+ - extract:
311
+ "dist/**/*.js":
312
+ to: public/lib
313
+ map: "^dist/"
314
+ lint:
315
+ - run: npm run lint
316
+ - run: npm run typecheck
317
+ ```
166
318
 
167
- - `local` (string, required): the path the alias resolves to, resolved against the project root. `sync`
168
- turns it into the `tsconfig` `paths` entry (and into the `importmap` entry unless `--cdn` is given),
169
- and `rewrite-paths` rewrites the built files' imports that point at it.
170
- - `type` (string, optional): the target holding the type declarations. It becomes the *first* entry of
171
- the generated `paths` array, so the editor finds the `.d.ts` next to the value. Unlike `local`, it is
172
- not resolved against the project root, so it has to be an absolute path.
173
- - `cdn` (string, optional): the URL that replaces `local` when `--cdn` is given.
319
+ ### Full example
320
+
321
+ ```yaml
322
+ $schema: .depflow/schema.json
323
+ outDir: dist
324
+ tsconfig: tsconfig.json
325
+ importmap: public/importmap.json
326
+
327
+ resolver:
328
+ "@app/*": src/app
329
+
330
+ actions:
331
+ build:
332
+ - run: npm run build
333
+
334
+ dependencies:
335
+ - name: NetFeez/vizui
336
+ repo: https://github.com/NetFeez/vizui.git
337
+ tag: v1.2.0
338
+ builder:
339
+ - run:
340
+ - npm ci
341
+ - npm run compile
342
+ - extract:
343
+ "build/**/*.js":
344
+ to: public/lib/vizui
345
+ map: "^build/"
346
+ "build/**/*.d.ts":
347
+ to: public/lib/vizui
348
+ map: "^build/"
349
+ resolver:
350
+ "@vizui": public/lib/vizui/vizui.js
351
+ "@vizui/*": public/lib/vizui
352
+
353
+ npmDependencies:
354
+ - name: "@netfeez/common"
355
+ version: latest
356
+ builder:
357
+ - extract:
358
+ "build/**/*.js":
359
+ to: public/lib/common
360
+ map: "^build/"
361
+ resolver:
362
+ "@netfeez/common": public/lib/common/index.js
363
+ "@netfeez/common/*": public/lib/common
364
+ ```
365
+
366
+ The same configuration can be kept as JSON when the file is named `.json`. The command reads the
367
+ config named by `--flow` (default `depflow.yml`) and writes a sibling file; its optional positional
368
+ argument is the **output** path, not the input:
174
369
 
175
- A `*` suffix on the alias turns it into a mapping, so `vizui/*` also covers `vizui/Button`.
370
+ ```bash
371
+ dep yaml-to-json # reads depflow.yml, writes depflow.json
372
+ dep json-to-yaml --flow depflow.json # reads depflow.json, writes depflow.yaml
373
+ dep yaml-to-json build/depflow.json # reads depflow.yml, writes build/depflow.json
374
+ ```
176
375
 
177
376
  ---
178
377
 
179
378
  ## CLI Reference
180
379
 
181
- Use the distribution script in `dist/cli/bin.js` or install the package globally.
182
-
183
- - `install`: Clone, build and extract artifacts for all dependencies in your config.
184
- - `sync`: Generate/update `tsconfig` paths and browser `importmap` according to `resolver` entries.
185
- - `list`: Show configured dependencies and whether each one is installed.
380
+ ```
381
+ dep <command> [arguments] [flags]
382
+ ```
186
383
 
187
- Use `node ./dist/cli/bin.js <command> --flow <config>` when running locally from the repository.
384
+ The **first token is always the command name**; global flags are parsed from the tokens that follow
385
+ it. `dep --flow x install` is read as the command `--flow`, so flags belong after the command:
386
+ `dep install --flow x`.
188
387
 
189
388
  ### Commands
190
389
 
191
- The CLI exposes the following commands (all commands accept the global `--flow <file>` flag to specify a custom configuration file):
192
-
193
390
  | Command | Usage | Description |
194
391
  |---|---|---|
195
- | `add` | `dep add <repo_url> [name] [--flow <file>]` | Add a git dependency to the configuration file. If the configuration file does not exist it will be created automatically, in the format its extension asks for (default: `depflow.yml`). When the name is omitted it is derived from the repository, which only a GitHub repository allows; any other repository needs the name to be given. A name already taken by another dependency is refused. |
196
- | `remove` | `dep remove <name\|repo_url> [--flow <file>]` | Remove a dependency by `name` or repository URL and uninstall its local files. An identifier that no dependency declares is an error. |
197
- | `install` | `dep install [name1 name2 ...] [--flow <file>]` | Clone, build and extract artifacts for all or specific dependencies. Runs `dep sync` after install. A dependency that is already present is brought to the revision of its `tag` instead of being cloned again. |
198
- | `list` | `dep list [--flow <file>]` | List all dependencies declared in the configuration, telling an `installed` one (its folder is in place under `.depflow`) from a `missing` one. |
199
- | `rewrite-paths` | `dep rewrite-paths [--watch] [--cdn] [--flow <file>]` | Rewrite built files' paths according to resolver aliases. Use `--watch` to run a watcher; use `--cdn` to apply CDN targets instead of local targets. A built file that cannot be rewritten makes the command fail instead of being left pointing at the source tree. |
200
- | `sync` | `dep sync [--cdn] [--flow <file>]` | Update `tsconfig` paths and generate `importmap` from resolver aliases. Use `--cdn` to prefer CDN targets when generating the importmap. |
392
+ | `add` | `dep add <repo> [name] [--tag <ref>]` or `dep add --npm <name>[@<version>]` | Add a dependency to the configuration, creating the file from the defaults if it does not exist. A git repository may be given as `user/repo`, as an HTTP(S) URL or as an ssh address, with or without the `.git` suffix; it is canonicalized to the URL git clones from, and its name is derived from it when omitted, which only a GitHub repository allows. `--tag` sets the tag, branch or commit it is checked out at (default `main`). With `--npm` the argument is an npm package `<name>[@<version>]`, defaulting to `latest`, registered under `npmDependencies`. A name already taken is refused. |
393
+ | `remove` | `dep remove <name\|repo_url>` | Remove a dependency by name (git or npm) or by git repository URL, and uninstall its local files. An identifier no dependency declares is an error. |
394
+ | `install` | `dep install [name...]` | Fetch, build and extract every dependency, or only the named ones. A checkout already in place is updated to its `tag` instead of cloned again. Runs `sync` afterwards. |
395
+ | `run` | `dep run <action>` | Run a named action from `actions`, in the project root. |
396
+ | `list` | `dep list` | List the declared dependencies, marking each one `installed` or `missing`. |
397
+ | `rewrite-paths` | `dep rewrite-paths [--watch] [--cdn]` | Rewrite import specifiers in the built files of `outDir` according to the resolver. A file that cannot be rewritten fails the command. |
398
+ | `sync` | `dep sync [--cdn]` | Write the resolver aliases into the configured `tsconfig` and `importmap`. |
399
+ | `resolver` | `dep resolver add <alias> <local> [--type <t>] [--cdn-url <url>] [--force] \| remove <alias> \| list \| clear` | Edit the resolver aliases. Without `--dep` the project resolver is edited; with it, the named dependency's own resolver. `add` refuses an alias already taken unless `--force` is given. |
400
+ | `builder` | `dep builder add <run\|extract\|transform> ... \| remove <index> \| move <from> <to> \| list \| clear` | Edit the build pipeline of the dependency named by `--dep` or of the action named by `--action`. `add run` takes one or more commands (`--max-time`, `--allow-fails`); `add extract` takes a glob (`--to`, `--map`); `add transform` takes a glob (`--search`, `--replace`, `--flags`). `--index` chooses where the step is inserted. |
401
+ | `action` | `dep action create <name> \| remove <name> \| list` | Create, remove or list the named actions of the configuration. A new action starts empty and is filled through `builder --action`. |
402
+ | `config` | `dep config get [key] \| set <key> <value> \| unset <key>` | Read and edit the top-level settings `outDir`, `tsconfig` and `importmap`. `set` accepts `null` for the nullable ones; `outDir` cannot be unset. |
403
+ | `json-to-yaml` | `dep json-to-yaml [output.yaml]` | Convert the config to YAML. The output name is derived from the input name when omitted. |
404
+ | `yaml-to-json` | `dep yaml-to-json [output.json]` | Convert the config to JSON. The output name is derived from the input name when omitted. |
405
+
406
+ ### Console commands
407
+
408
+ The CLI is built on a small console interface that also carries two commands:
409
+
410
+ | Command | Description |
411
+ |---|---|
412
+ | `dep help` | Print the global flags and every command, with its usage, description and arguments. The help is written by the terminal and is left untouched by `--silent` and `--decorate=false`. |
413
+ | `dep exit` | Leave the process. |
414
+
415
+ This build does not drive that interface interactively: the first token of an invocation is always
416
+ taken as the command name, so an empty invocation is reported as an unknown command and the help is
417
+ printed rather than a prompt being opened.
201
418
 
202
419
  ### Flags
203
420
 
204
- - `--flow <file>` / `-f <file>` / `-p <file>`: Specify an alternate configuration file (for example `depflow.json` or `depflow.yaml`). When omitted, the CLI uses `depflow.yml` in the current working directory; any other file has to be named here.
205
- - `--cdn`: When present for `sync` or `rewrite-paths`, instructs the tool to use CDN targets from resolver entries instead of `local` targets when generating the `importmap` or rewriting paths.
206
- - `--watch` / `-w`: For `rewrite-paths` only — run a file watcher that keeps rewriting paths as files change.
421
+ These are the global flags: every command accepts all of them.
422
+
423
+ | Flag | Aliases | Default | Description |
424
+ |---|---|---|---|
425
+ | `--flow <file>` | `-p`, `-f` | `depflow.yml` | Configuration file the command operates on. |
426
+ | `--cdn` | — | `false` | Resolve to CDN targets instead of local ones (for `sync` and `rewrite-paths`). |
427
+ | `--watch` | `-w` | `false` | Keep watching the built files and rewriting their paths on every change (`rewrite-paths`). |
428
+ | `--verbose` | `-v` | `false` | Stream the output of every command as it runs, attributed to the command that wrote it. |
429
+ | `--silent` | — | `false` | Say only what failed, one line per failed command. |
430
+ | `--decorate` | — | `true` | Draw boxes, indentation, timestamps, levels and names. Use `--decorate=false` to leave the content alone. |
431
+
432
+ Beside the global ones, an editing command declares the flags it owns. A flag is only accepted by the
433
+ command that declares it: `dep install --to x` is answered with `Unknown flag: --to`, and the help
434
+ lists the owned flags under their command.
435
+
436
+ | Command | Flag | Aliases | Default | Description |
437
+ |---|---|---|---|---|
438
+ | `add` | `--npm` | — | `false` | Add an npm dependency instead of a git one. |
439
+ | `add` | `--tag <ref>` | — | `main` | Tag, branch or commit the added git dependency is checked out at. |
440
+ | `resolver` | `--dep <name>` | — | — | Dependency whose resolver is edited. Omitted, the project resolver is edited. |
441
+ | `resolver` | `--type <type>` | — | — | Type identifier of a resolver target, set alongside its local path. |
442
+ | `resolver` | `--cdnUrl <url>` | `--cdn-url` | — | CDN URL of a resolver target, set alongside its local path. |
443
+ | `resolver` | `--force` | — | `false` | Overwrite an existing resolver alias instead of failing. |
444
+ | `builder` | `--dep <name>` | — | — | Dependency whose build pipeline is edited. |
445
+ | `builder` | `--action <name>` | — | — | Action whose build pipeline is edited. |
446
+ | `builder` | `--to <dir>` | — | — | Destination folder of an extract build step. |
447
+ | `builder` | `--map <pattern>` | — | — | Pattern applied to the destination path of an extract build step. |
448
+ | `builder` | `--search <regex>` | — | — | Regular expression a transform build step searches for. |
449
+ | `builder` | `--replace <text>` | — | — | Replacement string of a transform build step. |
450
+ | `builder` | `--flags <flags>` | — | `g` | Flags of the regular expression of a transform build step. |
451
+ | `builder` | `--maxTime <ms>` | `--max-time` | `60000` | Maximum execution time of a run build step; `-1` disables the limit. |
452
+ | `builder` | `--allowFails` | `--allow-fails` | `false` | Whether the commands of a run build step may fail. |
453
+ | `builder` | `--index <n>` | — | end | Position at which a build step is inserted. |
454
+
455
+ Flag parsing rules:
456
+
457
+ - A flag is the whole token; short clusters are not expanded (`-abc` is the single flag `-abc`).
458
+ - Names are matched with or without their dash prefix, so `-f` and `--flow` reach the same flag.
459
+ - A value flag takes the next token as its value when that token is not a flag, or an inline value as
460
+ `--flag=value`. A boolean flag never consumes the next token and only accepts `=true` or `=false`,
461
+ so the undecorated form is `--decorate=false`.
462
+ - The last occurrence of a flag wins, `--` ends the flags and turns every remaining token into a
463
+ positional argument, and an undeclared flag is an error.
207
464
 
208
- Every token starting with a dash is a flag, and a flag is the whole token, so short clusters are not expanded (`-abc` is the single flag `-abc`, not `-a -b -c`). A value flag takes the value from the next token when that token is not a flag, or written inline as `--flag=value`; a boolean flag never consumes the next token and only accepts `=true` or `=false` inline. Names are matched with or without their dash prefix, so `-f` and `--flow` reach the same flag. The last occurrence of a flag wins, `--` ends the flags and turns the remaining tokens into positional arguments, and an undeclared flag is reported as an error.
465
+ ```bash
466
+ dep install --flow .df.yml
467
+ dep sync --flow .df.yml --cdn
468
+ dep rewrite-paths --flow .df.yml --watch
469
+ dep run build --decorate=false
470
+ ```
209
471
 
210
- Examples:
472
+ ---
211
473
 
212
- ```bash
213
- # install using custom flow file
214
- dep install --flow .df.json
474
+ ## Run Modes and the Evidence Trail
215
475
 
216
- # sync using CDN targets for importmap
217
- dep sync --flow .df.json --cdn
476
+ Every command a run executes writes its **complete** output to
218
477
 
219
- # rewrite paths and start watcher (local targets)
220
- dep rewrite-paths --flow .df.json --watch
478
+ ```
479
+ .logs/{YYYY}.{MM}.{DD}/[name] {HH}.{mm}.{ss}.{ms}.vlog
221
480
  ```
222
481
 
482
+ under the working directory, whatever the mode. The file keeps the format tokens of the logger, so it
483
+ is a complete transcript of the run. What a mode changes is how much of that output reaches the
484
+ screen:
485
+
486
+ | Mode | Flags | What it shows |
487
+ |---|---|---|
488
+ | Default | *(none)* | One result line per command, and the complete output of a command that failed, under its diagnostic. |
489
+ | Verbose | `--verbose` / `-v` | Every line of every command as it comes, each attributed to the command that wrote it. The buffer is not repeated. |
490
+ | Silent | `--silent` | One line per failed command, and nothing else. |
491
+
492
+ `--silent` wins over `--verbose` when both are given. `--decorate=false` combines with any mode to
493
+ drop the boxes, indentation, timestamps, levels and names, keeping the color of the markers and the
494
+ diagnostics, which carry information.
495
+
496
+ Commands that are not part of a pipeline (the git and npm acquisition of a dependency) are reported
497
+ as `C<M>`; the commands inside a pipeline with more than one `run` step are qualified as
498
+ `S<N> · C<M>`, so a command identity is never ambiguous.
499
+
223
500
  ---
224
501
 
225
- ## Build steps in depth
502
+ ## How `sync` and `rewrite-paths` Work
503
+
504
+ `sync` compiles the resolver into aliases and writes them to the configured files:
505
+
506
+ - the **tsconfig** `compilerOptions.paths` receives one entry per alias, always pointing at the local
507
+ target. A wildcard alias becomes `<alias>/*`. When a target declares a `type`, the type path is the
508
+ first element of the array and the local path the second.
509
+ - the **importmap** `imports` receives one entry per alias. A wildcard alias's key keeps a trailing
510
+ `/`. Local targets are written relative to the directory of the importmap file. With `--cdn`, an
511
+ alias that declares a `cdn` target uses it; the others keep their local path. Existing `scopes` are
512
+ preserved.
513
+
514
+ `rewrite-paths` scans `outDir` for files ending in `.js`, `.ts`, `.jsx`, `.tsx`, `.cjs` or `.mjs`
515
+ and rewrites every `from '...'` specifier whose module path matches an alias:
226
516
 
227
- A `run` step is the only place where a shell script is interpreted, and it is where the failure semantics
228
- live:
517
+ - in **local** mode the specifier becomes a path relative to the file, written with `/` separators.
518
+ - in **cdn** mode an alias that declares a `cdn` target resolves to that URL; the rest keep their
519
+ local relative path.
520
+
521
+ Only `from '...'` specifiers are rewritten; a bare side-effect import such as `import './x'` is not
522
+ touched. `--watch` rewrites once and then keeps rewriting as files change.
523
+
524
+ ---
525
+
526
+ ## Project Layout
527
+
528
+ ```text
529
+ <project root>/
530
+ ├── depflow.yml # the configuration (any name, passed with --flow)
531
+ ├── .depflow/ # the flow folder, owned by DepFlow
532
+ │ ├── <user>/<repo>/ # one checkout per git dependency
533
+ │ ├── node_modules/ # npm dependencies, installed here and not in the project's
534
+ │ └── schema.json # the editor JSON Schema, refreshed on every config save
535
+ ├── <outDir>/ # the built files rewrite-paths scans (default: dist)
536
+ └── .logs/ # the evidence trail, under the working directory
537
+ └── {YYYY}.{MM}.{DD}/
538
+ └── [name] {HH}.{mm}.{ss}.{ms}.vlog
539
+ ```
540
+
541
+ The project root is the directory of the configuration file. The flow folder is reserved for
542
+ DepFlow: a dependency name may not lead with `schema.json` or `node_modules`, may not start with a
543
+ dot, and is at most one `/` (a `<user>/<repo>` pair), so no dependency folder can escape `.depflow`.
544
+
545
+ ---
546
+
547
+ ## Development
548
+
549
+ The project is ESM-only TypeScript, compiled with `tsc` and exercised by a bundled test runner; no
550
+ test framework is installed.
551
+
552
+ ```bash
553
+ npm install # install the dependencies
554
+ npm run build # clean and compile src/ into dist/
555
+ npm run dev # recompile on change (tsc --watch)
556
+ npm test # compile the tests and run the whole suite
557
+ npm run clean # remove dist/, dist-test/ and the .tsbuildinfo files
558
+ ```
559
+
560
+ The suite is offline: the git and npm fixtures are local, so the tests need no network. The test
561
+ entry point is `dist-test/tests/index.js`, and `npm test` exits non-zero on any failure.
562
+
563
+ ---
229
564
 
230
- - every command of the step runs, even after one of them fails, so a build reports the whole picture;
231
- - `allowFails: true` turns a failed command into information: the step completes and the build continues;
232
- - `maxTimeMs` is a deadline for the whole step, not per command, and a deadline that is reached fails the
233
- step even when `allowFails` is set: the work never finished, so the result is not the one that was asked for.
565
+ ## License
234
566
 
235
- The verdict of a step is awaited, never read from a log: a build that cannot do what it was configured to
236
- do fails, and the failure travels up to whoever asked for the build.
567
+ Apache-2.0. See [LICENCE](LICENCE).