Created
November 29, 2023 23:05
-
-
Save dfkaye/b6e0dca12269dd4107b8b78e5d946d14 to your computer and use it in GitHub Desktop.
using console parts to create styled output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 29-30 August 2023 | |
// console.styled.js | |
// Using console parts to create styled output. | |
// # Multiple output statements with `console.[method].apply` | |
// Usually we log console statements with any number of arguments. | |
console.log("one"); | |
console.log("two", "arguments"); | |
// Sometimes it makes sense to collect messages first, and output one at a time. | |
var parts = ["first", "second", "third"]; | |
parts.forEach(part => console.log(part)); | |
// We can, however, print them in one statement, using `console.[method].apply`. | |
console.log.apply(console, parts); | |
// # Styled output | |
// We describe a pattern for styling targeted content while ignoring prelude | |
// text (i.e., text that occurs before the styled content, and rest text (i.e., | |
// the rest of the text that occurs after the styled content). | |
// 1. color directive | |
// Browser console (and maybe even the Node.js REPL), provides a directive to | |
// indicate that string output following it is to be styled by a *subsequent* | |
// string containing a CSS rule-set. | |
console.log("%c Color me red ", "color: red;"); | |
// 2. "prelude" text | |
// If we prefix that text containing the directive, the prefix is not styled. | |
console.log("prefix to red text: " + "%c color me red ", "color: red;"); | |
// 3. "rest" text | |
// Any text provided *after* the styling rules is unstyled. | |
console.log("prefix to red text: " + "%ccolor me red", "color: red;", "*rest*"); | |
// A more complicated-looking set of statements... | |
console.log( | |
"unstyled prelude... " + "%cstyled content", | |
` | |
background: antiquewhite; | |
font-weight: 600; | |
outline: 1px solid red; | |
`, | |
"any subsequent unstyled text", | |
"\nmore unstyled text" | |
); | |
// 4. array of statements | |
// Text arguments like that last one can became hard to scan. We can put them in | |
// an array and use `console.log.apply` instead. | |
var parts = [ | |
"unstyled prelude... " + "%cstyled content", | |
` | |
background: antiquewhite; | |
font-weight: 600; | |
outline: 1px solid red; | |
`, | |
"any subsequent unstyled text", | |
"\nmore unstyled text" | |
]; | |
console.log.apply(console, parts); | |
// # Custom `console.styled()` output method | |
// Now we can define a method for the console that accepts properties to build | |
// up such arrays and apply them directly. | |
// An example shape: | |
var message = { | |
method: "warn", | |
title: null, | |
prelude: "aa <b> space </b>", | |
content: "aa", | |
style: "background: pink;", | |
rest: "<b> space </b> aa" | |
}; | |
// A console method for this type of message | |
console.styled = function({ level, title, prelude, content, style, rest }) { | |
level || (level = 'log'); | |
var param = arguments[0]; | |
if (param !== Object(param) | |
|| param.toString() != '[object Object]' | |
|| Object.keys(param).length === 0){ | |
return console.log("unstyled output:\n", param); | |
} | |
title = title ? title + '\n' : ''; | |
prelude = prelude ? prelude + '' : ''; | |
content = content ? content + '' : ''; | |
style = style ? style + '' : ''; | |
var output = title + [prelude, '%c', content].join(''); | |
var message = output.length | |
? [output, style] | |
: []; | |
rest && (message.push('' + rest)); | |
var method = level in console | |
? level | |
: 'log'; | |
console.assert( | |
method === level, | |
`console.styled() log level "${level}" not supported; using "${method}".` | |
); | |
console[method].apply(console, message); | |
}; | |
/* test it out */ | |
console.styled(message); | |
console.styled({ | |
content: "plain content" | |
}); | |
console.styled({ | |
content: "tomato content", | |
style: "background: tomato; color: white;" | |
}); | |
console.styled({ | |
prelude: "prelude: ", | |
content: "italic skyblue content", | |
style: "background: skyblue; font-style: italic;" | |
}); | |
console.styled({ | |
title: "TiTLE", | |
prelude: "prelude: ", | |
content: "underlined papayawhip content", | |
style: "background: papayawhip; text-decoration: underline;" | |
}); | |
console.styled({ | |
title: "TiTLE", | |
prelude: "<begin>", | |
content: "bold boxed content", | |
style: ` | |
background: gainsboro; | |
border: 2px solid fuchsia; | |
font-weight: bold; | |
padding: 2px 1em 0; | |
`, | |
rest: "</end>" | |
}); | |
// unsupported log level should print assertion message | |
// and then log "dog test" | |
console.styled({ | |
level: 'dog', | |
content: "dog test" | |
}); | |
// missing content param should log "rest" | |
console.styled({ | |
rest: "...rest..." | |
}); | |
// should capture error | |
var error; | |
try { console.styled(); } | |
catch (e) { error = e; } | |
finally { console.log(error); console.assert(error, "should get an error"); } | |
// should capture error | |
var error; | |
try { console.styled(null); } | |
catch (e) { error = e; } | |
finally { console.log(error); console.assert(error, "should get an error"); } | |
// should log Object { } | |
console.styled({ }); | |
// should log Array[ 'a' ] | |
console.styled(['a']); | |
// should log Number { 99 } | |
console.styled(new Number(99)); | |
// should log 1 | |
console.styled(1); | |
// should log Boolean { false } | |
console.styled(new Boolean()); | |
// should log true | |
console.styled(true); | |
// should log String { "string" } | |
console.styled(new String("string")); | |
// should log "ok" | |
console.styled("ok"); | |
// style with invalid CSS | |
console.styled({ | |
title: "a", | |
prelude: 'b', | |
content: "c", | |
style: "d", | |
rest: "e" | |
}); | |
/* | |
a | |
bc e | |
*/ | |
// style with valid CSS | |
console.styled({ | |
title: "a", | |
prelude: 'b ', | |
content: " c ", | |
style: "background: gainsboro; outline: 2px solid aqua;", | |
rest: "e" | |
}); | |
/* | |
a | |
bc e | |
*/ | |
/* test non-string arguments */ | |
// plain object | |
console.styled({ title: {}, prelude: {}, content: {}, style: {}, rest: {} }); | |
/* | |
[object Object] | |
[object Object][object Object] [object Object] | |
*/ | |
// object with valueOf() | |
console.styled({ | |
title: {valueOf() { return 'title'}}, | |
prelude: {valueOf() { return 'prelude'}}, | |
content: {valueOf() { return 'content'}}, | |
style: {valueOf() { return 'style'}}, | |
rest: {valueOf() { return 'rest'}} | |
}); | |
/* | |
title | |
preludecontent rest | |
*/ | |
// array of strings | |
console.styled({ | |
title: ["title"], | |
prelude: ["prelude"], | |
content: ["content"], | |
style: ["style"], | |
rest: ["rest"] | |
}); | |
/* | |
title | |
preludecontent rest | |
*/ | |
// number | |
console.styled({ title: 1, prelude: 2, content: 3, style: 4, rest: 5 }); | |
/* | |
1 | |
23 5 | |
*/ | |
// all args - date | |
console.styled({ | |
title: new Date, | |
prelude: new Date, | |
content: new Date, | |
style: new Date, | |
rest: new Date | |
}); | |
/* | |
Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time) | |
Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time)Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time) Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time) | |
*/ | |
// all args - regexp | |
console.styled({ | |
title: /title/i, | |
prelude: /^Prelude/, | |
content: /(?:content)+$/m, | |
style: /(?:style)/, | |
rest: /^rest$/m | |
}); | |
/* | |
/title/i | |
/^Prelude//(?:content)+$/m /^rest$/m | |
*/ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment