fix(lint): make noUndeclaredMacros an error, and fix what it found (ratchet 2/n, #376) #419

Merged
allan merged 1 commits from fix/lint-no-undeclared-macros into release/7.22 2026-11-01 01:41:33 +00:00
Collaborator

Rung 2 of the #376 ratchet, on top of #418. sas/.sasjslint promotes noUndeclaredMacros to error; its 25 findings on release/7.22 are cleared, and two of them were real faults rather than missing prose.

What was broken

Rather than trusting the linter alone, I compared each compiled service against the macros it calls: compile, then list every macro that a generated program calls but does not define (filtered to macros that exist somewhere in the project).

Three services were calling a macro that was absent from their own compiled program:

  • services/validations/tables_all.sas calls %mf_getuniquename() on its third line and never declared it.
  • services/validations/mpe_tables.dsn.sas calls %mf_getuniquename() and %dc_assignlib() and declared neither.
  • services/hooks/mpe_tables_postedit.sas calls %dc_assignlib(), which is supplied by the service that includes the hook (see below).

The two validation services are configured as rule_value entries in MPE_TABLES (mpe_makedata.sas and the v3.12/v3.13 migrations), so those calls run when a user reviews or filters a library, and each would have raised Apparent invocation of macro ... not resolved. Both now declare what they call, and the definitions are present in the compiled program.

What changed

  • 14 files declare the macros they call but had been relying on another declaration to pull them in: mf_getquotedstr, mf_nobs, mf_getuser (twice), mf_getapploc, mf_getattrn, mp_abort (six services), mf_getuniquename (twice), dc_assignlib, bitemporal_closeouts. These were already defined in the compiled program through another macro's header; the declarations make the dependency visible, and make the two validation services correct.
  • 6 hook scripts get a file-local @sasjslint {"ignoredMacros": [...]} (mp_abort, plus dc_assignlib in mpe_tables_postedit) instead of a macro list. Hooks are included at run time by the service that owns them, so those macros are already in the session, and these files are copied and edited by end users - they should not carry a declaration section to maintain. Recorded in AGENTS.md.
  • bitemporal_dataloader.test.2.sas loses its test 30 block. It is gated with and 0 ("skip until have a db") and its only setup line calls %assign_direct_lib, a macro that exists nowhere in this project or in @sasjs/core - enabling the block would fail on its first line.

Verification

  • npm run lint:sas: 18 warnings, 0 errors, exit 0.
  • sasjs compile: succeeds. The called-but-undefined list drops from three services to the single hook exception; every other definition-count change is an addition (no definition removed).
  • No new files call a macro that is not defined.

Remaining, per rung

18 warnings: noBannedStrings (13), macro name length (2) and case (2), indentationMultiple (1). Next PR takes the naming, indentation and banned-string findings, which are the same kind of mechanical edit.

Rung 2 of the #376 ratchet, on top of #418. `sas/.sasjslint` promotes `noUndeclaredMacros` to `error`; its 25 findings on `release/7.22` are cleared, and two of them were real faults rather than missing prose. ## What was broken Rather than trusting the linter alone, I compared each compiled service against the macros it calls: compile, then list every macro that a generated program calls but does not define (filtered to macros that exist somewhere in the project). Three services were calling a macro that was absent from their own compiled program: - `services/validations/tables_all.sas` calls `%mf_getuniquename()` on its third line and never declared it. - `services/validations/mpe_tables.dsn.sas` calls `%mf_getuniquename()` and `%dc_assignlib()` and declared neither. - `services/hooks/mpe_tables_postedit.sas` calls `%dc_assignlib()`, which is supplied by the service that includes the hook (see below). The two validation services are configured as `rule_value` entries in `MPE_TABLES` (`mpe_makedata.sas` and the v3.12/v3.13 migrations), so those calls run when a user reviews or filters a library, and each would have raised `Apparent invocation of macro ... not resolved`. Both now declare what they call, and the definitions are present in the compiled program. ## What changed - **14 files declare the macros they call** but had been relying on another declaration to pull them in: `mf_getquotedstr`, `mf_nobs`, `mf_getuser` (twice), `mf_getapploc`, `mf_getattrn`, `mp_abort` (six services), `mf_getuniquename` (twice), `dc_assignlib`, `bitemporal_closeouts`. These were already defined in the compiled program through another macro's header; the declarations make the dependency visible, and make the two validation services correct. - **6 hook scripts get a file-local `@sasjslint {"ignoredMacros": [...]}`** (`mp_abort`, plus `dc_assignlib` in `mpe_tables_postedit`) instead of a macro list. Hooks are included at run time by the service that owns them, so those macros are already in the session, and these files are copied and edited by end users - they should not carry a declaration section to maintain. Recorded in `AGENTS.md`. - **`bitemporal_dataloader.test.2.sas` loses its test 30 block.** It is gated with `and 0` ("skip until have a db") and its only setup line calls `%assign_direct_lib`, a macro that exists nowhere in this project or in `@sasjs/core` - enabling the block would fail on its first line. ## Verification - `npm run lint:sas`: 18 warnings, 0 errors, exit 0. - `sasjs compile`: succeeds. The called-but-undefined list drops from three services to the single hook exception; every other definition-count change is an addition (no definition removed). - No new files call a macro that is not defined. ## Remaining, per rung 18 warnings: `noBannedStrings` (13), macro name length (2) and case (2), `indentationMultiple` (1). Next PR takes the naming, indentation and banned-string findings, which are the same kind of mechanical edit.
hermes added 1 commit 2026-11-01 01:20:06 +00:00
fix(lint): make noUndeclaredMacros an error, and fix what it found
Build / Build-and-ng-test (pull_request) Successful in 6m26s
Lighthouse Checks / lighthouse (pull_request) Successful in 20m36s
Build / Build-and-test-development (pull_request) Successful in 35m20s
af28a79bd5
Rung 2 of the #376 ratchet: `sas/.sasjslint` promotes noUndeclaredMacros to
"error". Its 25 findings on release/7.22 are cleared, and two of them were
real faults rather than missing prose.

WHAT WAS BROKEN

Comparing the compiled program against the macros it calls (compile, then
list every project macro each generated service calls but does not define)
found three services calling macros that were absent from their own
compiled program:

- services/validations/tables_all.sas calls %mf_getuniquename() on its
  third line and never declared it.
- services/validations/mpe_tables.dsn.sas calls %mf_getuniquename() and
  %dc_assignlib() and declared neither.
- services/hooks/mpe_tables_postedit.sas calls %dc_assignlib(), which is
  supplied by the service that includes the hook (see below).

The two validation services are configured as rule_value entries in
MPE_TABLES (mpe_makedata.sas and the v3.12/v3.13 migrations), so the calls
run when a user reviews or filters a library - each would have raised
"Apparent invocation of macro ... not resolved". Both now declare what
they call, and the definitions are present in the compiled program.

WHAT CHANGED

- 14 files declare the macros they call but had been relying on another
  declaration to bring in: mf_getquotedstr, mf_nobs, mf_getuser (twice),
  mf_getapploc, mf_getattrn, mp_abort (six services), mf_getuniquename
  (twice), dc_assignlib, bitemporal_closeouts. These were defined in the
  compiled program already; the declarations make the dependency visible
  and the two validation services correct.
- 6 hook scripts get a file-local @sasjslint {"ignoredMacros": [...]}
  (mp_abort, plus dc_assignlib in mpe_tables_postedit) instead of a macro
  list. Hooks are included at run time by the service that owns them, so
  the macros are already in that session, and these files are copied and
  edited by end users - they should not carry a declaration section to
  maintain. Recorded in AGENTS.md.
- bitemporal_dataloader.test.2.sas loses its test 30 block: it is gated
  with `and 0` ("skip until have a db") and its only setup line calls
  %assign_direct_lib, a macro that exists nowhere in this project or in
  @sasjs/core. Enabling it would fail on the first line.

VERIFICATION

- `npm run lint:sas`: 18 warnings, 0 errors, exit 0.
- `sasjs compile`: succeeds; the called-but-undefined list drops from
  three services to the one hook exception; the only definition-count
  changes are additions.
- 18 warnings remain for the next rungs: noBannedStrings (13), macro name
  length (2) and case (2), indentationMultiple (1).
allan merged commit 4c09c02998 into release/7.22 2026-11-01 01:41:33 +00:00
allan deleted branch fix/lint-no-undeclared-macros 2026-11-01 01:41:33 +00:00
Sign in to join this conversation.