diff --git a/.travis.yml b/.travis.yml index ad337ff..6a468c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ -language: node_js -node_js: stable -sudo: false +dist: trusty +language: generic env: global: diff --git a/deploy.sh b/deploy.sh index 3e64011..a014a62 100644 --- a/deploy.sh +++ b/deploy.sh @@ -51,9 +51,7 @@ curl https://api.csswg.org/bikeshed/ -f -F file=@$INPUT_FILE -F md-status=LS-COM -F md-warning="Commit $SHA $COMMIT_URL_BASE$SHA replaced by $LS_URL" \ -F md-title="$TITLE (Commit Snapshot $SHA)" \ -F md-Text-Macro="SNAPSHOT-LINK $BACK_TO_LS_LINK" \ - > $COMMIT_DIR/index.intermediate.html; -node_modules/.bin/emu-algify < $COMMIT_DIR/index.intermediate.html > $COMMIT_DIR/index.html -rm $COMMIT_DIR/index.intermediate.html + > $COMMIT_DIR/index.html; mkdir $COMMIT_DIR/images cp images/*.* $COMMIT_DIR/images/ echo "Commit snapshot output to $WEB_ROOT/$COMMITS_DIR/$SHA" @@ -67,19 +65,15 @@ if [ $BRANCH != "master" ] ; then -F md-warning="Branch $BRANCH $BRANCH_URL_BASE$BRANCH replaced by $LS_URL" \ -F md-title="$TITLE (Branch Snapshot $BRANCH)" \ -F md-Text-Macro="SNAPSHOT-LINK $SNAPSHOT_LINK" \ - > $BRANCH_DIR/index.intermediate.html; - node_modules/.bin/emu-algify < $BRANCH_DIR/index.intermediate.html > $BRANCH_DIR/index.html + > $BRANCH_DIR/index.html; mkdir $BRANCH_DIR/images - rm $BRANCH_DIR/index.intermediate.html cp images/*.* $BRANCH_DIR/images/ echo "Branch snapshot output to $WEB_ROOT/$BRANCHES_DIR/$BRANCH" else # Living standard, if master curl https://api.csswg.org/bikeshed/ -f -F file=@$INPUT_FILE \ -F md-Text-Macro="SNAPSHOT-LINK $SNAPSHOT_LINK" \ - > $WEB_ROOT/index.intermediate.html; - node_modules/.bin/emu-algify < $WEB_ROOT/index.intermediate.html > $WEB_ROOT/index.html - rm $WEB_ROOT/index.intermediate.html + > $WEB_ROOT/index.html; mkdir $WEB_ROOT/images cp images/*.* $WEB_ROOT/images/ echo "Living standard output to $WEB_ROOT" diff --git a/index.bs b/index.bs index 433c55d..4b2dd90 100644 --- a/index.bs +++ b/index.bs @@ -1,13 +1,12 @@
 Title: Console Standard
-Group: WHATWG
 H1: Console
 Shortname: console
-Repository: whatwg/console
 Status: LS
+Group: WHATWG
+No Editor: true
+Repository: whatwg/console
 Boilerplate: omit conformance, omit feedback-header
-Editor: Terin Stock, https://terinstock.com, terin@terinstock.com
-Editor: Robert Kowalski, http://kowalski.gd, rok@kowalski.gd
 Abstract: This specification defines APIs for console debugging facilities.
 Logo: https://resources.whatwg.org/logo-console.svg
 !Participate: GitHub whatwg/console (new issue, open issues)
@@ -16,8 +15,8 @@ Logo: https://resources.whatwg.org/logo-console.svg
 !Commits: [SNAPSHOT-LINK]
 !Commits: @consolelog
 !Tests: web-platform-tests console/ (ongoing work)
-
-Opaque Elements: emu-alg
+Indent: 2
+Markup Shorthands: markdown yes
 
