├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── package-lock.json ├── package.json └── spec.emu /.gitattributes: -------------------------------------------------------------------------------- 1 | index.html -diff merge=ours 2 | spec.js -diff merge=ours 3 | spec.css -diff merge=ours 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Deploy spec 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v1 12 | with: 13 | node-version: '12.x' 14 | - run: npm install 15 | - run: npm run build 16 | - name: commit changes 17 | uses: elstudio/actions-js-build/commit@v3 18 | with: 19 | commitMessage: "fixup: [spec] `npm run build`" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # lockfile not ignored: https://classic.yarnpkg.com/blog/2016/11/24/lockfiles-for-all/ 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ECMA TC39 and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # String dedent 2 | 3 | Champions: [@jridgewell](https://github.com/jridgewell), [@hemanth](https://github.com/hemanth) 4 | 5 | Author: [@mmkal](https://github.com/mmkal) 6 | 7 | Status: [Stage 2](https://tc39.es/process-document/) 8 | 9 | ## Problem 10 | 11 | When trying to embed formatted text (for instance, Markdown contents, or the 12 | source text of a JS program) in JS code, developers are forced to make awkward 13 | concessions for readability of the code or output. For instance, to make the 14 | embedded text look consistent with the surrounding code, we'd write: 15 | 16 | ```javascript 17 | class MyClass { 18 | print() { 19 | console.log(` 20 | create table student( 21 | id int primary key, 22 | name text 23 | ) 24 | `); 25 | } 26 | } 27 | ``` 28 | 29 | This outputs (using `^` to mark the beginning of a line and `·` to mark a leading space): 30 | 31 | ```sql 32 | ^ 33 | ^······create table student( 34 | ^········id int primary key, 35 | ^········name text 36 | ^······) 37 | ^···· 38 | ``` 39 | 40 | In order to for the output to look sensible, our code becomes illegible: 41 | 42 | ```javascript 43 | class MyClass { 44 | print() { 45 | console.log(`create table student( 46 | id int primary key, 47 | name text 48 | )`); 49 | } 50 | } 51 | ``` 52 | 53 | This outputs a sensible: 54 | 55 | ```sql 56 | create table student( 57 | id int primary key, 58 | name text 59 | ) 60 | ``` 61 | 62 | ### With a library 63 | 64 | It's possible to write sensible code and have sensible output with the help of 65 | [libraries](https://www.npmjs.com/search?ranking=popularity&q=dedent). 66 | 67 | ```javascript 68 | import dedent from 'dedent' 69 | 70 | class MyClass { 71 | print() { 72 | console.log(dedent` 73 | create table student( 74 | id int primary key, 75 | name text 76 | ) 77 | `); 78 | } 79 | } 80 | ``` 81 | 82 | This outputs the sensible: 83 | 84 | ```sql 85 | create table student( 86 | id int primary key, 87 | name text 88 | ) 89 | ``` 90 | 91 | However, these libraries incur a runtime cost, and are subtly inconsistent with 92 | the way they perform "dedenting". The most popular package is stagnant without 93 | bug fixes and has problematic interpreting of the Template Object's `.raw` 94 | array, and none are able to pass the dedented text to tag template functions. 95 | 96 | ```javascript 97 | pythonInterpreter` 98 | print('Hello Python World') 99 | `; // IndentationError: unexpected indent 100 | 101 | const dedented = dedent` 102 | print('Hello Python World') 103 | `; 104 | 105 | pythonInterpreter`${dedented}`; // <- this doesn't work right. 106 | ``` 107 | 108 | Additionally, even if a userland library were to support passing to tagged 109 | templates, the array would not be a true Template Object in proposals like 110 | [`Array.isTemplateObject`](https://github.com/tc39/proposal-array-is-template-object). 111 | This harms the ability of tagged templates functions to differentiate dedented 112 | templates that exist in the actual program source text (and ascribe a higher 113 | trust level to) vs a dynamically generated string (which may contain a user 114 | generated exploit string). 115 | 116 | ## Proposed solution 117 | 118 | Implement a `String.dedent` tag template function, for a tagged template 119 | literal behaving almost the same as a regular single backticked template 120 | literal, with a few key differences: 121 | 122 | - The opening line (everything immediately right of the opening `` ` ``) must 123 | contain only a literal newline char. 124 | - The opening line's literal newline is removed. 125 | - The closing line (everything immediately to the left of the closing `` ` ``) 126 | may contain whitespace, but the whitespace is removed. 127 | - The closing line's preceding literal newline char is removed. 128 | - Lines which only contain whitespace are emptied. 129 | - The "common indentation" of all non-empty content lines (lines that are not the 130 | opening or closing) are calculated. 131 | - That common indentation is removed from the start of every line. 132 | 133 | Play around with a [REPL](https://output.jsbin.com/wiwovot/quiet) implementation. 134 | 135 | The examples above would be solved like this: 136 | 137 | ```javascript 138 | class MyClass { 139 | print() { 140 | console.log(String.dedent` 141 | create table student( 142 | id int primary key, 143 | name text 144 | ) 145 | `); 146 | } 147 | } 148 | ``` 149 | 150 | This outputs the sensible: 151 | 152 | ```sql 153 | create table student( 154 | id int primary key, 155 | name text 156 | ) 157 | ``` 158 | 159 | Expressions can be directly supported, as well as composition with 160 | another tagged template function: 161 | 162 | ```javascript 163 | const message = 'Hello Python World'; 164 | String.dedent(pythonInterpreter)` 165 | print('${message}') 166 | `; 167 | ``` 168 | 169 | ## In other languages 170 | 171 | - *CoffeeScript* - [block strings](https://coffeescript.org/#strings) using `'''` and `"""` triple-quotes. 172 | - *Java* - [text blocks](https://openjdk.java.net/jeps/378) using triple-quotes. 173 | - *Kotlin* - [raw strings](https://kotlinlang.org/docs/strings.html#raw-strings) using triple-quotes and `.trimIndent()`. 174 | - *Scala* - [multiline strings](https://docs.scala-lang.org/overviews/scala-book/two-notes-about-strings.html) 175 | using triple-quotes and `.stripMargin`. 176 | - *Python* - [multiline strings](https://docs.python.org/3/library/textwrap.html) using triple-quotes 177 | to avoid escaping and `textwrap.dedent`. 178 | - *Jsonnet* - [text blocks](https://jsonnet.org/learning/tutorial.html) with `|||` as a delimiter. 179 | - *Bash* - [`<<-` Heredocs](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04). 180 | - *Ruby* - [`<<~` Heredocs](https://www.rubyguides.com/2018/11/ruby-heredoc/). 181 | - *Swift* - [multiline string literals](https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#ID286) 182 | using triple-quotes - strips margin based on whitespace before closing 183 | delimiter. 184 | - _PHP_ - `<<<` [heredoc/nowdoc](https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes#closing_marker_indentation) 185 | The indentation of the closing marker dictates the amount of whitespace to 186 | strip from each line. 187 | 188 | ## Q&A 189 | 190 | ### Why not use a library? 191 | 192 | To summarise the [problem](#problem) section above: 193 | - avoid a dependency for the desired behaviour of the vast majority of 194 | multiline strings (dedent has millions of downloads per week). 195 | - avoiding inconsistencies between the multiple current implementations. 196 | - improved performance. 197 | - better discoverability - the feature can be documented publicly, and used in 198 | code samples which wouldn't otherwise rely on a package like dedent. 199 | - give code generators a way to output readable code with correct indentation 200 | properties (e.g. jest inline snapshots). 201 | - support "dedenting" tagged template literal functions with customized 202 | expression parameter behaviour (e.g. [slonik](https://npmjs.com/package/slonik)). 203 | - allow formatters/linters to safely enforce code style without needing to be 204 | coupled to the runtime behaviour of multiple libraries in combination. 205 | 206 | 207 | ## Additional Links 208 | 209 | - [Original TC39 thread](https://es.discourse.group/t/triple-backtick-template-literal-with-indentation-support/337) 210 | - [2020-09 Committee Meeting](https://github.com/tc39/notes/blob/HEAD/meetings/2020-09/sept-23.md#stringdedent-for-stage-1) 211 | - [2022-03 Committee Meeting](https://github.com/tc39/notes/blob/HEAD/meetings/2022-03/mar-30.md#stringdedent-status-update) 212 | - [2022-06 Committee Meeting](https://github.com/tc39/notes/blob/main/meetings/2022-06/jun-07.md#stringdedent) 213 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | String Dedent
2519 |

Stage 2 Draft / August 21, 2023

String Dedent

2528 | 2529 | 2530 |

1 Scope

2531 |

2532 | This is the spec text of the String Dedent proposal in ECMAScript. 2533 | String dedenting removes leading indentation from each line of a multiline string. 2534 |

2535 |
2536 | 2537 | 2538 |

2 Properties of the String Constructor 22.1.2

2539 | 2540 | 2541 | 2542 | 2543 |

2.1 String.dedent ( templateOrFn, ...substitutions )

2544 | Note 1
2545 |

The String.dedent function may be called with either a template array and a variable number of substitutions, or it may be called with a function which itself takes a template array and a variable number of substitutions.

2546 |

When called with a template and a variable number of substitutions, a string is returned which has common leading indentation removed from all lines with non-whitespace.

2547 |

When called with a function, a closure is returned which wraps the function. When the closure is called with a template and variable number of substitutions, the common leading indentation of the template is removed and the result of calling the function with this new dedented template and substitutions is returned.

2548 |

Common leading indentation is defined as the longest sequence of whitespace characters that match exactly on every line that contains non-whitespace. Empty lines and lines which contain only whitespace do not affect common leading indentation.

2549 |

When removing the common leading indentation, lines which contain only whitespace will have all whitespace removed.

2550 |
2551 |
  1. If templateOrFn is not an object, then
    1. NOTE: This check is to allow future extensions with different input types.
    2. Throw a TypeError exception.
  2. If IsCallable(templateOrFn) is true, then
    1. Let tag be templateOrFn.
    2. Let closure be a new Abstract Closure with parameters (template, ...substitutions) that captures tag and performs the following steps when called:
      1. If template is not an object, then
        1. Throw a TypeError exception.
      2. Let R be the this value.
      3. Let dedented be ? DedentTemplateStringsArray(template).
      4. Let args be the list-concatenation of « dedented » and substitutions.
      5. Return ? Call(tag, R, args).
    3. Return CreateBuiltinFunction(closure, 1, "", « »).
  3. Let template be templateOrFn.
  4. Let dedented be ? DedentTemplateStringsArray(template).
  5. Return ? CookTemplateStringsArray(dedented, substitutions, cooked).
2552 | Note 2
2553 |

The dedent function is intended for use as a tag function of a Tagged Template (13.3.11). When called as such, the first argument will be a well formed template object and the rest parameter will contain the substitution values.

2554 |
2555 |
2556 | 2557 | 2558 |

2.2 DedentTemplateStringsArray ( template )

2559 |

The abstract operation DedentTemplateStringsArray takes argument template (an Object) and returns either a normal completion containing an Array or a throw completion. It performs the following steps when called:

2560 |
  1. Let realm be the current Realm Record.
  2. Let dedentMap be realm.[[DedentMap]].
  3. Let rawInput be ? Get(template, "raw").
  4. For each element e of the dedentMap, do
    1. If e.[[Raw]] is not empty and SameValue(e.[[Raw]], rawInput) is true, return e.[[Dedented]].
  5. Assert: dedentMap does not currently contain an entry for rawInput.
  6. Let raw be ? DedentStringsArray(rawInput).
  7. Let cookedArr be CreateArrayFromList(CookStrings(raw)).
  8. Let rawArr be CreateArrayFromList(raw).
  9. Perform ! DefinePropertyOrThrow(cookedArr, "raw", PropertyDescriptor { [[Value]]: rawArr, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }).
  10. Perform ! SetIntegrityLevel(rawArr, frozen).
  11. Perform ! SetIntegrityLevel(cookedArr, frozen).
  12. Append the Record { [[Raw]]: rawInput, [[Dedented]]: cookedArr } to dedentMap.
  13. Return cookedArr.
