Skip to content

Consistent input validation, and a CHANGELOG - #2

Merged
tbeseda merged 1 commit into
mainfrom
fix/input-validation
Aug 14, 2026
Merged

Consistent input validation, and a CHANGELOG#2
tbeseda merged 1 commit into
mainfrom
fix/input-validation

Conversation

@tbeseda

@tbeseda tbeseda commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Follow-up to #1, and the last thing before 0.2.0.

The problem

treeify had three different reactions to the same class of mistake:

input before after
[] '' ''
[undefined] '' throws
null, 'root', {} '' throws
[1, ['child']] throws Error throws TypeError
['root', 42, 'b'] 42 silently dropped 42 renders
['root', [42, 'b']] 42 silently dropped 42 renders

A number where a string belongs threw at index 0 and was silently swallowed everywhere else. Input that wasn't an array at all was the quietest outcome of the lot, even though it's the one most likely to be a real bug.

The policy

Throw for what can't be rendered, render everything else.

  • Not an array → TypeError: array-treeify: expected an array, received null
  • First element isn't a string → TypeError: array-treeify: expected the first element to be a string, received number (1)
  • Anything that isn't an array is a label, stringified at any depth, and can be a parent node
  • treeify([]) still returns '' — a useful "nothing to render"

No error class is exported. The TypeError message is the API.

treeify(['deploys', [2025, ['spring', 'summer'], 2026, ['q1']]])
// deploys
// ├─ 2025
// │  ├─ spring
// │  └─ summer
// └─ 2026
//    └─ q1

number, bigint and boolean are now accepted as labels without a cast. The exported TreeInput type is unchanged.

Docs

The README claimed TypeScript "cannot enforce at the type level that the first element is a string". That isn't true — [string, ...(string | TreeInput)[]] does exactly that. It would rule out building a tree with push, which is the real reason for the permissive type, so the docs now say that instead. Added sections on labels and errors; the new example is covered by the README test suite.

CHANGELOG

Added, in Keep a Changelog format, backfilled from the tags (0.1.1 through 0.1.5). The breaking changes from this PR and from #1 are collected under Unreleased.

Verified

  • 23/23 tests pass; npm run check clean.
  • Valid trees render exactly as before: 15,000 renders of randomly generated string trees across all three option shapes (default, plain, custom chars) are byte-identical to the previous implementation.

treeify had three different reactions to the same class of mistake. A
non-string where a label belongs threw at index 0, was silently dropped
anywhere else, and input that wasn't an array at all returned '' -- the
quietest outcome for the input most likely to be a bug.

One policy now: throw for what can't be rendered, render everything else.

- Input that is not an array throws a TypeError instead of returning ''.
- A non-string first element throws a TypeError, including [undefined],
  which used to return ''. Messages name what was received, e.g.
  "array-treeify: expected the first element to be a string, received
  number (1)".
- Non-string labels are stringified instead of dropped, at any depth, and
  can be parent nodes. Numbers, bigints and booleans are accepted without
  a cast.
- treeify([]) still returns '', which is a useful "nothing to render".

No error class is exported; the TypeError message is the API.

Valid trees render exactly as before: 15,000 renders of randomly
generated string trees across all three option shapes are byte-identical
to the previous implementation.

The README claimed TypeScript "cannot enforce at the type level that the
first element is a string", which isn't true -- a tuple type can. It
would rule out building trees with push, which is the actual reason for
the permissive type, so the docs now say that instead. Also documents
labels and errors, with the new example covered by the README test.

Adds CHANGELOG.md, backfilled from the tags, with the breaking changes
above under Unreleased.
@tbeseda
tbeseda merged commit 7a4cc64 into main Aug 14, 2026
4 checks passed
@tbeseda
tbeseda deleted the fix/input-validation branch August 14, 2026 01:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant