Skip to content
Anton edited this page Aug 11, 2019 · 13 revisions

When placing examples, it is important to show the output that they produce. This can be achieved using the FORK marker.

%[/!_]FORK(-lang)? module ...args%

Listing examples and forking source code in documentation, gives another layer of Quality Assurance of the program, since after the compilation of the README file, any errors due to introduced changes to the source code will appear there. In fact, in some cases, documentation-driven development can even substitute tests.

On This Page

The %FORK% marker will make Documentary fork a Node.JS module using the child_process.fork function. The output is printed in a code block, with optionally given language. If the process cleared lines with \r, the output will be adjusted to account for that to be displayed like it would be in the terminal. The environment variables will be inherited from the parent doc process.

Markdown JavaScript
The program will output:

%FORK-fs example/fork/fork%
process.stdout.write('...\r')
process.stdout.write('!!\r')
process.stdout.write('?\r\n')
// Display a welcome message.
console.log('HELLO world')
Output
The program will output:

```fs
?!.
HELLO world
```

Stderr

By default, the FORK marker will print the stdout output. To print the stderr output, there is the FORKERR marker.

%FORKERR(-lang)? module ...args%

It works exactly the same as %FORK% but will print the output of the process's stderr stream.

Markdown JavaScript
In case of an error,
the program will print:

%FORKERR-fs example/fork/fork-stderr%
// Notify of an error.
console.error('Runtime error!')
Output
In case of an error,
the program will print:

```fs
Runtime error!
```

Caching

The output of forks will be cached in the .documentary/cache directory. When compiling documentation, Documentary will check for the presence of cache, check the mtime of the module and if it is the same as cached, analyse module's dependencies to see if any of them had changes (updates to package dependencies' versions, changes to source files).

When the cache is matched, no forking will take place and the value will be taken from the saved outputs. To explicitly prevent caching on a particular FORK marker, it should be prefixed with !: %!FORK module arg1 arg2%. To disable caching across all forks, the -c option can be passed to the CLI. In this case, even though caching was disabled, the new output will still be written to cache so that when Documentary is run next time, the latest known output is placed instantly.

Import/Exports Support

Documentary is able to fork modules that use import and export without the developer having to write a proxy file that would otherwise require @babel/register or other runtime transpilers. It was made possible with a simple ÀLaMode regex-based transpiler that will update the import/export statements on-the-fly. If there are any problems while using this feature, it can be disabled with the plain _ symbol: %_FORK module arg1 arg2%.

Replace Absolute Paths

With the / prefix in the FORK command, all absolute paths that contain the current working directory, will be replaced with relative paths.

%/FORKERR-table example/print-table%

This can help with documenting errors or other code that prints absolute paths in a nimble way.

example/fork/absolute.js:2
throw err
^

Error: test
    at Object.<anonymous> (example/fork/absolute.js:1:75)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3

<fork>

The <fork> component is the same as the %FORK% marker, but it offers extended functionality. The optional properties described above on this page are specified in the arguments, and the location of the fork module is passed as a child.

<fork nocache plain relative stderr lang="js"
  env="ENV_VAR=testing SECRET_KEY=hello-world">
  module/location/run.js
</fork>

Env Variables

All environment variables will be inherited from the Documentary process. Additional variables can be passed in the env argument, which is only available for the <fork> component and not the %FORK% marker. The variables will be split by whitespace, and the key-value pairs will be split by =. It's not possible to specify values with = in them at the moment.

Same forks but with different env variables are cached separately.

Both Channels

Whenever there are two forks of the same module with the same arguments and env variables, but one prints stdout and another one stderr, only one fork will be spawn, and its result reused. That saves time when trying to document the total output of the program, possibly in different sections, for example in a 2-column table:

<table>
<tr><th>STDOUT</th><th>STDERR</th></tr>
<!-- block-start -->
<tr><td>

<fork>example</fork>
</td>
<td>

<fork>example</fork>
</td></tr>
</table>

CLI Answers

If the fork interacts with the CLI via the stdin interface, it is possible to write answers which will be entered when the fork's output (either stdout or stderr) is matched against the regular expression given in the answer.

For example, the following README can be written:

<h2>Running the program</h2>

When you run the program, it will ask for your confirmation.

<fork lang="js">
  <answer regex="Are you sure">yes</answer>
  <answer regex="Please confirm">no</answer>
  <answer stderr regex="STDERR">documentary 123</answer>
  test/fixture/fork-comp.js
</fork>

And this is the source code of the fork:

import askQuestions from 'reloquent'
import { createInterface } from 'readline'

(async () => {
  const res = await askQuestions({
    'a': 'Are you sure?',
    'b': 'Please confirm',
  })
  console.log(res)
  const i = createInterface({
    input: process.stdin,
    output: process.stderr,
  })
  i.question('STDERR question: ', (answer) => {
    console.log(answer)
    i.close()
    process.exit()
  })
})()

The output:

Are you sure? yes
Please confirm: no
{ a: 'yes', b: 'no' }
documentary 123

Above, both answers to stdout are printed, and the answer to stderr, however because it is the fork of STDOUT only, stderr questions and user-supplied answer to it is not shown.

At the moment, the answers are not cached, so if they change, documentation must be compiled again with -c (or nocache argument). Also, if there are two same forks which use different answers that wouldn't work.

Clone this wiki locally