2561 |
2562 | 2563 | 2564 |

2.3 DedentStringsArray ( template )

2565 |

The abstract operation DedentStringsArray takes argument template (an ECMAScript language value) and returns either a normal completion containing a List of Strings, or a throw completion. It performs the following steps when called:

2566 |
  1. Let t be ? ToObject(template).
  2. Let len be ? LengthOfArrayLike(t).
  3. If len = 0, then
    1. NOTE: Well-formed template strings arrays always contain at least 1 string.
    2. Throw a TypeError exception.
  4. Let blocks be ? SplitTemplateIntoBlockLines(t, len).
  5. Perform ? EmptyWhiteSpaceLines(blocks).
  6. Perform ? RemoveOpeningAndClosingLines(blocks, len).
  7. Let common be DetermineCommonLeadingIndentation(blocks).
  8. Let count be the length of common.
  9. Let dedented be a new empty List.
  10. For each element lines of blocks, do
    1. Assert: lines is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block.
    2. Let out be "".
    3. Let index be 0.
    4. For each Record { [[String]], [[Newline]], [[LineEndsWithSubstitution]] } line of lines, do
      1. NOTE: The first line of each block does not need to be trimmed. It's either the opening line, or it's the continuation of a line after a substitution.
      2. If index = 0 or line.[[String]] is the empty String, let c be 0; else let c be count.
      3. Let strLen be the length of line.[[String]].
      4. Let trimmed be the substring of line.[[String]] from c to strLen.
      5. Set out to the string-concatenation of out, trimmed, and line.[[Newline]].
      6. Set index to index + 1.
    5. Append out to dedented.
  11. Return dedented.
2567 |
2568 | 2569 | 2570 |

2.4 CookStrings ( raw )

2571 |

The abstract operation CookStrings takes argument raw (a List of Strings) and returns a List of either String or undefined. It performs the following steps when called:

2572 |
  1. Let cooked be a new empty List.
  2. For each element str of raw, do
    1. Let parsed be ParseText(StringToCodePoints(str), CookStringsCharactersWithBackslash).
    2. Assert: parsed is a Parse Node.
    3. NOTE: Even though String.dedent can be manually invoked with a value, the CookStringsCharactersWithBackslash nonterminal matches every string, so the above parse is guaranteed to succeed.
    4. Let val be the TV of parsed as defined in 12.8.6.
    5. NOTE: val can actually be undefined if the raw string contains an invalid escape sequence.
    6. Append val to cooked.
  3. Return cooked.
2573 | 2574 | 2575 |

2.4.1 The CookStrings Grammar

2576 |

The following grammar is used by CookStrings. It is identical to TemplateCharacters except that it allows "${"" and "`" to appear without being preceded by a backslash, allows a backslash as the final character, and accepts the empty sequence. Every sequence of code points is matched by this grammar.

2577 | 2578 | 2579 | CookStringsCharactersWithBackslash :: 2580 | CookStringsCharactersopt 2581 | \opt 2582 | 2583 | 2584 | 2585 | CookStringsCharacters :: 2586 | CookStringsCharacter 2587 | CookStringsCharactersopt 2588 | 2589 | 2590 | 2591 | CookStringsCharacter :: 2592 | $ 2593 | [lookahead = {] 2594 | 2595 | 2596 | ` 2597 | 2598 | 2599 | TemplateCharacter 2600 | 2601 | 2602 | 2603 | 2604 | 2605 |

2.4.1.1 Static Semantics: TV

2606 | Editor's Note
The following lines are added to the definition of TV.
2607 | 2654 |
2655 |
2656 |
2657 | 2658 | 2659 |

2.5 SplitTemplateIntoBlockLines ( template, len )

2660 |

The abstract operation SplitTemplateIntoBlockLines takes arguments template (an ECMAScript language value) and len (a non-negative integer) and returns either a normal completion containing a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean), or a throw completion. It performs the following steps when called:

2661 |
  1. Let blocks be a new empty List.
  2. Let index be 0.
  3. Repeat, while index < len,
    1. Let str be ? Get(template, ! ToString(𝔽(index))).
    2. If Type(str) is String, then
      1. Let lines be a new empty List.
      2. Let strLen be the length of str.
      3. Let start be 0.
      4. Let i be 0.
      5. Repeat, while i < strLen,
        1. Let c be the substring of str from i to i + 1.
        2. Let n be 1.
        3. If c is "\r" and i + 1 < strLen, then
          1. Let next be the substring of str from i + 1 to i + 2.
          2. If next is "\n", set n to 2.
        4. If c is matched by LineTerminator, then
          1. Let substr be the substring of str from start to i.
          2. Let newline be the substring of str from i to i + n.
          3. Append the Record { [[String]]: substr, [[Newline]]: newline, [[LineEndsWithSubstitution]]: false } to lines.
          4. Set start to i + n.
        5. Set i to i + n.
      6. Let tail be the substring of str from start to strLen.
      7. If index + 1 < len, let lineEndsWithSubstitution be true; else let lineEndsWithSubstitution be false.
      8. Append the Record { [[String]]: tail, [[Newline]]: "", [[LineEndsWithSubstitution]]: lineEndsWithSubstitution } to lines.
      9. Append lines to blocks.
    3. Else,
      1. Throw a TypeError exception.
    4. Set index to index + 1.
  4. Return blocks.
2662 |
2663 | 2664 | 2665 |

2.6 EmptyWhiteSpaceLines ( blocks )

2666 |

The abstract operation EmptyWhiteSpaceLines takes argument blocks (a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean)). It performs the following steps when called:

2667 |
  1. For each element lines of blocks, do
    1. Let lineCount be the length of lines.
    2. NOTE: We start i at 1 because the first line of every block is either (a) the opening line which must be empty or (b) the continuation of a line directly after a template substitution. Neither can be the start of a content line.
    3. Let i be 1.
    4. Repeat, while i < lineCount,
      1. Let line be lines[i].
      2. If line.[[LineEndsWithSubstitution]] is false and IsAllWhiteSpace(line.[[String]]) is true, then
        1. NOTE: Lines which contain only whitespace are emptied in the output. Their trailing newline is not removed, so the line is maintained.
        2. Set line.[[String]] to "".
      3. Set i to i + 1.
2668 |
2669 | 2670 | 2671 |

2.7 RemoveOpeningAndClosingLines ( blocks, len )

2672 |

The abstract operation RemoveOpeningAndClosingLines takes arguments blocks (a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean)) and len (a non-negative integer). It performs the following steps when called:

2673 |
  1. Assert: blocks contains at least 1 element, because we know the length of the template strings array is at least 1.
  2. Let firstBlock be blocks[0].
  3. Assert: firstBlock is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block.
  4. Let lineCount be the length of firstBlock.
  5. If lineCount = 1, then
    1. NOTE: The opening line is required to contain a trailing newline, and checking that there are at least 2 elements in lines ensures it. If it does not, either the opening line and the closing line are the same line, or the opening line contains a substitution.
    2. Throw a TypeError exception.
  6. Let openingLine be firstBlock[0].
  7. If openingLine.[[String]] is not empty, then
    1. NOTE: The opening line must not contain code units besides the trailing newline.
    2. Throw a TypeError exception.
  8. NOTE: Setting openingLine.[[Newline]] removes the opening line from the output.
  9. Set openingLine.[[Newline]] to "".
  10. Let lastBlock be blocks[len - 1].
  11. Assert: lastBlock is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block.
  12. Set lineCount to the length of lastBlock.
  13. If lineCount = 1, then
    1. NOTE: The closing line is required to be preceded by a newline, and checking that there are at least 2 elements in lines ensures it. If it does not, either the opening line and the closing line are the same line, or the closing line contains a substitution.
    2. Throw a TypeError exception.
  14. Let closingLine be lastBlock[lineCount - 1].
  15. If closingLine.[[String]] is not the empty String, then
    1. NOTE: The closing line may only contain whitespace. We've already performed EmptyWhiteSpaceLines, so if the line is not empty now, it contained some non-whitespace character.
    2. Throw a TypeError exception.
  16. Let preceding be lastBlock[lineCount - 2].
  17. NOTE: Setting closingLine.[[String]] and preceding.[[Newline]] removes the closing line from the output.
  18. Set closingLine.[[String]] to "".
  19. Set preceding.[[Newline]] to "".
2674 |
2675 | 2676 | 2677 |

2.8 DetermineCommonLeadingIndentation ( blocks )

2678 |

The abstract operation DetermineCommonLeadingIndentation takes argument blocks (a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean)) and returns a String. It performs the following steps when called:

2679 |
  1. Let common be empty.
  2. For each element lines of blocks, do
    1. Let lineCount be the length of lines.
    2. NOTE: We start i at 1 because because the first line of every block is either (a) the opening line which must be empty or (b) the continuation of a line directly after a template substitution. Neither can be the start of a content line.
    3. Let i be 1.
    4. Repeat, while i < lineCount,
      1. Let line be lines[i].
      2. NOTE: Lines which contain substitutions are considered when finding the common indentation. Lines which contain only whitespace have already been emptied.
      3. If line.[[LineEndsWithSubstitution]] is true or line.[[String]] is not the empty String, then
        1. Let leading be LeadingWhiteSpaceSubstring(line.[[String]]).
        2. If common is empty, then
          1. Set common to leading.
        3. Else,
          1. Set common to LongestMatchingLeadingSubstring(common, leading).
      4. Set i to i + 1.
  3. Assert: common is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block, and we know the length of the template strings array is at least 1.
  4. Return common.
2680 |
2681 | 2682 | 2683 |

2.9 LeadingWhiteSpaceSubstring ( str )

2684 |

The abstract operation LeadingWhiteSpaceSubstring takes argument str (a String) and returns a String. It performs the following steps when called:

2685 |
  1. Let len be the length of str.
  2. Let i be 0.
  3. Repeat, while i < len,
    1. Let c be the substring of str from i to i + 1.
    2. If c does not match WhiteSpace, then
      1. Return the substring of str from 0 to i.
    3. Set i to i + 1.
  4. Return str.
2686 |

When determining whether a Unicode code point is in Unicode general category “Space_Separator” (“Zs”), code unit sequences are interpreted as UTF-16 encoded code point sequences as specified in 6.1.4.

2687 |
2688 | 2689 | 2690 |

2.10 IsAllWhiteSpace ( str )

2691 |

The abstract operation IsAllWhiteSpace takes argument str (a String) and returns a Boolean. It performs the following steps when called:

2692 |
  1. Let trimmed be ! TrimString(str, start).
  2. If trimmed is the empty String, return true.
  3. Return false.
2693 |
2694 | 2695 | 2696 |

2.11 LongestMatchingLeadingSubstring ( a, b )

2697 |

The abstract operation LongestMatchingLeadingSubstring takes arguments a (a String) and b (a String) and returns a String. It performs the following steps when called:

2698 |
  1. Let aLen be the length of a.
  2. Let bLen be the length of b.
  3. Let len be min(aLen, bLen).
  4. Let i be 0.
  5. Repeat, while i < len,
    1. Let aChar be the substring of a from i to i + 1.
    2. Let bChar be the substring of b from i to i + 1.
    3. If aChar is not bChar, then
      1. Return the substring of a from 0 to i.
    4. Set i to i + 1.
  6. Return the substring of a from 0 to len.
2699 |
2700 | 2701 |
2702 | 2703 | 2704 |

2.12 CookTemplateStringsArray ( template, substitutions, prep )

