Files
dc/.agents/skills/sasjs-core/SKILL.md
T
hermes f7db8719f5
Build / Build-and-ng-test (pull_request) Successful in 5m8s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m24s
Build / Build-and-test-development (pull_request) Successful in 25m20s
fix: agent skills and nextviya deploys
2026-08-19 17:17:30 +01:00

4.4 KiB

name, description
name description
sasjs-core Standards and conventions for the @sasjs/core SAS macro library (mf_*, mp_*, mm*, ms_*, mv_* macros). Use when writing or editing SAS macros in a sasjs/core-style repo, picking an existing macro over reinventing one, or the sasjs/core build, lint, doxygen, and testing conventions.

@sasjs/core — SAS Macro Library

@sasjs/core is an MIT-licensed library of production-quality SAS macros for SAS application development, portable across SAS 9 (meta), Viya, and SASjs server.

Coding standards (mandatory)

  • One macro per file; filename must match the macro name (lowercase, no spaces)
  • Macro definitions must use parentheses: %macro x(); not %macro x;
  • Macro calls are NOT terminated with a semicolon: %my_macro() not %my_macro();
  • All macro variables must be declared %local to prevent scope leakage
  • Always use mf_getuniquefileref when assigning filerefs, and mf_getuniquelibref when assigning librefs (never hardcode or hand-roll unique references)
  • 2-space indentation, no tabs, no trailing spaces, no invisible characters, max line length 300 (hard lint limit) but keep lines to 80 chars max where possible
  • Every file must have a Doxygen header:
/**
  @file
  @brief One-line description of the macro

  <h4> SAS Macros </h4>
  @li mf_othermacro.sas

  @param [in] paramname Description
  @param [out] outparam Description

  <h4> Related Macros </h4>
  @li mp_related.sas

  @version 9.4
  @author Your Name
**/

Folder / prefix conventions

Folder Prefix Platform
base/ mf_ (function-style), mp_ (procedure-style) All platforms
meta/ mm_ SAS 9 metadata
metax/ mmx_ SAS 9 metadata (OS command dependent)
viya/ mv_ Viya
server/ ms_ SASjs server
xplatform/ mx_ Runtime platform detection
fcmp/, lua/, ddl/ — PROC FCMP functions, LUA wrappers, DDL

Use mf_ macros when the macro returns a value usable in an expression; use mp_ for procedural macros that generate code/statements.

Cross-suite rule: mp_ macros must never reference mx_ macros. Platform dispatching (SAS 9 / Viya / SASjs server) belongs in the mx_ suite, which delegates to ms_/mv_/PROC STP per platform. If an mp_ macro seems to need platform-specific behaviour, the macro itself belongs in xplatform/ as an mx_ macro instead.

Reuse before writing

Before writing a new macro, check the library for an existing one — common utilities already exist, e.g. mp_abort (the deprecated mf_abort is retained for backwards compatibility — don't use it in new code), mf_existds, mf_existvar, mf_existfileref, mf_getuser, mp_jsonout (SAS datasets → JSON for _webout), mp_ds2ddl, mp_hashdataset. Platform-specific variants exist under meta/, viya/, server/ and are selected at compile time by the CLI.

Aborting safely

Never invoke %mp_abort from inside an %if/%else block — as a procedural macro, the macro processor can continue executing statements after it before the abort takes effect. Use the iftrue= condition parameter instead:

%mp_abort(iftrue= (&syscc ne 0)
  ,mac=&_program
  ,msg=%str(Something went wrong)
)

When %mp_abort is called from within a %include block, SAS cannot exit cleanly (e.g. to _webout). Call %mp_abort(mode=INCLUDE) after the include (OUTSIDE any macro wrapper) — it checks work.mp_abort_errds for an abort status:

%mp_abort(mode=INCLUDE)

Note: %includes inside macros should be performed with %mp_include() so the _SYSINCLUDEFILEDEVICE indicator is set and the abort dataset (work.mp_abort_errds) is passed back to the calling program.

Testing macros (mandatory conventions)

  • Always apply %mp_assertscope around the macro under test to catch scope leakage (macro variables must stay %local):
%mp_assertscope(SNAPSHOT)
%mx_foo(args)
%mp_assertscope(COMPARE,
  desc=Test 1: mx_foo does not leak scope,
  outds=work.test_results
)
  • Assertions go to work.test_results via %mp_assert(iftrue=(...), desc=..., outds=work.test_results).

Lint and build

  • Run sasjs lint after every change; do not consider work done until it passes
  • NEVER bump the version in package.json (semantic-release handles it)
  • Do NOT edit generated files by hand: all.sas, mc_*.sas, the lua/ wrappers, and sasjsbuild/ outputs are produced by the CI build
  • Markdown files: never hard-wrap; one paragraph per line