Skip to content

Commit

Permalink
move Console to build-support
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Nov 24, 2024
1 parent a642b6c commit 78024a6
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 55 deletions.
63 changes: 8 additions & 55 deletions Cakefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
oldConsole = require 'console'
fs = require 'fs'
os = require 'os'
path = require 'path'
Expand All @@ -7,10 +6,12 @@ _ = require 'underscore'
{ spawn, exec, execSync } = require 'child_process'
CoffeeScript = require './lib/coffeescript'
helpers = require './lib/coffeescript/helpers'
{ setupConsole } = require './build-support/console'

# ANSI Terminal Colors.
bold = red = green = yellow = reset = ''
unless process.env.NODE_DISABLE_COLORS
USE_COLORS = process.stdout.hasColors?() and not process.env.NODE_DISABLE_COLORS
if USE_COLORS
bold = '\x1B[0;1m'
red = '\x1B[0;31m'
green = '\x1B[0;32m'
Expand All @@ -31,59 +32,11 @@ header = """
# Used in folder names like `docs/v1`.
majorVersion = parseInt CoffeeScript.VERSION.split('.')[0], 10


class CakeConsole extends oldConsole.Console
@LEVELS: ['debug', 'info', 'log', 'warn', 'error', 'trace']
@levelNumsMap: do =>
ret = {}
ret[k] = i for k, i in @LEVELS
ret
@validLevels: => "[#{(@LEVELS.map (l) -> "'#{l}'").join ', '}]"

constructor: ({@level = 'log', ...opts} = {}) ->
super opts
unless @level in @constructor.LEVELS
throw new TypeError "argument '#{@level}' was not a valid log level
(should be: #{@constructor.validLevels()})"

@getLevelNum: (l) => @levelNumsMap[l] ? throw new TypeError "invalid level #{l}"
curLevelNum: -> @constructor.getLevelNum @level
doesThisLevelApply: (l) -> @curLevelNum() <= @constructor.getLevelNum l

# TODO: for some reason this is done lazily in buildParser, so let's do the same here.
helpers.extend global, require 'util'
for l in @LEVELS
do (l) => @::[l] = (...args) ->
if @doesThisLevelApply l
# NB: it's literally impossible to extend Console and propagate to the parent class because
# of some horrific unexplained initialization code used for the singleton console
# object, which employs a very complex prototype chain that makes it impossible to do
# the simple thing: https://github.com/nodejs/node/blob/17fae65c72321659390c4cbcd9ddaf248accb953/lib/internal/console/global.js#L29-L33.
# Undo the prototype chain nonsense and bind the method back to our subclass.
(oldConsole[l].bind @) ...args
else global.format ...args

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


option '-l', '--level [LEVEL]', 'log level [debug < info < log(default) < warn < error]'

setupConsole = ({level} = {}) ->
global.cakeConsole = CakeConsole.stdio {level}
global.console = global.cakeConsole
console.info "log level = #{level}"

consoleTask = (name, description, action) ->
task = (name, description, action) ->
global.task name, description, ({level = 'log', ...opts} = {}) ->
setupConsole {level}
setupConsole {level, useColors: USE_COLORS}
action {...opts}

# Log a message with a color.
Expand Down Expand Up @@ -196,7 +149,7 @@ watchAndBuildAndTest = (harmony = no) ->
buildAndTest no, harmony


consoleTask 'build', 'build the CoffeeScript compiler from source', build
task 'build', 'build the CoffeeScript compiler from source', build

task 'build:parser', 'build the Jison parser only', buildParser

Expand Down Expand Up @@ -265,7 +218,7 @@ task 'build:browser:full', 'merge the built scripts into a single file for use i
console.log "built ... running browser tests:"
invoke 'test:browser'

consoleTask 'build:watch', 'watch and continually rebuild the CoffeeScript compiler, running tests on each build', ->
task 'build:watch', 'watch and continually rebuild the CoffeeScript compiler, running tests on each build', ->
watchAndBuildAndTest()

task 'build:watch:harmony', 'watch and continually rebuild the CoffeeScript compiler, running harmony tests on each build', ->
Expand Down Expand Up @@ -622,7 +575,7 @@ option null, '--negFile [REGEXP*]', 'test file patterns to negatively match'
option '-d', '--desc [REGEXP*]', 'test description patterns to positively match'
option null, '--negDesc [REGEXP*]', 'test description patterns to negatively match'

consoleTask 'test', 'run the CoffeeScript language test suite', ({
task 'test', 'run the CoffeeScript language test suite', ({
file = [],
negFile = ['sourcemap'],
desc = [],
Expand Down
95 changes: 95 additions & 0 deletions build-support/console.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{ 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, useColors}) ->
if global.cakeConsole?
return global.cakeConsole

opts = {level}
unless useColors
opts.colorMode = no
global.console = global.cakeConsole = cakeConsole = CakeConsole.stdio opts
console.debug "log level = #{level}"
cakeConsole

0 comments on commit 78024a6

Please sign in to comment.