Skip to content

Commit 78024a6

Browse files
move Console to build-support
1 parent a642b6c commit 78024a6

File tree

2 files changed

+103
-55
lines changed

2 files changed

+103
-55
lines changed

Cakefile

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
oldConsole = require 'console'
21
fs = require 'fs'
32
os = require 'os'
43
path = require 'path'
@@ -7,10 +6,12 @@ _ = require 'underscore'
76
{ spawn, exec, execSync } = require 'child_process'
87
CoffeeScript = require './lib/coffeescript'
98
helpers = require './lib/coffeescript/helpers'
9+
{ setupConsole } = require './build-support/console'
1010

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

34-
35-
class CakeConsole extends oldConsole.Console
36-
@LEVELS: ['debug', 'info', 'log', 'warn', 'error', 'trace']
37-
@levelNumsMap: do =>
38-
ret = {}
39-
ret[k] = i for k, i in @LEVELS
40-
ret
41-
@validLevels: => "[#{(@LEVELS.map (l) -> "'#{l}'").join ', '}]"
42-
43-
constructor: ({@level = 'log', ...opts} = {}) ->
44-
super opts
45-
unless @level in @constructor.LEVELS
46-
throw new TypeError "argument '#{@level}' was not a valid log level
47-
(should be: #{@constructor.validLevels()})"
48-
49-
@getLevelNum: (l) => @levelNumsMap[l] ? throw new TypeError "invalid level #{l}"
50-
curLevelNum: -> @constructor.getLevelNum @level
51-
doesThisLevelApply: (l) -> @curLevelNum() <= @constructor.getLevelNum l
52-
53-
# TODO: for some reason this is done lazily in buildParser, so let's do the same here.
54-
helpers.extend global, require 'util'
55-
for l in @LEVELS
56-
do (l) => @::[l] = (...args) ->
57-
if @doesThisLevelApply l
58-
# NB: it's literally impossible to extend Console and propagate to the parent class because
59-
# of some horrific unexplained initialization code used for the singleton console
60-
# object, which employs a very complex prototype chain that makes it impossible to do
61-
# the simple thing: https://github.com/nodejs/node/blob/17fae65c72321659390c4cbcd9ddaf248accb953/lib/internal/console/global.js#L29-L33.
62-
# Undo the prototype chain nonsense and bind the method back to our subclass.
63-
(oldConsole[l].bind @) ...args
64-
else global.format ...args
65-
66-
@stdio: ({
67-
stdout = process.stdout,
68-
stderr = process.stderr,
69-
...opts,
70-
} = {}) => new @ {
71-
stdout,
72-
stderr,
73-
...opts
74-
}
75-
76-
7735
option '-l', '--level [LEVEL]', 'log level [debug < info < log(default) < warn < error]'
7836

79-
setupConsole = ({level} = {}) ->
80-
global.cakeConsole = CakeConsole.stdio {level}
81-
global.console = global.cakeConsole
82-
console.info "log level = #{level}"
83-
84-
consoleTask = (name, description, action) ->
37+
task = (name, description, action) ->
8538
global.task name, description, ({level = 'log', ...opts} = {}) ->
86-
setupConsole {level}
39+
setupConsole {level, useColors: USE_COLORS}
8740
action {...opts}
8841

8942
# Log a message with a color.
@@ -196,7 +149,7 @@ watchAndBuildAndTest = (harmony = no) ->
196149
buildAndTest no, harmony
197150

198151

199-
consoleTask 'build', 'build the CoffeeScript compiler from source', build
152+
task 'build', 'build the CoffeeScript compiler from source', build
200153

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

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

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

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

625-
consoleTask 'test', 'run the CoffeeScript language test suite', ({
578+
task 'test', 'run the CoffeeScript language test suite', ({
626579
file = [],
627580
negFile = ['sourcemap'],
628581
desc = [],

build-support/console.coffee

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{ Console } = require 'console'
2+
process = require 'process'
3+
4+
exports.CakeConsole = class CakeConsole extends Console
5+
@LEVELS: ['trace', 'debug', 'info', 'log', 'warn', 'error']
6+
@validLevels: => "[#{(@LEVELS.map (l) -> "'#{l}'").join ', '}]"
7+
@checkLevel: (level) =>
8+
unless level in @LEVELS
9+
throw new TypeError "argument '#{level}' was not a valid log level (should be: #{@validLevels()})"
10+
level
11+
12+
constructor: ({level, ...opts} = {}) ->
13+
super opts
14+
@level = @constructor.checkLevel level ? 'log'
15+
16+
@getLevelNum: (l) => @LEVELS.indexOf @checkLevel l
17+
curLevelNum: -> @constructor.getLevelNum @level
18+
doesThisLevelApply: (l) -> @curLevelNum() <= @constructor.getLevelNum(l)
19+
20+
# Always log, regardless of level. This is for terminal output not intended to be configured by
21+
# logging level.
22+
unconditionalLog: (...args) ->
23+
super.log ...args
24+
25+
# Define the named logging methods (.log(), .warn(), ...) by extracting them from the superclass.
26+
trace: (...args) ->
27+
if @doesThisLevelApply 'trace'
28+
super ...args
29+
30+
debug: (...args) ->
31+
if @doesThisLevelApply 'debug'
32+
super ...args
33+
34+
info: (...args) ->
35+
if @doesThisLevelApply 'info'
36+
super ...args
37+
38+
log: (...args) ->
39+
if @doesThisLevelApply 'log'
40+
super ...args
41+
42+
warn: (...args) ->
43+
if @doesThisLevelApply 'warn'
44+
super ...args
45+
46+
error: (...args) ->
47+
if @doesThisLevelApply 'error'
48+
super ...args
49+
50+
# Call .dir(), but filtering by configured level.
51+
dirLevel: (level, ...args) ->
52+
if @doesThisLevelApply level
53+
super.dir ...args
54+
55+
# We want to be able to call .dir() as normal, but we also want to be able to call .dir.log() to
56+
# explicitly set the logging level for .dir().
57+
Object.defineProperty @::, 'dir',
58+
configurable: yes
59+
get: ->
60+
# By default, .dir() uses the 'log' level.
61+
dir = (...args) -> @dirLevel 'log', ...args
62+
Object.defineProperties dir, Object.fromEntries do => for k in @constructor.LEVELS
63+
f = do (k) => (...args) => @dirLevel k, ...args
64+
[k,
65+
enumerable: yes
66+
writable: yes
67+
configurable: yes
68+
value: Object.defineProperty f, 'name',
69+
configurable: yes
70+
value: k]
71+
# We wouldn't normally have to set this, but Console does some wonky prototype munging:
72+
# https://github.com/nodejs/node/blob/17fae65c72321659390c4cbcd9ddaf248accb953/lib/internal/console/constructor.js#L145-L147
73+
set: (dir) -> # ignore
74+
75+
@stdio: ({
76+
stdout = process.stdout,
77+
stderr = process.stderr,
78+
...opts,
79+
} = {}) => new @ {
80+
stdout,
81+
stderr,
82+
...opts
83+
}
84+
85+
86+
exports.setupConsole = ({level, useColors}) ->
87+
if global.cakeConsole?
88+
return global.cakeConsole
89+
90+
opts = {level}
91+
unless useColors
92+
opts.colorMode = no
93+
global.console = global.cakeConsole = cakeConsole = CakeConsole.stdio opts
94+
console.debug "log level = #{level}"
95+
cakeConsole

0 commit comments

Comments
 (0)