iwe
Added
--project/--add-fieldsaccept block-addressed sources:{ $content: PREDICATE }narrows a document's body to the selected blocks (rendered at their original depth),$blocks/{ $blocks: PREDICATE }lists each selected block astype/path/textdata, and{ $matches: REGEX }greps matching lines with their section paths.findmarkdown output renders$blocksand$matchesentries one line each askey › section path › text, and switches to the fenced-block form with the narrowed body when a parameterized$contentfield is projected.--projectaccepts a bare block predicate —--project '$header: {}'renders each document's body narrowed to the selected blocks (the headers-only form) underkeyandcontentfields, so--format json/yamloutput keeps the document identity that the markdown fence already carries.updategains a block-edit flag per operator —--replace,--replace-text,--insert-before,--insert-after,--append,--delete— each taking a{ <selector>, payload }mapping and composing with--set/--unsetinto one atomic update. A validation failure (unmetexpect, overlapping selections, incompatible target) prints the offending blocks and exits non-zero without writing.--replace-textaccepts afrom-less argument ({ $header: Goals, to: Aims }) that rewrites the block's entire own text — the clean way to rename a header or restate a line.- A block edit targeting a
$headeracts on the heading line alone:--delete '{ $header: Goals }'dissolves the section (contents re-attach to the parent and re-level) and--replace '{ $header: Goals, content: "## Aims" }'retitles it (contents kept), while--delete '{ $section: Goals }'removes the whole tree.--insert-after '{ $header: Goals, content: ... }'adds content at the top of the section, below the heading line. updateanddeletegain--expect— a document-level guard asserting the number of matched documents (Nor{ min, max }); on a mismatch the command lists the matched documents askey › titleand exits non-zero without writing. Both also gain--strict, which requires anexpectguard on every mutating application (the document-level--expectand each block operator'sexpect) and aborts before writing if any is missing;--dry-runis exempt so counts can be learned.find --blocks PREDadds ablocksfield listing each block matching the predicate (lowers toaddFields: { blocks: { $blocks: PRED } }), andfind --matches PATTERNrestricts results to documents whose content matches PATTERN and adds amatchesgrep field (lowers to a$contentmembership filter plusaddFields: { matches: { $matches: PATTERN } }).find --filteraccepts the$contentblock-membership operator —--filter '$content: { $header: Status }'selects documents that contain at least one block satisfying the predicate.
Changed
update -k/--keyis repeatable, matchingfind: one key lowers to$eq, two or more to$in(body-overwrite mode still takes exactly one). Previously it accepted a single key only.updatewrites only documents whose rendered content actually changes and reports honestly —Updated N document(s)when every matched document changed,Matched N document(s), M changedotherwise (No documents matchedwhen none) — so a no-op edit (e.g.expect: 0) leaves the file, and its mtime, untouched.
Fixed
--project/--add-fieldsnow parse the argument as a YAML mapping whenever it contains a:or{, and report a parse error on malformed input instead of silently falling back to the comma list. Previously an unbraced multi-field mapping like--project 'a: { $content: ... }, b: { $content: ... }'failed the YAML parse, degraded to the comma list, and emitteda: null, b: nullwith no error. The comma list keeps thename,name=source, and bare$selectorforms; write multi-field or block projections as a braced mapping.
iwec
Added
iwe_querytool runs an IWE query/block-selection operation document —operationisfind/count/update/deleteanddocumentis the operation as a YAML string. It exposes the$contentmembership filter, the$content/$blocks/$matchesprojection sources, and the block update operators ($replace,$replaceText,$insertBefore,$insertAfter,$append,$delete).findandcountread;updateapplies frontmatter and block edits;deleteremoves documents with reference cleanup. The tool is always strict: every mutating application must carry anexpectguard or the operation is refused with the missing guards named.update/deleteacceptdry_runto preview without writing.
liwe
Added
query::blockmodule with theBlockPredicategrammar for addressing blocks inside a document: text and regex predicates,$within/$containsaxes, per-type operators ($section,$header,$paragraph,$item,$list,$quote,$code,$table,$ref,$hr),$references, and$and/$or/$norcomposition.- Block-addressed projection sources:
{ $content: PREDICATE }renders the selected blocks,$blocksreports each selected block astype/path/text, and{ $matches: REGEX }greps matching lines with their section paths — all evaluated through the newquery::block_eval::BlockIndex. IntoBlockPredicatetrait accepting scalar shorthands wherever a block predicate is expected.FindOp::add_fieldssets an additive (addFields) projection;CountOpandDeleteOpimplementFrom<FindOp>, reinterpreting a built find with its projection dropped.projectaccepts a$-prefixed block predicate mapping (project: { $header: {} }), lowering it to akeyfield and acontentfield carrying the narrowed body.- Block update operators in the
updatedocument —$replace,$replaceText,$insertBefore,$insertAfter,$append,$delete— each pairing a block predicate selector with its payload and an optionalexpectguard, validated and applied atomically; represented byBlockUpdate,BlockUpdateOp, andExpectonUpdate::block_ops. - Unit block operators act on their target as selected: a
$headernode covers its heading line alone ($deletedissolves the section, a heading$replaceretitles it) while a$sectioncovers the whole tree. UpdateOpandDeleteOpcarry an optionalexpectguard asserting the number of matched documents; on violation nothing is written and the error lists each matched document.$contentfilter operator (Filter::Content) matches documents holding at least one block satisfying a block predicate; it composes with every other filter clause.query::strict_guard_violationsnames the mutating applications that lack anexpectguard.
Changed
query::executereturnsResult<Outcome, block_update::EvalError>(wasOutcome) so a failed block update reports its validation error instead of writing;find,count, anddeletealways returnOk.Updatecarriesblock_ops: Vec<BlockUpdate>alongside the frontmatteroperators.Projectioncarries abase: ProjectionBase(Empty/Frontmatter/Document) in place ofmode: ProjectionMode, soFindOp::projectis a plainProjection(wasOption<Projection>);Projection::document_fields()replacesProjection::default_for_find().ProjectionContextis constructed withProjectionContext::new(graph, key)(was a public struct literal).
Fixed
- A mis-typed
projectmapping now reports a parse error instead of being silently read as a comma list of frontmatter field names and yieldingnull.
Removed
query::preludemodule (with itsWithFiltertrait) — the Rust builder functions moved into the test suite; constructOperation,FindOp, andFilterdirectly.query::project::apply_projection_or_default—apply_projectioncovers the no-projection case.