Skip to content

Commit

Permalink
add console and color support
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Nov 23, 2024
1 parent 7ebe288 commit 82999a2
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 7 deletions.
24 changes: 18 additions & 6 deletions Cakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
assert = require 'assert'
{ createHash } = require 'crypto'
oldConsole = require 'console'
fs = require 'fs'
os = require 'os'
path = require 'path'
Expand All @@ -11,11 +10,24 @@ CoffeeScript = require './lib/coffeescript'
helpers = require './lib/coffeescript/helpers'
util = require 'util'
process = require 'process'

{ setupStyler } = require './build-support/colors'
{ setupConsole } = require './build-support/console'
{
spawnNodeProcess,
NonZeroExit,
} = require './build-support/subprocess'


option '-l', '--level [LEVEL]', 'log level [debug < info < log(default) < warn < error]'
option null, '--no-color', 'disable colored output'

task = (name, description, action) ->
global.task name, description, ({level = 'log', ...opts} = {}) ->
setupStyler {colors: not opts['no-color']}
setupConsole {level}
action {...opts}

sha256 = -> createHash 'sha256'

checksumFile = (inPath) ->
Expand All @@ -30,7 +42,7 @@ checksumFile = (inPath) ->

# ANSI Terminal Colors.
bold = red = green = yellow = reset = ''
unless process.env.NODE_DISABLE_COLORS
if process.stdout.hasColors() and not process.env.NODE_DISABLE_COLORS
bold = '\x1B[0;1m'
red = '\x1B[0;31m'
green = '\x1B[0;32m'
Expand All @@ -54,7 +66,7 @@ majorVersion = parseInt CoffeeScript.VERSION.split('.')[0], 10

# Log a message with a color.
log = (message, color, explanation) ->
console.log color + message + reset + ' ' + (explanation or '')
console.log stylize(color)(message) + ' ' + (explanation or '')


# Run a CoffeeScript through our node/coffee interpreter.
Expand All @@ -74,7 +86,7 @@ buildAttestation = (inputPaths, outputPath, attestationPath, execute) ->
[inputHashes..., outputHash] = attestation.split ':'
if (outputHash == outputChecksum and
[0...checksummedPaths.length].every (i) -> checksummedPaths[i] == inputHashes[i])
console.debug 'success! using cache...'
console.debug "#{stylize('yellow', 'italic')('success!')} using cache..."
return yes
console.warn 'attestation was out of date, ...'
# TODO: ?????
Expand Down Expand Up @@ -246,11 +258,11 @@ watchAndBuildAndTest = (harmony = no) ->
buildAndTest yes, harmony
fs.watch 'src/', interval: 200, (eventType, filename) ->
if eventType is 'change'
log "src/#{filename} changed, rebuilding..."
log "src/#{filename} changed, rebuilding...", green
buildAndTest (filename is 'grammar.coffee'), harmony
fs.watch 'test/', {interval: 200, recursive: yes}, (eventType, filename) ->
if eventType is 'change'
log "test/#{filename} changed, rebuilding..."
log "test/#{filename} changed, rebuilding...", green
buildAndTest no, harmony


Expand Down
42 changes: 42 additions & 0 deletions build-support/colors.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
process = require 'process'
util = require 'util'

class Styler
constructor: ({colors} = {}) ->
@colors = colors ? yes

@styleTable: util.inspect.colors

@lookupStyle: (style) => @styleTable[style] ? throw new TypeError "style not found: '#{style}'"

@passThrough: (str) -> str

@doStylize = (...styles) =>
starts = []
ends = []
for style in styles
[start, end] = @lookupStyle style
starts.push start
ends.unshift end
(str) -> "\x1B[#{starts.join ';'}m#{str}\x1B[#{ends.join ';'}m"

stylize: (...styles) ->
if @colors then @constructor.doStylize(...styles) else @constructor.passThrough

@doReset: '\x1B[0m'

reset: -> if @colors then @constructor.doReset else ''


exports.setupStyler = ({colors} = {}) ->
return if global.styler?

if process.env.NODE_DISABLE_COLORS
colors = no
unless process.stdout.hasColors()
colors = no

styler = new Styler {colors}

global.styler = styler
global.stylize = (...args) -> styler.stylize ...args
89 changes: 89 additions & 0 deletions build-support/console.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{ Console } = require 'console'
process = require 'process'

exports.CakeConsole = class CakeConsole extends Console
@LEVELS: ['trace', 'debug', 'info', 'log', 'warn', 'error']
@validLevels: => "[#{(@LEVELS.map (l) -> "'#{l}'").join ', '}]"
@checkLevel: (level) =>
unless level in @LEVELS
throw new TypeError "argument '#{level}' was not a valid log level (should be: #{@validLevels()})"
level

constructor: ({level, ...opts} = {}) ->
super opts
@level = @constructor.checkLevel level ? 'log'

@getLevelNum: (l) => @LEVELS.indexOf @checkLevel l
curLevelNum: -> @constructor.getLevelNum @level
doesThisLevelApply: (l) -> @curLevelNum() <= @constructor.getLevelNum(l)

# Always log, regardless of level. This is for terminal output not intended to be configured by
# logging level.
unconditionalLog: (...args) ->
super.log ...args

# Define the named logging methods (.log(), .warn(), ...) by extracting them from the superclass.
trace: (...args) ->
if @doesThisLevelApply 'trace'
super ...args

debug: (...args) ->
if @doesThisLevelApply 'debug'
super ...args

info: (...args) ->
if @doesThisLevelApply 'info'
super ...args

log: (...args) ->
if @doesThisLevelApply 'log'
super ...args

warn: (...args) ->
if @doesThisLevelApply 'warn'
super ...args

error: (...args) ->
if @doesThisLevelApply 'error'
super ...args

# Call .dir(), but filtering by configured level.
dirLevel: (level, ...args) ->
if @doesThisLevelApply level
super.dir ...args

# We want to be able to call .dir() as normal, but we also want to be able to call .dir.log() to
# explicitly set the logging level for .dir().
Object.defineProperty @::, 'dir',
configurable: yes
get: ->
# By default, .dir() uses the 'log' level.
dir = (...args) -> @dirLevel 'log', ...args
Object.defineProperties dir, Object.fromEntries do => for k in @constructor.LEVELS
f = do (k) => (...args) => @dirLevel k, ...args
[k,
enumerable: yes
writable: yes
configurable: yes
value: Object.defineProperty f, 'name',
configurable: yes
value: k]
# We wouldn't normally have to set this, but Console does some wonky prototype munging:
# https://github.com/nodejs/node/blob/17fae65c72321659390c4cbcd9ddaf248accb953/lib/internal/console/constructor.js#L145-L147
set: (dir) -> # ignore

@stdio: ({
stdout = process.stdout,
stderr = process.stderr,
...opts,
} = {}) => new @ {
stdout,
stderr,
...opts
}


exports.setupConsole = ({level}) ->
return if global.cakeConsole?
global.console = global.cakeConsole = CakeConsole.stdio {level}
console.info "log level = #{level}"
2 changes: 1 addition & 1 deletion test/support/helpers.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ exports.inspect = (obj) ->
else
require('util').inspect obj,
depth: 10
colors: if process.env.NODE_DISABLE_COLORS then no else yes
colors: if process.env.NODE_DISABLE_COLORS then no else process.stdout.hasColors()

# Helpers to get AST nodes for a string of code.
exports.getAstRoot = getAstRoot = (code) ->
Expand Down

0 comments on commit 82999a2

Please sign in to comment.