From 78024a6a462a943a73f76d9221b637babd5ad461 Mon Sep 17 00:00:00 2001 From: Danny McClanahan <1305167+cosmicexplorer@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:32:50 -0500 Subject: [PATCH] move Console to build-support --- Cakefile | 63 +++--------------------- build-support/console.coffee | 95 ++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 55 deletions(-) create mode 100644 build-support/console.coffee diff --git a/Cakefile b/Cakefile index fb6f7ae2e5..8a5ab2787d 100644 --- a/Cakefile +++ b/Cakefile @@ -1,4 +1,3 @@ -oldConsole = require 'console' fs = require 'fs' os = require 'os' path = require 'path' @@ -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' @@ -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. @@ -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 @@ -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', -> @@ -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 = [], diff --git a/build-support/console.coffee b/build-support/console.coffee new file mode 100644 index 0000000000..c6d1055ea5 --- /dev/null +++ b/build-support/console.coffee @@ -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