2705 |

The abstract operation CookTemplateStringsArray takes arguments template (an ECMAScript language value), substitutions (a List of ECMAScript language values), and prep (cooked or raw) and returns either a normal completion containing a String or a throw completion.

2706 | Note
2707 |

This abstract operation merges the behaviour of String.raw with the String.cooked proposal.

2708 |
2709 |

It performs the following steps when called:

2710 |
  1. Let substitutionCount be the number of elements in substitutions.
  2. Let cooked be ? ToObject(template).
  3. If prep is cooked, let literals be cooked; else let literals be ? ToObject(? Get(cooked, "raw")).
  4. Let literalCount be ? LengthOfArrayLike(literals).
  5. If literalCount ≤ 0, return the empty String.
  6. Let R be the empty String.
  7. Let nextIndex be 0.
  8. Repeat,
    1. Let nextLiteralVal be ? Get(literals, ! ToString(𝔽(nextIndex))).
    2. Let nextLiteral be ? ToString(nextLiteralVal).
    3. Set R to the string-concatenation of R and nextLiteral.
    4. If nextIndex + 1 = literalCount, return R.
    5. If nextIndex < substitutionCount, then
      1. Let nextSubVal be substitutions[nextIndex].
      2. Let nextSub be ? ToString(nextSubVal).
      3. Set R to the string-concatenation of R and nextSub.
    6. Set nextIndex to nextIndex + 1.
2711 |
2712 |
2713 | 2714 | 2715 |

3 Realms

2716 |

Before it is evaluated, all ECMAScript code must be associated with a realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.

2717 |

A realm is represented in this specification as a Realm Record with the fields specified in Table 1:

2718 |
Table 1: Realm Record Fields
2719 | 2720 | 2721 | 2724 | 2727 | 2730 | 2731 | 2732 | 2735 | 2738 | 2741 | 2742 | 2743 | 2746 | 2749 | 2752 | 2753 | 2754 | 2757 | 2760 | 2763 | 2764 | 2765 | 2768 | 2771 | 2775 | 2776 | 2777 | 2780 | 2783 | 2786 | 2787 | 2788 | 2791 | 2794 | 2799 | 2800 |
2722 | Field Name 2723 | 2725 | Value 2726 | 2728 | Meaning 2729 |
2733 | [[Intrinsics]] 2734 | 2736 | a Record whose field names are intrinsic keys and whose values are objects 2737 | 2739 | The intrinsic values used by code associated with this realm 2740 |
2744 | [[GlobalObject]] 2745 | 2747 | an Object or undefined 2748 | 2750 | The global object for this realm 2751 |
2755 | [[GlobalEnv]] 2756 | 2758 | a Global Environment Record 2759 | 2761 | The global environment for this realm 2762 |
2766 | [[TemplateMap]] 2767 | 2769 | a List of Record { [[Site]]: Parse Node, [[Array]]: Object } 2770 | 2772 |

Template objects are canonicalized separately for each realm using its Realm Record's [[TemplateMap]]. Each [[Site]] value is a Parse Node that is a TemplateLiteral. The associated [[Array]] value is the corresponding template object that is passed to a tag function.

2773 | Note
Once a Parse Node becomes unreachable, the corresponding [[Array]] is also unreachable, and it would be unobservable if an implementation removed the pair from the [[TemplateMap]] list.
2774 |
2778 | [[HostDefined]] 2779 | 2781 | anything (default value is undefined) 2782 | 2784 | Field reserved for use by hosts that need to associate additional information with a Realm Record. 2785 |
2789 | [[DedentMap]] 2790 | 2792 | a List of Record { [[Raw]]: Object, [[Dedented]]: Object } 2793 | 2795 | 2796 | The [[DedentMap]] ensures template tag functions wrapped with String.dedent see consistent object identity for a given input template. The [[Raw]] key weakly holds the value of a template object's raw property. The associated [[Dedented]] value is the result of performing dedenting on that raw value. 2797 | 2798 |
2801 |
2802 | 2803 | 2804 |

3.1 CreateRealm ( )

2805 |

The abstract operation CreateRealm takes no arguments and returns a Realm Record. It performs the following steps when called:

2806 |
  1. Let realmRec be a new Realm Record.
  2. Perform CreateIntrinsics(realmRec).
  3. Set realmRec.[[GlobalObject]] to undefined.
  4. Set realmRec.[[GlobalEnv]] to undefined.
  5. Set realmRec.[[TemplateMap]] to a new empty List.
  6. Set realmRec.[[DedentMap]] to a new empty List.
  7. Return realmRec.
2807 |
2808 |
2809 | 2810 | 2811 |

4 Execution 9.10.3

2812 | 2813 |

At any time, if a set of objects S is not live, an ECMAScript implementation may perform the following steps atomically:

2814 | 2815 |
  1. For each element obj of S, do
    1. For each WeakRef ref such that ref.[[WeakRefTarget]] is obj, do
      1. Set ref.[[WeakRefTarget]] to empty.
    2. For each FinalizationRegistry fg such that fg.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is obj, do
      1. Set cell.[[WeakRefTarget]] to empty.
      2. Optionally, perform HostEnqueueFinalizationRegistryCleanupJob(fg).
    3. For each WeakMap map such that map.[[WeakMapData]] contains a Record r such that r.[[Key]] is obj, do
      1. Set r.[[Key]] to empty.
      2. Set r.[[Value]] to empty.
    4. For each WeakSet set such that set.[[WeakSetData]] contains obj, do
      1. Replace the element of set.[[WeakSetData]] whose value is obj with an element whose value is empty.
    5. Let realm be the current Realm Record.
    6. If realm.[[DedentMap]] contains a Record r such that r.[[Raw]] is obj, then
      1. Set r.[[Raw]] to empty.
      2. Set r.[[Dedented]] to empty.
2816 | 2817 | Note 1
2818 |

Together with the definition of liveness, this clause prescribes legal optimizations that an implementation may apply regarding WeakRefs.

2819 | 2820 |

It is possible to access an object without observing its identity. Optimizations such as dead variable elimination and scalar replacement on properties of non-escaping objects whose identity is not observed are allowed. These optimizations are thus allowed to observably empty WeakRefs that point to such objects.

2821 | 2822 |

On the other hand, if an object's identity is observable, and that object is in the [[WeakRefTarget]] internal slot of a WeakRef, optimizations such as rematerialization that observably empty the WeakRef are prohibited.

2823 | 2824 |

Because calling HostEnqueueFinalizationRegistryCleanupJob is optional, registered objects in a FinalizationRegistry do not necessarily hold that FinalizationRegistry live. Implementations may omit FinalizationRegistry callbacks for any reason, e.g., if the FinalizationRegistry itself becomes dead, or if the application is shutting down.

2825 |
2826 | Note 2
2827 |

Implementations are not obligated to empty WeakRefs for maximal sets of non-live objects.

2828 |

If an implementation chooses a non-live set S in which to empty WeakRefs, it must empty WeakRefs for all objects in S simultaneously. In other words, an implementation must not empty a WeakRef pointing to an object obj without emptying out other WeakRefs that, if not emptied, could result in an execution that observes the Object value of obj.

2829 |
2830 |
2831 |

A Copyright & Software License

2832 | 2833 |

Copyright Notice

2834 |

© 2023 Justin Ridgewell

2835 | 2836 |

Software License

2837 |

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

2838 | 2839 |

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

2840 | 2841 |
    2842 |
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. 2843 |
  3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  4. 2844 |
  5. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
  6. 2845 |
