3.5 KiB
name, description
| name | description |
|---|---|
| sas | Use this skill whenever writing, modifying, or debugging SAS code in this repository — SAS macros, sasjs services, hooks, or test files (*.sas). Triggers include: SAS macro compilation errors, parameter parsing issues, writing sasjs tests with mp_assert / mp_assertdsobs / mp_assertscope, macro-quoting questions (%str, %nrstr, %superq), %mp_abort usage, or unexpected behaviour when passing free-text values (descriptions, messages) to macros. Also covers repo conventions such as running `sasjs lint` after touching .sas files and the maximum line length rule. |
SAS Development
Conventions and pitfalls for SAS code in this repository (macros in sas/sasjs/macros/, services
in sas/sasjs/services/, tests alongside them as *.test.sas).
Always %str() free-text macro parameters
A comma inside a macro parameter value is parsed as a parameter delimiter. Free-text
parameters such as desc= (in %mp_assert, %mp_assertdsobs, %mp_assertscope) and msg= (in
%mp_abort) must be wrapped in %str() — even when they currently contain no comma, so later
edits cannot silently break the call.
Wrong — the text after the comma becomes an unexpected positional parameter and the compilation fails (or worse, is misparsed):
%mp_assert(iftrue=(&oldrows=0),
desc=Test 2 - all staged records loaded, delete flags ignored,
outds=work.test_results
)
Right:
%mp_assert(iftrue=(&oldrows=0),
desc=%str(Test 2 - all staged records loaded, delete flags ignored),
outds=work.test_results
)
The same applies to any macro parameter that carries user-facing text: %mp_abort(msg=%str(...)),
etlsource= values containing punctuation (use %superq() when passing macro variables that may
contain special characters), etc.
Related quoting rules of thumb:
%str()masks commas, parentheses, semicolons and quotes at compile time — sufficient for static text likedesc=.- Use
%nrstr()if the text must also mask%and&(rare in descriptions). - Use
%superq(var)when forwarding a macro variable whose value may contain special characters (e.g.etlsource=inmpe_targetloader.sas).
Tests must be idempotent
A test file must pass when run repeatedly (including after a run that failed partway). Conventions:
- Start the file with
%let syscc=0;— many macros (e.g.%mp_lockanytable(LOCK)) abort on entry if&syscc>0, and anyWARNINGin a previous test bumpssysccto 4. - Clean up all persistent state, not just the obvious one:
MPE_TABLESregistrations,MPE_LOCKANYTABLElock records (a run dying between LOCK and UNLOCK leaves a staleLOCKEDrow), physical tables indctest(proc datasets ... delete), and global macro variables created viaselect ... into:(%symdel). - Make prep defensive: delete-then-insert config records (handles leftovers from an aborted run), and recreate physical tables rather than assuming they are absent.
Repo conventions for .sas files
- Run
npx sasjs lintfrom thesas/directory after creating or modifying any.sasfile; the files you touched must have zero warnings (pre-existing warnings in other files can be ignored). - Maximum line length is 80 characters (lint-enforced) — this is why long
msg=%str(...)values sometimes need shortening. - Test files are named
<thing>.test.sas(or<thing>.test.N.sas) and run vianpm run 4gl && sasjs test -t 4glfromsas/— see.agent/docs/testing.md. sas/sasjsbuild/is generated build output — never hand-edit it; edit sources undersas/sasjs/only.