Fabr 0.3.1 released

New in this release: 'fabr deps' now implements the usual sort of dependency tree you'd expect:

And because this is fabr, you can do this on any reference (eg 'fabr deps @npm:react:18.0.0'). As a bonus, 'fabr ls @npm:react' finally works and lists all available versions of the package.

We've also now changed JS sourcemap paths so that they're all consistent fabr references. For ordinary source files, this means they'll have their project-relative path like 'fabr:packages/core/src/index.ts' , while generated files will carry their origin, such as 'fabr:reference_docs:js-targets.md'.

This might not seem that useful (so in practice you probably still want sourceContents for debugging) but it gives a clear tree in devtools, and as far as we've been able to determine there isn't really a better way to do it under the sourcemap spec.

Finally, fabr now fetches your project node for you (irrespective of what's running fabr itself) for properly hermetic builds. The default is currently 24.22.1, and you can set it with eg:

NODE = @node:24.22.1:bin/node;

And there's lots of other small fixes, improvements and bugfixes below.

Full changelog

@fabr-build/core:

  • Resolve dependencies separately from fetching and building them, so a version conflict fails before anything is downloaded and fabr deps needs no package contents.
  • Find dependency cycles in the computation graph itself, fixing some cycles that went unreported.
  • Circular dependency errors list the written references making up the cycle, closing one first.
  • Built packages now participate normally in dependency resolution, including ? and ! marks.
  • Add the PACKAGES property type, for properties that take packages rather than plain files.
  • A repository named on its own (deps = @npm;) is now an error rather than silently naming nothing.
  • Generalize fabr_home to the whole installed tree (@fabr-home:<package>), with @fabr-build/* falling back to the installed packages.
  • Allow - in property names.
  • Optimize package downloading, and stop re-reading metadata for cached packages.
  • Fix handling of constraints in variable substitutions and string lookups.
  • Keep fabr run installs between runs, updating only what changed; run -w swaps between two.
  • Add incremental and changes to the generate target.
  • Rename the plugin API's packageLibFile to getPackageLibFile.

@fabr-build/cli:

  • Add fabr deps: print the dependency tree of targets or packages, marking conflicting versions (!).
  • Add fabr test --coverage[=DIR], writing an lcov report.
  • fabr ls lists a namespace where its repository can enumerate one (fabr ls @npm:glob).
  • fabr build and fabr test check every name before building anything, and refuse a path or a file selection.

@fabr-build/js:

  • A sibling package depended on under a rename (deps = mylib -> foo;) is declared in npm's alias
    form ("foo": "npm:mylib@1.2.3").
  • Move the drivers and test runners into their own package, @fabr-build/js-tools, installed with fabr.
  • Add optional_provided_deps (written as optional peerDependencies).
  • Source maps name each source as a fabr: reference, by its path in the project where it has one.
  • Sass and postcss steps recompile only when a stylesheet they read changes.
  • postcss resolves composes from packages through the PnP table.
  • Add test coverage reporting (COVERAGE=on).
  • Add node distribution repository to download node.js.
blue and red cargo ship on sea during daytime