Comparing version 0.2.0 to 0.3.0
@@ -7,8 +7,24 @@ #!/usr/bin/env node | ||
, theme = settings.resolveTheme() | ||
, opts = settings.getSettings() | ||
, highlighted | ||
; | ||
opts.theme = theme; | ||
function usage() { | ||
var msg = [ | ||
'Usage: cdl <filename.js> [options]' | ||
, '' | ||
, 'Options (~/.cardinalrc overrides):' | ||
, ' --nonum: turn off line printing' | ||
, '' | ||
, 'Unix Pipe Example: cat filename.js | grep console | cdl' | ||
, '' | ||
].join('\n'); | ||
console.log(msg); | ||
} | ||
function highlightFile () { | ||
try { | ||
highlighted = cardinal.highlightFileSync(args[2], theme); | ||
highlighted = cardinal.highlightFileSync(args[2], opts); | ||
console.log(highlighted); | ||
@@ -24,2 +40,16 @@ } catch (e) { | ||
var opt = args[3]; | ||
// E.g., "cardinal myfile.js --nonum" | ||
if (opt && opt.indexOf('--') === 0 ) { | ||
if ((/^--(nonum|noline)/i).test(opt)) opts.linenos = false; | ||
else { | ||
usage(); | ||
return console.error('Unknown option: ', opt); | ||
} | ||
return highlightFile(); | ||
} | ||
// UNIX pipes e.g., "cat myfile.js | grep console | cardinal | ||
@@ -29,2 +59,5 @@ var stdin = process.stdin | ||
// line numbers don't make sense when we are printing line by line | ||
opts.linenos = false; | ||
stdin.resume(); | ||
@@ -36,3 +69,3 @@ stdin.setEncoding('utf-8'); | ||
try { | ||
stdout.write(cardinal.highlight(line, theme) + '\n'); | ||
stdout.write(cardinal.highlight(line, opts) + '\n'); | ||
} catch (e) { | ||
@@ -39,0 +72,0 @@ // line doesn't represent a valid js snippet and therefore cannot be parsed -> just print as is |
@@ -5,2 +5,4 @@ var redeyed = require('redeyed') | ||
, util = require('util') | ||
, colors = require('./colors') | ||
, colorSurround = colors.brightBlack.split(':') | ||
; | ||
@@ -12,5 +14,70 @@ | ||
function highlight (code, theme_) { | ||
function addLinenos (highlightedCode, firstline) { | ||
var highlightedLines = highlightedCode.split('\n'); | ||
trimEmptyLines(highlightedLines); | ||
var linesLen = highlightedLines.length | ||
, lines = [] | ||
, totalDigits | ||
, lineno | ||
; | ||
function getDigits (n) { | ||
if (n < 10) return 1; | ||
if (n < 100) return 2; | ||
if (n < 1000) return 3; | ||
if (n < 10000) return 4; | ||
// this works for up to 99,999 lines - any questions? | ||
return 5; | ||
} | ||
function pad (n, totalDigits) { | ||
// not pretty, but simple and should perform quite well | ||
var padDigits= totalDigits - getDigits(n); | ||
switch(padDigits) { | ||
case 0: return '' + n; | ||
case 1: return ' ' + n; | ||
case 2: return ' ' + n; | ||
case 3: return ' ' + n; | ||
case 4: return ' ' + n; | ||
case 5: return ' ' + n; | ||
} | ||
} | ||
totalDigits = getDigits(linesLen + firstline - 1); | ||
for (var i = 0; i < linesLen; i++) { | ||
lineno = [ | ||
colorSurround[0] | ||
, pad(i + firstline, totalDigits) | ||
, ': ' | ||
, colorSurround[1] | ||
].join(''); | ||
lines.push(lineno + highlightedLines[i]); | ||
} | ||
return lines.join('\n'); | ||
} | ||
function trimEmptyLines(lines) { | ||
// remove lines from the end until we find a non-empy one | ||
var line = lines.pop(); | ||
while(!line || !line.length) | ||
line = lines.pop(); | ||
// put the non-empty line back | ||
if (line) lines.push(line); | ||
} | ||
function highlight (code, opts) { | ||
opts = opts || { }; | ||
try { | ||
return redeyed(code, theme_ || theme).code; | ||
var result = redeyed(code, opts.theme || theme) | ||
, firstline = opts.firstline && !isNaN(opts.firstline) ? opts.firstline : 1; | ||
return opts.linenos ? addLinenos(result.code, firstline) : result.code; | ||
} catch (e) { | ||
@@ -22,6 +89,5 @@ e.message = 'Unable to perform highlight. The code contained syntax errors: ' + e.message; | ||
function highlightFile (fullPath, theme_, cb) { | ||
if (isFunction(theme_)) { | ||
cb = theme_; | ||
theme_ = theme; | ||
function highlightFile (fullPath, opts, cb) { | ||
if (isFunction(opts)) { | ||
cb = opts; | ||
} | ||
@@ -32,3 +98,3 @@ | ||
try { | ||
cb(null, highlight(code, theme_)); | ||
cb(null, highlight(code, opts)); | ||
} catch (e) { | ||
@@ -40,5 +106,5 @@ cb(e); | ||
function highlightFileSync (fullPath, theme_) { | ||
function highlightFileSync (fullPath, opts) { | ||
var code = fs.readFileSync(fullPath, 'utf-8'); | ||
return highlight(code, theme_); | ||
return highlight(code, opts); | ||
} | ||
@@ -54,5 +120,5 @@ | ||
highlightFile(__filename, require('./themes/no-semicolons'), function (err, res) { | ||
highlightFile(__filename, { linenos: true, firstline: 80 }, function (err, res) { | ||
if (err) return console.error(err); | ||
console.log(res); | ||
}); |
@@ -10,3 +10,3 @@ // This file will highlight itself using the default theme when run via: "node highlight-self" | ||
cardinal.highlightFile(__filename, function (err, res) { | ||
cardinal.highlightFile(__filename, { linenos: true }, function (err, res) { | ||
if (err) return console.error(err); | ||
@@ -13,0 +13,0 @@ console.log(res); |
{ | ||
"name": "cardinal", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Syntax highlights JavaScript code with ANSI colors to be printed to the terminal.", | ||
@@ -5,0 +5,0 @@ "main": "cardinal.js", |
@@ -11,2 +11,3 @@ # cardinal [![Build Status](https://secure.travis-ci.org/thlorenz/cardinal.png)](http://travis-ci.org/thlorenz/cardinal) | ||
- theming support, see [custom color themes](https://github.com/thlorenz/cardinal/tree/master/themes) | ||
- optionally print line numbers | ||
- API and command line interface (`cdl`) | ||
@@ -28,7 +29,9 @@ - `.cardinalrc` config to customize settings | ||
- [API](#api) | ||
- [highlight(code[, theme])](#highlightcode-theme) | ||
- [highlightFileSync(fullPath[, theme])](#highlightfilesyncfullpath-theme) | ||
- [highlightFile(fullPath[, theme], callback)](#highlightfilefullpath-theme-callback) | ||
- [Examples](#examples-browse) | ||
- [*highlight(code[, opts])*](#highlightcode-opts) | ||
- [*highlightFileSync(fullPath[, opts])*](#highlightfilesyncfullpath-opts) | ||
- [*highlightFile(fullPath[, opts], callback)*](#highlightfilefullpath-opts-callback) | ||
- [opts](#opts) | ||
- [Examples ([*browse*](https://github.com/thlorenz/cardinal/tree/master/examples))](#examples-[browse]https://githubcom/thlorenz/cardinal/tree/master/examples) | ||
## Installation | ||
@@ -52,4 +55,7 @@ | ||
cdl file.js | ||
cdl <file.js> [options] | ||
**options**: | ||
- `--nonum`: turns off line number printing (relevant if it is turned on inside `~/.cardinalrc` | ||
### As part of a UNIX pipe | ||
@@ -74,29 +80,39 @@ | ||
{ | ||
"theme": "hide-semicolons" | ||
"theme": "hide-semicolons", | ||
"linenos": true|false | ||
} | ||
``` | ||
`theme` can be the name of any of the [built-in themes](https://github.com/thlorenz/cardinal/tree/master/themes) or the | ||
- `theme` can be the name of any of the [built-in themes](https://github.com/thlorenz/cardinal/tree/master/themes) or the | ||
full path to a custom theme anywhere on your computer. | ||
- linenos toggles line number printing | ||
## API | ||
### *highlight(code[, theme])* | ||
### *highlight(code[, opts])* | ||
- returns the highlighted version of the passed code ({String}) or throws an error if it was not able to parse it | ||
- `theme` ({Object}) is used to optionally override the theme used to highlight | ||
- opts (see below) | ||
### *highlightFileSync(fullPath[, theme])* | ||
### *highlightFileSync(fullPath[, opts])* | ||
- returns the highlighted version of the file whose fullPath ({String}) was passed or throws an error if it was not able | ||
to parse it | ||
- `theme` ({Object}) is used to optionally override the theme used to highlight | ||
- opts (see below) | ||
### *highlightFile(fullPath[, theme], callback)* | ||
### *highlightFile(fullPath[, opts], callback)* | ||
- calls back with the highlighted version of the file whose fullPath ({String}) was passed or with an error if it was not able | ||
to parse it | ||
- `theme` ({Object}) is used to optionally override the theme used to highlight | ||
- opts (see below) | ||
- `callback` ({Function}) has the following signature: `function (err, highlighted) { .. }` | ||
### opts | ||
opts is an {Object} with the following properties: | ||
- `theme` {Object} is used to optionally override the theme used to highlight | ||
- `linenos` {Boolean} if `true` line numbers are included in the highlighted code | ||
- `firstline` {Integer} sets line number of the first line when line numbers are printed | ||
## Examples ([*browse*](https://github.com/thlorenz/cardinal/tree/master/examples)) | ||
@@ -108,3 +124,3 @@ | ||
- [file that highlights itself](https://github.com/thlorenz/cardinal/blob/master/examples/highlight-self.js) via | ||
***highlightFile()*** | ||
***highlightFile()*** including line numbers | ||
- [file that highlights itself hiding all | ||
@@ -111,0 +127,0 @@ semicolons](https://github.com/thlorenz/cardinal/blob/master/examples/highlight-self-hide-semicolons.js) via |
@@ -5,12 +5,7 @@ var path = require('path') | ||
, utl = require('./utl') | ||
, home = process.env.HOME; | ||
, home = process.env.HOME | ||
, settings; | ||
// home_ mainly to be used during tests | ||
// Resolves the preferred theme from the .cardinalrc found in the HOME directory | ||
// If it couldn't be resolved, undefined is returned | ||
function resolveTheme (home_) { | ||
var settingsJson | ||
, settings | ||
, themePath; | ||
function getSettings (home_) { | ||
if (settings) return settings; | ||
try { | ||
@@ -22,9 +17,22 @@ settingsJson = fs.readFileSync(path.join(home_ || home, '.cardinalrc'), 'utf-8'); | ||
} | ||
try { | ||
return JSON.parse(settingsJson); | ||
} catch (e) { | ||
// Have a .cardinalrc, but something about it is wrong - warn the user | ||
// Coudn't parse the contained JSON | ||
console.error(e); | ||
return undefined; | ||
} | ||
} | ||
settings = JSON.parse(settingsJson); | ||
// home_ mainly to be used during tests | ||
// Resolves the preferred theme from the .cardinalrc found in the HOME directory | ||
// If it couldn't be resolved, undefined is returned | ||
function resolveTheme (home_) { | ||
var themePath | ||
, settings = getSettings(home_); | ||
if (!settings.theme) return undefined; | ||
if (!settings || !settings.theme) return undefined; | ||
try { | ||
// allow specifying just the name of a built-in theme or a full path to a custom theme | ||
@@ -35,4 +43,3 @@ themePath = utl.isPath(settings.theme) ? settings.theme : path.join(__dirname, 'themes', settings.theme); | ||
} catch (e) { | ||
// Have a .cardinalrc, but something about it is wrong - warn the user | ||
// Either we couldn't parse the contained JSON, or the specified theme path is invalid | ||
// Specified theme path is invalid | ||
console.error(e); | ||
@@ -44,4 +51,5 @@ return undefined; | ||
module.exports = { | ||
resolveTheme: resolveTheme | ||
resolveTheme: resolveTheme | ||
, getSettings: getSettings | ||
}; | ||
@@ -19,3 +19,3 @@ 'use strict'; | ||
test('supplying custom theme', function (t) { | ||
cardinal.highlightFile(file, customTheme, function (err, highlighted) { | ||
cardinal.highlightFile(file, { theme: customTheme }, function (err, highlighted) { | ||
@@ -22,0 +22,0 @@ t.equals(null, err, 'no error') |
@@ -19,3 +19,3 @@ 'use strict'; | ||
test('supplying custom theme', function (t) { | ||
var highlighted = cardinal.highlightFileSync(file, customTheme); | ||
var highlighted = cardinal.highlightFileSync(file, { theme: customTheme }); | ||
@@ -22,0 +22,0 @@ t.equals(highlighted, '\u001b[94mfunction\u001b[39m \u001b[96mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m \n \u001b[32mvar\u001b[39m \u001b[96ma\u001b[39m \u001b[93m=\u001b[39m \u001b[34m3\u001b[39m\u001b[90m;\u001b[39m \u001b[31mreturn\u001b[39m \u001b[96ma\u001b[39m \u001b[93m>\u001b[39m \u001b[34m2\u001b[39m \u001b[93m?\u001b[39m \u001b[31mtrue\u001b[39m \u001b[93m:\u001b[39m \u001b[91mfalse\u001b[39m\u001b[90m;\u001b[39m \n\u001b[33m}\u001b[39m\n') |
@@ -18,3 +18,3 @@ 'use strict'; | ||
test('supplying custom theme', function (t) { | ||
var highlighted = cardinal.highlight(code, customTheme); | ||
var highlighted = cardinal.highlight(code, { theme: customTheme }); | ||
@@ -40,1 +40,33 @@ t.equals(highlighted, '\u001b[94mfunction\u001b[39m \u001b[96mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m \u001b[32mvar\u001b[39m \u001b[96ma\u001b[39m \u001b[93m=\u001b[39m \u001b[34m3\u001b[39m\u001b[90m;\u001b[39m \u001b[31mreturn\u001b[39m \u001b[96ma\u001b[39m \u001b[93m>\u001b[39m \u001b[34m2\u001b[39m \u001b[93m?\u001b[39m \u001b[31mtrue\u001b[39m \u001b[93m:\u001b[39m \u001b[91mfalse\u001b[39m\u001b[90m;\u001b[39m \u001b[33m}\u001b[39m') | ||
}) | ||
test('line numbers no firstline given', function (t) { | ||
var highlighted = cardinal.highlight(code, { linenos: true }); | ||
t.equals(highlighted, '\u001b[90m1: \u001b[39m\u001b[94mfunction\u001b[39m \u001b[37mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m \u001b[32mvar\u001b[39m \u001b[37ma\u001b[39m \u001b[93m=\u001b[39m \u001b[34m3\u001b[39m\u001b[90m;\u001b[39m \u001b[31mreturn\u001b[39m \u001b[37ma\u001b[39m \u001b[93m>\u001b[39m \u001b[34m2\u001b[39m \u001b[93m?\u001b[39m \u001b[91mtrue\u001b[39m \u001b[93m:\u001b[39m \u001b[91mfalse\u001b[39m\u001b[90m;\u001b[39m \u001b[33m}\u001b[39m') | ||
t.end() | ||
}) | ||
test('line numbers firstline 99', function (t) { | ||
var highlighted = cardinal.highlight(code, { linenos: true, firstline: 99 }); | ||
t.equals(highlighted, '\u001b[90m99: \u001b[39m\u001b[94mfunction\u001b[39m \u001b[37mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m \u001b[32mvar\u001b[39m \u001b[37ma\u001b[39m \u001b[93m=\u001b[39m \u001b[34m3\u001b[39m\u001b[90m;\u001b[39m \u001b[31mreturn\u001b[39m \u001b[37ma\u001b[39m \u001b[93m>\u001b[39m \u001b[34m2\u001b[39m \u001b[93m?\u001b[39m \u001b[91mtrue\u001b[39m \u001b[93m:\u001b[39m \u001b[91mfalse\u001b[39m\u001b[90m;\u001b[39m \u001b[33m}\u001b[39m') | ||
t.end() | ||
}) | ||
test('line numbers multi line no first line given', function (t) { | ||
var multilineCode = '' + | ||
function foo () { | ||
return 1; | ||
}; | ||
var highlighted = cardinal.highlight(multilineCode, { linenos: true }); | ||
t.equals(highlighted,'\u001b[90m1: \u001b[39m\u001b[94mfunction\u001b[39m \u001b[37mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m\n\u001b[90m2: \u001b[39m \u001b[31mreturn\u001b[39m \u001b[34m1\u001b[39m\u001b[90m;\u001b[39m\n\u001b[90m3: \u001b[39m \u001b[33m}\u001b[39m') | ||
t.end() | ||
}) | ||
test('line numbers multi line first line 99', function (t) { | ||
var multilineCode = '' + | ||
function foo () { | ||
return 1; | ||
}; | ||
var highlighted = cardinal.highlight(multilineCode, { linenos: true, firstline: 99 }); | ||
t.equals(highlighted,'\u001b[90m 99: \u001b[39m\u001b[94mfunction\u001b[39m \u001b[37mfoo\u001b[39m\u001b[90m(\u001b[39m\u001b[90m)\u001b[39m \u001b[33m{\u001b[39m\n\u001b[90m100: \u001b[39m \u001b[31mreturn\u001b[39m \u001b[34m1\u001b[39m\u001b[90m;\u001b[39m\n\u001b[90m101: \u001b[39m \u001b[33m}\u001b[39m') | ||
t.end() | ||
}) |
'use strict'; | ||
/*jshint asi: true*/ | ||
var test = require('tap').test | ||
, path = require('path') | ||
, fs = require('fs') | ||
, settings = require('../settings') | ||
, existsSync = fs.existsSync || path.existsSync | ||
var test = require('tap').test | ||
, path = require('path') | ||
, fs = require('fs') | ||
, hideSemicolonsTheme = require('../themes/hide-semicolons') | ||
, home = path.join(__dirname, 'fixtures', 'home') | ||
, rcpath = path.join(home, '.cardinalrc') | ||
, existsSync = fs.existsSync || path.existsSync | ||
, settingsResolve = require.resolve('../settings') | ||
, settings | ||
function setup () { | ||
delete require.cache[settingsResolve] | ||
settings = require(settingsResolve) | ||
} | ||
function writerc(config) { | ||
@@ -28,5 +34,13 @@ fs.writeFileSync(rcpath, JSON.stringify(config), 'utf-8') | ||
function getSettings (config) { | ||
writerc(config) | ||
var result = settings.getSettings(home) | ||
removerc() | ||
return result; | ||
} | ||
if (!existsSync(home)) fs.mkdirSync(home); | ||
test('no .cardinalrc in home', function (t) { | ||
setup() | ||
var theme = settings.resolveTheme(home) | ||
@@ -38,2 +52,3 @@ t.equals(theme, undefined, 'resolves no theme') | ||
test('.cardinalrc with theme "hide-semicolons" in home', function (t) { | ||
setup() | ||
var theme = resolveTheme({ theme: "hide-semicolons" }) | ||
@@ -45,2 +60,3 @@ t.deepEquals(theme, hideSemicolonsTheme, 'resolves hide-semicolons theme') | ||
test('.cardinalrc with full path to "hide-semicolons.js" in home', function (t) { | ||
setup() | ||
var theme = resolveTheme({ theme: path.join(__dirname, '..', 'themes', 'hide-semicolons.js') }) | ||
@@ -50,1 +66,16 @@ t.deepEquals(theme, hideSemicolonsTheme, 'resolves hide-semicolons theme') | ||
}) | ||
test('.cardinalrc with linenos: true', function (t) { | ||
setup() | ||
var opts = { linenos: true } | ||
t.deepEquals(getSettings(opts), opts) | ||
t.end() | ||
}) | ||
test('.cardinalrc with linenos: true and theme', function (t) { | ||
setup() | ||
var opts = { linenos: true, theme: 'some theme' } | ||
t.deepEquals(getSettings(opts), opts) | ||
t.end() | ||
}) | ||
@@ -1,27 +0,3 @@ | ||
// Don't touch this definition | ||
var colorNums = { | ||
white : 37 | ||
, black : 30 | ||
, blue : 34 | ||
, cyan : 36 | ||
, green : 32 | ||
, magenta : 35 | ||
, red : 31 | ||
, yellow : 33 | ||
, brightBlack : 90 | ||
, brightRed : 91 | ||
, brightGreen : 92 | ||
, brightYellow : 93 | ||
, brightBlue : 94 | ||
, brightMagenta : 95 | ||
, brightCyan : 96 | ||
, brightWhite : 97 | ||
} | ||
, colors = {}; | ||
var colors = require('../colors'); | ||
Object.keys(colorNums).forEach(function (k) { | ||
colors[k] = '\u001b[' + colorNums[k] + 'm:\u001b[39m'; | ||
}); | ||
// Change the below definitions in order to tweak the color theme. | ||
@@ -28,0 +4,0 @@ module.exports = { |
@@ -7,28 +7,4 @@ /* | ||
// Don't touch this definition | ||
var colorNums = { | ||
white : 37 | ||
, black : 30 | ||
, blue : 34 | ||
, cyan : 36 | ||
, green : 32 | ||
, magenta : 35 | ||
, red : 31 | ||
, yellow : 33 | ||
, brightBlack : 90 | ||
, brightRed : 91 | ||
, brightGreen : 92 | ||
, brightYellow : 93 | ||
, brightBlue : 94 | ||
, brightMagenta : 95 | ||
, brightCyan : 96 | ||
, brightWhite : 97 | ||
} | ||
, colors = {}; | ||
var colors = require('../colors'); | ||
Object.keys(colorNums).forEach(function (k) { | ||
colors[k] = '\u001b[' + colorNums[k] + 'm:\u001b[39m'; | ||
}); | ||
// Change the below definitions in order to tweak the color theme. | ||
@@ -35,0 +11,0 @@ module.exports = { |
@@ -1,27 +0,3 @@ | ||
// Don't touch this definition | ||
var colorNums = { | ||
white : 37 | ||
, black : 30 | ||
, blue : 34 | ||
, cyan : 36 | ||
, green : 32 | ||
, magenta : 35 | ||
, red : 31 | ||
, yellow : 33 | ||
, brightBlack : 90 | ||
, brightRed : 91 | ||
, brightGreen : 92 | ||
, brightYellow : 93 | ||
, brightBlue : 94 | ||
, brightMagenta : 95 | ||
, brightCyan : 96 | ||
, brightWhite : 97 | ||
} | ||
, colors = {}; | ||
var colors = require('../colors'); | ||
Object.keys(colorNums).forEach(function (k) { | ||
colors[k] = '\u001b[' + colorNums[k] + 'm:\u001b[39m'; | ||
}); | ||
// Change the below definitions in order to tweak the color theme. | ||
@@ -28,0 +4,0 @@ module.exports = { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40479
28
1019
126
12