+
+urlPrefix: https://tc39.github.io/ecma262/#; spec: ECMASCRIPT
+  type: abstract-op
+    text: ObjectCreate; url: sec-objectcreate
+    text: Type; url: sec-ecmascript-data-types-and-values
+    text: ToString; url: sec-tostring
+    text: %parseFloat%; url: sec-parsefloat-string
+    text: %parseInt%; url: sec-parseint-string-radix
+  type: interface
+    text: %ObjectPrototype%; url: sec-properties-of-the-object-prototype-object
+
+ @@ -59,59 +53,252 @@ and constructive. Please join us in the issue tracker for more discussion. +

Namespace {{console}}

+ +
+[Exposed=(Window,Worker,Worklet)]
+namespace console { // but see namespace object requirements below
+  // Logging
+  void assert(optional boolean condition = false, any... data);
+  void clear();
+  void count(optional DOMString label = "default");
+  void debug(any... data);
+  void error(any... data);
+  void info(any... data);
+  void log(any... data);
+  void table(any tabularData, optional sequence<DOMString> properties);
+  void trace(any... data);
+  void warn(any... data);
+  void dir(any item, optional object? options);
+  void dirxml(any... data);
+
+  // Grouping
+  void group(any... data);
+  void groupCollapsed(any... data);
+  void groupEnd();
+
+  // Timing
+  void time(optional DOMString label = "default");
+  void timeEnd(optional DOMString label = "default");
+};
+
+ +

+ For historical reasons, {{console}} is lowercased. +

+ +

+ It is important that {{console}} is always visible and usable to scripts, even if the developer + console has not been opened or + does not exist. +

+ +For historical web-compatibility reasons, the namespace object for {{console}} must have as +its \[[Prototype]] an empty object, created as if by +ObjectCreate({{%ObjectPrototype%}}), instead of {{%ObjectPrototype%}}. + +

Logging methods

+ +Each {{console}} namespace object has an associated count map, which is a map of +strings to labels, initially empty. + +

assert(|condition|, ...|data|)

+ +1. If |condition| is true, return. +1. Let |message| be a string without any formatting specifiers indicating generically an assertion + failure (such as "Assertion failed"). +1. If |data| is [=list/is empty|empty=], [=list/append=] |message| to |data|. +1. Otherwise: + 1. Let |first| be |data|[0]. + 1. If Type(|first|) is not String, then [=list/prepend=] |message| to |data|. + 1. Otherwise: + 1. Let |concat| be the concatenation of |message|, U+003A (:), U+0020 SPACE, and |first|. + 1. Set |data|[0] to |concat|. +1. Perform Logger("assert", |data|). + +

clear()

+ +1. [=stack/Empty=] the appropriate group stack. +1. If possible for the environment, clear the console. (Otherwise, do nothing.) + +

count(|label|)

+ +1. Let |map| be the associated count map. +1. If |map|[|label|] [=map/exists=], [=map/set=] |map|[|label|] to |map|[|label|] + 1. +1. Otherwise, [=map/set=] |map|[|label|] to 1. +1. Let |concat| be the concatenation of |label|, U+003A (:), U+0020 SPACE, and + ToString(|map|[|label|]). +1. Perform Logger("count", « |concat| »). + +

debug(...|data|)

+ +1. Perform Logger("debug", |data|). + +

error(...|data|)

+ +1. Perform Logger("error", |data|). + +

info(...|data|)

+ +1. Perform Logger("info", |data|). + +

log(...|data|)

+ +1. Perform Logger("log", |data|). + +

table(|tabularData|, |properties|)

+ +Try to construct a table with the columns of the properties of |tabularData| (or use +|properties|) and rows of |tabularData| and log it with a logLevel of "log". Fall +back to just logging the argument if it can't be parsed as tabular. + +

TODO: This will need a good algorithm.

+ +

trace(...|data|)

+ +1. Let |trace| be some implementation-specific, potentially-interactive representation of the + callstack from where this method was called. +1. Optionally, let |formattedData| be the result of Formatter(|data|), and + incorporate |formattedData| as a label for |trace|. +1. Perform Printer("trace", « |trace| »). + +

