• v2.2.0 1fc3d988f7

    v2.2.0 Stable

    michael released this 2026-10-16 21:30:45 +02:00 | 0 commits to main since this release

    daw-lua-common v2.2.0

    Highlights

    The pure-Lua YAML parser now reads a defined subset meant for files
    written by hand (question catalogs, tax rules), and everything outside
    it returns nil, err instead of silently different data. dump() and
    load() are round-trip safe. sys gains run_interactive() for
    programs that need the terminal.

    New

    • YAML block scalars |, >, |-, >- (pure-Lua backend).
    • YAML flow maps on one line -- {name: "UK VAT", rate: 20.0},
      also as list items; quoted commas inside [...], trailing comma.
    • YAML comment after a quoted value -- text: "x" # note.
    • YAML leading --- is accepted and ignored.
    • yaml/scalar.lua -- new internal submodule for single-line
      values; parse.lua keeps line structure and block scalars.
    • sys:run_interactive(cmd) -- runs a command with the terminal
      passed through (e.g. $EDITOR), returns the exit code; a signal
      maps to 128 + signal.
    • 11 new daw_i18n/v1 resources (240 -> 251).
    • test/test_yaml_subset.lua -- round-trip, subset and rejection
      tests (147 checks).

    Fixed

    • YAML quoted strings: \\ \" \n \t \r in double quotes and ''
      in single quotes are now resolved, so load(dump(x)) returns x.
      Other escapes stay literal ("^\d{5}$" keeps \d).
      Closes #60.
    • YAML multiline strings round-trip through dump()/load();
      block scalars no longer fail or load as "|".
      Closes #61.
    • YAML list items - {id: x}, - "a: b" and - http://x were
      read as one-key maps; they are now a table, a string and a string.
    • YAML {} loads as an empty table (was the string "{}", although
      dump() writes it for empty tables).
    • YAML key: # comment is null or a nested block (was the string
      "# comment").
    • yaml.dump() quotes strings containing \r or %; both did not
      survive a round-trip before.
    • YAML quoted keys: dump() quoted keys with :, # or spaces,
      but load() kept the quotes as part of the key ("a:b" even became
      "a). Quoted keys now load unquoted (block maps, list items,
      {...}); dump() escapes quotes inside keys and quotes - k.
    • yaml.dump() on a cyclic table overflowed the stack (a raw Lua
      error leaving the library, or the process being killed); it now
      returns nil, err (cyclic_table).

    Changed

    • YAML input outside the subset is rejected with nil, err
      (code unsupported, unterminated_quote, trailing_text or
      flow_entry; data.feature names unsupported syntax): anchors,
      aliases, tags, |+/>+, multi-document, tab indentation, nested or
      multi-line flow collections. The subset is
      documented in docs/yaml.md.

    Migration notes

    Files that only use plain maps, lists and simple scalars load as
    before. Things to check if you rely on details:

    • Double-quoted values containing \\ or \", and single-quoted
      values containing '', now load resolved (previously literal).
    • Values that used to load silently wrong (see Fixed) now load
      correctly or return nil, err -- code that worked around them can
      drop the workaround.
    • Programs pinned to an older version (e.g. the vendored
      daw.lua.common.yaml) are unaffected until they update.
    Downloads
  • v2.1.1 3cdcf84ac0

    v2.1.1 Stable

    michael released this 2026-09-21 16:38:59 +02:00 | 6 commits to main since this release

    daw-lua-common v2.1.1

    Highlights

    Every error site in daw-lua-common now carries a resource_id that
    points into the new daw_i18n/v1 language resources (i18n/en.json,
    canonical, and i18n/de.json). The error contract itself is unchanged
    -- code, message, data and cause behave as in 2.1.0 -- the
    resource_id is an additional field so a host can later look up the
    message in its own language.

    The bootstrap case is now uniform across the whole library: if
    daw.common.error is unreachable, or error.new() itself fails, every
    module returns the reserved daw-error-facility-unavailable sentinel
    (with its own resource_id), never a plain string and never nil.

    New

    • resource_id / cell_id -- error.new() accepts the optional
      fields cell_id and resource_id and returns them on the error
      object. Every error construction site in the library sets its own
      resource_id.
    • i18n/en.json and i18n/de.json -- 240 daw_i18n/v1 resources
      with context, parameter declarations and, in de.json, the
      source_hash of the canonical English text. A resource is exactly one
      error construction site.
    • Module reference documents in docs/ for base64,
      config_parser, uuid, json, yaml and the root module.
    • New error codes: tool_detection_failed (crypto.hash, see
      below) and attributes_query_failed (fs.exists()/fs.is_dir(),
      see below).

    Fixed

    • fs.exists() / fs.is_dir(): every lfs.attributes() failure
      was folded into false, contradicting their documented "confirmed
      absent (false) vs. could not check (nil, err)" contract. Only
      ENOENT and ENOTDIR now mean false; any other failure (e.g.
      EACCES, a symlink cycle) returns nil, daw_error/v1
      (attributes_query_failed).
      Closes #57.
    • crypto.hash: a genuine sys:run() failure while detecting
      sha256sum was silently treated as "not installed" and fell through
      to sha256 -r. It now returns tool_detection_failed with the run
      error as cause; an empty result (tool not found) still selects the
      BSD fallback.
      Closes #54.
    • Error helpers, all 26 modules: if daw_error.new() succeeded but
      returned neither an object nor an error, fail() returned nil, so
      callers ended up with nil, nil (in yaml.dump this even caused a
      raw Lua error). Both a raising and a returning-nothing new() now
      fall through to the sentinel.
      Closes #53.
    • decimal.is_decimal(): int and scale are now validated as
      integers.
    • crypto.hmac: tmpfile() failures are reported as cause, not
      as data.
    • crypto, decimal, fs: the pcall around daw_error.new()
      was restored where a refactoring had dropped it.

    Changed

    • The bootstrap fallback is the sentinel object in every module
      (sys, time, uuid, json, yaml, fs, decimal, crypto,
      root init); crypto no longer treats daw.common.error as an
      optional dependency.
    • sys:run() is now explicitly documented (docs/sys.md, code
      comment): the exit status is deliberately not evaluated, run_rc()
      is the variant for it. No behaviour change.
      See #58.
    • The Makefile no longer has install / uninstall targets; the
      library is shipped as a git submodule (lib/daw/common/).
      Closes #59.
    • README: the Contributing section follows the GitHub Issues policy
      (issues and feedback via GitHub Issues are welcome and handled
      there).
      Closes #51.

    Migration notes

    Code that only checks if err then or err.code is unaffected.
    Things to look at if you rely on details:

    • fs.exists() / fs.is_dir() can now return nil, err for a path
      that exists but cannot be checked (previously false). Code that
      tests the first value for truthiness behaves as before; code that
      compares against false or evaluates the second value should handle
      attributes_query_failed.
    • In the bootstrap case (daw.common.error unavailable) the return
      value is the sentinel object; code that matched a plain string there
      needs to check err.id == "daw-error-facility-unavailable" instead.
    • resource_id on errors built through daw.common.error is set with
      this version of daw-lua-common; consumers pinned to 2.1.0 still get
      the same errors, but without the field.
    • make install no longer exists; use the git submodule.
    Downloads
  • v2.1.0 2c7a7441b8

    v2.1.0 Stable

    michael released this 2026-08-06 22:25:10 +02:00 | 80 commits to main since this release

    daw-lua-common v2.1.0

    Highlights

    daw-lua-common now returns a structured daw_error/v1 object from every
    public function on failure, instead of a plain error string. This is the
    biggest architectural change in this release: every module boundary now
    follows the same error contract, the same "no uncaught Lua errors leave
    a library module" rule, and the same internal-helper-returns-plain-text
    / public-API-builds-one-error-object pattern.

    See README.md and
    daw-contracts: daw_error/v1
    for the full contract.

    New

    • daw.common.error -- new public module, the daw_error/v1
      constructor (error.new(), error.is_error()) used by every other
      module in this library.
    • fs.copy_preserve(src, dst) -- new function shelling out to
      cp -a, preserving symlinks, permissions, timestamps, and ownership.
      fs.copy()/fs.copy_dir() remain content-only (read+rewrite, no
      metadata preservation) and are now explicitly documented as such.
      Closes #40.

    Fixed

    • sys:run_rc(): stderr from the executed command was not actually
      being captured, contrary to the documented contract ("stdout and
      stderr are both captured"). The trailing 2>&1 redirect bound only
      to the marker-printing printf, not to the command itself, due to
      normal shell parsing of cmd; printf ... 2>&1. Fixed by wrapping the
      whole sequence in a POSIX brace group.
    • fs.write_file(): a failed write could go unnoticed. f:write()
      can report success even when the underlying write later fails on
      close() (stdio buffering) -- both are now checked.
    • config_parser: section type (the part before the name in
      [type "name"]) now follows the same [a-z0-9_-] naming convention
      as the section name. Previously [Server "abc"] was silently
      accepted despite the uppercase type.
    • decimal.round()/decimal.div(): decimals/target_scale are
      now validated as non-negative integers, not just "is a number" --
      negative or fractional values previously reached the internal
      power-of-ten helper with undefined behavior.

    Changed

    • decimal.lua and daw.common.error are now directory modules
      (decimal/, error/) split into focused submodules behind a stable
      facade -- require paths are unchanged.
    • Every module's fail()/err() helper now also guards against
      daw.common.error.new() itself raising (not just against require()
      failing), consistent with "no module propagates an uncaught Lua
      error."

    Migration notes

    If any consumer code inspects the err return value directly (e.g.
    err:match(...), string concatenation, pattern matching on error
    text), that code will break -- err is now a table
    ({ schema, id, source, code, message, cause?, data? }), not a string.
    Use err.code for programmatic checks and err.message for the
    human-readable text, or daw.common.error.is_error(err) to check the
    shape.

    This release only touches daw-lua-common itself. Consumer projects
    are migrated to the new contract individually and at their own pace;
    daw-lua-common v1.x behavior for callers not yet updated is
    unaffected until they upgrade their submodule pin.

    Downloads
  • v2.0.0 8e563ccdb2

    v2.0.0 Stable

    michael released this 2026-07-20 07:13:22 +02:00 | 84 commits to main since this release

    daw-lua-common 2.0.0

    Erstes größeres Major-Release seit Beginn der Bibliothek – durchgängige Umstellung der Fehlerbehandlung auf nil, err, mehrere Modul-Splits, ein vollständiger Team-Review-Durchlauf über alle Module, und eine repo-weite Vereinheitlichung der Fehlermeldungen.

    Breaking Changes

    • uuid.lua: validate() → is_valid(), get_short_code() → short_code(), is_version_4() entfernt (war redundant zu is_valid())
    • config_parser.lua: convert() erkennt keine wissenschaftliche Notation (1e5) oder Hex-Literale (0x10) mehr als Zahlen – bleiben jetzt bewusst String
    • yaml.dump(): nicht serialisierbare Typen (Funktionen, Coroutines) liefern jetzt nil, err statt eines Platzhalter-Strings
    • json.encode(): NaN/Infinity werden jetzt abgelehnt statt als ungültiges JSON ausgegeben
    • crypto.hmac_*: Keys mit NUL-Bytes oder abschließendem Zeilenumbruch werden jetzt aktiv abgelehnt statt still fehlinterpretiert
    • Fehlermeldungen: einheitlich [ERROR] modul.funktion: ... im ganzen Repository (vorher mehrere uneinheitliche Varianten)

    Neu

    • base64.lua: jetzt vollständig ohne externe Abhängigkeit (kein openssl mehr nötig)
    • fs.remove_dir_recursive(), yaml.dump(), vollständige fs/-, json/- und yaml/-Modulaufteilung
    • crypto/ in hash.lua + hmac.lua + Fassade aufgeteilt (fragjan 250-Zeilen-Limit)

    Robustheit

    • Kalender- und Zeitzonen-Validierung in time.lua
    • Vollständiges RFC-8259-Escaping in json/encode.lua, passende \uXXXX-Dekodierung in json/decode.lua
    • Shell-Quoting-Fixes, Typprüfungen an praktisch jeder öffentlichen Funktion
    • decimal.is_valid() garantiert jetzt, dass parse() danach nicht mehr scheitert

    Zahlen

    • 391 Tests (vorher ~220), grün unter Lua 5.1 und 5.4
    • fragjan: 34 Dateien, 711 Checks, clean

    Bekannte offene Punkte (nicht release-blockierend)

    • fs-Shell-Fallback ohne lfs verschoben auf 2.1 (#7, #3)
    • Laufzeit-Versionsauskunft blockiert durch merkwerk.lua-Bugs (#18)
    Downloads