Skip to content

Read a project whose whole definition is one matlab.toml - #61

Merged
ww-mw merged 3 commits into
mainfrom
toml-project-reader
Oct 2, 2026
Merged

ww-mw merged 3 commits into
mainfrom
toml-project-reader

Conversation

@ww-mw

@ww-mw ww-mw commented Oct 2, 2026

Copy link
Copy Markdown
Member

R2026b added a fourth project definition format, matlab.project.DefinitionFiles.Toml:
the project's entire definition is one hand-editable matlab.toml at the project root,
and both resources/ and the <name>.prj marker are deleted with it. This reads it.

There is no store to walk, so src/datamodel/parser/TomlProject.ts is a reader of its
own rather than a fourth layout in ProjectParser. What the two share is the result,
ParsedProject, so a page, a node tree and a host see one project shape whichever of
the four formats it arrived as. parseProject dispatches on finding the file among a
store's entries, which keeps every existing caller at one call.

What the format does not record

Two new fields carry that, because an empty list would otherwise be read as a claim
about the project rather than about the format:

  • ParsedProject.membersEnumerated — whether the FORMAT records a member list, not
    whether members were found. true on every XML path (a damaged store enumerated
    nothing, which is a different sentence from a format that enumerates nothing, and the
    memberCount: 0 a host already shows for one is correct and unchanged); false only
    for TOML, where MATLAB's rule is that the files under the project root ARE the
    members — about the filesystem, not about the document.
  • ProjectLabel.declaredFiles — the paths or patterns a label was declared against, as
    written. Empty on every XML layout, which assigns labels the other way round, per
    member file.

The page follows: memberCount, labelledCount and each label's count become
number | null, and a label's declared entries stand in place of a count it does not
have. null rather than a sentinel is deliberate — the consuming webview's esc()
takes string | number, so a null reaching it is a compile error at the call site and
a renderer is forced to branch. A -1 would have type-checked and shipped.

Identity

A project is now identified by an extension OR by a name, so isProjectFile is
name-aware and projectFallbackName reduces a marker PATH: every project in the new
format spells its definition file identically, so stripping an extension would title all
of them "matlab", and the parent folder's name is the rule that works. That widening has
one reachable consequence inside this package, which is why ingest gains a branch
ahead of its .prj one: a .prj is a zip and this is text, so unzipping first would
fail with "invalid zip data" on a perfectly healthy project.

It is the file NAME and emphatically not the .toml extension, which would make every
Cargo.toml and pyproject.toml in a workspace a MATLAB project.

Conservative readings, each recorded where it is made

  • [dependencies] yields a reference only for an inline table carrying a string path.
    A bare string there is a package version constraint — a valid entry of a kind this
    package does not model, not damage — so it is skipped in silence. A warning there
    would fire on healthy files, and a count that cries wolf is a count a host learns to
    hide. [project.shortcuts] takes both spellings, because under that key there is
    nothing else a bare string could mean.
  • Every read goes through a helper that tolerates the wrong type. This is the one format
    a user edits by hand, so a number where a path belongs is an ordinary state of a real
    file; what could not be read is said in warnings instead of thrown.
  • No folder walk to synthesize membership, by the maintainer's decision. It would have
    been verifiable against the corpus — MATLAB reports 9 members for the converted
    fixture — but it would make a page's numbers depend on disk state rather than on the
    document.

Tests

test/tomlProject.test.ts reads the committed parity fixture for every assertion of the
form "this is what MATLAB writes", and inline documents for what a person writes, since
hand editing is the whole point of the format: comments including a # inside a string,
basic vs literal strings, dotted keys, trailing commas, a single string where MATLAB
writes an array, and every field given the wrong TOML type.

The parity suite's three assertions that this format was unread are replaced by the
agreement they were standing in for: a TOML parse equals an XML parse of the same
project field for field on everything the format records, entry-point run order included
— a linked list in a store, an array here. Ids are excluded and the reason is in the
test: conversion preserves MATLAB's UUIDs between XML layouts, while this format records
none, so every id here is synthetic. The lossiness measurements (LabelDataLoss, the
dropped read-only category) stay as they are.

npm run verify green: 5241 tests / 175 files, check:pack (dist-only, 539 files,
588.1 kB), check:leak, check:browser (148 modules, no node: import reachable from
the barrel).

