Skip to content

SASjs Artefacts

SASjs projects are full of files with .sas extensions. With the exception of tests, the only way to tell them apart is to start from the sasjs/sasjsconfig.json file. Each file type is described below.

Primary Artefacts

The three Primary Artefacts are Job, Service, and Test. These artefacts are compiled, added to a build pack, and deployed to SAS.

Job

A SASjs Job is a .sas program found in a directory listed in the jobFolders array of the jobConfig object. Where there are jobFolders at both target and root level in the sasjsconfig.json file, the subdirectory/jobname.sas files at target level will take precedence.

Jobs are not expected to write to _webout and so are not compiled with the %webout() macro and it's dependencies. Jobs are always created in a /jobs/ folder under the target appLoc.

A Job may contain:

  • Data Inputs / Outputs - used to generate the data lineage
  • Macros - listed under <h4> SAS Macros </h4>
  • SAS Includes - listed under <h4> SAS Includes </h4>
  • Binary Files - under <h4> Binary Files </h4>

Service

A SASjs Service is a .sas program found in a directory listed in the serviceFolders array of the serviceConfig object. Where there are serviceFolders at both target and root level in the sasjsconfig.json file, the subdirectory/servicename.sas files at target level will take precedence.

Services are expected to write to _webout and so are compiled along with the %webout() macro and dependencies. Services are always created in a /services/ folder under the target appLoc.

A Service may contain:

  • Service Inputs / Outputs - helpful for the JS developers
  • Macros - listed under <h4> SAS Macros </h4>
  • SAS Includes - listed under <h4> SAS Includes </h4>
  • Binary Files - under <h4> Binary Files </h4>

Test

A SASjs Test is a .test.sas (or .test.[integer].sas) program found in ANY of the macroFolders, serviceFolders or jobFolders arrays.

Tests are compiled like services (with %webout() and dependencies) so that test results can be returned in the output JSON. Tests are always created in a /tests/ folder under the target appLoc as follows:

  • $appLoc/tests/macros -> Macro tests
  • $appLoc/tests/jobs -> Job tests
  • $appLoc/tests/services -> Service tests

A test may contain:

  • Macros - listed under <h4> SAS Macros </h4>
  • SAS Includes - listed under <h4> SAS Includes </h4>
  • Binary Files - under <h4> Binary Files </h4>

Secondary Artefacts

SAS Macros

Macro dependencies can be specified in the following artefacts:

  • Jobs
  • Services
  • Tests
  • Macros (extracted recursively)
  • initProgram
  • termProgram

They are NOT compiled from SAS Includes or Binary Files.

To add a set of macros to a compiled file, just add the following in the header of the source file (artefact):

  <h4> SAS Macros </h4>
  @li macro1.sas
  @li macro2.sas

During compilation, these macros will be sourced from the following locations (in this order):

  • target-level macroFolders array in the sasjsconfig.json file
  • root-level macroFolders array in the sasjsconfig.json file
  • SASjs Core under node_modules/@sasjs/core
  • SASjs Core under node_modules/@sasjs/cli/node_modules/@sasjs/core
  • SASjs Core from the GLOBAL install of the SASjs CLI

As soon as a macro is found, the search stops. So if an mf_nobs.sas macro was placed in a directory from the root-level macroFolders array, then the same-named definition would NOT be taken from SASjs Core.

If a macro is not found then the compilation will immediately fail.

To avoid continually re-scanning the locations above, macros are added to an internal object (compileTree) as they are found, along with their dependents and source folder location. After compilation this object is exported to sasjsbuild/compileTree.json.

The compiled file does not contain duplicate macros. When compiling each Job / Service / Test, a distinct list of 'top level' macro names are taken from any initProgram and termProgram definitions, in addition to the %webout() dependencies if a Service or Test.

The header of each macro is removed in order to reduce the overall compiled file size.

SAS Includes

Whilst macro definitions can be easily copy pasted into the beginning of a job, arbitrary SAS code files cannot (as they are executed immediately rather than compiled into a macro catalog).

To enable arbitrary SAS code files (SAS Includes), the compile process will wrap the code in data step put '(source code);'; statements and assign a user-provided fileref to enable the code to be easily %inc'd at the preferred point of execution.

SAS Include dependencies can be specified in the following artefacts:

  • Jobs
  • Services
  • Tests

They are NOT compiled from macros or other SAS Includes.

To add a set of SAS Includes to a compiled file, add the following in the source file (artefact) header:

  <h4> SAS Includes </h4>
  @li somefile.sas MYREF
  @li anotherfile.ddl MOJFREF

During compilation, the locations below will be searched for files named somefile.sas and anotherfile.ddl:

When the file is found, it is wrapped in put statements and added to the compiled file, along with a filename statement corresponding to the user-provided fileref (eg MYREF or MOJREF).

To run this code as part of your Job, Service, or Test - just execute as follows:

%inc MYREF;
%inc MOJREF;

Binary Files

In rare cases you may wish to embed non textual content into your Job / Service / Test - such as Excel, Zip, Images, even video. This is all possible thanks to a common technique known as Base64 encoding. This allows ANY binary content to be represented as a text string - with the caveat that the encoded file will be at least 33% larger (4 bytes used for every 3 bytes of input).

The compilation process both base64 encodes the source file AND wraps it in put statements with a corresponding fileref for developer use.

Binary Files can be specified in the following artefacts:

  • Job
  • Service
  • Test

They are not compiled from Macros or SAS Includes.

To add a set of Binary Files to a compiled file, add the following in the source file (artefact) header:

  <h4> Binary Files </h4>
  @li myfile.zip MYZIP
  @li base.xlsx XL

During compilation, the locations below will be searched for files named myfile.zip and base.xlsx:

When the file is found, it is base64 encoded then wrapped in put statements and added to the compiled file, along with a filename statement corresponding to the user-provided fileref (eg MYZIP or XL).

To run this code as part of your Job, Service, or Test - just execute, for example, as follows:

%mp_unzip(ziploc="%sysfunc(pathname(MYZIP))",outdir=&sasjswork)

initProgram

The initProgram attribute is found in the following objects:

  • jobConfig
  • serviceConfig
  • testConfig

Any Macros in the initProgram are compiled along with those in the termProgram, the Job / Service / Test itself, and the webout() macros (if a Service or Test).

The initProgram code itself is inserted without modification into the compiled file right before the main Job / Service / Test code.

Only one initProgram may be used (target level or root level), and it is always applied to ALL instances of the particular type (ie Job / Service / Test).

termProgram

The termProgram attribute is found in the following objects:

  • jobConfig
  • serviceConfig
  • testConfig

Any Macros in the termProgram are compiled along with those in the initProgram, the Job / Service / Test itself, and the webout() macros (if a Service or Test).

The termProgram code itself is inserted without modification into the compiled file right after the main Job / Service / Test code.

Only one termProgram may be used (target level or root level), and it is always applied to ALL instances of the particular type (ie Job / Service / Test).