Skip to content
Ilya Sher edited this page Oct 3, 2025 · 3 revisions

Note: this page is a work in progress.

What is ngsfile?

ngsfile is a script in NGS programming language that is residing in a file named ngsfile.

Running ngs . is exactly the same as running ngs ./ngsfile. The ability to run the script typing less is the only special feature in ngsfile as opposed to other scripts in the NGS programming language.

What is the purpose of ngsfile?

The purpose of ngsfile is to contain CLI commands specific to the project where it resides. Examples:

  • Run tsc, fetch ECS container environment variables, and start your TypeScript project with these.
  • start/stop finch/docker containers on which the project depends to run locally, fill the DB in a container with sample/test so it's usable.
  • Implement CLI client for the project. That's an API client that uses curl/grpcurl.
  • Implement integration tests: run the server, issue requests
  • Debugging
    • Check that your .env file is properly configured for your environment
    • Assist debugging by fetchig/tailing appropriate logs from AWS
    • Fetch data from Amazon DynamoDB that's relevant for debugging

Alternatives

Usual suspects for project-specific CLIs are:

  • A bunch of shell scripts, typically with .sh extension, employing sh or bash.
  • Makefile with arbitrarty commands instead of build instructions
  • For JS/TS projects - package.json, the scripts field

The advantage of the NGS language over the alternatives above:

  • NGS is a fully fledged programming language
  • NGS has domain specific facilities for running external programs, small scale data manipulation, etc.

Where is ngsfile located?

Typically, ngsfile is located at the root of the project.

Additionally, a common assumption is that the script is also run from that directory. This assumption makes the code in ngsfile easier to write and maintain.

Accessing project-specific CLI globally

If you wish to use ngsfile of a particular project globally, add the following (or the equivalent in your shell) to your .bashrc:

function ppp() {
	(cd ~/path/to/your/project && ngs . "$@")
}

Replace ppp with your project name (make sure it doesn't collide with existing shell command or a program).

Replace the path as appropriate.

Before this setup you would need to run ngsfile like this:

cd ~/path/to/your/project
ngs . MY_ARG1 MY_ARG2

After this setup you will be able to run your ngsfile like this:

ppp MY_ARG1 MY_ARG2

Sample Techniques

This section describes NGS language features that are best fitting the use case of ngsfile.

Namespacing

To take advantage of automatic command line arguments parsing by NGS and hierarchical commands, the script should use namespaces - ns. Example of overall layout:

ns {
    api = ns {
        F list_items() ...
        F add_item() ...
        F delete_item() ...
    }
    dev = ns {
        F run() ...
    }
    dbg = ns {
        ...
    }
    _test = ns {
        F basic() {
            test("Port is listening", {
                ...
            })
        }
    }
    _exprorts.test = _test  # trick to not shadow the global test() method
    ...
}

Having such layout allows the script to be called as follows:

ngs . api list_items
ngs . api add_item
ngs . api delete_item
ngs . dev run
ngs . test basic

Note that calling ngsfile from the command line and from other NGS code is conceptually very similar. Example:

ngs -e 'require("./ngsfile")::dev::run()'.

Command Line Arguments Parsing by NGS

NGS automatically parses command line arguments (for scripts that either have main functions or like in our case, scripts that use namespaces).

ns {
    dev = ns {
        F run(port:Int) ...
    }
}

Can be called as:

ngs . dev run 8080

TODO: expand about booleans and optional parameters

Returning Values

NGS automatically detects "tables" (array of Hashes where keys of all Hashes are the same) and would format the data accordingly on the screen.

If the output is not going to the terminal but rather piped or redirected to a file, NGS would encode the returned value as JSON.

TODO: expand this section

Reading Environment Variables

In NGS, reading evnironment variables is done using the ENV Hash. Example: ENV.HOME.

It is an error to try to read non-existent environment variable. Use ENV.get('MYVAR') (returns null if missing) or ENV.get('MYVAR', 'my_default').

To check if an environment variable exists, use ENV.has('MYVAR').

Tip: if your script requires MYVAR, you can place ENV.MYVAR at the top of the script (but inside the ns). That way it will fail immediately as opposed to doing half of the work and failing later when trying to access the variable.

Running External Programs

NGS has plenty of funcionality around running external programs.

Syntax

  • $(my_prog arg1 arg2 ...) - runs the program
  • $(my_prog arg1 arg2 ... &) - runs the program in the background, returns a reference to it so you can wait(p) or kill(p).
  • my_prog arg1 arg2 ... - runs the program, captures its output
  • line: my_prog arg1 arg2 ... - runs the program, captures its output, returns the first line.
  • my_prog arg1 arg2 ... - runs the program, captures its output, and parses the output. Result is a data structure.
  • $[my_prog arg1 arg2 ...] - runs the program without capturing the output. The output passes through to the terminal (or to the pipe/file if redirected).

Arguments substitution is supported in all cases above. Example:

arg = 'xyz'
args = ['aa', 'bb']
$(my_prog $arg $*args)

Note that $arg expands to single argument, while $*args expands to multiple arguments.

TODO: wiki/documentation page with everything related to running external programs (and link from here)

Clone this wiki locally