//BEGIN enum LogLevel /** * Instances of `LogLevel` * @type LogLevel[] */ const generatedLogLevelInstances = [, , , , , , ]; /** * A log level. * * If this were in a module, you'd export the class, but not the array above. * * @enum {string|number} */ class LogLevel { /** * The current log level as a number * @type number */ #lv; /** * The current log level as a string * @type string */ #name; constructor(lv) { switch (typeof lv) { case 'number': if (lv < 0 || lv > this.constructor.values.length - 1) throw new TypeError(`LogLevel(lv) must be within [0,${this.constructor.values.length - 1}]!`); if (generatedLogLevelInstances[lv]) return generatedLogLevelInstances[lv]; [this.#lv, this.#name] = [lv, this.constructor.values[lv]]; generatedLogLevelInstances[lv] = this; break; case 'string': const name = lv.toUpperCase(); const level = this.constructor.values.indexOf(name); if (generatedLogLevelInstances[level]) return generatedLogLevelInstances[level]; if (level === -1) throw new TypeError(`LogLevel(lv) must be within [0,${this.constructor.values.length - 1}]!`); [this.#lv, this.#name] = [level, name]; generatedLogLevelInstances[level] = this; break; case 'object': if (lv instanceof this.constructor) return lv; default: throw new TypeError('LogLevel must be number, string or LogLevel!'); } Object.freeze(this); } /** * The possible values of LogLevel */ static get values() { return Object.freeze([ 'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'LOG', 'DEBUG', 'TRACE' ]); } [Symbol.toPrimitive](hint) { switch (hint) { case 'default': case 'number': return this.#lv; default: return this.#name; } } [Symbol.name]() { return this[Symbol.toStringTag](); } [Symbol.toStringTag]() { return 'LogLevel'; } /** * Log level 0 * @returns {LogLevel} */ static get CRITICAL() { return new LogLevel(0); } /** * Log level 1 * @returns {LogLevel} */ static get ERROR() { return new LogLevel(1); } /** * Log level 2 * @returns {LogLevel} */ static get WARNING() { return new LogLevel(2); } /** * Log level 3 * @returns {LogLevel} */ static get INFO() { return new LogLevel(3); } /** * Log level 4 * @returns {LogLevel} */ static get LOG() { return new LogLevel(4); } /** * Log level 5 * @returns {LogLevel} */ static get DEBUG() { return new LogLevel(5); } /** * Log level 6 * @returns {LogLevel} */ static get TRACE() { return new LogLevel(6); } } Object.freeze(LogLevel); //END enum LogLevel //------------------------------==============================------------------------------ //BEGIN tests const tests = [ ['LogLevel.INFO===new LogLevel("INFO")', true], ['LogLevel.INFO===new LogLevel(3)', true], ['LogLevel.INFO===LogLevel.INFO', true], ['LogLevel.INFO==3', true], ['String(LogLevel.INFO)==="INFO"', true], ['LogLevel.ERROR<LogLevel.INFO', true], ['LogLevel.INFO===LogLevel.DEBUG', false], ['LogLevel.TRACE<LogLevel.DEBUG', false], ['LogLevel.INFO*3', 9], ['String(new LogLevel(LogLevel.INFO+2))', 'DEBUG'], ['`A message of level ${LogLevel.ERROR} got logged!`', 'A message of level ERROR got logged!'], ['new LogLevel("OOPS")', new TypeError('LogLevel(lv) must be within [0,6]!')], ['new LogLevel(7)', new TypeError('LogLevel(lv) must be within [0,6]!')], ['LogLevel.someNonexistentProp = 7', new TypeError('can\'t define property "someNonexistentProp": Function is not extensible')], ['LogLevel.INFO.someNonexistentProp = "Oops!"', new TypeError('can\'t define property "someNonexistentProp": Object is not extensible')], ['LogLevel.someNonexistentProp', undefined], ['LogLevel.INFO.someNonexistentProp', ] ]; console.info('All tests run in strict mode.'); console.info('Please note that expected error messages are written with Firefox in mind. If you are on a different browser the exact error message may look different but should be equivalent.'); for (const test of tests) { let result; try { result = eval(`'use strict';\n${test[0]}`, { generatedLogLevelInstances, LogLevel }); } catch (err) { result = err; } console.log(`Test: ${test[0]}\nExpect: ${(test[1] instanceof Error)?test[1]:JSON.stringify(test[1])}\nResult: ${(result instanceof Error)?result:JSON.stringify(result)}`); } //END tests
div.as-console-wrapper { /* Make the StackSnippet console fill the entire iframe. Not needed for JS to work, just as convenience. */ top: 0 !important; bottom: 0 !important; max-height: 100vh !important; }
JSON.stringify(). Can't serialize / deserializeSymbol.