+ The identifier of a function printed in a stack trace is implementation-dependant. It is also not + guaranteed to be the same identifier that would be seen in `new Error().stack`. +

+ +

warn(...|data|)

+ +1. Perform Logger("warn", |data|). + +

dir(|item|, |options|)

+ +1. Let |object| be |item| with generic JavaScript object formatting applied. +1. Perform Printer("dir", « |object| », |options|). + +

dirxml(...|data|)

+ +1. Let |finalList| be a new list, initially empty. +1. [=list/For each=] |item| of |data|: + 1. Let |converted| be a DOM tree representation of |item| if possible; otherwise let + |converted| be |item| with optimally useful formatting applied. + 1. Append |converted| to |finalList|. +1. Perform Logger("dirxml", |finalList|). + +

Grouping methods

+ +A group is an implementation-specific, potentially-interactive view +for output produced by calls to Printer, with one further level of indentation +than its parent. Each {{console}} namespace object has an associated group stack, which +is a stack, initially empty. Only the last group in a group stack will host +output produced by calls to Printer. + +

group(...|data|)

+ +1. Let |group| be a new group. +1. If |data| is not [=list/is empty|empty=], let |groupLabel| be the result of + Formatter(|data|). Otherwise, let |groupLabel| be an implementation-chosen + label representing a group. +1. Incorporate |groupLabel| as a label for |group|. +1. Optionally, if the environment supports interactive groups, |group| should be expanded by + default. +1. Perform Printer("group", « |group| »). +1. Push |group| onto the appropriate group stack. + +

groupCollapsed(...|data|)

+ +1. Let |group| be a new group. +1. If |data| is not empty, let |groupLabel| be the result of + Formatter(|data|). Otherwise, let |groupLabel| be an implementation-chosen + label representing a group. +1. Incorporate |groupLabel| as a label for |group|. +1. Optionally, if the environment supports interactive groups, |group| should be collapsed by + default. +1. Perform Printer("groupCollapsed", « |group| »). +1. Push |group| onto the appropriate group stack. + +

groupEnd()

+ +1. Pop the last group from the group stack. + +

Timing methods

+ +Each {{console}} namespace object has an associated timer table, which is a map of +strings to times, initially empty. + +

time(|label|)

+ +1. If the associated timer table [=map/contains=] an entry with key |label|, return, + optionally reporting a warning to the console indicating that a timer with label |label| has + already been started. +1. Otherwise, [=map/set=] the value of the entry with key |label| in the associated + timer table to the current time. + +

timeEnd(|label|)

+ +1. Let |startTime| be the result of [=map/getting=] the value of the entry with key |label| in the + associated timer table. +1. Let |duration| be a string representing the difference between the current time and + |startTime|, in an implementation-defined format. +

"4650", "4650.69 ms", "5 seconds", and "00:05" + are all reasonable ways of displaying a 4650.69 ms duration.

+1. Let |concat| be the concatenation of |label|, U+003A (:), U+0020 SPACE, and |duration|. +1. Perform Logger("timeEnd", « |concat| »). +

Supporting abstract operations

-

Logger(logLevel, args)

+

Logger(|logLevel|, |args|)

-The logger operation accepts a log level and a List of other arguments. Its main output is the +The logger operation accepts a log level and a [=list=] of other arguments. Its main output is the implementation-defined side effect of printing the result to the console. This specification describes how it processes format specifiers while doing so. - - 1. If _args_ is empty, abort these steps. - 1. Let _first_ be the first element of _args_. - 1. Let _rest_ be all elements following _first_ in _args_. - 1. If _rest_ is empty, perform Printer(_logLevel_, «_first_»). Abort these steps. - 1. If _first_ does not contain any format specifiers, perform Printer(_logLevel_, _args_). - 1. Otherwise, perform Printer(_logLevel_, Formatter(_args_)). - 1. Return *undefined*. - +1. If |args| is [=list/is empty|empty=], return. +1. Let |first| be |args|[0]. +1. Let |rest| be all elements following |first| in |args|. +1. If |rest| is [=list/is empty|empty=], perform + Printer(|logLevel|, « |first| ») and return. +1. If |first| does not contain any format specifiers, perform + Printer(|logLevel|, |args|). +1. Otherwise, perform Printer(|logLevel|, Formatter(|args|)). +1. Return *undefined*.
It's important that the printing occurs before returning from the algorithm. Many developer consoles print the result of the last operation entered into them. In such consoles, when a - developer enters console.log("hello!"), this should first print "hello!", then the + developer enters `console.log("hello!")`, this will first print "hello!", then the undefined return value from the console.log call. Indicating that printing is done before return
-

Formatter(args)

+

Formatter(|args|)

The formatter operation tries to format the first argument provided, using the other arguments. It will try to format the input until no formatting specifiers are left in the first argument, or no -more arguments are left. It returns a List of objects suitable for printing. - - - 1. Let _target_ be the first element of _args_. - 1. Let _current_ be the second element of _args_. - 1. Find the first possible format specifier _specifier_, from the left to the right in _target_. - 1. If _specifier_ is `%s`, let _converted_ be the result of ToString(_current_). - 1. If _specifier_ is `%d` or `%i`, let _converted_ be the result of %parseInt%(_current_, 10). - 1. If _specifier_ is `%f`, let _converted_ be the result of %parseFloat%(_current_, 10). - 1. If _specifier_ is `%o`, optionally let _converted_ be _current_ with - optimally useful formatting applied. - 1. If _specifier_ is `%O`, optionally let _converted_ be _current_ with - generic JavaScript object formatting applied. - 1.

TODO: process %c

- 1. If any of the previous steps set _converted_, replace _specifier_ in _target_ with - _converted_. - 1. Let _result_ be a List containing _target_ together with the elements of _args_ starting - from the third onward. - 1. If _target_ does not have any format specifiers left, return _result_. - 1. If _result_ contains just one element, return _result_. - 1. Return Formatter(_result_). -
+more arguments are left. It returns a [=list=] of objects suitable for printing. + +1. Let |target| be the first element of |args|. +1. Let |current| be the second element of |args|. +1. Find the first possible format specifier |specifier|, from the left to the right in |target|. + 1. If |specifier| is `%s`, let |converted| be the result of + ToString(|current|). + 1. If |specifier| is `%d` or `%i`, let |converted| be the result of + %parseInt%(|current|, 10). + 1. If |specifier| is `%f`, let |converted| be the result of + %parseFloat%(|current|). + 1. If |specifier| is `%o`, optionally let |converted| be |current| with + optimally useful formatting applied. + 1. If |specifier| is `%O`, optionally let |converted| be |current| with + generic JavaScript object formatting applied. + 1.

TODO: process %c

+ 1. If any of the previous steps set |converted|, replace |specifier| in |target| with + |converted|. + 1. Let |result| be a [=list=] containing |target| together with the elements of |args| starting + from the third onward. +1. If |target| does not have any format specifiers left, return |result|. +1. If |result|'s [=list/size=] is 1, return |result|. +1. Return Formatter(|result|).

Summary of formatting specifiers

@@ -126,69 +313,67 @@ The following is an informative summary of the format specifiers processed by th - %s + `%s` Element which substitutes is converted to a string - ToString(element) + ToString(|element|) - %d or %i + `%d` or `%i` Element which substitutes is converted to an integer - %parseInt%(element, 10) + %parseInt%(|element|, 10) - %f + `%f` Element which substitutes is converted to a float - %parseFloat%(element, 10) + %parseFloat%(|element|, 10) - %o + `%o` Element is displayed with optimally useful formatting n/a - %O + `%O` Element is displayed with generic JavaScript object formatting n/a - %c + `%c` Applies provided CSS n/a -

