depflow 3.0.0-dev.11 → 3.0.0-dev.13

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,568 @@
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, and whenever `dep install` or `dep sync` runs, DepFlow also refreshes the
88
+ editor JSON Schema at `.depflow/schema.json` and points `$schema` at it, which gives validation and
89
+ autocompletion in editors that understand JSON Schema. Refreshing it before an installation is what
90
+ lets an editor validate the configuration even when the installation itself fails.
91
+
92
+ ### Generated configuration
93
+
94
+ A freshly generated `depflow.yml` looks like this:
95
+
96
+ ```yaml
97
+ # Depflow Configuration File
98
+ # You can use the Red Hat extension for JSON schema validation in VSCode: "$schema: .depflow/schema.json"
99
+
100
+
101
+ # Path to the JSON Schema describing the configuration. Used by editors and tools to provide validation, autocompletion and other features.
102
+ $schema: .depflow/schema.json
103
+ # Output directory for built files. Can be relative or absolute. Defaults to "dist".
104
+ outDir: dist
105
+ # Path to the tsconfig.json file. Can be relative or absolute. Defaults to "tsconfig.json".
106
+ tsconfig: null
107
+ # Path to the importmap.json file. Can be relative or absolute. Defaults to "importmap.json".
108
+ importmap: null
109
+ # Named build actions. Each action runs a pipeline of run, extract and transform steps.
110
+ actions: {}
111
+ # Mapping of dependency names to their resolution targets (local file or CDN). Paths are resolved relative to this folder.
112
+ resolver: {}
113
+ # Git dependencies to clone and build, each an object with a name and a repo.
114
+ dependencies: []
115
+ # NPM dependencies to install and build, each an object with a name and a version.
116
+ npmDependencies: []
117
+ ```
118
+
119
+ ### Top-level keys
120
+
121
+ | Key | Type | Default | Meaning |
122
+ |---|---|---|---|
123
+ | `$schema` | string | `.depflow/schema.json` | Path to the JSON Schema used by editors. Refreshed on every save, and on `install` and `sync`. |
124
+ | `outDir` | string | `dist` | Output root scanned by `rewrite-paths` and its watcher. Relative or absolute. |
125
+ | `tsconfig` | string \| null | `null` | Path to a `tsconfig.json` whose `compilerOptions.paths` `sync` updates. When `null`, synchronization of the tsconfig is skipped. |
126
+ | `importmap` | string \| null | `null` | Path to an `importmap.json` that `sync` writes. When `null`, synchronization of the import map is skipped. |
127
+ | `actions` | object | `{}` | Named build pipelines runnable with `dep run <action>`. |
128
+ | `resolver` | object | `{}` | Aliases shared by the whole project, merged with each dependency's own `resolver`. |
129
+ | `dependencies` | array | `[]` | Git dependencies. |
130
+ | `npmDependencies` | array | `[]` | NPM dependencies. |
131
+
132
+ Streaming collections default to a fresh empty value on every load, so a processed document never
133
+ shares state with the schema.
134
+
135
+ ### Dependencies
136
+
137
+ A **git dependency** is cloned into `.depflow/<user>/<repo>` and rebuilt from its `tag` on every install:
138
+
139
+ ```yaml
140
+ dependencies:
141
+ - name: NetFeez/vizui
142
+ repo: https://github.com/NetFeez/vizui.git
143
+ tag: main
144
+ builder: []
145
+ resolver: {}
119
146
  ```
120
147
 
148
+ | Key | Type | Default | Meaning |
149
+ |---|---|---|---|
150
+ | `name` | string | — (required) | Identity of the dependency. See [Dependency identity](#dependency-identity). |
151
+ | `repo` | string | — (required) | Any value `git clone` accepts, always ending in `.git`. |
152
+ | `tag` | string | `main` | Tag, branch or commit the checkout is left on. |
153
+ | `builder` | array | `[]` | Build pipeline applied after cloning. |
154
+ | `resolver` | object | `{}` | Aliases contributed by this dependency. |
155
+
156
+ An **NPM dependency** is installed into `.depflow/node_modules/<name>` and built the same way:
157
+
158
+ ```yaml
159
+ npmDependencies:
160
+ - name: "@netfeez/common"
161
+ version: latest
162
+ builder: []
163
+ resolver: {}
164
+ ```
165
+
166
+ | Key | Type | Default | Meaning |
167
+ |---|---|---|---|
168
+ | `name` | string | — (required) | Package name, optionally scoped. |
169
+ | `version` | string | — (required) | Version or semver range to install. |
170
+ | `builder` | array | `[]` | Build pipeline applied after installing. |
171
+ | `resolver` | object | `{}` | Aliases contributed by this dependency. |
172
+
173
+ Git dependencies are installed before NPM dependencies.
174
+
121
175
  ### Dependency identity
122
176
 
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`).
177
+ The `name` of a dependency is an identity, not an arbitrary path:
178
+
179
+ - A git name is a `<user>/<repo>` pair or a **single path segment** (letters, digits, `.`, `_`, `-`),
180
+ and it is also the path of its checkout folder inside `.depflow`. It may not lead with
181
+ `schema.json` or `node_modules`, the two names the flow folder reserves for itself, and it is at
182
+ most one `/`.
183
+ - An NPM name is a package name, optionally scoped (`@scope/name`).
126
184
 
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`.
185
+ The name of a git dependency can be derived from its repository only when that repository is a GitHub
186
+ one, where it becomes `<user>/<repo>` (for example `NetFeez/vizui`). For any other repository the
187
+ name has to be given explicitly to `dep add`.
130
188
 
131
- ### Builder rules
189
+ `dep add` accepts a GitHub repository written in any of its usual forms, canonicalizes it to the
190
+ repository git clones from, always ending in `.git`, and derives the name from it when no name is
191
+ given:
132
192
 
133
- A pipeline is an ordered list of steps, each of them exactly one of:
193
+ ```bash
194
+ dep add netfeez/vizui # https://github.com/netfeez/vizui.git, name netfeez/vizui
195
+ dep add https://github.com/netfeez/vizui # https://github.com/netfeez/vizui.git, name netfeez/vizui
196
+ dep add https://github.com/netfeez/vizui.git # https://github.com/netfeez/vizui.git, name netfeez/vizui
197
+ dep add git@github.com:/netfeez/vizui # git@github.com:netfeez/vizui.git, name netfeez/vizui
198
+ ```
134
199
 
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.
200
+ ### Build pipelines
146
201
 
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:
202
+ The `builder` of a dependency, and each entry of a named `action`, is an ordered list of steps. Every
203
+ step is an object carrying exactly one of `run`, `extract` or `transform`. A step that fails without
204
+ tolerating its failures stops the pipeline, and the steps after it are reported as steps that never
205
+ ran.
149
206
 
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`.
207
+ **`run`** executes one shell command, or a list of them, in the pipeline's working directory, which is
208
+ the dependency checkout for an install and the project root for a `dep run` action:
209
+
210
+ ```yaml
211
+ builder:
212
+ - run: npm run build
213
+ - run:
214
+ - npm ci
215
+ - npm run compile
216
+ maxTimeMs: 120000
217
+ allowFails: false
218
+ ```
154
219
 
155
- ```json
156
- { "map": "^build/" }
157
- { "map": { "search": "^build/(.*)\\.js$", "replace": "$1.js" } }
220
+ | Key | Type | Default | Meaning |
221
+ |---|---|---|---|
222
+ | `run` | string \| string[] | — (required) | Command or commands to execute, in order. |
223
+ | `maxTimeMs` | number | `60000` | Deadline for the whole step in milliseconds. `-1` disables the limit. |
224
+ | `allowFails` | boolean | `false` | Whether a failed command is tolerated, so the step completes anyway. |
225
+
226
+ **`extract`** copies files matched by source globs from the working directory into a destination:
227
+
228
+ ```yaml
229
+ builder:
230
+ - extract:
231
+ "build/**/*.js":
232
+ to: dist/vizui
233
+ map: "^build/"
234
+ "build/**/*.d.ts":
235
+ to: dist/vizui
236
+ map: "^build/"
158
237
  ```
159
238
 
160
- An object whose `replace` is empty removes the matches exactly as the string form does.
239
+ The `extract` value is either a mapping of glob → entry, or a single string used as a shorthand for
240
+ extracting every file (`**/*`) into that folder. Each entry is:
241
+
242
+ | Key | Type | Meaning |
243
+ |---|---|---|
244
+ | `to` | string — required | Destination folder. A relative path is resolved against the project root; an absolute one is used as it stands. |
245
+ | `map` | transform | Transformation applied to the destination path of each file, relative to the working directory. |
246
+ | `transform` | transform | Transformation applied to the content of each file. |
247
+
248
+ **`transform`** applies a search/replace transformation in place to every file matched by a glob:
249
+
250
+ ```yaml
251
+ builder:
252
+ - transform:
253
+ glob: "build/**/*.js"
254
+ search: "process\\.env\\.NODE_ENV"
255
+ replace: "\"production\""
256
+ flags: g
257
+ ```
258
+
259
+ ### Transformations
260
+
261
+ `map`, the `transform` of an extraction entry and the in-place `transform` step all accept one of two
262
+ forms, and they do not mean the same thing:
263
+
264
+ - a **string** is a pattern whose matches are **removed**. `"^build/"` strips that prefix from every
265
+ matched path.
266
+ - an **object** is the only form that **substitutes**: `search` is the pattern, `replace` what takes
267
+ its place, and `flags` (default `g`) is applied to the regular expression. An object with an empty
268
+ or absent `replace` removes the matches, exactly as the string form does.
269
+
270
+ ```yaml
271
+ map: "^build/"
272
+ transform:
273
+ search: "^\\.\\/(.*)$"
274
+ replace: "$1"
275
+ flags: g
276
+ ```
161
277
 
162
278
  ### Resolver entries
163
279
 
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:
280
+ The `resolver` of the project and the `resolver` of a dependency are mappings of an alias to its
281
+ target. The target is either a plain string path or an object:
282
+
283
+ ```yaml
284
+ resolver:
285
+ "@utils": src/utils
286
+ "@app/*": src/app
287
+ "@vizui":
288
+ local: dist/vizui/index.js
289
+ type: /abs/path/types/vizui.d.ts
290
+ cdn: https://cdn.example.com/vizui/index.js
291
+ ```
292
+
293
+ | Key | Type | Meaning |
294
+ |---|---|---|
295
+ | `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. |
296
+ | `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. |
297
+ | `cdn` | string | The URL that replaces `local` when `--cdn` is given. |
298
+
299
+ An alias ending in `/` or `/*` is a **wildcard** alias: `@app/*` also covers `@app/Button`. Dependency
300
+ resolvers are compiled before the project resolver, so a project entry with the same alias wins.
301
+
302
+ ### Named actions
303
+
304
+ `actions` maps a name to a list of `run`, `extract` and `transform` steps, run in the project root by
305
+ `dep run <name>`:
306
+
307
+ ```yaml
308
+ actions:
309
+ build:
310
+ - run: npm run build
311
+ - extract:
312
+ "dist/**/*.js":
313
+ to: public/lib
314
+ map: "^dist/"
315
+ lint:
316
+ - run: npm run lint
317
+ - run: npm run typecheck
318
+ ```
166
319
 
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.
320
+ ### Full example
321
+
322
+ ```yaml
323
+ $schema: .depflow/schema.json
324
+ outDir: dist
325
+ tsconfig: tsconfig.json
326
+ importmap: public/importmap.json
327
+
328
+ resolver:
329
+ "@app/*": src/app
330
+
331
+ actions:
332
+ build:
333
+ - run: npm run build
334
+
335
+ dependencies:
336
+ - name: NetFeez/vizui
337
+ repo: https://github.com/NetFeez/vizui.git
338
+ tag: v1.2.0
339
+ builder:
340
+ - run:
341
+ - npm ci
342
+ - npm run compile
343
+ - extract:
344
+ "build/**/*.js":
345
+ to: public/lib/vizui
346
+ map: "^build/"
347
+ "build/**/*.d.ts":
348
+ to: public/lib/vizui
349
+ map: "^build/"
350
+ resolver:
351
+ "@vizui": public/lib/vizui/vizui.js
352
+ "@vizui/*": public/lib/vizui
353
+
354
+ npmDependencies:
355
+ - name: "@netfeez/common"
356
+ version: latest
357
+ builder:
358
+ - extract:
359
+ "build/**/*.js":
360
+ to: public/lib/common
361
+ map: "^build/"
362
+ resolver:
363
+ "@netfeez/common": public/lib/common/index.js
364
+ "@netfeez/common/*": public/lib/common
365
+ ```
366
+
367
+ The same configuration can be kept as JSON when the file is named `.json`. The command reads the
368
+ config named by `--flow` (default `depflow.yml`) and writes a sibling file; its optional positional
369
+ argument is the **output** path, not the input:
174
370
 
175
- A `*` suffix on the alias turns it into a mapping, so `vizui/*` also covers `vizui/Button`.
371
+ ```bash
372
+ dep yaml-to-json # reads depflow.yml, writes depflow.json
373
+ dep json-to-yaml --flow depflow.json # reads depflow.json, writes depflow.yaml
374
+ dep yaml-to-json build/depflow.json # reads depflow.yml, writes build/depflow.json
375
+ ```
176
376
 
177
377
  ---
178
378
 
179
379
  ## CLI Reference
180
380
 
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.
381
+ ```
382
+ dep <command> [arguments] [flags]
383
+ ```
186
384
 
187
- Use `node ./dist/cli/bin.js <command> --flow <config>` when running locally from the repository.
385
+ The **first token is always the command name**; global flags are parsed from the tokens that follow
386
+ it. `dep --flow x install` is read as the command `--flow`, so flags belong after the command:
387
+ `dep install --flow x`.
188
388
 
189
389
  ### Commands
190
390
 
191
- The CLI exposes the following commands (all commands accept the global `--flow <file>` flag to specify a custom configuration file):
192
-
193
391
  | Command | Usage | Description |
194
392
  |---|---|---|
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. |
393
+ | `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. |
394
+ | `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. |
395
+ | `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. |
396
+ | `run` | `dep run <action>` | Run a named action from `actions`, in the project root. |
397
+ | `list` | `dep list` | List the declared dependencies, marking each one `installed` or `missing`. |
398
+ | `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. |
399
+ | `sync` | `dep sync [--cdn]` | Write the resolver aliases into the configured `tsconfig` and `importmap`. |
400
+ | `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. |
401
+ | `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. |
402
+ | `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`. |
403
+ | `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. |
404
+ | `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. |
405
+ | `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. |
406
+
407
+ ### Console commands
408
+
409
+ The CLI is built on a small console interface that also carries two commands:
410
+
411
+ | Command | Description |
412
+ |---|---|
413
+ | `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`. |
414
+ | `dep exit` | Leave the process. |
415
+
416
+ This build does not drive that interface interactively: the first token of an invocation is always
417
+ taken as the command name, so an empty invocation is reported as an unknown command and the help is
418
+ printed rather than a prompt being opened.
201
419
 
202
420
  ### Flags
203
421
 
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.
422
+ These are the global flags: every command accepts all of them.
423
+
424
+ | Flag | Aliases | Default | Description |
425
+ |---|---|---|---|
426
+ | `--flow <file>` | `-p`, `-f` | `depflow.yml` | Configuration file the command operates on. |
427
+ | `--cdn` | — | `false` | Resolve to CDN targets instead of local ones (for `sync` and `rewrite-paths`). |
428
+ | `--watch` | `-w` | `false` | Keep watching the built files and rewriting their paths on every change (`rewrite-paths`). |
429
+ | `--verbose` | `-v` | `false` | Stream the output of every command as it runs, attributed to the command that wrote it. |
430
+ | `--silent` | — | `false` | Say only what failed, one line per failed command. |
431
+ | `--decorate` | — | `true` | Draw boxes, indentation, timestamps, levels and names. Use `--decorate=false` to leave the content alone. |
432
+
433
+ Beside the global ones, an editing command declares the flags it owns. A flag is only accepted by the
434
+ command that declares it: `dep install --to x` is answered with `Unknown flag: --to`, and the help
435
+ lists the owned flags under their command.
436
+
437
+ | Command | Flag | Aliases | Default | Description |
438
+ |---|---|---|---|---|
439
+ | `add` | `--npm` | — | `false` | Add an npm dependency instead of a git one. |
440
+ | `add` | `--tag <ref>` | — | `main` | Tag, branch or commit the added git dependency is checked out at. |
441
+ | `resolver` | `--dep <name>` | — | — | Dependency whose resolver is edited. Omitted, the project resolver is edited. |
442
+ | `resolver` | `--type <type>` | — | — | Type identifier of a resolver target, set alongside its local path. |
443
+ | `resolver` | `--cdnUrl <url>` | `--cdn-url` | — | CDN URL of a resolver target, set alongside its local path. |
444
+ | `resolver` | `--force` | — | `false` | Overwrite an existing resolver alias instead of failing. |
445
+ | `builder` | `--dep <name>` | — | — | Dependency whose build pipeline is edited. |
446
+ | `builder` | `--action <name>` | — | — | Action whose build pipeline is edited. |
447
+ | `builder` | `--to <dir>` | — | — | Destination folder of an extract build step. |
448
+ | `builder` | `--map <pattern>` | — | — | Pattern applied to the destination path of an extract build step. |
449
+ | `builder` | `--search <regex>` | — | — | Regular expression a transform build step searches for. |
450
+ | `builder` | `--replace <text>` | — | — | Replacement string of a transform build step. |
451
+ | `builder` | `--flags <flags>` | — | `g` | Flags of the regular expression of a transform build step. |
452
+ | `builder` | `--maxTime <ms>` | `--max-time` | `60000` | Maximum execution time of a run build step; `-1` disables the limit. |
453
+ | `builder` | `--allowFails` | `--allow-fails` | `false` | Whether the commands of a run build step may fail. |
454
+ | `builder` | `--index <n>` | — | end | Position at which a build step is inserted. |
455
+
456
+ Flag parsing rules:
457
+
458
+ - A flag is the whole token; short clusters are not expanded (`-abc` is the single flag `-abc`).
459
+ - Names are matched with or without their dash prefix, so `-f` and `--flow` reach the same flag.
460
+ - A value flag takes the next token as its value when that token is not a flag, or an inline value as
461
+ `--flag=value`. A boolean flag never consumes the next token and only accepts `=true` or `=false`,
462
+ so the undecorated form is `--decorate=false`.
463
+ - The last occurrence of a flag wins, `--` ends the flags and turns every remaining token into a
464
+ positional argument, and an undeclared flag is an error.
207
465
 
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.
466
+ ```bash
467
+ dep install --flow .df.yml
468
+ dep sync --flow .df.yml --cdn
469
+ dep rewrite-paths --flow .df.yml --watch
470
+ dep run build --decorate=false
471
+ ```
209
472
 
210
- Examples:
473
+ ---
211
474
 
212
- ```bash
213
- # install using custom flow file
214
- dep install --flow .df.json
475
+ ## Run Modes and the Evidence Trail
215
476
 
216
- # sync using CDN targets for importmap
217
- dep sync --flow .df.json --cdn
477
+ Every command a run executes writes its **complete** output to
218
478
 
219
- # rewrite paths and start watcher (local targets)
220
- dep rewrite-paths --flow .df.json --watch
479
+ ```
480
+ .logs/{YYYY}.{MM}.{DD}/[name] {HH}.{mm}.{ss}.{ms}.vlog
221
481
  ```
222
482
 
483
+ under the working directory, whatever the mode. The file keeps the format tokens of the logger, so it
484
+ is a complete transcript of the run. What a mode changes is how much of that output reaches the
485
+ screen:
486
+
487
+ | Mode | Flags | What it shows |
488
+ |---|---|---|
489
+ | Default | *(none)* | One result line per command, and the complete output of a command that failed, under its diagnostic. |
490
+ | Verbose | `--verbose` / `-v` | Every line of every command as it comes, each attributed to the command that wrote it. The buffer is not repeated. |
491
+ | Silent | `--silent` | One line per failed command, and nothing else. |
492
+
493
+ `--silent` wins over `--verbose` when both are given. `--decorate=false` combines with any mode to
494
+ drop the boxes, indentation, timestamps, levels and names, keeping the color of the markers and the
495
+ diagnostics, which carry information.
496
+
497
+ Commands that are not part of a pipeline (the git and npm acquisition of a dependency) are reported
498
+ as `C<M>`; the commands inside a pipeline with more than one `run` step are qualified as
499
+ `S<N> · C<M>`, so a command identity is never ambiguous.
500
+
223
501
  ---
224
502
 
225
- ## Build steps in depth
503
+ ## How `sync` and `rewrite-paths` Work
504
+
505
+ `sync` compiles the resolver into aliases and writes them to the configured files:
506
+
507
+ - the **tsconfig** `compilerOptions.paths` receives one entry per alias, always pointing at the local
508
+ target. A wildcard alias becomes `<alias>/*`. When a target declares a `type`, the type path is the
509
+ first element of the array and the local path the second.
510
+ - the **importmap** `imports` receives one entry per alias. A wildcard alias's key keeps a trailing
511
+ `/`. Local targets are written relative to the directory of the importmap file. With `--cdn`, an
512
+ alias that declares a `cdn` target uses it; the others keep their local path. Existing `scopes` are
513
+ preserved.
514
+
515
+ `rewrite-paths` scans `outDir` for files ending in `.js`, `.ts`, `.jsx`, `.tsx`, `.cjs` or `.mjs`
516
+ and rewrites every `from '...'` specifier whose module path matches an alias:
226
517
 
227
- A `run` step is the only place where a shell script is interpreted, and it is where the failure semantics
228
- live:
518
+ - in **local** mode the specifier becomes a path relative to the file, written with `/` separators.
519
+ - in **cdn** mode an alias that declares a `cdn` target resolves to that URL; the rest keep their
520
+ local relative path.
521
+
522
+ Only `from '...'` specifiers are rewritten; a bare side-effect import such as `import './x'` is not
523
+ touched. `--watch` rewrites once and then keeps rewriting as files change.
524
+
525
+ ---
526
+
527
+ ## Project Layout
528
+
529
+ ```text
530
+ <project root>/
531
+ ├── depflow.yml # the configuration (any name, passed with --flow)
532
+ ├── .depflow/ # the flow folder, owned by DepFlow
533
+ │ ├── <user>/<repo>/ # one checkout per git dependency
534
+ │ ├── node_modules/ # npm dependencies, installed here and not in the project's
535
+ │ └── schema.json # the editor JSON Schema, refreshed on every config save
536
+ ├── <outDir>/ # the built files rewrite-paths scans (default: dist)
537
+ └── .logs/ # the evidence trail, under the working directory
538
+ └── {YYYY}.{MM}.{DD}/
539
+ └── [name] {HH}.{mm}.{ss}.{ms}.vlog
540
+ ```
541
+
542
+ The project root is the directory of the configuration file. The flow folder is reserved for
543
+ DepFlow: a dependency name may not lead with `schema.json` or `node_modules`, may not start with a
544
+ dot, and is at most one `/` (a `<user>/<repo>` pair), so no dependency folder can escape `.depflow`.
545
+
546
+ ---
547
+
548
+ ## Development
549
+
550
+ The project is ESM-only TypeScript, compiled with `tsc` and exercised by a bundled test runner; no
551
+ test framework is installed.
552
+
553
+ ```bash
554
+ npm install # install the dependencies
555
+ npm run build # clean and compile src/ into dist/
556
+ npm run dev # recompile on change (tsc --watch)
557
+ npm test # compile the tests and run the whole suite
558
+ npm run clean # remove dist/, dist-test/ and the .tsbuildinfo files
559
+ ```
560
+
561
+ The suite is offline: the git and npm fixtures are local, so the tests need no network. The test
562
+ entry point is `dist-test/tests/index.js`, and `npm test` exits non-zero on any failure.
563
+
564
+ ---
229
565
 
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.
566
+ ## License
234
567
 
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.
568
+ Apache-2.0. See [LICENCE](LICENCE).