2846 | 2847 |

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2848 | 2849 |
2850 |
-------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proposal-string-dedent", 3 | "requires": true, 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "@babel/code-frame": { 7 | "version": "7.12.11", 8 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 9 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 10 | "dev": true, 11 | "requires": { 12 | "@babel/highlight": "^7.10.4" 13 | } 14 | }, 15 | "@babel/helper-validator-identifier": { 16 | "version": "7.16.7", 17 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", 18 | "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", 19 | "dev": true 20 | }, 21 | "@babel/highlight": { 22 | "version": "7.17.12", 23 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", 24 | "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", 25 | "dev": true, 26 | "requires": { 27 | "@babel/helper-validator-identifier": "^7.16.7", 28 | "chalk": "^2.0.0", 29 | "js-tokens": "^4.0.0" 30 | }, 31 | "dependencies": { 32 | "ansi-styles": { 33 | "version": "3.2.1", 34 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 35 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 36 | "dev": true, 37 | "requires": { 38 | "color-convert": "^1.9.0" 39 | } 40 | }, 41 | "chalk": { 42 | "version": "2.4.2", 43 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 44 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 45 | "dev": true, 46 | "requires": { 47 | "ansi-styles": "^3.2.1", 48 | "escape-string-regexp": "^1.0.5", 49 | "supports-color": "^5.3.0" 50 | } 51 | }, 52 | "color-convert": { 53 | "version": "1.9.3", 54 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 55 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 56 | "dev": true, 57 | "requires": { 58 | "color-name": "1.1.3" 59 | } 60 | }, 61 | "color-name": { 62 | "version": "1.1.3", 63 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 64 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 65 | "dev": true 66 | }, 67 | "has-flag": { 68 | "version": "3.0.0", 69 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 70 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 71 | "dev": true 72 | }, 73 | "supports-color": { 74 | "version": "5.5.0", 75 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 76 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 77 | "dev": true, 78 | "requires": { 79 | "has-flag": "^3.0.0" 80 | } 81 | } 82 | } 83 | }, 84 | "@esfx/async-canceltoken": { 85 | "version": "1.0.0-pre.30", 86 | "resolved": "https://registry.npmjs.org/@esfx/async-canceltoken/-/async-canceltoken-1.0.0-pre.30.tgz", 87 | "integrity": "sha512-4he0W+ZKH4OO4RvGfmATIibO5JzGLQqwm4Dp3X15bWnguDTmmOFt3Qt169Doij/gXxn2aPpZvxUaYIEebi8Xig==", 88 | "dev": true, 89 | "requires": { 90 | "@esfx/cancelable": "^1.0.0-pre.30", 91 | "@esfx/collections-linkedlist": "^1.0.0-pre.24", 92 | "@esfx/disposable": "^1.0.0-pre.30", 93 | "@esfx/internal-guards": "^1.0.0-pre.23", 94 | "@esfx/internal-tag": "^1.0.0-pre.19", 95 | "tslib": "^2.1.0" 96 | } 97 | }, 98 | "@esfx/cancelable": { 99 | "version": "1.0.0-pre.30", 100 | "resolved": "https://registry.npmjs.org/@esfx/cancelable/-/cancelable-1.0.0-pre.30.tgz", 101 | "integrity": "sha512-fo0+/D3tEcSOHdZ8HiCR7qOKl5Tkk6Nw6QJNNXSQ0ejlpP3HU4S2i0rb/tjHQ1EkUcWZfB3g2jzfL0ioQSEgGg==", 102 | "dev": true, 103 | "requires": { 104 | "@esfx/disposable": "^1.0.0-pre.30", 105 | "@esfx/internal-deprecate": "^1.0.0-pre.24", 106 | "@esfx/internal-guards": "^1.0.0-pre.23", 107 | "@esfx/internal-tag": "^1.0.0-pre.19" 108 | } 109 | }, 110 | "@esfx/collection-core": { 111 | "version": "1.0.0-pre.24", 112 | "resolved": "https://registry.npmjs.org/@esfx/collection-core/-/collection-core-1.0.0-pre.24.tgz", 113 | "integrity": "sha512-OIgMS91JmjSoRWD7u/DfnDzo8vDggeTeUPRi1p5WhyboY0+IwmetEqgeHZb8bpka/SsmtYX5qxqEjeqNXqh+pA==", 114 | "dev": true, 115 | "requires": { 116 | "@esfx/internal-deprecate": "^1.0.0-pre.24", 117 | "@esfx/internal-guards": "^1.0.0-pre.23" 118 | } 119 | }, 120 | "@esfx/collections-linkedlist": { 121 | "version": "1.0.0-pre.24", 122 | "resolved": "https://registry.npmjs.org/@esfx/collections-linkedlist/-/collections-linkedlist-1.0.0-pre.24.tgz", 123 | "integrity": "sha512-Maya8jXH0xvzyfeSH88/j2b5gavO/mluslgIC2Ttdz8rh6+3o8/pVYriceH/Jinn4pgTEzDhO6Rn/aruZG0+Ug==", 124 | "dev": true, 125 | "requires": { 126 | "@esfx/collection-core": "^1.0.0-pre.24", 127 | "@esfx/equatable": "^1.0.0-pre.19", 128 | "@esfx/internal-guards": "^1.0.0-pre.23" 129 | } 130 | }, 131 | "@esfx/disposable": { 132 | "version": "1.0.0-pre.30", 133 | "resolved": "https://registry.npmjs.org/@esfx/disposable/-/disposable-1.0.0-pre.30.tgz", 134 | "integrity": "sha512-njBGIQO+HW+lMqqMjURC+MWn+55ufulgebPLXzlxbwVSz5hZkoCsv6n9sIBQbnvg/PYQmWK5Dk6gDSmFfihTUg==", 135 | "dev": true 136 | }, 137 | "@esfx/equatable": { 138 | "version": "1.0.0-pre.19", 139 | "resolved": "https://registry.npmjs.org/@esfx/equatable/-/equatable-1.0.0-pre.19.tgz", 140 | "integrity": "sha512-+f6Xm6GOigyGx7t0D0IyG9Z0AuYDhNWjwV49vs5uNG/+0VQAOSYjmnpSzTZRYcYwxW52DmWJWFYNY8bvCDD2ag==", 141 | "dev": true 142 | }, 143 | "@esfx/internal-deprecate": { 144 | "version": "1.0.0-pre.24", 145 | "resolved": "https://registry.npmjs.org/@esfx/internal-deprecate/-/internal-deprecate-1.0.0-pre.24.tgz", 146 | "integrity": "sha512-TSU5k04+nuVQdyfYhaVXxyskdiwYQHgwN20J3cbyRrm/YFi2dOoFSLFvkMNh7LNOPGWSOg6pfAm3kd23ISR3Ow==", 147 | "dev": true 148 | }, 149 | "@esfx/internal-guards": { 150 | "version": "1.0.0-pre.23", 151 | "resolved": "https://registry.npmjs.org/@esfx/internal-guards/-/internal-guards-1.0.0-pre.23.tgz", 152 | "integrity": "sha512-y2svuwRERA2eKF1T/Stq+O8kPjicFQcUTob5je3L6iloOHnOD0sX6aQLvheWmTXXS7hAnjlyMeSN/ec84BRyHg==", 153 | "dev": true, 154 | "requires": { 155 | "@esfx/type-model": "^1.0.0-pre.23" 156 | } 157 | }, 158 | "@esfx/internal-tag": { 159 | "version": "1.0.0-pre.19", 160 | "resolved": "https://registry.npmjs.org/@esfx/internal-tag/-/internal-tag-1.0.0-pre.19.tgz", 161 | "integrity": "sha512-/v1D5LfvBnbvHzL22Vh6yobrOTVCBhsW/l9M+/GRA51eqCN27yTmWGaYUSd1QXp2vxHwNr0sfckVoNtTzeaIqQ==", 162 | "dev": true 163 | }, 164 | "@esfx/type-model": { 165 | "version": "1.0.0-pre.23", 166 | "resolved": "https://registry.npmjs.org/@esfx/type-model/-/type-model-1.0.0-pre.23.tgz", 167 | "integrity": "sha512-jwcSY9pqEmGoDNhfT+0LUmSTyk6zXF/pbgKb7KU7mTfCrWfVCT/ve61cD1CreerDRBSat/s55se0lJXwDSjhuA==", 168 | "dev": true 169 | }, 170 | "@nodelib/fs.scandir": { 171 | "version": "2.1.5", 172 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 173 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 174 | "dev": true, 175 | "requires": { 176 | "@nodelib/fs.stat": "2.0.5", 177 | "run-parallel": "^1.1.9" 178 | } 179 | }, 180 | "@nodelib/fs.stat": { 181 | "version": "2.0.5", 182 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 183 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 184 | "dev": true 185 | }, 186 | "@nodelib/fs.walk": { 187 | "version": "1.2.8", 188 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 189 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 190 | "dev": true, 191 | "requires": { 192 | "@nodelib/fs.scandir": "2.1.5", 193 | "fastq": "^1.6.0" 194 | } 195 | }, 196 | "@tc39/ecma262-biblio": { 197 | "version": "2.0.2321", 198 | "resolved": "https://registry.npmjs.org/@tc39/ecma262-biblio/-/ecma262-biblio-2.0.2321.tgz", 199 | "integrity": "sha512-mvqK81EIXy4IPKNiUc1q/F3g8doQPsrdYSQKG5ZdPOk0N6Rfiuiqg/Hiz7ZZElrEwinIRZv+kpmzRWH89UHb6A==", 200 | "dev": true 201 | }, 202 | "@tootallnate/once": { 203 | "version": "2.0.0", 204 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", 205 | "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", 206 | "dev": true 207 | }, 208 | "abab": { 209 | "version": "2.0.6", 210 | "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", 211 | "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", 212 | "dev": true 213 | }, 214 | "acorn": { 215 | "version": "8.7.1", 216 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", 217 | "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", 218 | "dev": true 219 | }, 220 | "acorn-globals": { 221 | "version": "6.0.0", 222 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", 223 | "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", 224 | "dev": true, 225 | "requires": { 226 | "acorn": "^7.1.1", 227 | "acorn-walk": "^7.1.1" 228 | }, 229 | "dependencies": { 230 | "acorn": { 231 | "version": "7.4.1", 232 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 233 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 234 | "dev": true 235 | } 236 | } 237 | }, 238 | "acorn-walk": { 239 | "version": "7.2.0", 240 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", 241 | "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", 242 | "dev": true 243 | }, 244 | "agent-base": { 245 | "version": "6.0.2", 246 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 247 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 248 | "dev": true, 249 | "requires": { 250 | "debug": "4" 251 | } 252 | }, 253 | "ansi-styles": { 254 | "version": "4.3.0", 255 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 256 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 257 | "dev": true, 258 | "requires": { 259 | "color-convert": "^2.0.1" 260 | } 261 | }, 262 | "argparse": { 263 | "version": "1.0.10", 264 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 265 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 266 | "dev": true, 267 | "requires": { 268 | "sprintf-js": "~1.0.2" 269 | } 270 | }, 271 | "array-back": { 272 | "version": "3.1.0", 273 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 274 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", 275 | "dev": true 276 | }, 277 | "asynckit": { 278 | "version": "0.4.0", 279 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 280 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 281 | "dev": true 282 | }, 283 | "braces": { 284 | "version": "3.0.2", 285 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 286 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 287 | "dev": true, 288 | "requires": { 289 | "fill-range": "^7.0.1" 290 | } 291 | }, 292 | "browser-process-hrtime": { 293 | "version": "1.0.0", 294 | "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", 295 | "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", 296 | "dev": true 297 | }, 298 | "chalk": { 299 | "version": "4.1.2", 300 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 301 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 302 | "dev": true, 303 | "requires": { 304 | "ansi-styles": "^4.1.0", 305 | "supports-color": "^7.1.0" 306 | } 307 | }, 308 | "color-convert": { 309 | "version": "2.0.1", 310 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 311 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 312 | "dev": true, 313 | "requires": { 314 | "color-name": "~1.1.4" 315 | } 316 | }, 317 | "color-name": { 318 | "version": "1.1.4", 319 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 320 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 321 | "dev": true 322 | }, 323 | "combined-stream": { 324 | "version": "1.0.8", 325 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 326 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 327 | "dev": true, 328 | "requires": { 329 | "delayed-stream": "~1.0.0" 330 | } 331 | }, 332 | "command-line-args": { 333 | "version": "5.2.1", 334 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", 335 | "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", 336 | "dev": true, 337 | "requires": { 338 | "array-back": "^3.1.0", 339 | "find-replace": "^3.0.0", 340 | "lodash.camelcase": "^4.3.0", 341 | "typical": "^4.0.0" 342 | } 343 | }, 344 | "command-line-usage": { 345 | "version": "6.1.3", 346 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", 347 | "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", 348 | "dev": true, 349 | "requires": { 350 | "array-back": "^4.0.2", 351 | "chalk": "^2.4.2", 352 | "table-layout": "^1.0.2", 353 | "typical": "^5.2.0" 354 | }, 355 | "dependencies": { 356 | "ansi-styles": { 357 | "version": "3.2.1", 358 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 359 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 360 | "dev": true, 361 | "requires": { 362 | "color-convert": "^1.9.0" 363 | } 364 | }, 365 | "array-back": { 366 | "version": "4.0.2", 367 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 368 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 369 | "dev": true 370 | }, 371 | "chalk": { 372 | "version": "2.4.2", 373 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 374 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 375 | "dev": true, 376 | "requires": { 377 | "ansi-styles": "^3.2.1", 378 | "escape-string-regexp": "^1.0.5", 379 | "supports-color": "^5.3.0" 380 | } 381 | }, 382 | "color-convert": { 383 | "version": "1.9.3", 384 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 385 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 386 | "dev": true, 387 | "requires": { 388 | "color-name": "1.1.3" 389 | } 390 | }, 391 | "color-name": { 392 | "version": "1.1.3", 393 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 394 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 395 | "dev": true 396 | }, 397 | "has-flag": { 398 | "version": "3.0.0", 399 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 400 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 401 | "dev": true 402 | }, 403 | "supports-color": { 404 | "version": "5.5.0", 405 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 406 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 407 | "dev": true, 408 | "requires": { 409 | "has-flag": "^3.0.0" 410 | } 411 | }, 412 | "typical": { 413 | "version": "5.2.0", 414 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 415 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 416 | "dev": true 417 | } 418 | } 419 | }, 420 | "cssom": { 421 | "version": "0.5.0", 422 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", 423 | "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", 424 | "dev": true 425 | }, 426 | "cssstyle": { 427 | "version": "2.3.0", 428 | "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", 429 | "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", 430 | "dev": true, 431 | "requires": { 432 | "cssom": "~0.3.6" 433 | }, 434 | "dependencies": { 435 | "cssom": { 436 | "version": "0.3.8", 437 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", 438 | "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", 439 | "dev": true 440 | } 441 | } 442 | }, 443 | "data-urls": { 444 | "version": "3.0.2", 445 | "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", 446 | "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", 447 | "dev": true, 448 | "requires": { 449 | "abab": "^2.0.6", 450 | "whatwg-mimetype": "^3.0.0", 451 | "whatwg-url": "^11.0.0" 452 | }, 453 | "dependencies": { 454 | "whatwg-url": { 455 | "version": "11.0.0", 456 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", 457 | "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", 458 | "dev": true, 459 | "requires": { 460 | "tr46": "^3.0.0", 461 | "webidl-conversions": "^7.0.0" 462 | } 463 | } 464 | } 465 | }, 466 | "debug": { 467 | "version": "4.3.4", 468 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 469 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 470 | "dev": true, 471 | "requires": { 472 | "ms": "2.1.2" 473 | } 474 | }, 475 | "decimal.js": { 476 | "version": "10.3.1", 477 | "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", 478 | "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", 479 | "dev": true 480 | }, 481 | "dedent-js": { 482 | "version": "1.0.1", 483 | "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", 484 | "integrity": "sha1-vuX7fJ5yfYXf+iRZDRDsGrElUwU=", 485 | "dev": true 486 | }, 487 | "deep-extend": { 488 | "version": "0.6.0", 489 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 490 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 491 | "dev": true 492 | }, 493 | "deep-is": { 494 | "version": "0.1.4", 495 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 496 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 497 | "dev": true 498 | }, 499 | "delayed-stream": { 500 | "version": "1.0.0", 501 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 502 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 503 | "dev": true 504 | }, 505 | "domexception": { 506 | "version": "4.0.0", 507 | "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", 508 | "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", 509 | "dev": true, 510 | "requires": { 511 | "webidl-conversions": "^7.0.0" 512 | } 513 | }, 514 | "ecmarkdown": { 515 | "version": "7.0.0", 516 | "resolved": "https://registry.npmjs.org/ecmarkdown/-/ecmarkdown-7.0.0.tgz", 517 | "integrity": "sha512-hJxPALjSOpSMMcFjSzwzJBk8EWOu20mYlTfV7BnVTh9er0FEaT2eSx16y36YxqQfdFxPUsa0CSH4fLf0qUclKw==", 518 | "dev": true, 519 | "requires": { 520 | "escape-html": "^1.0.1" 521 | } 522 | }, 523 | "ecmarkup": { 524 | "version": "12.1.0", 525 | "resolved": "https://registry.npmjs.org/ecmarkup/-/ecmarkup-12.1.0.tgz", 526 | "integrity": "sha512-I5p5sWmmb2jSCza4s8OSnoIgUzGok098kq3eYqlkU1nmHzTMhrHPOyulILhYHhxKS9s155VUeQFJrJh6TVsRWA==", 527 | "dev": true, 528 | "requires": { 529 | "chalk": "^4.1.2", 530 | "command-line-args": "^5.2.0", 531 | "command-line-usage": "^6.1.1", 532 | "dedent-js": "^1.0.1", 533 | "ecmarkdown": "^7.0.0", 534 | "eslint-formatter-codeframe": "^7.32.1", 535 | "fast-glob": "^3.2.7", 536 | "grammarkdown": "^3.2.0", 537 | "highlight.js": "11.0.1", 538 | "html-escape": "^1.0.2", 539 | "js-yaml": "^3.13.1", 540 | "jsdom": "^19.0.0", 541 | "parse5": "^6.0.1", 542 | "prex": "^0.4.7", 543 | "promise-debounce": "^1.0.1" 544 | } 545 | }, 546 | "escape-html": { 547 | "version": "1.0.3", 548 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 549 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", 550 | "dev": true 551 | }, 552 | "escape-string-regexp": { 553 | "version": "1.0.5", 554 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 555 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 556 | "dev": true 557 | }, 558 | "escodegen": { 559 | "version": "2.0.0", 560 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", 561 | "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", 562 | "dev": true, 563 | "requires": { 564 | "esprima": "^4.0.1", 565 | "estraverse": "^5.2.0", 566 | "esutils": "^2.0.2", 567 | "optionator": "^0.8.1", 568 | "source-map": "~0.6.1" 569 | } 570 | }, 571 | "eslint-formatter-codeframe": { 572 | "version": "7.32.1", 573 | "resolved": "https://registry.npmjs.org/eslint-formatter-codeframe/-/eslint-formatter-codeframe-7.32.1.tgz", 574 | "integrity": "sha512-DK/3Q3+zVKq/7PdSYiCxPrsDF8H/TRMK5n8Hziwr4IMkMy+XiKSwbpj25AdajS63I/B61Snetq4uVvX9fOLyAg==", 575 | "dev": true, 576 | "requires": { 577 | "@babel/code-frame": "7.12.11", 578 | "chalk": "^4.0.0" 579 | } 580 | }, 581 | "esprima": { 582 | "version": "4.0.1", 583 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 584 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 585 | "dev": true 586 | }, 587 | "estraverse": { 588 | "version": "5.3.0", 589 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 590 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 591 | "dev": true 592 | }, 593 | "esutils": { 594 | "version": "2.0.3", 595 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 596 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 597 | "dev": true 598 | }, 599 | "fast-glob": { 600 | "version": "3.2.11", 601 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", 602 | "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", 603 | "dev": true, 604 | "requires": { 605 | "@nodelib/fs.stat": "^2.0.2", 606 | "@nodelib/fs.walk": "^1.2.3", 607 | "glob-parent": "^5.1.2", 608 | "merge2": "^1.3.0", 609 | "micromatch": "^4.0.4" 610 | } 611 | }, 612 | "fast-levenshtein": { 613 | "version": "2.0.6", 614 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 615 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 616 | "dev": true 617 | }, 618 | "fastq": { 619 | "version": "1.13.0", 620 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", 621 | "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", 622 | "dev": true, 623 | "requires": { 624 | "reusify": "^1.0.4" 625 | } 626 | }, 627 | "fill-range": { 628 | "version": "7.0.1", 629 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 630 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 631 | "dev": true, 632 | "requires": { 633 | "to-regex-range": "^5.0.1" 634 | } 635 | }, 636 | "find-replace": { 637 | "version": "3.0.0", 638 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 639 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 640 | "dev": true, 641 | "requires": { 642 | "array-back": "^3.0.1" 643 | } 644 | }, 645 | "form-data": { 646 | "version": "4.0.0", 647 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 648 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 649 | "dev": true, 650 | "requires": { 651 | "asynckit": "^0.4.0", 652 | "combined-stream": "^1.0.8", 653 | "mime-types": "^2.1.12" 654 | } 655 | }, 656 | "glob-parent": { 657 | "version": "5.1.2", 658 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 659 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 660 | "dev": true, 661 | "requires": { 662 | "is-glob": "^4.0.1" 663 | } 664 | }, 665 | "grammarkdown": { 666 | "version": "3.2.0", 667 | "resolved": "https://registry.npmjs.org/grammarkdown/-/grammarkdown-3.2.0.tgz", 668 | "integrity": "sha512-pEVUvG2Kxv/PwM3Dm3kFEU1/GHRkNcFWmk/zkqN/y0uoQtPaZ+5VaBacMQAaFOIL9WGYjHXtqpkT5YRvySsISQ==", 669 | "dev": true, 670 | "requires": { 671 | "@esfx/async-canceltoken": "^1.0.0-pre.13", 672 | "@esfx/cancelable": "^1.0.0-pre.13" 673 | } 674 | }, 675 | "has-flag": { 676 | "version": "4.0.0", 677 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 678 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 679 | "dev": true 680 | }, 681 | "highlight.js": { 682 | "version": "11.0.1", 683 | "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.0.1.tgz", 684 | "integrity": "sha512-EqYpWyTF2s8nMfttfBA2yLKPNoZCO33pLS4MnbXQ4hECf1TKujCt1Kq7QAdrio7roL4+CqsfjqwYj4tYgq0pJQ==", 685 | "dev": true 686 | }, 687 | "html-encoding-sniffer": { 688 | "version": "3.0.0", 689 | "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", 690 | "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", 691 | "dev": true, 692 | "requires": { 693 | "whatwg-encoding": "^2.0.0" 694 | } 695 | }, 696 | "html-escape": { 697 | "version": "1.0.2", 698 | "resolved": "https://registry.npmjs.org/html-escape/-/html-escape-1.0.2.tgz", 699 | "integrity": "sha1-X6eHwFaAkP4zLtWzz0qk9kZCGnQ=", 700 | "dev": true 701 | }, 702 | "http-proxy-agent": { 703 | "version": "5.0.0", 704 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", 705 | "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", 706 | "dev": true, 707 | "requires": { 708 | "@tootallnate/once": "2", 709 | "agent-base": "6", 710 | "debug": "4" 711 | } 712 | }, 713 | "https-proxy-agent": { 714 | "version": "5.0.1", 715 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", 716 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", 717 | "dev": true, 718 | "requires": { 719 | "agent-base": "6", 720 | "debug": "4" 721 | } 722 | }, 723 | "iconv-lite": { 724 | "version": "0.6.3", 725 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 726 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 727 | "dev": true, 728 | "requires": { 729 | "safer-buffer": ">= 2.1.2 < 3.0.0" 730 | } 731 | }, 732 | "is-extglob": { 733 | "version": "2.1.1", 734 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 735 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 736 | "dev": true 737 | }, 738 | "is-glob": { 739 | "version": "4.0.3", 740 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 741 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 742 | "dev": true, 743 | "requires": { 744 | "is-extglob": "^2.1.1" 745 | } 746 | }, 747 | "is-number": { 748 | "version": "7.0.0", 749 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 750 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 751 | "dev": true 752 | }, 753 | "is-potential-custom-element-name": { 754 | "version": "1.0.1", 755 | "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", 756 | "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", 757 | "dev": true 758 | }, 759 | "js-tokens": { 760 | "version": "4.0.0", 761 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 762 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 763 | "dev": true 764 | }, 765 | "js-yaml": { 766 | "version": "3.14.1", 767 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 768 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 769 | "dev": true, 770 | "requires": { 771 | "argparse": "^1.0.7", 772 | "esprima": "^4.0.0" 773 | } 774 | }, 775 | "jsdom": { 776 | "version": "19.0.0", 777 | "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", 778 | "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", 779 | "dev": true, 780 | "requires": { 781 | "abab": "^2.0.5", 782 | "acorn": "^8.5.0", 783 | "acorn-globals": "^6.0.0", 784 | "cssom": "^0.5.0", 785 | "cssstyle": "^2.3.0", 786 | "data-urls": "^3.0.1", 787 | "decimal.js": "^10.3.1", 788 | "domexception": "^4.0.0", 789 | "escodegen": "^2.0.0", 790 | "form-data": "^4.0.0", 791 | "html-encoding-sniffer": "^3.0.0", 792 | "http-proxy-agent": "^5.0.0", 793 | "https-proxy-agent": "^5.0.0", 794 | "is-potential-custom-element-name": "^1.0.1", 795 | "nwsapi": "^2.2.0", 796 | "parse5": "6.0.1", 797 | "saxes": "^5.0.1", 798 | "symbol-tree": "^3.2.4", 799 | "tough-cookie": "^4.0.0", 800 | "w3c-hr-time": "^1.0.2", 801 | "w3c-xmlserializer": "^3.0.0", 802 | "webidl-conversions": "^7.0.0", 803 | "whatwg-encoding": "^2.0.0", 804 | "whatwg-mimetype": "^3.0.0", 805 | "whatwg-url": "^10.0.0", 806 | "ws": "^8.2.3", 807 | "xml-name-validator": "^4.0.0" 808 | } 809 | }, 810 | "levn": { 811 | "version": "0.3.0", 812 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 813 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 814 | "dev": true, 815 | "requires": { 816 | "prelude-ls": "~1.1.2", 817 | "type-check": "~0.3.2" 818 | } 819 | }, 820 | "lodash.camelcase": { 821 | "version": "4.3.0", 822 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 823 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", 824 | "dev": true 825 | }, 826 | "merge2": { 827 | "version": "1.4.1", 828 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 829 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 830 | "dev": true 831 | }, 832 | "micromatch": { 833 | "version": "4.0.5", 834 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 835 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 836 | "dev": true, 837 | "requires": { 838 | "braces": "^3.0.2", 839 | "picomatch": "^2.3.1" 840 | } 841 | }, 842 | "mime-db": { 843 | "version": "1.52.0", 844 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 845 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 846 | "dev": true 847 | }, 848 | "mime-types": { 849 | "version": "2.1.35", 850 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 851 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 852 | "dev": true, 853 | "requires": { 854 | "mime-db": "1.52.0" 855 | } 856 | }, 857 | "ms": { 858 | "version": "2.1.2", 859 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 860 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 861 | "dev": true 862 | }, 863 | "nwsapi": { 864 | "version": "2.2.0", 865 | "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", 866 | "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", 867 | "dev": true 868 | }, 869 | "optionator": { 870 | "version": "0.8.3", 871 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 872 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 873 | "dev": true, 874 | "requires": { 875 | "deep-is": "~0.1.3", 876 | "fast-levenshtein": "~2.0.6", 877 | "levn": "~0.3.0", 878 | "prelude-ls": "~1.1.2", 879 | "type-check": "~0.3.2", 880 | "word-wrap": "~1.2.3" 881 | } 882 | }, 883 | "parse5": { 884 | "version": "6.0.1", 885 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", 886 | "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", 887 | "dev": true 888 | }, 889 | "picomatch": { 890 | "version": "2.3.1", 891 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 892 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 893 | "dev": true 894 | }, 895 | "prelude-ls": { 896 | "version": "1.1.2", 897 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 898 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 899 | "dev": true 900 | }, 901 | "prex": { 902 | "version": "0.4.7", 903 | "resolved": "https://registry.npmjs.org/prex/-/prex-0.4.7.tgz", 904 | "integrity": "sha512-ulhl3iyjmAW/GroRQJN4CG+pC6KJ+W+deNRBkEShQwe16wLP9k92+x6RmLJuLiVSGkbxhnAqHpGdJJCh3bRpUQ==", 905 | "dev": true, 906 | "requires": { 907 | "@esfx/cancelable": "^1.0.0-pre.13", 908 | "@esfx/disposable": "^1.0.0-pre.13" 909 | } 910 | }, 911 | "promise-debounce": { 912 | "version": "1.0.1", 913 | "resolved": "https://registry.npmjs.org/promise-debounce/-/promise-debounce-1.0.1.tgz", 914 | "integrity": "sha1-btdvj3nQFE/b0BzBVYnOV/nXHng=", 915 | "dev": true 916 | }, 917 | "psl": { 918 | "version": "1.8.0", 919 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 920 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", 921 | "dev": true 922 | }, 923 | "punycode": { 924 | "version": "2.1.1", 925 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 926 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 927 | "dev": true 928 | }, 929 | "queue-microtask": { 930 | "version": "1.2.3", 931 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 932 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 933 | "dev": true 934 | }, 935 | "reduce-flatten": { 936 | "version": "2.0.0", 937 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 938 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", 939 | "dev": true 940 | }, 941 | "reusify": { 942 | "version": "1.0.4", 943 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 944 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 945 | "dev": true 946 | }, 947 | "run-parallel": { 948 | "version": "1.2.0", 949 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 950 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 951 | "dev": true, 952 | "requires": { 953 | "queue-microtask": "^1.2.2" 954 | } 955 | }, 956 | "safer-buffer": { 957 | "version": "2.1.2", 958 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 959 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 960 | "dev": true 961 | }, 962 | "saxes": { 963 | "version": "5.0.1", 964 | "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", 965 | "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", 966 | "dev": true, 967 | "requires": { 968 | "xmlchars": "^2.2.0" 969 | } 970 | }, 971 | "source-map": { 972 | "version": "0.6.1", 973 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 974 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 975 | "dev": true, 976 | "optional": true 977 | }, 978 | "sprintf-js": { 979 | "version": "1.0.3", 980 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 981 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 982 | "dev": true 983 | }, 984 | "supports-color": { 985 | "version": "7.2.0", 986 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 987 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 988 | "dev": true, 989 | "requires": { 990 | "has-flag": "^4.0.0" 991 | } 992 | }, 993 | "symbol-tree": { 994 | "version": "3.2.4", 995 | "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", 996 | "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", 997 | "dev": true 998 | }, 999 | "table-layout": { 1000 | "version": "1.0.2", 1001 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 1002 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 1003 | "dev": true, 1004 | "requires": { 1005 | "array-back": "^4.0.1", 1006 | "deep-extend": "~0.6.0", 1007 | "typical": "^5.2.0", 1008 | "wordwrapjs": "^4.0.0" 1009 | }, 1010 | "dependencies": { 1011 | "array-back": { 1012 | "version": "4.0.2", 1013 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1014 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 1015 | "dev": true 1016 | }, 1017 | "typical": { 1018 | "version": "5.2.0", 1019 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1020 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1021 | "dev": true 1022 | } 1023 | } 1024 | }, 1025 | "to-regex-range": { 1026 | "version": "5.0.1", 1027 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1028 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1029 | "dev": true, 1030 | "requires": { 1031 | "is-number": "^7.0.0" 1032 | } 1033 | }, 1034 | "tough-cookie": { 1035 | "version": "4.0.0", 1036 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", 1037 | "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", 1038 | "dev": true, 1039 | "requires": { 1040 | "psl": "^1.1.33", 1041 | "punycode": "^2.1.1", 1042 | "universalify": "^0.1.2" 1043 | } 1044 | }, 1045 | "tr46": { 1046 | "version": "3.0.0", 1047 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", 1048 | "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", 1049 | "dev": true, 1050 | "requires": { 1051 | "punycode": "^2.1.1" 1052 | } 1053 | }, 1054 | "tslib": { 1055 | "version": "2.4.0", 1056 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", 1057 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", 1058 | "dev": true 1059 | }, 1060 | "type-check": { 1061 | "version": "0.3.2", 1062 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1063 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1064 | "dev": true, 1065 | "requires": { 1066 | "prelude-ls": "~1.1.2" 1067 | } 1068 | }, 1069 | "typical": { 1070 | "version": "4.0.0", 1071 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 1072 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", 1073 | "dev": true 1074 | }, 1075 | "universalify": { 1076 | "version": "0.1.2", 1077 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 1078 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 1079 | "dev": true 1080 | }, 1081 | "w3c-hr-time": { 1082 | "version": "1.0.2", 1083 | "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", 1084 | "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", 1085 | "dev": true, 1086 | "requires": { 1087 | "browser-process-hrtime": "^1.0.0" 1088 | } 1089 | }, 1090 | "w3c-xmlserializer": { 1091 | "version": "3.0.0", 1092 | "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", 1093 | "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", 1094 | "dev": true, 1095 | "requires": { 1096 | "xml-name-validator": "^4.0.0" 1097 | } 1098 | }, 1099 | "webidl-conversions": { 1100 | "version": "7.0.0", 1101 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", 1102 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", 1103 | "dev": true 1104 | }, 1105 | "whatwg-encoding": { 1106 | "version": "2.0.0", 1107 | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", 1108 | "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", 1109 | "dev": true, 1110 | "requires": { 1111 | "iconv-lite": "0.6.3" 1112 | } 1113 | }, 1114 | "whatwg-mimetype": { 1115 | "version": "3.0.0", 1116 | "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", 1117 | "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", 1118 | "dev": true 1119 | }, 1120 | "whatwg-url": { 1121 | "version": "10.0.0", 1122 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", 1123 | "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", 1124 | "dev": true, 1125 | "requires": { 1126 | "tr46": "^3.0.0", 1127 | "webidl-conversions": "^7.0.0" 1128 | } 1129 | }, 1130 | "word-wrap": { 1131 | "version": "1.2.3", 1132 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1133 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1134 | "dev": true 1135 | }, 1136 | "wordwrapjs": { 1137 | "version": "4.0.1", 1138 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 1139 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 1140 | "dev": true, 1141 | "requires": { 1142 | "reduce-flatten": "^2.0.0", 1143 | "typical": "^5.2.0" 1144 | }, 1145 | "dependencies": { 1146 | "typical": { 1147 | "version": "5.2.0", 1148 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1149 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1150 | "dev": true 1151 | } 1152 | } 1153 | }, 1154 | "ws": { 1155 | "version": "8.6.0", 1156 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz", 1157 | "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==", 1158 | "dev": true 1159 | }, 1160 | "xml-name-validator": { 1161 | "version": "4.0.0", 1162 | "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", 1163 | "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", 1164 | "dev": true 1165 | }, 1166 | "xmlchars": { 1167 | "version": "2.2.0", 1168 | "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", 1169 | "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", 1170 | "dev": true 1171 | } 1172 | } 1173 | } 1174 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "proposal-string-dedent", 4 | "description": "TC39 proposal to remove leading whitespace from multiline strings.", 5 | "scripts": { 6 | "build": "npm run build-loose -- --strict --lint-spec", 7 | "build-loose": "ecmarkup --load-biblio @tc39/ecma262-biblio --verbose spec.emu index.html", 8 | "start": "npm run build-loose -- --watch" 9 | }, 10 | "homepage": "https://github.com/mmkal/proposal-multi-backtick-templates#readme", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/mmkal/proposal-multi-backtick-templates.git" 14 | }, 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@tc39/ecma262-biblio": "2.0.2321", 18 | "ecmarkup": "12.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /spec.emu: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
  7 | title: String Dedent
  8 | status: proposal
  9 | stage: 2
 10 | contributors: Justin Ridgewell
 11 | location: https://tc39.es/proposal-string-dedent/
 12 | markEffects: true
 13 | 
14 | 15 | 16 |

Scope

17 |

18 | This is the spec text of the String Dedent proposal in ECMAScript. 19 | String dedenting removes leading indentation from each line of a multiline string. 20 |

21 |
22 | 23 | 24 |

Properties of the String Constructor

25 | 26 | 27 | 28 | 29 |

String.dedent ( _templateOrFn_, ..._substitutions_ )

30 | 31 |

The `String.dedent` function may be called with either a template array and a variable number of substitutions, or it may be called with a function which itself takes a template array and a variable number of substitutions.

32 |

When called with a template and a variable number of substitutions, a string is returned which has common leading indentation removed from all lines with non-whitespace.

33 |

When called with a function, a closure is returned which wraps the function. When the closure is called with a template and variable number of substitutions, the common leading indentation of the template is removed and the result of calling the function with this new dedented template and substitutions is returned.

34 |

Common leading indentation is defined as the longest sequence of whitespace characters that match exactly on every line that contains non-whitespace. Empty lines and lines which contain only whitespace do not affect common leading indentation.

35 |

When removing the common leading indentation, lines which contain only whitespace will have all whitespace removed.

36 |
37 | 38 | 1. If _templateOrFn_ is not an object, then 39 | 1. NOTE: This check is to allow future extensions with different input types. 40 | 1. Throw a *TypeError* exception. 41 | 1. If IsCallable(_templateOrFn_) is *true*, then 42 | 1. Let _tag_ be _templateOrFn_. 43 | 1. Let _closure_ be a new Abstract Closure with parameters (_template_, ..._substitutions_) that captures _tag_ and performs the following steps when called: 44 | 1. If _template_ is not an object, then 45 | 1. Throw a *TypeError* exception. 46 | 1. Let _R_ be the *this* value. 47 | 1. Let _dedented_ be ? DedentTemplateStringsArray(_template_). 48 | 1. Let _args_ be the list-concatenation of « _dedented_ » and _substitutions_. 49 | 1. Return ? Call(_tag_, _R_, _args_). 50 | 1. Return CreateBuiltinFunction(_closure_, 1, *""*, « »). 51 | 1. Let _template_ be _templateOrFn_. 52 | 1. Let _dedented_ be ? DedentTemplateStringsArray(_template_). 53 | 1. Return ? CookTemplateStringsArray(_dedented_, _substitutions_, ~cooked~). 54 | 55 | 56 |

The `dedent` function is intended for use as a tag function of a Tagged Template (). When called as such, the first argument will be a well formed template object and the rest parameter will contain the substitution values.

57 |
58 |
59 | 60 | 61 |

62 | DedentTemplateStringsArray ( 63 | _template_: an Object, 64 | ): either a normal completion containing an Array or a throw completion 65 |

66 |
67 |
68 | 69 | 1. Let _realm_ be the current Realm Record. 70 | 1. Let _dedentMap_ be _realm_.[[DedentMap]]. 71 | 1. Let _rawInput_ be ? Get(_template_, *"raw"*). 72 | 1. For each element _e_ of the _dedentMap_, do 73 | 1. If _e_.[[Raw]] is not ~empty~ and SameValue(_e_.[[Raw]], _rawInput_) is *true*, return _e_.[[Dedented]]. 74 | 1. Assert: _dedentMap_ does not currently contain an entry for _rawInput_. 75 | 1. Let _raw_ be ? DedentStringsArray(_rawInput_). 76 | 1. Let _cookedArr_ be CreateArrayFromList(CookStrings(_raw_)). 77 | 1. Let _rawArr_ be CreateArrayFromList(_raw_). 78 | 1. Perform ! DefinePropertyOrThrow(_cookedArr_, *"raw"*, PropertyDescriptor { [[Value]]: _rawArr_, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }). 79 | 1. Perform ! SetIntegrityLevel(_rawArr_, ~frozen~). 80 | 1. Perform ! SetIntegrityLevel(_cookedArr_, ~frozen~). 81 | 1. Append the Record { [[Raw]]: _rawInput_, [[Dedented]]: _cookedArr_ } to _dedentMap_. 82 | 1. Return _cookedArr_. 83 | 84 |
85 | 86 | 87 |

88 | DedentStringsArray ( 89 | _template_: an ECMAScript language value, 90 | ): either a normal completion containing a List of Strings, or a throw completion 91 |

92 |
93 |
94 | 95 | 1. Let _t_ be ? ToObject(_template_). 96 | 1. Let _len_ be ? LengthOfArrayLike(_t_). 97 | 1. If _len_ = 0, then 98 | 1. NOTE: Well-formed template strings arrays always contain at least 1 string. 99 | 1. Throw a *TypeError* exception. 100 | 1. Let _blocks_ be ? SplitTemplateIntoBlockLines(_t_, _len_). 101 | 1. Perform ? EmptyWhiteSpaceLines(_blocks_). 102 | 1. Perform ? RemoveOpeningAndClosingLines(_blocks_, _len_). 103 | 1. Let _common_ be DetermineCommonLeadingIndentation(_blocks_). 104 | 1. Let _count_ be the length of _common_. 105 | 1. Let _dedented_ be a new empty List. 106 | 1. For each element _lines_ of _blocks_, do 107 | 1. Assert: _lines_ is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block. 108 | 1. Let _out_ be *""*. 109 | 1. Let _index_ be 0. 110 | 1. For each Record { [[String]], [[Newline]], [[LineEndsWithSubstitution]] } _line_ of _lines_, do 111 | 1. NOTE: The first line of each block does not need to be trimmed. It's either the opening line, or it's the continuation of a line after a substitution. 112 | 1. If _index_ = 0 or _line_.[[String]] is the empty String, let _c_ be 0; else let _c_ be _count_. 113 | 1. Let _strLen_ be the length of _line_.[[String]]. 114 | 1. Let _trimmed_ be the substring of _line_.[[String]] from _c_ to _strLen_. 115 | 1. Set _out_ to the string-concatenation of _out_, _trimmed_, and _line_.[[Newline]]. 116 | 1. Set _index_ to _index_ + 1. 117 | 1. Append _out_ to _dedented_. 118 | 1. Return _dedented_. 119 | 120 |
121 | 122 | 123 |

124 | CookStrings ( 125 | _raw_: a List of Strings, 126 | ): a List of either String or *undefined* 127 |

128 |
129 |
130 | 131 | 1. Let _cooked_ be a new empty List. 132 | 1. For each element _str_ of _raw_, do 133 | 1. Let _parsed_ be ParseText(StringToCodePoints(_str_), |CookStringsCharactersWithBackslash|). 134 | 1. Assert: _parsed_ is a Parse Node. 135 | 1. NOTE: Even though String.dedent can be manually invoked with a value, the |CookStringsCharactersWithBackslash| nonterminal matches every string, so the above parse is guaranteed to succeed. 136 | 1. Let _val_ be the TV of _parsed_ as defined in . 137 | 1. NOTE: _val_ can actually be *undefined* if the raw string contains an invalid escape sequence. 138 | 1. Append _val_ to _cooked_. 139 | 1. Return _cooked_. 140 | 141 | 142 | 143 |

The CookStrings Grammar

144 |

The following grammar is used by CookStrings. It is identical to |TemplateCharacters| except that it allows *"${"*" and *"`"* to appear without being preceded by a backslash, allows a backslash as the final character, and accepts the empty sequence. Every sequence of code points is matched by this grammar.

145 | 146 | 147 | CookStringsCharactersWithBackslash :: 148 | CookStringsCharacters? `\`? 149 | 150 | CookStringsCharacters :: 151 | CookStringsCharacter CookStringsCharacters? 152 | 153 | CookStringsCharacter :: 154 | `$` [lookahead = `{`] 155 | ``` 156 | TemplateCharacter 157 | 158 | 159 | 160 |

Static Semantics: TV

161 | The following lines are added to the definition of TV. 162 |
    163 |
  • 164 | The TV of CookStringsCharactersWithBackslash :: [empty] is the empty String. 165 |
  • 166 |
  • 167 | The TV of CookStringsCharactersWithBackslash :: `\` is *undefined*. 168 |
  • 169 |
  • 170 | The TV of CookStringsCharactersWithBackslash :: CookStringsCharacters `\` is *undefined*. 171 |
  • 172 |
  • 173 | The TV of CookStringsCharacters :: CookStringsCharacter CookStringsCharacters is *undefined* if either the TV of |CookStringsCharacter| is *undefined* or the TV of |CookStringsCharacters| is *undefined*. Otherwise, it is the string-concatenation of the TV of |CookStringsCharacter| and the TV of |CookStringsCharacters|. 174 |
  • 175 |
  • 176 | The TV of CookStringsCharacter :: `$` [lookahead = `{`] is *"$"*. 177 |
  • 178 |
  • 179 | The TV of CookStringsCharacter :: ``` is *"`"*. 180 |
  • 181 |
182 |
183 |
184 |
185 | 186 | 187 |

188 | SplitTemplateIntoBlockLines ( 189 | _template_: an ECMAScript language value, 190 | _len_: a non-negative integer, 191 | ): either a normal completion containing a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean), or a throw completion 192 |

193 |
194 |
195 | 196 | 1. Let _blocks_ be a new empty List. 197 | 1. Let _index_ be 0. 198 | 1. Repeat, while _index_ < _len_, 199 | 1. Let _str_ be ? Get(_template_, ! ToString(𝔽(_index_))). 200 | 1. If Type(_str_) is String, then 201 | 1. Let _lines_ be a new empty List. 202 | 1. Let _strLen_ be the length of _str_. 203 | 1. Let _start_ be 0. 204 | 1. Let _i_ be 0. 205 | 1. Repeat, while _i_ < _strLen_, 206 | 1. Let _c_ be the substring of _str_ from _i_ to _i_ + 1. 207 | 1. Let _n_ be 1. 208 | 1. If _c_ is *"\r"* and _i_ + 1 < _strLen_, then 209 | 1. Let _next_ be the substring of _str_ from _i_ + 1 to _i_ + 2. 210 | 1. If _next_ is *"\n"*, set _n_ to 2. 211 | 1. If _c_ is matched by |LineTerminator|, then 212 | 1. Let _substr_ be the substring of _str_ from _start_ to _i_. 213 | 1. Let _newline_ be the substring of _str_ from _i_ to _i_ + _n_. 214 | 1. Append the Record { [[String]]: _substr_, [[Newline]]: _newline_, [[LineEndsWithSubstitution]]: *false* } to _lines_. 215 | 1. Set _start_ to _i_ + _n_. 216 | 1. Set _i_ to _i_ + _n_. 217 | 1. Let _tail_ be the substring of _str_ from _start_ to _strLen_. 218 | 1. If _index_ + 1 < _len_, let _lineEndsWithSubstitution_ be *true*; else let _lineEndsWithSubstitution_ be *false*. 219 | 1. Append the Record { [[String]]: _tail_, [[Newline]]: *""*, [[LineEndsWithSubstitution]]: _lineEndsWithSubstitution_ } to _lines_. 220 | 1. Append _lines_ to _blocks_. 221 | 1. Else, 222 | 1. Throw a *TypeError* exception. 223 | 1. Set _index_ to _index_ + 1. 224 | 1. Return _blocks_. 225 | 226 |
227 | 228 | 229 |

230 | EmptyWhiteSpaceLines ( 231 | _blocks_: a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean), 232 | ) 233 |

234 |
235 |
236 | 237 | 1. For each element _lines_ of _blocks_, do 238 | 1. Let _lineCount_ be the length of _lines_. 239 | 1. NOTE: We start _i_ at 1 because the first line of every block is either (a) the opening line which must be empty or (b) the continuation of a line directly after a template substitution. Neither can be the start of a content line. 240 | 1. Let _i_ be 1. 241 | 1. Repeat, while _i_ < _lineCount_, 242 | 1. Let _line_ be _lines_[_i_]. 243 | 1. If _line_.[[LineEndsWithSubstitution]] is *false* and IsAllWhiteSpace(_line_.[[String]]) is *true*, then 244 | 1. NOTE: Lines which contain only whitespace are emptied in the output. Their trailing newline is not removed, so the line is maintained. 245 | 1. Set _line_.[[String]] to *""*. 246 | 1. Set _i_ to _i_ + 1. 247 | 248 |
249 | 250 | 251 |

252 | RemoveOpeningAndClosingLines ( 253 | _blocks_: a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean), 254 | _len_: a non-negative integer, 255 | ) 256 |