Printer(logLevel, args [, options])

+

Printer(|logLevel|, |args|[, |options|])

The printer operation is implementation-defined. It accepts a log level indicating severity, a List of arguments to print, and an optional object of implementation-specific formatting options. -Elements appearing in args will be one of the following: +Elements appearing in |args| will be one of the following: - - JavaScript objects of any type. - - Implementation-specific representations of printable things such as a stack trace or - group. - - Objects with either generic JavaScript object formatting or - optimally useful formatting applied. +- JavaScript objects of any type. +- Implementation-specific representations of printable things such as a stack trace or group. +- Objects with either generic JavaScript object formatting or + optimally useful formatting applied. -If the options object is passed, and is not undefined or null, implementations may use -options to apply implementation-specific formatting to the elements in args. +If the |options| object is passed, and is not undefined or null, implementations may use |options| +to apply implementation-specific formatting to the elements in |args|. -How the implementation prints args is up to the implementation, but implementations -should separate the objects by a space or something similar, as that has become a developer -expectation. +How the implementation prints |args| is up to the implementation, but implementations should +separate the objects by a space or something similar, as that has become a developer expectation. By the time the printer operation is called, all format specifiers will have been taken into -account, and any arguments that are meant to be consumed by format specifiers will not be present -in args. The implementation's job is simply to print the List. The output produced by -calls to Printer should appear only within the last group on the appropriate -group stack if the group stack is not empty, or elsewhere in the console otherwise. +account, and any arguments that are meant to be consumed by format specifiers will not be present in +|args|. The implementation's job is simply to print the List. The output produced by calls to +Printer should appear only within the last group on the appropriate group stack if the +group stack is not empty, or elsewhere in the console otherwise. -If the console is not open when the printer operation is called, -implementations should buffer messages to show them in the future up to an -implementation-chosen limit (typically on the order of at least 100). +If the console is not open when the printer operation is called, implementations should buffer +messages to show them in the future up to an implementation-chosen limit (typically on the order of +at least 100). -

Indicating logLevel severity

+

Indicating |logLevel| severity

-Each {{console}} method uses a unique value for the logLevel parameter when calling +Each {{console}} method uses a unique value for the |logLevel| parameter when calling Printer, allowing implementations to customize each printed message depending on the method from which it originated. However, it is common practice to group together certain methods and treat their output similarly, in four broad categories. This table summarizes these common groupings: @@ -204,10 +389,8 @@ their output similarly, in four broad categories. This table summarizes these co log - - {{console/log()}}, {{console/trace()}}, {{console/dir()}}, {{console/dirxml()}}, - {{console/group()}}, {{console/groupCollapsed()}}, {{console/debug()}} - + {{console/log()}}, {{console/trace()}}, {{console/dir()}}, {{console/dirxml()}}, + {{console/group()}}, {{console/groupCollapsed()}}, {{console/debug()}} A generic log @@ -215,21 +398,21 @@ their output similarly, in four broad categories. This table summarizes these co info - {{console/count()}}, {{console/info()}}, {{console/timeEnd()}} + {{console/count()}}, {{console/info()}}, {{console/timeEnd()}} An informative log warn - {{console/warn()}} + {{console/warn()}} A log warning the user of something indicated by the message error - {{console/error()}}, {{console/assert()}} + {{console/error()}}, {{console/assert()}} A log indicating an error to the user @@ -247,15 +430,16 @@ providing special behavior for each method, as in the following examples:
- Calls to {{console/count()}} might not always print new output, but instead could update previously-output counts. + Calls to {{console/count()}} might not always print new output, but instead could update + previously-output counts. A demonstration of count behavior

Printer user experience innovation

-Since Printer is implementation-defined, it is common to see UX innovations in its implementations. -The following is a non-exhaustive list of potential UX enhancements: +Since Printer is implementation-defined, it is common to see UX innovations in +its implementations. The following is a non-exhaustive list of potential UX enhancements: