npm package: @fenixengine/jscc
Description: Tiny and powerful preprocessor for conditional comments and replacement of compile-time variables in text files
Author: aMarCruz
Latest version: 1.3.0

# FeniXJscc

[![jscc on npm][npm-badge]][npm-url]
[![License MIT][license-badge]][license-url]

*This is a fork of [jscc](https://github.com/aMarCruz/jscc) for use with `FeniXWizard` and the `FeniXEngine` tools and RPG Maker plugin suite.*

Featuring some of the C preprocessor characteristics through special, configurable comments, jscc can be used in any type of files to build multiple versions of your software from the same code base.

With jscc, you have:

- Conditional inclusion/exclusion of blocks, based on compile-time variables*
- Compile-time variables with all the power of JavaScript expressions
- Replacement of variables in the sources, by its value at compile-time
- Sourcemap support, useful for JavaScript sources.
- TypeScript v3 definitions

\* This feature allows you the conditional declaration of ES6 imports (See the [example](#example)).

jscc is derived on [jspreproc](http://amarcruz.github.io/jspreproc), the tiny source file preprocessor in JavaScript, enhanced with sourcemap support but without the file importer nor the removal of comments ([rollup](https://rollupjs.org/guide/en) with [rollup-plugin-cleanup](https://www.npmjs.com/package/rollup-plugin-cleanup) does it better).

jscc works in NodeJS 6 or later, with minimal dependencies and footprint. It was designed to operate on small to medium pieces of code (like most nowadays) and, since the whole process is done in memory, it is _really fast_.

jscc is **not** a minifier tool, but it does well what it does...

## Install

Use the instructions of the plugin for your toolchain:

- [Rollup w/ FeniXJscc](https://gitlab.com/FeniXEngineMV/rollup-plugin-jscc)
- ~~[Rollup](https://www.npmjs.com/package/rollup-plugin-jscc)~~
- [Brunch](https://www.npmjs.com/package/jscc-brunch)
- [Browserify](https://www.npmjs.com/package/jsccify)
- [Gulp](https://www.npmjs.com/package/gulp-jscc)
- [WebPack](https://github.com/OrangeLab/webpack-plugin-jscc) - Thanks to @duanlikang

or install the jscc package from npm if you need direct access to its API:

```sh
npm i jscc -D
```

### Direct Usage

```js
const jscc = require('jscc');

const result = jscc(sourceCode, options);

// or in async mode:
jscc(sourceCode, options, (err, result) => {
  if (err) {
    console.error(err);
  } else {
    console.log(result.code);
    console.log(result.map);
  }
})
```

The result is a plain JS object with a property `code`, a string with the processed source, and a property `map`, with a raw sourcemap object, if required by the `sourcemap` option (its default is `true`).

If a callback is provided, jscc will operate asynchronously and call the callback with an error object, if any, or `null` in the first parameter and the result in the second.

Please see the Wiki to know the supported [options](https://github.com/aMarCruz/jscc/wiki/Options).

## Directives

jscc works with _directives_ inserted in the text and prefixed with configurable character sequences, that defaults to `'/*'`, `'//'` and `'<!--'`.

This directives allows you set or get compile-time variables, and exclude code blocks based in its value.

Here, I will refer to the names of the compile-time variables as _varnames_, to distinguish them from the JavaScript run-time variables.

To be valid, a `<varname>` must match the regular expression `/^_[0-9A-Z][_0-9A-Z]*$/`.

> That is, it must start with an underscore, followed by a digit or uppercase letter, and then zero or more underscores, digits or uppercase letters. The character `$` has a special use in jscc and is not allowed for varnames.

### `#set <varname> = <value>`

Defines or redefines a `varname`.

The `value` can be a literal value, another varname, or an expression. If you don't specify a value, it is set to `undefined`.

### `#unset <varname>`

Removes the definition of the given `varname`.

Both the definition or removal of a varname take immediate effect.

### `#if <expression>`

Remove the block of code that follows this `#if` if `expression` is _falsy_.

You can nest multiple `#if` blocks.

### `#ifset <varname>`

Check the existence of a `varname`.

The returned value is `true` if the variable exists, even if its value is `undefined`. Apart from this, the behavior of `#ifset` is the same as `#if`, so references to the latter will imply both.

### `#ifnset <varname>`

This is the opposite to `#ifset`, it returns `false` if the `varname` does not exists.

### `#elif <expression>`

The behavior of `#elif` is similar to the JS `else if` statement.

The `expression` will be evaluated if the previous `#if` or `#elif` was _falsy_.

You can have zero or more `#elif` directives following one `#if`.

## `#else`

Includes the block that follows if the previous `#if` or `#elif` expressions were _falsy_.

### `#endif`

Closes the current conditional block.

### `#error <expression>`

Generates an exception at compile time with the result of the given character `expression`.

You can learn more about this in the [Wiki](https://github.com/aMarCruz/jscc/wiki).

## Known Issues

- If you are using ESM imports with Typescript, you must enable `esModuleInterop` in your tsconfig.json or use `import jscc = require("jscc")`.
- jscc does not work in a browser, but it must work without issues on the back-end.

### ES6 TL

Remember that jscc is language agnostic, the following block may or may not work as you think:

```js
const template = `
//#if _DEBUG
console.log('debug mode is on.')
//#endif
`
fs.writeFile('code.js', template, 'utf8')
```

Directive searching knows nothing about ES6 TL, so the `#if..#endif` within the template will be evaluated at compile-time, just like any other (code.js is written without directives).

## TODO

- [X] ~~Async mode~~ (v1.0.0)
- [ ] Explanatory error messages, with location of the error
- [ ] Different prefixes for different file types
- [ ] Express middleware
- [X] WebPack plugin
- [ ] Better documentation
- [ ] Syntax hilighter for some editores? Perhaps you want to contribute.

## License

The [MIT](LICENSE) License.

&copy; 2018, Alberto Martínez