257 |
258 |
259 | 260 | 1. Assert: _blocks_ contains at least 1 element, because we know the length of the template strings array is at least 1. 261 | 1. Let _firstBlock_ be _blocks_[0]. 262 | 1. Assert: _firstBlock_ is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block. 263 | 1. Let _lineCount_ be the length of _firstBlock_. 264 | 1. If _lineCount_ = 1, then 265 | 1. NOTE: The opening line is required to contain a trailing newline, and checking that there are at least 2 elements in _lines_ ensures it. If it does not, either the opening line and the closing line are the same line, or the opening line contains a substitution. 266 | 1. Throw a *TypeError* exception. 267 | 1. Let _openingLine_ be _firstBlock_[0]. 268 | 1. If _openingLine_.[[String]] is not empty, then 269 | 1. NOTE: The opening line must not contain code units besides the trailing newline. 270 | 1. Throw a *TypeError* exception. 271 | 1. NOTE: Setting _openingLine_.[[Newline]] removes the opening line from the output. 272 | 1. Set _openingLine_.[[Newline]] to *""*. 273 | 1. Let _lastBlock_ be _blocks_[_len_ - 1]. 274 | 1. Assert: _lastBlock_ is not empty, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block. 275 | 1. Set _lineCount_ to the length of _lastBlock_. 276 | 1. If _lineCount_ = 1, then 277 | 1. NOTE: The closing line is required to be preceded by a newline, and checking that there are at least 2 elements in _lines_ ensures it. If it does not, either the opening line and the closing line are the same line, or the closing line contains a substitution. 278 | 1. Throw a *TypeError* exception. 279 | 1. Let _closingLine_ be _lastBlock_[_lineCount_ - 1]. 280 | 1. If _closingLine_.[[String]] is not the empty String, then 281 | 1. NOTE: The closing line may only contain whitespace. We've already performed EmptyWhiteSpaceLines, so if the line is not empty now, it contained some non-whitespace character. 282 | 1. Throw a *TypeError* exception. 283 | 1. Let _preceding_ be _lastBlock_[_lineCount_ - 2]. 284 | 1. NOTE: Setting _closingLine_.[[String]] and _preceding_.[[Newline]] removes the closing line from the output. 285 | 1. Set _closingLine_.[[String]] to *""*. 286 | 1. Set _preceding_.[[Newline]] to *""*. 287 | 288 |
289 | 290 | 291 |

