├── .gitignore ├── .npmignore ├── .travis.yml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .build/ 3 | .devnotes/ 4 | .node_modules/ 5 | lib/ts/ 6 | lib/tests/ 7 | *.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | tests/ 3 | docs/ 4 | .vscode/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | - 7 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nathan Ridley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tiny Preprocessor 2 | 3 | > A tiny DEV vs PROD preprocessor for JS and TS code 4 | 5 | It's super annoying to have to strip out logging and debug code, or to have to clean up values and function arguments that were changed to make debugging and testing easier during development, particularly if your development-only code is necessary for ongoing development between releases. 6 | 7 | The library exports a single function -- `preprocess` -- which takes a string argument (your source code), transforms it according to preprocessor comments you've included, then returns the result. 8 | 9 | Insert it into your preferred build pipeline so that your source is transformed before being passed to any transpilers, compilers, or just directly copied to a distributable folder. Be sure to run your test suite after preprocessing, to make sure you haven't accidentally broken your library with erroneous preprocessor comments. 10 | 11 | During development, compile and test using whatever regular process you use outside of production builds, and keep the 12 | production build process separate for when you're ready to release. 13 | 14 | ## Preprocessor Syntax: 15 | 16 | Preprocessor blocks are simply IF or IF-ELSE constructs. They start with `## DEV|PROD`, and are terminated with another 17 | `##` token. `// ## DEV ##` comments affect the entire line. Square brackets `[[` and `]]` define the start and end of an 18 | affected block of code. Both forms of comment syntax are supported, depending on your needs. Typically your 19 | production-only code blocks will be contained within block comments, seeing as you don't want them to be active during 20 | development. 21 | 22 | ```js 23 | // --- OMIT A SINGLE LINE ---------------------------------------------------- 24 | 25 | log("This line will be excluded from the build"); // ## DEV ## 26 | 27 | // --- OMIT A WHOLE BLOCK ---------------------------------------------------- 28 | 29 | // ## DEV [[ 30 | console.warn('This line will be excluded.'); 31 | write('This line too.'); 32 | // ]] ## 33 | 34 | // --- USE A DIFFERENT VALUE IN PRODUCTION ----------------------------------- 35 | 36 | var value = /* ## DEV [[ */ 3 /* ]] ELSE [[ 27 ]] ## */; 37 | // The production build for the above line will render as: 38 | var value = 27; 39 | 40 | // ## DEV [[ 41 | trace.silent(status1); 42 | trace.silent(status2); 43 | /* ]] ELSE [[ 44 | trace.verbose(status1); 45 | trace.verbose(status2); 46 | ]] ## */ 47 | 48 | // The production build for the above lines will render as: 49 | trace.verbose(status1); 50 | trace.verbose(status2); 51 | 52 | // --- PRODUCTION-ONLY CODE -------------------------------------------------- 53 | 54 | /* ## PROD [[ 55 | trace.verbose(status1); 56 | trace.verbose(status2); 57 | ]] ## */ 58 | 59 | // The production build for the above lines will render as: 60 | trace.verbose(status1); 61 | trace.verbose(status2); 62 | ``` 63 | 64 | ## Installation 65 | 66 | ```bash 67 | $ npm install --save-dev tiny-preprocessor 68 | ``` 69 | 70 | or 71 | 72 | ```bash 73 | $ yarn add --dev tiny-preprocessor 74 | ``` 75 | 76 | ## Usage 77 | 78 | ```js 79 | import {preprocess} from 'tiny-preprocessor'; 80 | 81 | const input = '... some source code ...'; 82 | const output = preprocess(input); 83 | ``` 84 | 85 | ## Gulp 86 | 87 | I like to use Gulp, so this is how I use tiny-preprocessor: 88 | 89 | ```js 90 | // gulpfile.js 91 | 92 | const {preprocess} = require(`tiny-preprocessor`); 93 | const gulp = require(`gulp`); 94 | const merge = require(`merge2`); 95 | const plumber = require(`gulp-plumber`); 96 | const sourcemaps = require(`gulp-sourcemaps`); 97 | const transform = require(`gulp-transform`); 98 | 99 | // ... 100 | 101 | function preprocessSourceText(buffer) { 102 | return preprocess(buffer.toString()); 103 | } 104 | 105 | function prebuild() { 106 | return merge([ 107 | gulp.src(`src/**/*.ts`) 108 | .pipe(plumber()) 109 | .pipe(transform(preprocessSourceText)) 110 | .pipe(gulp.dest(`.build/ts`)), // copy to a temporary build folder (omitted from the repo and npm) 111 | 112 | gulp.src(`tests/**/*.ts`) 113 | .pipe(plumber()) 114 | .pipe(transform(preprocessSourceText)) 115 | .pipe(transform(replace(/\.\.\/src/g, `../ts`))) // fix paths so that tests will still compile 116 | .pipe(gulp.dest(`.build/ts.tests`)), 117 | ]); 118 | } 119 | 120 | // ... 121 | 122 | function compile() { 123 | // your compile function should read from the build folder, e.g. .build/* in this case 124 | const src = gulp.src(`.build/ts/**/*.ts`) 125 | .pipe(plumber()) 126 | .pipe(sourcemaps.init()) 127 | // ... 128 | ; 129 | 130 | const tests = gulp.src(`.build/ts.tests/**/*.ts`) 131 | .pipe(plumber()) 132 | .pipe(sourcemaps.init()) 133 | // ... 134 | ; 135 | 136 | return merge([ 137 | src, 138 | tests 139 | ]); 140 | } 141 | 142 | gulp.task(`prebuild`, prebuild); 143 | gulp.task(`compile`, [`prebuild`], compile); 144 | 145 | // ... 146 | ``` -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Preprocessor Directives 3 | ======================= 4 | 5 | // --- OMIT A SINGLE LINE ---------------------------------------------------- 6 | 7 | log("This line will be excluded from the build"); // ## DEV ## 8 | 9 | // --- OMIT A WHOLE BLOCK ---------------------------------------------------- 10 | 11 | // ## DEV [[ 12 | console.warn('This line will be excluded.'); 13 | write('This line too.'); 14 | // ]] ## 15 | 16 | // --- USE A DIFFERENT VALUE IN PRODUCTION ----------------------------------- 17 | 18 | var value = ⁄* ## DEV [[ *⁄ 3 ⁄* ]] ELSE [[ 27 ]] ## *⁄; 19 | // The production build for the above line will render as: 20 | var value = 27; 21 | 22 | // ## DEV [[ 23 | trace.silent(status1); 24 | trace.silent(status2); 25 | /* ]] ELSE [[ 26 | trace.verbose(status1); 27 | trace.verbose(status2); 28 | ]] ## *⁄ 29 | 30 | // The production build for the above lines will render as: 31 | trace.verbose(status1); 32 | trace.verbose(status2); 33 | 34 | // --- PRODUCTION-ONLY CODE -------------------------------------------------- 35 | 36 | ⁄* ## PROD [[ 37 | trace.verbose(status1); 38 | trace.verbose(status2); 39 | ]] ## *⁄ 40 | 41 | // The production build for the above lines will render as: 42 | trace.verbose(status1); 43 | trace.verbose(status2); 44 | */ 45 | 46 | function preprocess(src) { 47 | let next = 'start', type = ''; 48 | const rxStart = /(?:\/\*|(.*)\/\/) ## (DEV|PROD) (##|\[\[) *(?:\*\/)?/g; 49 | const rxElse = /(?:\/\*|\/\/ )? *\]\] (?:(ELSE) \[\[|##) *(?:\*\/)?/g; 50 | const rxEnd = /(?:\/\*|\/\/ )? *\]\] ##(?: \*\/)?/g; 51 | let rx = rxStart, out = '', i = 0; 52 | for(let match = rx.exec(src); match; match = rx.exec(src)) { 53 | switch(next) { 54 | case 'start': { 55 | type = match[2]; 56 | out += src.substring(i, match.index); 57 | next = match[3] === '[[' ? 'else' : 'start'; 58 | break; 59 | } 60 | case 'else': { 61 | if(type === 'PROD') { 62 | out += src.substring(i, match.index); 63 | } 64 | if(match[1] === 'ELSE') { 65 | type = type === 'PROD' ? 'DEV' : 'PROD'; 66 | next = 'end'; 67 | } 68 | else { 69 | next = 'start'; 70 | } 71 | break; 72 | } 73 | case 'end': 74 | if(type === 'PROD') { 75 | out += src.substring(i, match.index); 76 | } 77 | next = 'start'; 78 | break; 79 | } 80 | switch(next) { 81 | case 'start': rx = rxStart; break; 82 | case 'else': rx = rxElse; break; 83 | case 'end': rx = rxEnd; break; 84 | } 85 | rx.lastIndex = i = match.index + match[0].length; 86 | }; 87 | out += src.substr(i); 88 | out = out.replace(/^(\r?\n){2,}/mg, `$1`); 89 | return out; 90 | } 91 | 92 | module.exports = {preprocess}; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiny-preprocessor", 3 | "version": "1.0.0", 4 | "description": "A tiny DEV vs PROD preprocessor for JS and TS code", 5 | "main": "index.js", 6 | "author": "Nathan Ridley ", 7 | "license": "MIT", 8 | "bugs": "https://github.com/axefrog/tiny-preprocessor/issues", 9 | "repository": "git@github.com:axefrog/tiny-preprocessor.git" 10 | } 11 | --------------------------------------------------------------------------------