The parser folder may now reach datamodel/fileKinds.ts as well as blockIdentity.ts,
and test/moduleBoundaries.test.ts records why: both are tables of rules about names
shared with code outside the folder, neither imports anything itself, and re-spelling
'matlab.toml' inside the folder to avoid the edge would be the exact defect fileKinds
was written to end. No folder-level edge is added — datamodel/parser -> datamodel
already existed.

ww-mw added 3 commits October 2, 2026 14:18
A `matlab.toml` project file is designed to be hand-edited, so it will carry
comments, quoting variants, dotted keys and multi-line arrays. A subset parser
that mis-reads one of those renders a confidently wrong project page, which is
the expensive failure; smol-toml is a spec-compliant parse with no dependencies
of its own, is browser-safe, and ships under the same BSD-3-Clause license this
package does.

The lockfile's `resolved` URL is rewritten to the public registry, as every
entry here must be. Its recorded version also catches up to package.json, which
a bump had left behind at 1.13.1.
R2026b's `matlab.project.DefinitionFiles.Toml` puts a project's entire
definition into one hand-editable `matlab.toml` at the project root, and
deletes `resources/` and the `<name>.prj` marker with it. There is no store to
walk, so this is a separate reader rather than a fourth layout in
`ProjectParser`; what the two share is the result, `ParsedProject`, so a page,
a node tree and a host see one project shape whichever of the four formats it
arrived as. `parseProject` dispatches on finding the file among a store's
entries, which keeps every existing caller at one call.

Two fields carry what the format cannot say. `membersEnumerated` answers
whether the FORMAT records a member list, not whether members were found: an
XML store that enumerates none means "0 members", and a `matlab.toml` means
"ask the filesystem", which is a different sentence and the one a host needs to
tell apart. `ProjectLabel.declaredFiles` holds the paths a label was declared
against, which only this format has — a store assigns labels the other way
round, per member file.

A project is now identified by an extension OR by a name, so `isProjectFile`
is name-aware and `projectFallbackName` reduces a marker PATH: every project in
the new format spells its file identically, so stripping an extension would
title all of them "matlab", and the rule that works is the parent folder's
name. That widening has one reachable consequence, which is why `ingest` gains
a branch ahead of its `.prj` one: a `.prj` is a zip and this is text, so
unzipping first would fail with "invalid zip data" on a healthy project.

The parser folder may now reach `datamodel/fileKinds.ts` as well as
`blockIdentity.ts`. Both are tables of rules about names shared with code
outside the folder, neither imports anything itself, and re-spelling
'matlab.toml' inside the folder to avoid the edge would be the exact defect
`fileKinds` was written to end.
A project page built from a format that records no member list must not report
one. `memberCount`, `labelledCount` and each label's `count` become
`number | null`, `null` exactly when `ParsedProject.membersEnumerated` is
false, because 0 is a sentence — "this project contains nothing" — and it is
false about a project whose members are every file under its root. The
maintainer's decision is to declare only what the file declares, with no folder
walk to synthesize a membership the document does not have.

`null` rather than a sentinel, deliberately: the consuming webview's `esc()`
takes `string | number`, so a `null` reaching it is a compile error at the call
site and a renderer is forced to branch. A -1 would have type-checked and
shipped.

What a page shows instead is on the new `ProjectPageLabel.declaredFiles`,
carried through from the parse: an XML store assigns labels per member file and
the count is the whole story there, while this format inverts it — the label
declares its files — so the list stands in place of the count rather than
beside it. With no assignments to count, the label ordering falls back to the
name; "used labels first" would order every label as if it were known to be
unused.

Tests: a reader suite over the committed parity fixture for what MATLAB writes,
and over inline documents for what a person writes, since hand editing is the
whole point of the format — comments, a `#` inside a string, literal strings,
dotted keys, trailing commas, a single string where MATLAB writes an array, and
every field given the wrong TOML type. The parity suite's three assertions that
the format was unread are replaced by the agreement they were standing in for:
a TOML parse equals an XML parse of the same project field for field on
everything the format records, entry-point run order included, which is a
linked list in a store and an array here. The lossiness measurements stay as
they are.
@ww-mw
ww-mw merged commit 7a4870b into main Oct 2, 2026
4 checks passed
@ww-mw
ww-mw deleted the toml-project-reader branch October 2, 2026 19:12
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