292 | DetermineCommonLeadingIndentation ( 293 | _blocks_: a List of Lists of Records with fields [[String]] (a String), [[Newline]] (a String), and [[LineEndsWithSubstitution]] (a Boolean), 294 | ): a String 295 |

296 |
297 |
298 | 299 | 1. Let _common_ be ~empty~. 300 | 1. For each element _lines_ of _blocks_, do 301 | 1. Let _lineCount_ be the length of _lines_. 302 | 1. NOTE: We start _i_ at 1 because because the first line of every block is either (a) the opening line which must be empty or (b) the continuation of a line directly after a template substitution. Neither can be the start of a content line. 303 | 1. Let _i_ be 1. 304 | 1. Repeat, while _i_ < _lineCount_, 305 | 1. Let _line_ be _lines_[_i_]. 306 | 1. NOTE: Lines which contain substitutions are considered when finding the common indentation. Lines which contain only whitespace have already been emptied. 307 | 1. If _line_.[[LineEndsWithSubstitution]] is *true* or _line_.[[String]] is not the empty String, then 308 | 1. Let _leading_ be LeadingWhiteSpaceSubstring(_line_.[[String]]). 309 | 1. If _common_ is ~empty~, then 310 | 1. Set _common_ to _leading_. 311 | 1. Else, 312 | 1. Set _common_ to LongestMatchingLeadingSubstring(_common_, _leading_). 313 | 1. Set _i_ to _i_ + 1. 314 | 1. Assert: _common_ is not ~empty~, because SplitTemplateIntoBlockLines guarantees there is at least 1 line per block, and we know the length of the template strings array is at least 1. 315 | 1. Return _common_. 316 | 317 |
318 | 319 | 320 |

