• v2.2.0 cbe0eec9f8

    v2.2.0 Stable

    michael released this 2026-10-17 11:35:31 +02:00 | 0 commits to main since this release

    Breaking changes

    • Contribution labels are daw_i18n/v1 resource references. label
      (a { de = ..., en = ... } table) is now label_resource_id (a
      resource id string) on groups, commands and subcommands -- in the
      contribution.json input and in the output of composer.compose()
      and scanner.build_index(). Hard cutover, no transition period.
      berhtjan-core passes the id through unresolved. See
      DAW/daw-modul-berhtjan-core#12.
    • lang.resolve_label() is removed, together with its error code
      label_not_found. resolve_resource(resource_id, catalogs, languages)
      replaces it and returns result, nil | nil, daw_error/v1, the result
      being { text, requested_language, resolved_language, fallback_occurred }. catalogs holds one catalog per language,
      catalogs[language][resource_id]. Every language of languages must
      have a catalog (catalog_not_loaded otherwise -- nothing is skipped
      silently); an unknown id and a missing translation are both
      no_translation_available.
    • lang.resolve_lang() validates its context. A non-table ctx is
      invalid_ctx, a non-string user_locale or lang is
      invalid_ctx_field, and ctx.lang must be a language code of
      lowercase letters (invalid_language_code) -- any string was
      accepted before.
    • scanner.build_index() rejects a command defined by two
      contributions
      with command_name_collision (nil, err). It used to
      keep the later one and drop the earlier one silently. See
      DAW/daw-modul-berhtjan-core#16.
    • berhtjan-cli 2.1.0 does not work with this release. It calls
      core.resolve_label() at several places. A matching berhtjan-cli
      release follows.

    New

    • lang.language_chain(ctx) -- the ordered language chain for
      resolve_resource(): the resolved user language, then
      ctx.default_lang unless it is the same language. Exported by the
      facade.
    • Build-time logic for the per-language resource catalogs
      (resources.lua, facade exports parse_resource_source() and
      generate_catalogs()): validate daw_i18n/v1 sources, merge them by
      priority per (resource id, language), require the default language to
      be complete, and write a catalog as a Lua data file. Pure functions;
      the host reads the sources and installs the result. See
      DAW/daw-modul-berhtjan-core#13.
    • scanner.build_index(): command entries carry module, the
      contribution's module identity.
    • i18n/en.json and i18n/de.json -- 79 daw_i18n/v1 resources; every
      error site now carries a resource_id.

    Fixes

    • lang.resolve_lang(): a malformed context (for example
      user_locale = 123) raised a raw Lua error; it now returns
      daw_error/v1.
    • lang.lua: the bootstrap fallback was a plain string; it is the
      reserved daw-error-facility-unavailable sentinel now, in all
      modules.

    Internal

    • loader.lua: the shared _check_deps() plain-string helper is gone;
      the five parse_contribution() error sites carry a resource_id.
    • Test suite: 207 -> 541 tests, Lua 5.1 and 5.4.

    Migrating

    1. In every contribution.json, replace "label": { ... } with
      "label_resource_id": "<uuid>" and ship the text as a
      daw_i18n/v1 resource (canonical English in i18n/en.json).
    2. Replace resolve_label(label, lang, default_lang) with
      language_chain(ctx) and resolve_resource(id, catalogs, chain).
    3. Pass only language codes of lowercase letters (or nothing) as
      ctx.lang and ctx.default_lang.

    Requires daw-lua-common >= 2.1.0.

    Downloads
  • v2.1.0 1fa85ab46c

    v2.1.0 Stable

    michael released this 2026-08-11 17:40:53 +02:00 | 41 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