Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,12 @@ jobs:
# ticket/wasm-size-optimization (2026-08-16): wasm-opt flag tuning
# (-Oz --flatten --rereloop -Oz --converge --strip-producers) plus
# sort_unstable at four tie-free sites (value.rs, evaluator.rs,
# builtins.rs x2). PR2 baseline 844,172, post-change 841,937
# (wasm-pack 0.15.0 bundled wasm-opt v117, nodejs target, measured
# locally at HEAD 13cb2a5 before commit). Net local savings: -2,235 bytes.
# NOTE: local uses bundled wasm-opt v117, CI uses Binaryen v129 -- the
# analysis predicted -7,527 bytes (flags) + ~4-6 KB (sort) with v129;
# local savings with v117 are smaller. CI number is authoritative.
# Guard NOT raised: >=5,828 bytes (>=0.69%) headroom on local toolchain;
# CI Binaryen v129 is expected to show a larger reduction.
# builtins.rs x2). PR2 baseline 844,172. CI-measured post-change:
# 836,126 bytes (Binaryen v129, CI run 31946611856). Local wasm-opt
# v117 (bundled by wasm-pack) reads roughly 2-3 KB higher (841,937
# was the local pre-commit estimate; CI number is authoritative).
# Net CI savings vs PR2 baseline: -8,046 bytes.
# Guard NOT raised: 13,874 bytes (1.63%) headroom.
# Toolchain now pinned to 1.96.0 in the wasm job (see companion commit).
if [ "$raw" -gt 850000 ]; then
echo "::error::WASM binary exceeds 850,000 byte threshold: ${label} is ${raw} bytes"
Expand Down
1,987 changes: 1,002 additions & 985 deletions CHANGELOG.md

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions crates/mds-cli/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,12 @@ impl miette::Diagnostic for StdinRelabeledError {
/// inner diagnostic that already carries a `NamedSource` (which these do) wins
/// and the replacement is ignored.
///
/// Call sites (verified line numbers, §5 step 1a of the implementation plan):
/// - `mds check -`: `crates/mds-cli/src/main.rs:280`
/// - `mds build -` (single-file path): `crates/mds-cli/src/build.rs:714`
/// - `mds build -` (directory stdin path): `crates/mds-cli/src/build.rs:1176`
/// - `mds lint -`: `crates/mds-cli/src/lint.rs` via
/// `emit_analysis_failure_json_or_stderr` (indirect; symbol cited instead of
/// a line number — avoids stale citations after line insertions)
/// Call sites (symbolic references; prefer these over line numbers to avoid stale citations):
/// - `mds check -`: `run_check` in `crates/mds-cli/src/main.rs`
/// - `mds build -` (single-file path): `compile_to_content` in `crates/mds-cli/src/build.rs`
/// - `mds build -` (directory stdin path): `run_build` in `crates/mds-cli/src/build.rs`
/// - `mds lint -`: `run_lint_stdin` in `crates/mds-cli/src/lint.rs` (direct call)
/// and `run_lint_file` via `emit_analysis_failure_json_or_stderr` (indirect)
///
/// Any new CLI boundary that renders a stdin analysis failure must call this
/// function; skipping it renders `<source>` and breaks the uniform-sentinel rule.
Expand Down
2 changes: 1 addition & 1 deletion crates/mds-cli/tests/cli_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,7 @@ fn dir_fix_json_residuals_keyed_by_relative_path_not_input_mds() {
// diag.file to STRING_SOURCE_MAP_LABEL ("input.mds"). Without set_diag_display_path
// in the single-file Fixed/PartiallyFixed arms, `mds lint --fix --format json <file>`
// emitted "input.mds" instead of the real basename. Directory mode already had the
// correct relabel (lint.rs:1176/1197); this test pins the single-file parity.
// correct relabel (`run_lint_file` in lint.rs); this test pins the single-file parity.
//
// Fixture: a file with duplicate-export (Tier A, auto-fixed) + unused-variable
// (Tier C, residual after fix). After --fix, the residual must appear under
Expand Down
4 changes: 3 additions & 1 deletion crates/mds-napi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ Source-map options are **not accepted** — check does not generate output.
### `lint(source, opts?)` / `lintFile(path, opts?)` / `lintVirtual(modules, entry, opts?)`

Static analysis. Returns the canonical lint JSON:
`{ version: 1, files: [{file, diagnostics: [{rule, severity, message, help, fixable, fix_edits, span?},...]},...], truncated: bool, lint_warnings?: string[] }`
`{ version: 1, files: [{file, diagnostics: [{rule, severity, message, help: string | null, fixable, fix_edits: ... | null, span: LintSpan | null},...]},...], truncated: bool, lint_warnings?: string[] }`

`help`, `span`, and `fix_edits` are always-present keys in the JSON object; their value is `null` when the rule emits no hint, produces no source span, or carries no fix edits respectively.

Options: `basePath` (lint only — lintFile derives the base from the file path; lintVirtual resolves against the module map), `vars`, `rules` (`Record<string, "off"|"info"|"warn"|"error">`).
Unknown rule names in `rules` emit a warning and lint continues — the unknown name has no effect but `result.lint_warnings` (a `string[]` field, absent when empty) is populated so callers can surface the issue; unknown severity values throw `mds::invalid_options`.
Expand Down
2 changes: 1 addition & 1 deletion examples/linting/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Linting demo

`mds lint` runs nine static-analysis rules over a template *without executing it*,
`mds lint` runs ten static-analysis rules over a template *without executing it*,
catching correctness and style problems that `mds check` does not. This directory
demonstrates the rules, the JSON output, the auto-fixer, and per-rule severity
configuration via `mds.json`.
Expand Down
11 changes: 8 additions & 3 deletions packages/mds/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ file-path methods derive the base directory from the file argument.

```ts
// CheckOptions — accepted by check() (string source)
// basePath: required when the source contains @import or @extends.
// basePath: defaults to process cwd when omitted. Caution: omitting it resolves
// imports against cwd, which may be the wrong directory. Provide an explicit
// path when the source contains @import or @extends.
// WASM backend: basePath throws mds::invalid_options (no filesystem access);
// set MDS_BACKEND=native to use the native backend with import resolution.
// {basePath: undefined} is treated as absent on both backends.
Expand Down Expand Up @@ -157,7 +159,9 @@ interface CheckFileOptions {
}

// LintOptions — accepted by lint() (string-source)
// basePath: required when the source contains @import or @extends.
// basePath: defaults to process cwd when omitted. Caution: omitting it resolves
// imports against cwd, which may be the wrong directory. Provide an explicit
// path when the source contains @import or @extends.
// WASM backend: basePath throws mds::invalid_options — rejects instead of
// silently ignoring so misconfigured callers see an actionable error.
// Set MDS_BACKEND=native to use the native backend, or use lintVirtual with
Expand Down Expand Up @@ -204,5 +208,6 @@ surfaces it appears in `lint_warnings`.
**Lint result shape:**
```ts
{ version: 1, files: [{ file: string, diagnostics: LintDiagnostic[] }], truncated: boolean, lint_warnings?: string[] }
// LintDiagnostic: { rule, severity, message, help?, fixable, fix_edits, span? }
// LintDiagnostic: { rule, severity, message, help?: string | null, fixable, fix_edits?: ... | null, span?: LintSpan | null }
// help, span, and fix_edits are always-present keys in the JSON wire format; their value is null when absent.
```
27 changes: 20 additions & 7 deletions packages/mds/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,14 @@ export interface CheckOptions {
vars?: Record<string, unknown>;
/**
* Base directory for resolving `@import` directives in the source string.
* Required when the source contains `@import` or `@extends`.
* Defaults to the process cwd when omitted.
*
* **WASM backend:** rejected at runtime with `mds::invalid_options` — the WASM
* **Caution:** omitting `basePath` resolves imports against the process cwd,
* which succeeds silently but resolves against the wrong directory if the
* source string was not loaded from cwd. Provide an explicit path when the
* source contains `@import` or `@extends`.
*
* **WASM backend:** rejected at runtime with `mds::invalid_options` -- the WASM
* backend has no filesystem access. Set `MDS_BACKEND=native` to force the native
* backend.
*/
Expand Down Expand Up @@ -198,12 +203,15 @@ export interface LintDiagnostic {
severity: 'error' | 'warn' | 'info';
/** Human-readable description of the finding. */
message: string;
/** Optional guidance on how to resolve the finding. */
help?: string;
/** Optional guidance on how to resolve the finding. `null` when the rule emits no hint. */
help?: string | null;
/** Whether the lint engine can auto-fix this diagnostic (`--fix`). */
fixable: boolean;
/** Source location of the finding, if available. */
span?: LintSpan;
/**
* Source location of the finding. `null` when the rule produces no source span.
* The key is always present in the JSON wire format; only the value is `null`.
*/
span?: LintSpan | null;
/**
* Byte-range replacement edits the fix engine would apply, if available.
* Each edit is `{ start, end, new_text }` with byte offsets into the source.
Expand Down Expand Up @@ -314,7 +322,12 @@ export interface LintOptions {
rules?: Record<string, RuleSeverity>;
/**
* Base directory for resolving `@import` directives in the source string.
* Required when the source contains `@import` or `@extends`.
* Defaults to the process cwd when omitted.
*
* **Caution:** omitting `basePath` resolves imports against the process cwd,
* which succeeds silently but resolves against the wrong directory if the
* source string was not loaded from cwd. Provide an explicit path when the
* source contains `@import` or `@extends`.
*
* The WASM backend **rejects** a non-null `basePath` with
* `mds::invalid_options` rather than silently ignoring it. This surfaces the
Expand Down
Loading