321 | LeadingWhiteSpaceSubstring ( 322 | _str_: a String, 323 | ): a String 324 |

325 |
326 |
327 | 328 | 1. Let _len_ be the length of _str_. 329 | 1. Let _i_ be 0. 330 | 1. Repeat, while _i_ < _len_, 331 | 1. Let _c_ be the substring of _str_ from _i_ to _i_ + 1. 332 | 1. If _c_ does not match |WhiteSpace|, then 333 | 1. Return the substring of _str_ from 0 to _i_. 334 | 1. Set _i_ to _i_ + 1. 335 | 1. Return _str_. 336 | 337 |

When determining whether a Unicode code point is in Unicode general category “Space_Separator” (“Zs”), code unit sequences are interpreted as UTF-16 encoded code point sequences as specified in .

338 |
339 | 340 | 341 |

342 | IsAllWhiteSpace ( 343 | _str_: a String, 344 | ): a Boolean 345 |

346 |
347 |
348 | 349 | 1. Let _trimmed_ be ! TrimString(_str_, ~start~). 350 | 1. If _trimmed_ is the empty String, return *true*. 351 | 1. Return *false*. 352 | 353 |
354 | 355 | 356 |

357 | LongestMatchingLeadingSubstring ( 358 | _a_: a String, 359 | _b_: a String, 360 | ): a String 361 |

