• v2.1.0 1fa85ab46c

    v2.1.0 Stable

    michael released this 2026-08-11 17:40:53 +02:00 | 6 commits to main since this release

    Breaking changes

    • All public functions across composer, loader, scanner, types,
      lang now return nil, <daw_error/v1 object> instead of
      nil, <string>. The return contract itself (value, nil | nil, err)
      is unchanged -- only what err is. See
      MIGRATION-DAW-MODUL-BERHTJAN-CORE-2.1.md for the full code
      reference and cause-chain examples.
    • M.PRIMITIVES, M.is_primitive(), M.primitives() removed
      entirely. types.resolve() is now pure registry lookup -- no field
      type name is known in code, not even the six former primitives
      (text, textarea, number, boolean, select, date). See
      daw_field_type/v1 (DAW/daw-contracts#3).
    • loader.parse_types() now structurally validates every type
      definition against daw_field_type/v1 at load time. A malformed
      definition is rejected with a specific error code and
      data.rule pointing at the exact contract rule violated.
    • loader.merge_types() is now fallible
      (registry, nil | nil, err). A field type id defined more than
      once across merged tables is an error (duplicate_field_type), not
      a silent override.
    • scanner.build_index() is now two-valued
      (index, nil | nil, err).
    • lang.resolve_lang() no longer falls back to a hardcoded "en" --
      a ctx with neither user_locale nor lang is now a real error
      (no_language_resolvable).
    • lang.resolve_label() gained a third parameter, default_lang, and
      no longer falls back to "en" or to pairs()'s nondeterministic
      first match. A label with neither the requested lang nor
      default_lang present is now label_not_found instead of a silent
      substitute.
    • composer.compose()'s resolved fields carry type_def (the full
      daw_field_type/v1 definition) instead of the old primitive
      string field, which no longer has a meaningful value under the new
      model.
    • init.lua's facade no longer crashes via error() at load time if
      a submodule is missing -- every export degrades individually via a
      missing() stub (nil, daw_error/v1, code submodule_unavailable).

    Fixes

    • scanner: project_root was silently ignored since commit
      25e7557 -- module.conf for a host program's own contribution was
      looked up relative to the scan root instead of project_root
      (DAW/daw-modul-berhtjan-core#5, regressed during the "canonical
      module resolution" refactor). Restored, with a regression test
      fixture that deliberately differs scan root and project root.
    • scanner.scan_root(): the recursive branch called
      ipairs(scan_dir(subdir)) directly, ignoring that scan_dir() can
      return nil, err -- ipairs(nil) raised a raw Lua error instead of
      reporting it as daw_error/v1. Now checked like the non-recursive
      call.
    • loader.parse_contribution() / parse_types(): json.decode() no
      longer throws since daw-lua-common 2.0, but the pcall-wrapping
      around it here was never updated -- it silently stopped catching
      anything, and a decode failure crashed downstream on nil data
      instead of returning an error. Fixed to read json.decode()'s own
      value, nil | nil, err contract directly.
    • loader.parse_contribution(): a bare JSON scalar (e.g. 42) or a
      top-level null previously crashed on data.module instead of
      being rejected -- now invalid_contribution.
    • lang.resolve_label(): label[lang] then ... used truthiness,
      silently treating a deliberately empty string (label.de = "") as
      "missing" and falling through to the next candidate. Now checked via
      ~= nil, so an intentional "" is returned as-is.
    • scanner.sorted_subcommands() (new, DAW/daw-modul-berhtjan-core#4):
      hardened beyond the issue's original proposal -- a malformed cmd
      now returns nil, daw_error/v1 instead of crashing, since this is a
      publicly exported function used by daw-modul-berhtjan-cli.

    Internal

    • scanner.lua (flat file) split into scanner/ (init.lua,
      roots.lua, discover.lua, index.lua) -- exceeded the 250-line
      limit. require("daw.berhtjan_core.scanner") unchanged.
    • types.resolve(): reduced to ~40 lines, pure registry lookup.
    • test/dev-module-map.lua: added daw.common.error and the new
      scanner.* submodule entries; added the missing
      daw.berhtjan_core (facade) entry, previously absent entirely.
    • New test/test_berhtjan-core-init.lua covering the root facade
      (submodule aggregation, missing() stub behavior) -- didn't exist
      before this release.
    • Test suite: 192 -> 207 tests.

    Migration

    Two independent things changed at once: the error contract
    (daw_error/v1) and the field type contract (daw_field_type/v1,
    replacing M.PRIMITIVES). Projects only checking if err then are
    unaffected by the first; every project composing contributions is
    affected by the second, since a registry with the six former
    primitives must now be supplied explicitly.
    MIGRATION-DAW-MODUL-BERHTJAN-CORE-2.1.md walks through both, plus
    the full error-code reference.

    Requires daw-lua-common >= 2.1.0 (for daw.common.error).

    There is no separately published 2.0.0 -- this release moves directly
    from the 1.1.x line to 2.1.0.

    Downloads