Skip to content
/ jscc Public

Tiny and powerful preprocessor for conditional comments and replacement of compile-time variables in text files

License

Notifications You must be signed in to change notification settings

aMarCruz/jscc

Repository files navigation

jscc

jscc on npm License MIT Linux Build Codacy Coverage

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).

jscc is derived on jspreproc, the tiny source file preprocessor in JavaScript, enhanced with sourcemap support but without the file importer nor the removal of comments (rollup with 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:

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

npm i jscc -D

Direct Usage

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.

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.

Changes in This Version

  • Closes #8 : Removel of trailing jscc comment is breaking the expression.
  • Removed Codebeat tests.
  • More unity tests.

See details in the Changelog.

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:

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

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

Support my Work

I'm a full-stack developer with more than 20 year of experience and I try to share most of my work for free and help others, but this takes a significant amount of time, effort and coffee so, if you like my work, please consider...

Of course, feedback, PRs, and stars are also welcome 🙃

Thanks for your support!

License

The MIT License.

© 2018, Alberto Martínez

Windows Build CodeClimate Vulnerabilities Last commit