362 |
363 |
364 | 365 | 1. Let _aLen_ be the length of _a_. 366 | 1. Let _bLen_ be the length of _b_. 367 | 1. Let _len_ be min(_aLen_, _bLen_). 368 | 1. Let _i_ be 0. 369 | 1. Repeat, while _i_ < _len_, 370 | 1. Let _aChar_ be the substring of _a_ from _i_ to _i_ + 1. 371 | 1. Let _bChar_ be the substring of _b_ from _i_ to _i_ + 1. 372 | 1. If _aChar_ is not _bChar_, then 373 | 1. Return the substring of _a_ from 0 to _i_. 374 | 1. Set _i_ to _i_ + 1. 375 | 1. Return the substring of _a_ from 0 to _len_. 376 | 377 |
378 | 379 |
380 | 381 | 382 |

383 | CookTemplateStringsArray ( 384 | _template_: an ECMAScript language value, 385 | _substitutions_: a List of ECMAScript language values, 386 | _prep_: ~cooked~ or ~raw~, 387 | ): either a normal completion containing a String or a throw completion 388 |

389 |
390 |
391 | 392 |

This abstract operation merges the behaviour of `String.raw` with the String.cooked proposal.

393 |
394 | 395 | 1. Let _substitutionCount_ be the number of elements in _substitutions_. 396 | 1. Let _cooked_ be ? ToObject(_template_). 397 | 1. If _prep_ is ~cooked~, let _literals_ be _cooked_; else let _literals_ be ? ToObject(? Get(_cooked_, *"raw"*)). 398 | 1. Let _literalCount_ be ? LengthOfArrayLike(_literals_). 399 | 1. If _literalCount_ ≤ 0, return the empty String. 400 | 1. Let _R_ be the empty String. 401 | 1. Let _nextIndex_ be 0. 402 | 1. Repeat, 403 | 1. Let _nextLiteralVal_ be ? Get(_literals_, ! ToString(𝔽(_nextIndex_))). 404 | 1. Let _nextLiteral_ be ? ToString(_nextLiteralVal_). 405 | 1. Set _R_ to the string-concatenation of _R_ and _nextLiteral_. 406 | 1. If _nextIndex_ + 1 = _literalCount_, return _R_. 407 | 1. If _nextIndex_ < _substitutionCount_, then 408 | 1. Let _nextSubVal_ be _substitutions_[_nextIndex_]. 409 | 1. Let _nextSub_ be ? ToString(_nextSubVal_). 410 | 1. Set _R_ to the string-concatenation of _R_ and _nextSub_. 411 | 1. Set _nextIndex_ to _nextIndex_ + 1. 412 | 413 |
414 |
415 | 416 | 417 |

Realms

418 |

Before it is evaluated, all ECMAScript code must be associated with a realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.

419 |

A realm is represented in this specification as a Realm Record with the fields specified in :

420 | 421 | 422 | 423 | 426 | 429 | 432 | 433 | 434 | 437 | 440 | 443 | 444 | 445 | 448 | 451 | 454 | 455 | 456 | 459 | 462 | 465 | 466 | 467 | 470 | 473 | 477 | 478 | 479 | 482 | 485 | 488 | 489 | 490 | 493 | 496 | 501 | 502 |
424 | Field Name 425 | 427 | Value 428 | 430 | Meaning 431 |
435 | [[Intrinsics]] 436 | 438 | a Record whose field names are intrinsic keys and whose values are objects 439 | 441 | The intrinsic values used by code associated with this realm 442 |
446 | [[GlobalObject]] 447 | 449 | an Object or *undefined* 450 | 452 | The global object for this realm 453 |
457 | [[GlobalEnv]] 458 | 460 | a Global Environment Record 461 | 463 | The global environment for this realm 464 |
468 | [[TemplateMap]] 469 | 471 | a List of Record { [[Site]]: Parse Node, [[Array]]: Object } 472 | 474 |

Template objects are canonicalized separately for each realm using its Realm Record's [[TemplateMap]]. Each [[Site]] value is a Parse Node that is a |TemplateLiteral|. The associated [[Array]] value is the corresponding template object that is passed to a tag function.

475 | Once a Parse Node becomes unreachable, the corresponding [[Array]] is also unreachable, and it would be unobservable if an implementation removed the pair from the [[TemplateMap]] list. 476 |
480 | [[HostDefined]] 481 | 483 | anything (default value is *undefined*) 484 | 486 | Field reserved for use by hosts that need to associate additional information with a Realm Record. 487 |
491 | [[DedentMap]] 492 | 494 | a List of Record { [[Raw]]: Object, [[Dedented]]: Object } 495 | 497 | 498 | The [[DedentMap]] ensures template tag functions wrapped with `String.dedent` see consistent object identity for a given input template. The [[Raw]] key weakly holds the value of a template object's raw property. The associated [[Dedented]] value is the result of performing dedenting on that raw value. 499 | 500 |
503 |
504 | 505 | 506 |

CreateRealm ( ): a Realm Record

507 |
508 |
509 | 510 | 1. Let _realmRec_ be a new Realm Record. 511 | 1. Perform CreateIntrinsics(_realmRec_). 512 | 1. Set _realmRec_.[[GlobalObject]] to *undefined*. 513 | 1. Set _realmRec_.[[GlobalEnv]] to *undefined*. 514 | 1. Set _realmRec_.[[TemplateMap]] to a new empty List. 515 | 1. Set _realmRec_.[[DedentMap]] to a new empty List. 516 | 1. Return _realmRec_. 517 | 518 |
519 |
520 | 521 | 522 |

Execution

523 | 524 |

At any time, if a set of objects _S_ is not live, an ECMAScript implementation may perform the following steps atomically:

525 | 526 | 527 | 1. For each element _obj_ of _S_, do 528 | 1. For each WeakRef _ref_ such that _ref_.[[WeakRefTarget]] is _obj_, do 529 | 1. Set _ref_.[[WeakRefTarget]] to ~empty~. 530 | 1. For each FinalizationRegistry _fg_ such that _fg_.[[Cells]] contains a Record _cell_ such that _cell_.[[WeakRefTarget]] is _obj_, do 531 | 1. Set _cell_.[[WeakRefTarget]] to ~empty~. 532 | 1. Optionally, perform HostEnqueueFinalizationRegistryCleanupJob(_fg_). 533 | 1. For each WeakMap _map_ such that _map_.[[WeakMapData]] contains a Record _r_ such that _r_.[[Key]] is _obj_, do 534 | 1. Set _r_.[[Key]] to ~empty~. 535 | 1. Set _r_.[[Value]] to ~empty~. 536 | 1. For each WeakSet _set_ such that _set_.[[WeakSetData]] contains _obj_, do 537 | 1. Replace the element of _set_.[[WeakSetData]] whose value is _obj_ with an element whose value is ~empty~. 538 | 1. Let _realm_ be the current Realm Record. 539 | 1. If _realm_.[[DedentMap]] contains a Record _r_ such that _r_.[[Raw]] is _obj_, then 540 | 1. Set _r_.[[Raw]] to ~empty~. 541 | 1. Set _r_.[[Dedented]] to ~empty~. 542 | 543 | 544 | 545 |

Together with the definition of liveness, this clause prescribes legal optimizations that an implementation may apply regarding WeakRefs.

546 | 547 |

It is possible to access an object without observing its identity. Optimizations such as dead variable elimination and scalar replacement on properties of non-escaping objects whose identity is not observed are allowed. These optimizations are thus allowed to observably empty WeakRefs that point to such objects.

548 | 549 |

On the other hand, if an object's identity is observable, and that object is in the [[WeakRefTarget]] internal slot of a WeakRef, optimizations such as rematerialization that observably empty the WeakRef are prohibited.

550 | 551 |

Because calling HostEnqueueFinalizationRegistryCleanupJob is optional, registered objects in a FinalizationRegistry do not necessarily hold that FinalizationRegistry live. Implementations may omit FinalizationRegistry callbacks for any reason, e.g., if the FinalizationRegistry itself becomes dead, or if the application is shutting down.

552 |
553 | 554 |

Implementations are not obligated to empty WeakRefs for maximal sets of non-live objects.

555 |

If an implementation chooses a non-live set _S_ in which to empty WeakRefs, it must empty WeakRefs for all objects in _S_ simultaneously. In other words, an implementation must not empty a WeakRef pointing to an object _obj_ without emptying out other WeakRefs that, if not emptied, could result in an execution that observes the Object value of _obj_.

556 |
557 |
558 | --------------------------------------------------------------------------------