]> git.kianting.info Git - anotherTypesetter/commitdiff
add some parsing w/o maintext
authorTan Kian-ting <chenjt30@gmail.com>
Sun, 10 Dec 2023 15:25:18 +0000 (23:25 +0800)
committerTan Kian-ting <chenjt30@gmail.com>
Sun, 10 Dec 2023 15:25:18 +0000 (23:25 +0800)
14 files changed:
.gitignore [new file with mode: 0644]
docs/defineASTandGrammar.md
src/ch1/package.json [new file with mode: 0644]
src/ch1/src/index.d.ts [new file with mode: 0644]
src/ch1/src/index.js [new file with mode: 0644]
src/ch1/src/index.js.map [new file with mode: 0644]
src/ch1/src/index.ts [new file with mode: 0644]
src/ch1/src/test/parser.d.ts [new file with mode: 0644]
src/ch1/src/test/parser.js [new file with mode: 0644]
src/ch1/src/test/parser.js.map [new file with mode: 0644]
src/ch1/src/test/parser.ts [new file with mode: 0644]
src/ch1/tsconfig.json [new file with mode: 0644]
src/ch1/tslint.json [new file with mode: 0644]
src/ch1/yarn.lock [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e2f3d0d
--- /dev/null
@@ -0,0 +1,3 @@
+docs/.*#*
+src/ch1/package-lock.json
+src/ch1/node_modules
\ No newline at end of file
index 78c999045b1b6240c567676d51399627122aff6a..a641bc9f89906d25a0acb596c2dbb6fe6f071ccb 100644 (file)
@@ -61,25 +61,36 @@ C語言、Python語言就算有許多的關鍵字、操作符、符號或是常
 所以我們可以定義以下的BNF風文法:
 
 ```
-Language ::= PrintTxt | Exprs
+Language ::= MainTxt | Exprs | Comment
 
-PrintTxt ::= (('\' '@')| 非@字元)+ //「我是一隻貓」或是「www\@example.com」
+Comment ::= '/*' (不含'*/'的任何字元組合)* '*/'
 
+
+MainTxt ::= (('\' '@')| 非@非空白字元)+ //顯示的文字。「我是一隻貓」或是「www\@example.com」
+
+// Exprs 表示一群定義變數、常數、函數、函數套用的表達式
 Exprs ::= @ Expr* @ // *表示前面的重複0次以上(包含不出現)
 
-Expr ::= (Letting | Setting | Lambda | Apply | Var| Const) | "(" Expr ")"
+// Comment also included
+// "(" and ")" only for applying function
+Expr ::= (Letting | Setting | Lambda |  | Var| Const) | "(" Applying ")" | Comment
 
 Letting ::= "let" Var "=" Expr "in" Expr // let foo = 12 in ...
 
 Setting ::= Var ":=" Expr "in"  Expr // foo := a in ...
 
-Lambda ::= "fn" Var "->" Expr // fn x -> 12
+// we force every function have at least 1 argument.
+Lambda ::= "fn" LambdaArgs "->" Expr // fn x y -> 12
+
+LambdaArgs ::= Var | Var LambdaArgs
 
-Apply ::= Expr Expr // foo 3 即foo(3)
+Applying ::= Expr ExprArgs   // foo 3 9 即foo(3, 9)
+
+ExprArgs ::= Expr | (Expr ExprArgs)
 
 Var ::= ID
 
-Const ::= String | Float | Int
+Const ::= String | Float | Integer
 
 ID ::=  ("_" | [a-z] |  [A-Z])  ("_" | [0-9] | [a-z] |  [A-Z])+
 
@@ -90,7 +101,14 @@ Float ::= [0-9]+ "." [0-9]+
 String ::= '"' (不是「"」的任一字元|('\' '"'))   '"'
 ```
 
-## 用ParserCombinator進行tokenize
+而上述的item可以被1個以上半形空白或tab(`\t`)以及1個「`\n`或`\r\n`」(換行符號)隔開。而為求簡化這些符號在MainTxt均指代一個半形空白。也就是空一個半形空白、兩個半形空白、一個tab、一個換行符號等等都會顯示如一個半形符號。而在Expr表達式區,把它忽略掉。另外兩個換行符號設定為換行指令,而這在Expr區會被忽略。所以要加另外兩條:
+
+```
+Space = (' ' | '\t')* | '\n' | '\r\n'
+NewPara = = ('\n' |'\r' '\n' ) ('\n' |'\r' '\n' )
+```
+
+## 用ts-parsec和regexp進行tokenize
 Parser combinator(分析器組合子)是一種利用高階函數來簡化分析器撰寫的辦法。這講到頭來會涉及「遞歸下降分析」以及其他編譯理論的東西,但太難了(聽說可以讀編譯理論的「龍書我們可以製作一個小的tokenizer。但是因為自己寫parser combinator太累了,所以我們就用nom來幫我們代勞。
 」)。講一個簡單的案例吧:
 
@@ -109,7 +127,7 @@ else{
 }
 ```
 
-假設我們要將字串`s`的前3個字的match 0~9呢?如果會高階函數的話,引入一個`then`函數,然後把`match0to9`傳進去,這樣寫起來比較簡潔,行數可以比較少
+假設我們要將字串`s`的前3個字的match 0~9呢?如果會高階函數的話,引入一個`then`函數,然後把`match0to9`傳進去,這樣寫起來比較不會太糾結,比較好維護
 
 ```
 function thenDo(input, fun){
@@ -140,96 +158,143 @@ thenDo(thenDo(thenDo(sWrapped, match0to9), match0to9), match0to9)
 
 安裝`ts-parsec`可以用:`npm install -g typescript-parsec`。底下的程式使用的函數的詳細說明可以參考[官方文件](https://github.com/microsoft/ts-parsec/blob/master/doc/ParserCombinators.md)。
 
-假設我們要match 0-9任意次以上(就是integer),我們可以這樣寫:
+因為這個軟體在 tokenize 的時候使用regex,所以我們就用這個東西來處理。
+
+我們編輯Node.js的進入點程式(假設為src/index.js`),底下為定義tokenizer的型別和regex pattern:
+
+```typescript
+/** the type of token  */
+enum TokenKind {
+    Int, // 3
+    Flo, // 3.1416
+    Id, // foo, _123, etc
+    At, // @
+    Comt, // comment /*
+    Str, /** "foo" */
+    Assign, /** = */
+    Set, /** := */
+    Keyword, /** let, in */
+    LParen, /** ( */
+    RParen, /** ) */
+    Space, /** semi-width space tab, \r\n? */
+    NewPara, /** breaking paragraph, (\r\n?){2} */
+    MainTxt, /** used in main text */
+}
+
 
+// tokenizer
+const tokenizer = parsec.buildLexer([
+    [true, /^\d+/g, TokenKind.Int],
+    [true, /^\d+\.\d+/g, TokenKind.Flo],
+    [true, /^(let|in)/g, TokenKind.Keyword], // let and in
+    [true, /^[_a-zA-Z][_0-9a-zA-Z]*/g, TokenKind.Id],
+    [true, /^\@/g, TokenKind.At],
+    /* inside comment, only accept 1. non / character
+    or  2. "/ + non * character" */
+    [true, /^\/\*(\/[^*]|[^\\]?)*\*\//g, TokenKind.Comt],
+    [true, /^\"(\\\"|[^\"]?)*\"/g, TokenKind.Str],
+    [true, /^\:\=/g, TokenKind.Set],
+    [true, /^\=/g, TokenKind.Assign],
+    [true, /^\(/g, TokenKind.LParen],
+    [true, /^\)/g, TokenKind.RParen],
+    [true, /^([ \t]+|\n)/g, TokenKind.Space],
+    [true, /^(\r?\n){2}/g, TokenKind.NewPara],
+    [true, /^(\\\@|[^@\s])+/g, TokenKind.MainTxt],
+]);
 ```
 
-// import all the parser unit for string
-use nom::character::complete::*;
-// for the return type
-use nom::IResult;
+### 常數parsing
+
+增加儲存實際變數值的`ASTNode`型別
 
-// integer ::= [0-9]+
-pub fn integer(input: &str) -> IResult<&str, &str> {
-    return digit1(input) ; // [0-9]+
+```typescript
+// add "actualValue" in the parsed Token
+export interface ASTNode extends parsec.Token<TokenKind>{
+    // number is for float number;
+    //it's optional. since keyword has no value
+    actualValue? : bigint | number | string;
 }
+```
 
-// test parser
-#[cfg(test)]
-mod tests {
-    // import the functions ouside mod tests
-    use super::*;
-
-    // test integer
-    #[test]
-    fn test_integer() {
-    //if no error is shown, the function passes the test
-    assert_eq!(integer("12345"), Ok(("", "12345")));
-    assert_eq!(integer("0"), Ok(("", "0")));
-    }
+增加處理常數的parser。`...value`有擴充object的意思。
+```typescript
+function applyInteger(value: parsec.Token<TokenKind.Int>): ASTNode {
+    // extend value to ASTNode
+    const newNode : ASTNode  = {
+        actualValue : BigInt(value.text) ,
+        ...value};
+    return newNode;
 }
 
+function applyFloat(value: parsec.Token<TokenKind.Flo>): ASTNode {
+    // extend value to ASTNode
+    const newNode : ASTNode  = {
+        actualValue : parseFloat(value.text) ,
+        ...value};
+    return newNode;
+}
 
+function applyString(value: parsec.Token<TokenKind.Str>): ASTNode {
+    // extend value to ASTNode
+    const newNode : ASTNode  = {
+        // get only text[1,2,...,the second last char]
+        actualValue : value.text.slice(1,value.text.length-1).replace(/\\\"/g, "\"") ,
+        ...value};
+    return newNode;
+}
 ```
 
-用`cargo run`可以順利通過:
 
+製作`CONST`這個parser,然後再加上rule:
+
+```typescript
+const CONST = parsec.rule<TokenKind, ASTNode>();
+/*
+CONST ::=  INT | FLOAT | STRING
+*/
+CONST.setPattern(
+    parsec.alt(
+        parsec.apply(parsec.tok(TokenKind.Int), applyInteger),
+        parsec.apply(parsec.tok(TokenKind.Flo), applyFloat),
+        parsec.apply(parsec.tok(TokenKind.Str), applyString),
+    )
+);
 ```
-running 1 test
-test tests::test_integer ... ok
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
-```
-
-我們做第二個tokenizer,`float`:
+最後包起來進行測試:
 
-其中的`recognize`蒐集所有包在裡面的`parsers`的string。
-```
-// collect matched strings of all the parsers,
-use nom::combinator::recognize;
-// given 2 parser and gets the result as (1st_matched, 2nd_matched),
-use nom::sequence::pair;
-// exact matching characters
-use nom::bytes::complete::tag;
-
-// float ::= [0-9]+ "." [0-9]+
-pub fn float(input: &str) -> IResult<&str, &str>{
-    // [0-9]+ "." [0-9]+
-    // "12.345" returns Ok((else, (("12", '.'), "345"))), then recgonize them as
-    // Ok("12.345")
-    let a = 
-        recognize(pair(pair(digit1, tag(".")), digit1))(input);
-    return a;
 
+```typescript
+function mainParse(inputStr : string){
+    return parsec.expectSingleResult(parsec.expectEOF(
+        CONST.parse(tokenizer.parse(inputStr))));
 }
 
-```
 
-parser `identifier`(引用的函數的名稱空間略)。使用`fold_may0`和新的空vector來儲存match多次的parser的符合結果:
+// test
+function main(){
+    // bigint has suffix `n`
+    assert.strictEqual(mainParse('123455667').actualValue, 123455667n);
+    assert.strictEqual(mainParse('000').actualValue, 0n);
+    assert.strictEqual(mainParse('1.22').actualValue, 1.22);
+    assert.strictEqual(mainParse('0.0').actualValue, 0.0);
+    assert.strictEqual(mainParse(`""`).actualValue, "");
+    assert.strictEqual(mainParse(`"the little town"`).actualValue, `the little town`);
+    assert.strictEqual(mainParse(`"\\\"Alice\\\""`).actualValue, `"Alice"`);
+
+
+};
 ```
-pub fn identifier(input : &str) -> IResult<&str, &str>{
-    return recognize(pair(
-        // 1st character is a-z, A-Z or _
-        satisfy(|c| (is_alphabetic(c as u8) || c == '_')),
-        // the tail characters (0+ times matched) storing in a vector
-    fold_many0(
-        // a-z, A-Z, 0-9, _ 
-        satisfy(|c| (is_alphanumeric(c as u8) || c == '_')),
-        // initial vector
-        Vec::new,
-        // once it matches, append the matched item to the vector.
-        |mut acc: Vec<_>, item| {
-          acc.push(item);
-          acc
-        }
-      )))(input);
-    
-}
 
 
+### 表達式
+定義`AST型別`:
+
+```type AST = AST[] | ASTNode;
 ```
 
 
+
 ## 平面操作
 
 ### 基本函數與直譯器
diff --git a/src/ch1/package.json b/src/ch1/package.json
new file mode 100644 (file)
index 0000000..eec0cf8
--- /dev/null
@@ -0,0 +1,24 @@
+{
+  "name": "ch1",
+  "version": "0.0.1",
+  "description": "little typesetting draught",
+  "main": "src/index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [
+    "typesetting",
+    "pdf"
+  ],
+  "author": "Tan Kian-ting",
+  "license": "MIT",
+  "dependencies": {
+    "typescript-parsec": "^0.3.4"
+  },
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^6.13.2",
+    "@typescript-eslint/parser": "^6.13.2",
+    "tslint": "^6.1.3",
+    "@types/node": "^20.10.4"
+  }
+}
diff --git a/src/ch1/src/index.d.ts b/src/ch1/src/index.d.ts
new file mode 100644 (file)
index 0000000..95ee14b
--- /dev/null
@@ -0,0 +1,27 @@
+import * as parsec from 'typescript-parsec';
+/** the type of token  */
+declare enum TokenKind {
+    Int = 0,
+    Flo = 1,
+    Id = 2,
+    At = 3,
+    Comt = 4,
+    Str = /** "foo" */ 5,
+    Lambda = /** -> */ 6,
+    Assign = /** = */ 7,
+    Set = /** := */ 8,
+    Keyword = /** let, in */ 9,
+    LParen = /** ( */ 10,
+    RParen = /** ) */ 11,
+    Space = /** semi-width space tab, \r\n? */ 12,
+    NewPara = /** breaking paragraph, (\r\n?){2} */ 13,
+    MainTxt = /** used in main text */ 14
+}
+export interface ASTNode extends parsec.Token<TokenKind> {
+    actualValue?: bigint | number | string;
+}
+/** AST Tree */
+declare type AST = AST[] | ASTNode;
+/** from AST to S-exp */
+export declare function astToSExp(ast: AST): any;
+export {};
diff --git a/src/ch1/src/index.js b/src/ch1/src/index.js
new file mode 100644 (file)
index 0000000..a710000
--- /dev/null
@@ -0,0 +1,194 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.astToSExp = void 0;
+const parsec = require("typescript-parsec"); // import parsec
+/* for test */
+const assert = require("assert");
+/** the type of token  */
+var TokenKind;
+(function (TokenKind) {
+    TokenKind[TokenKind["Int"] = 0] = "Int";
+    TokenKind[TokenKind["Flo"] = 1] = "Flo";
+    TokenKind[TokenKind["Id"] = 2] = "Id";
+    TokenKind[TokenKind["At"] = 3] = "At";
+    TokenKind[TokenKind["Comt"] = 4] = "Comt";
+    TokenKind[TokenKind["Str"] = 5] = "Str";
+    TokenKind[TokenKind["Lambda"] = 6] = "Lambda";
+    TokenKind[TokenKind["Assign"] = 7] = "Assign";
+    TokenKind[TokenKind["Set"] = 8] = "Set";
+    TokenKind[TokenKind["Keyword"] = 9] = "Keyword";
+    TokenKind[TokenKind["LParen"] = 10] = "LParen";
+    TokenKind[TokenKind["RParen"] = 11] = "RParen";
+    TokenKind[TokenKind["Space"] = 12] = "Space";
+    TokenKind[TokenKind["NewPara"] = 13] = "NewPara";
+    TokenKind[TokenKind["MainTxt"] = 14] = "MainTxt";
+})(TokenKind || (TokenKind = {}));
+/** from AST to S-exp */
+function astToSExp(ast) {
+    // if it's an array
+    if (Array.isArray(ast)) {
+        return "(" + ast.map((x) => astToSExp(x)).join(" ") + ")";
+        // if it's a item
+    }
+    else {
+        return ast.text;
+    }
+}
+exports.astToSExp = astToSExp;
+// tokenizer
+const tokenizer = parsec.buildLexer([
+    [true, /^\d+/g, TokenKind.Int],
+    [true, /^\d+\.\d+/g, TokenKind.Flo],
+    [true, /^(let|in|fn)/g, TokenKind.Keyword],
+    [true, /^[_a-zA-Z][_0-9a-zA-Z]*/g, TokenKind.Id],
+    [true, /^\@/g, TokenKind.At],
+    /* inside comment, only accept 1. non / character
+    or  2. "/ + non * character" */
+    [true, /^\/\*(\/[^*]|[^\\]?)*\*\//g, TokenKind.Comt],
+    [true, /^\"(\\\"|[^\"]?)*\"/g, TokenKind.Str],
+    [true, /^\:\=/g, TokenKind.Set],
+    [true, /^\=/g, TokenKind.Assign],
+    [true, /^->/g, TokenKind.Lambda],
+    [true, /^\(/g, TokenKind.LParen],
+    [true, /^\)/g, TokenKind.RParen],
+    [true, /^([ \t]+|[ \t]*\r?\n[ \t]*)/g, TokenKind.Space],
+    [true, /^(\r?\n){2}/g, TokenKind.NewPara],
+    [true, /^(\\\@|[^@\s])/g, TokenKind.MainTxt],
+]);
+/** ignore spaces ,new lines, and comments */
+const _ = parsec.opt(parsec.alt(parsec.tok(TokenKind.Space), parsec.tok(TokenKind.NewPara), 
+// space or newPara + comment + space or newPara
+parsec.seq(parsec.opt(parsec.alt(parsec.tok(TokenKind.Space), parsec.tok(TokenKind.NewPara))), parsec.tok(TokenKind.Comt), parsec.opt(parsec.alt(parsec.tok(TokenKind.Space), parsec.tok(TokenKind.NewPara))))));
+function applyInteger(value) {
+    // extend value to ASTNode
+    const newNode = {
+        actualValue: BigInt(value.text),
+        ...value
+    };
+    return newNode;
+}
+function applyFloat(value) {
+    const newNode = {
+        actualValue: parseFloat(value.text),
+        ...value
+    };
+    return newNode;
+}
+function applyString(value) {
+    const newNode = {
+        // get only text[1,2,...,the second last char]
+        actualValue: value.text.slice(1, value.text.length - 1).replace(/\\\"/g, "\""),
+        ...value
+    };
+    return newNode;
+}
+function applyIdentifier(value) {
+    const newNode = {
+        actualValue: value.text,
+        ...value
+    };
+    return newNode;
+}
+/** apply LETTING.
+ * returns [let, [var, x], expr] */
+function applyLetting(input) {
+    // node representing let
+    let letNode = input[0];
+    let varNode = input[2];
+    let valueNode = input[6];
+    let exprAST = input[10];
+    return [letNode, [varNode, valueNode], exprAST];
+}
+/** apply SETTING */
+function applySetting(input) {
+    // node representing let
+    let setNode = input[2];
+    let varNode = input[0];
+    let valueNode = input[4];
+    let exprAST = input[8];
+    //  (:= (var val) expr) : set var = val in expr
+    return [setNode, [varNode, valueNode], exprAST];
+}
+function applyLambda(input) {
+    let lambdaNode = input[0];
+    let argHead = input[1];
+    let argTail = input[2];
+    let body = input[6];
+    let args = [argHead].concat(argTail);
+    // return (fn (args) body) like lambda in Scheme
+    return [lambdaNode, args, body];
+}
+function applyApplying(input) {
+    let applier = input[0];
+    let applieeHead = input[2];
+    let applieeTail = input[3];
+    let appliee = [(applieeHead)].concat(applieeTail);
+    // foo 2 3 => (foo (2 3))
+    return [applier, appliee];
+}
+/** define all the parser sentence */
+const CONST = parsec.rule();
+const VAR = parsec.rule();
+const ARG = parsec.rule();
+const EXPR = parsec.rule();
+const LETTING = parsec.rule();
+const SETTING = parsec.rule();
+const LAMBDA = parsec.rule();
+const APPLYING = parsec.rule();
+/*
+CONST ::=  INT | FLOAT | STRING
+*/
+CONST.setPattern(parsec.alt(parsec.apply(parsec.tok(TokenKind.Int), applyInteger), parsec.apply(parsec.tok(TokenKind.Flo), applyFloat), parsec.apply(parsec.tok(TokenKind.Str), applyString)));
+/** VAR = ID  */
+VAR.setPattern(parsec.apply(parsec.tok(TokenKind.Id), applyIdentifier));
+/** ARG = ID  */
+ARG.setPattern(parsec.apply(parsec.tok(TokenKind.Id), applyIdentifier));
+/**SETTING ::= VAR ":=" EXPR in EXPR
+ * and ignore the spaces and new lines with `_`
+*/
+SETTING.setPattern(parsec.apply(parsec.seq(VAR, _, parsec.str(":="), _, EXPR, _, parsec.str("in"), _, EXPR), applySetting));
+/**LETTING ::= "let" VAR "=" EXPR in EXPR
+ * and ignore the spaces and new lines with `_`
+*/
+LETTING.setPattern(parsec.apply(parsec.seq(parsec.str("let"), _, VAR, _, parsec.str("="), _, EXPR, _, parsec.str("in"), _, EXPR), applyLetting));
+/**LAMBDA ::= "fn" (Args)+ "->" EXPR
+ * and ignore the spaces and new lines with `_`
+*/
+LAMBDA.setPattern(parsec.apply(parsec.seq(parsec.str("fn"), parsec.kright(_, ARG), // arg SpaceNL
+parsec.rep_sc(parsec.kright(_, ARG)), //other (arg SpaceNL), repeat 0+times
+_, parsec.str("->"), _, EXPR), applyLambda));
+// APPLYING = ( "(" APPLYING ")" |LAMBDA|VAR) APPLIEE+
+APPLYING.setPattern(parsec.apply(parsec.seq(parsec.alt(LAMBDA, VAR, parsec.kmid(parsec.seq(parsec.str('('), _), APPLYING, parsec.seq(_, parsec.str(')')))), _, EXPR, parsec.rep_sc(parsec.kright(_, EXPR))), applyApplying));
+/** EXPR = CONST | VAR
+ * | LETTING | SETTING
+ * | LAMBDA | APPLYING
+ * | "(" APPLYING ")" */
+EXPR.setPattern(parsec.alt(CONST, VAR, LETTING, SETTING, LAMBDA, parsec.kmid(parsec.seq(parsec.str('('), _), APPLYING, parsec.seq(_, parsec.str(')')))));
+function mainParse(inputStr) {
+    return parsec.expectSingleResult(parsec.expectEOF(EXPR.parse(tokenizer.parse(inputStr))));
+}
+// test
+function main() {
+    // bigint has suffix `n`
+    assert.strictEqual(mainParse('123455667').actualValue, 123455667n);
+    assert.strictEqual(mainParse('000').actualValue, 0n);
+    assert.strictEqual(mainParse('1.22').actualValue, 1.22);
+    assert.strictEqual(mainParse('0.0').actualValue, 0.0);
+    assert.strictEqual(mainParse(`""`).actualValue, "");
+    assert.strictEqual(mainParse(`"the little town"`).actualValue, `the little town`);
+    assert.strictEqual(mainParse(`"\\\"Alice\\\""`).actualValue, `"Alice"`);
+    assert.strictEqual(mainParse(`foo`).actualValue, "foo");
+    assert.strictEqual(astToSExp(mainParse(`let x = 12 in 23`)), "(let (x 12) 23)");
+    assert.strictEqual(astToSExp(mainParse(`let y = 10 in let x = 12 in 23`)), "(let (y 10) (let (x 12) 23))");
+    assert.strictEqual(astToSExp(mainParse(`let y = 10 in y := 12 in 23`)), "(let (y 10) (:= (y 12) 23))");
+    assert.strictEqual(astToSExp(mainParse(`fn x y -> 234`)), "(fn (x y) 234)");
+    assert.strictEqual(astToSExp(mainParse(`(add 12 23 )`)), "(add (12 23))");
+    assert.strictEqual(astToSExp(mainParse(`(foo x y)`)), "(foo (x y))");
+    assert.strictEqual(astToSExp(mainParse(`((foo 6 7) bar)`)), "((foo (6 7)) (bar))");
+    assert.strictEqual(astToSExp(mainParse(`fn x y ->
+    /* foo bar */
+    (foo x y)`)), "(fn (x y) (foo (x y)))");
+}
+;
+main();
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/src/ch1/src/index.js.map b/src/ch1/src/index.js.map
new file mode 100644 (file)
index 0000000..2dfcf61
--- /dev/null
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/src/ch1/src/index.ts b/src/ch1/src/index.ts
new file mode 100644 (file)
index 0000000..bbabf63
--- /dev/null
@@ -0,0 +1,360 @@
+import * as parsec from 'typescript-parsec'; // import parsec
+/* for test */
+import * as assert from 'assert';
+
+/** the type of token  */
+enum TokenKind {
+    Int, // 3
+    Flo, // 3.1416
+    Id, // foo, _123, etc
+    At, // @
+    Comt, // comment /*
+    Str, /** "foo" */
+    Lambda, /** -> */
+    Assign, /** = */
+    Set, /** := */
+    Keyword, /** let, in */
+    LParen, /** ( */
+    RParen, /** ) */
+    Space, /** semi-width space tab, \r\n? */
+    NewPara, /** breaking paragraph, (\r\n?){2} */
+    MainTxt, /** used in main text */
+}
+
+// add "actualValue" in the parsed Token
+export interface ASTNode extends parsec.Token<TokenKind>{
+    // number is for float number;
+    //it's optional. since keyword has no value
+    actualValue? : bigint | number | string;    
+}
+
+/** AST Tree */
+type AST = AST[] | ASTNode;
+
+/** from AST to S-exp */
+export function astToSExp(ast : AST){
+    // if it's an array
+    if (Array.isArray(ast)){
+        return "(" + ast.map((x : AST)=>astToSExp(x)).join(" ") + ")";
+    // if it's a item
+    }else{
+        return ast.text;
+    }
+}
+
+
+// tokenizer
+const tokenizer = parsec.buildLexer([
+    [true, /^\d+/g, TokenKind.Int],
+    [true, /^\d+\.\d+/g, TokenKind.Flo],
+    [true, /^(let|in|fn)/g, TokenKind.Keyword], // let, in, fn
+    [true, /^[_a-zA-Z][_0-9a-zA-Z]*/g, TokenKind.Id],
+    [true, /^\@/g, TokenKind.At],
+    /* inside comment, only accept 1. non / character
+    or  2. "/ + non * character" */
+    [true, /^\/\*(\/[^*]|[^\\]?)*\*\//g, TokenKind.Comt],
+    [true, /^\"(\\\"|[^\"]?)*\"/g, TokenKind.Str],
+    [true, /^\:\=/g, TokenKind.Set],
+    [true, /^\=/g, TokenKind.Assign],
+    [true, /^->/g, TokenKind.Lambda],
+    [true, /^\(/g, TokenKind.LParen],
+    [true, /^\)/g, TokenKind.RParen],
+    [true, /^([ \t]+|[ \t]*\r?\n[ \t]*)/g, TokenKind.Space],
+    [true, /^(\r?\n){2}/g, TokenKind.NewPara],
+    [true, /^(\\\@|[^@\s])/g, TokenKind.MainTxt],
+]);
+
+
+/** ignore spaces ,new lines, and comments */
+const _ = parsec.opt(parsec.alt(
+    parsec.tok(TokenKind.Space),
+    parsec.tok(TokenKind.NewPara),
+
+    // space or newPara + comment + space or newPara
+    parsec.seq(
+        parsec.opt(parsec.alt(
+            parsec.tok(TokenKind.Space),
+            parsec.tok(TokenKind.NewPara))),
+        parsec.tok(TokenKind.Comt),
+        parsec.opt(parsec.alt(
+            parsec.tok(TokenKind.Space),
+            parsec.tok(TokenKind.NewPara))),
+        )
+    )
+);
+
+
+
+
+function applyInteger(value: parsec.Token<TokenKind.Int>): ASTNode {
+    // extend value to ASTNode
+    const newNode : ASTNode  = {
+        actualValue : BigInt(value.text) ,
+        ...value};
+    return newNode;
+}
+
+function applyFloat(value: parsec.Token<TokenKind.Flo>): ASTNode {
+    const newNode : ASTNode  = {
+        actualValue : parseFloat(value.text) ,
+        ...value};
+    return newNode;
+}
+
+function applyString(value: parsec.Token<TokenKind.Str>): ASTNode {
+    const newNode : ASTNode  = {
+        // get only text[1,2,...,the second last char]
+        actualValue : value.text.slice(1,value.text.length-1).replace(/\\\"/g, "\"") ,
+        ...value};
+    return newNode;
+}
+
+function applyIdentifier(value: parsec.Token<TokenKind.Id>): ASTNode {
+    const newNode : ASTNode  = {
+        actualValue : value.text,
+        ...value};
+    return newNode;
+}
+
+/** apply LETTING.
+ * returns [let, [var, x], expr] */
+function applyLetting(input: [parsec.Token<TokenKind>, // let
+                              parsec.Token<TokenKind> | undefined, // space
+                              ASTNode, // var
+                              parsec.Token<TokenKind>| undefined, // space
+                              parsec.Token<TokenKind>, // =
+                              parsec.Token<TokenKind>| undefined, // space
+                              AST, // val
+                              parsec.Token<TokenKind>| undefined, // space
+                              parsec.Token<TokenKind>, // in
+                              parsec.Token<TokenKind>| undefined, // space
+                              AST // expr
+                            ]): AST {
+    // node representing let
+    let letNode : ASTNode = input[0];
+    let varNode  = input[2];
+    let valueNode = input[6];
+    let exprAST = input[10];
+
+    return [letNode, [varNode, valueNode], exprAST];
+
+}
+
+/** apply SETTING */
+function applySetting(input: [ASTNode, // var
+                              parsec.Token<TokenKind>| undefined, // space
+                              parsec.Token<TokenKind>, // :=
+                              parsec.Token<TokenKind>| undefined, // space
+                              AST, // val
+                              parsec.Token<TokenKind>| undefined, // space
+                              parsec.Token<TokenKind>, // in
+                              parsec.Token<TokenKind>| undefined, // space
+                              AST // expr
+                            ]): AST {
+    // node representing let
+    let setNode = input[2];
+    let varNode  = input[0];
+    let valueNode = input[4];
+    let exprAST = input[8];
+
+    //  (:= (var val) expr) : set var = val in expr
+    return [setNode, [varNode, valueNode], exprAST];
+
+}
+
+function applyLambda(input: [ASTNode, // fn
+        ASTNode, // arg
+        ASTNode[], // args
+        parsec.Token<TokenKind>| undefined, // space
+        parsec.Token<TokenKind>, // ->
+        parsec.Token<TokenKind>| undefined, // space
+        AST // expr
+]): AST {
+    let lambdaNode = input[0];
+    let argHead = input[1];
+    let argTail = input[2];
+    let body = input[6];
+    let args = [argHead].concat(argTail)
+
+    // return (fn (args) body) like lambda in Scheme
+    return [lambdaNode, args, body];
+}
+
+
+function applyApplying(input : [ASTNode, // caller
+    parsec.Token<TokenKind> |undefined, // space
+    ASTNode, // head of callee
+    AST[] // tail of callee
+    ]){
+    let applier = input[0];
+    let applieeHead = input[2];
+    let applieeTail = input[3];
+    let appliee = [<AST>(applieeHead)].concat(applieeTail);
+
+
+    // foo 2 3 => (foo (2 3))
+    return [applier, appliee];
+
+}
+
+/** define all the parser sentence */
+const CONST = parsec.rule<TokenKind, ASTNode>();
+const VAR = parsec.rule<TokenKind, ASTNode>();
+const ARG = parsec.rule<TokenKind, ASTNode>();
+const EXPR = parsec.rule<TokenKind, AST>();
+const LETTING = parsec.rule<TokenKind, AST>();
+const SETTING = parsec.rule<TokenKind, AST>();
+const LAMBDA = parsec.rule<TokenKind, AST>();
+const APPLYING = parsec.rule<TokenKind, AST>();
+
+
+
+/*
+CONST ::=  INT | FLOAT | STRING
+*/
+CONST.setPattern(
+    parsec.alt(
+        parsec.apply(parsec.tok(TokenKind.Int), applyInteger),
+        parsec.apply(parsec.tok(TokenKind.Flo), applyFloat),
+        parsec.apply(parsec.tok(TokenKind.Str), applyString),
+    )
+);
+
+/** VAR = ID  */
+VAR.setPattern(
+        parsec.apply(parsec.tok(TokenKind.Id), applyIdentifier),
+);
+
+/** ARG = ID  */
+ARG.setPattern(
+    parsec.apply(parsec.tok(TokenKind.Id), applyIdentifier),
+);
+
+
+
+
+/**SETTING ::= VAR ":=" EXPR in EXPR
+ * and ignore the spaces and new lines with `_`
+*/
+
+SETTING.setPattern(
+    parsec.apply(
+        parsec.seq(
+        VAR,
+        _,
+        parsec.str(":="),
+        _,
+        EXPR,
+        _,
+        parsec.str("in"),
+        _,
+        EXPR), applySetting));
+
+/**LETTING ::= "let" VAR "=" EXPR in EXPR
+ * and ignore the spaces and new lines with `_`
+*/
+LETTING.setPattern(
+    parsec.apply(
+        parsec.seq(
+        parsec.str("let"),
+        _,
+        VAR,
+        _,
+        parsec.str("="),
+        _,
+        EXPR,
+        _,
+        parsec.str("in"),
+        _,
+        EXPR), applyLetting));
+
+
+
+/**LAMBDA ::= "fn" (Args)+ "->" EXPR 
+ * and ignore the spaces and new lines with `_`
+*/
+LAMBDA.setPattern(
+    parsec.apply(
+        parsec.seq(
+            parsec.str("fn"),
+            parsec.kright(_, ARG), // arg SpaceNL
+            parsec.rep_sc(parsec.kright(_, ARG)), //other (arg SpaceNL), repeat 0+times
+            _,
+            parsec.str("->"),
+            _,
+            EXPR),
+    applyLambda)
+)
+
+// APPLYING = ( "(" APPLYING ")" |LAMBDA|VAR) APPLIEE+
+APPLYING.setPattern(
+    parsec.apply(
+        parsec.seq(
+            parsec.alt(
+                LAMBDA,
+                VAR,
+                parsec.kmid(
+                    parsec.seq(parsec.str('('), _),
+                    APPLYING,
+                    parsec.seq(_, parsec.str(')')))
+            ),
+            _,
+            EXPR,
+            parsec.rep_sc(parsec.kright(_, EXPR))),
+        applyApplying));
+
+/** EXPR = CONST | VAR 
+ * | LETTING | SETTING 
+ * | LAMBDA | APPLYING
+ * | "(" APPLYING ")" */
+EXPR.setPattern(
+    parsec.alt(
+       CONST,
+       VAR,
+       LETTING,
+       SETTING,
+       LAMBDA,
+        parsec.kmid(
+            parsec.seq(parsec.str('('), _),
+            APPLYING,
+            parsec.seq(_, parsec.str(')')))
+    )
+);
+
+
+
+
+
+function mainParse(inputStr : string){
+    return parsec.expectSingleResult(parsec.expectEOF(
+        EXPR.parse(tokenizer.parse(inputStr))));
+}
+
+
+// test
+function main(){
+    // bigint has suffix `n`
+    assert.strictEqual((<ASTNode>mainParse('123455667')).actualValue, 123455667n);
+    assert.strictEqual((<ASTNode>mainParse('000')).actualValue, 0n);
+    assert.strictEqual((<ASTNode>mainParse('1.22')).actualValue, 1.22);
+    assert.strictEqual((<ASTNode>mainParse('0.0')).actualValue, 0.0);
+    assert.strictEqual((<ASTNode>mainParse(`""`)).actualValue, "");
+    assert.strictEqual((<ASTNode>mainParse(`"the little town"`)).actualValue, `the little town`);
+    assert.strictEqual((<ASTNode>mainParse(`"\\\"Alice\\\""`)).actualValue, `"Alice"`);
+
+    assert.strictEqual((<ASTNode>mainParse(`foo`)).actualValue, "foo");
+    assert.strictEqual(astToSExp(mainParse(`let x = 12 in 23`)), "(let (x 12) 23)");
+    assert.strictEqual(astToSExp(mainParse(`let y = 10 in let x = 12 in 23`)), "(let (y 10) (let (x 12) 23))");
+    assert.strictEqual(astToSExp(mainParse(`let y = 10 in y := 12 in 23`)), "(let (y 10) (:= (y 12) 23))");
+    assert.strictEqual(astToSExp(mainParse(`fn x y -> 234`)), "(fn (x y) 234)");
+    assert.strictEqual(astToSExp(mainParse(`(add 12 23 )`)), "(add (12 23))");
+    assert.strictEqual(astToSExp(mainParse(`(foo x y)`)), "(foo (x y))");
+    assert.strictEqual(astToSExp(mainParse(`((foo 6 7) bar)`)), "((foo (6 7)) (bar))");
+    assert.strictEqual(astToSExp(mainParse(`fn x y ->
+    /* foo bar */
+    (foo x y)`)), "(fn (x y) (foo (x y)))");
+
+
+};
+
+main();
\ No newline at end of file
diff --git a/src/ch1/src/test/parser.d.ts b/src/ch1/src/test/parser.d.ts
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/ch1/src/test/parser.js b/src/ch1/src/test/parser.js
new file mode 100644 (file)
index 0000000..7a6700d
--- /dev/null
@@ -0,0 +1 @@
+//# sourceMappingURL=parser.js.map
\ No newline at end of file
diff --git a/src/ch1/src/test/parser.js.map b/src/ch1/src/test/parser.js.map
new file mode 100644 (file)
index 0000000..c75b197
--- /dev/null
@@ -0,0 +1 @@
+{"version":3,"file":"parser.js","sourceRoot":"","sources":["parser.ts"],"names":[],"mappings":""}
\ No newline at end of file
diff --git a/src/ch1/src/test/parser.ts b/src/ch1/src/test/parser.ts
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/ch1/tsconfig.json b/src/ch1/tsconfig.json
new file mode 100644 (file)
index 0000000..069fa4a
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "lib": ["es2020", "dom"],
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "target": "es2020",
+
+    "declaration": true,
+    "sourceMap": true,
+    
+    "noEmitOnError": true,
+    "noUnusedLocals": true,
+    "strictNullChecks": true,
+  },
+  "exclude": ["node_modules"]
+}
diff --git a/src/ch1/tslint.json b/src/ch1/tslint.json
new file mode 100644 (file)
index 0000000..0a27bf7
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "defaultSeverity": "error",
+    "extends": [
+        "tslint:recommended"
+    ],
+    "jsRules": {},
+    "rules": {
+        "no-console": false
+    },
+    "rulesDirectory": []
+}
\ No newline at end of file
diff --git a/src/ch1/yarn.lock b/src/ch1/yarn.lock
new file mode 100644 (file)
index 0000000..587f778
--- /dev/null
@@ -0,0 +1,606 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+  version "7.23.5"
+  resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz"
+  integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==
+  dependencies:
+    "@babel/highlight" "^7.23.4"
+    chalk "^2.4.2"
+
+"@babel/helper-validator-identifier@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz"
+  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/highlight@^7.23.4":
+  version "7.23.4"
+  resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz"
+  integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.22.20"
+    chalk "^2.4.2"
+    js-tokens "^4.0.0"
+
+"@eslint-community/eslint-utils@^4.4.0":
+  version "4.4.0"
+  resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
+  integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+  dependencies:
+    eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.5.1":
+  version "4.10.0"
+  resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz"
+  integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
+
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+  version "2.0.5"
+  resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+  version "1.2.8"
+  resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@types/json-schema@^7.0.12":
+  version "7.0.15"
+  resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
+  integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/node@^20.10.4":
+  version "20.10.4"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198"
+  integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==
+  dependencies:
+    undici-types "~5.26.4"
+
+"@types/semver@^7.5.0":
+  version "7.5.6"
+  resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz"
+  integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
+
+"@typescript-eslint/eslint-plugin@^6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz"
+  integrity sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==
+  dependencies:
+    "@eslint-community/regexpp" "^4.5.1"
+    "@typescript-eslint/scope-manager" "6.13.2"
+    "@typescript-eslint/type-utils" "6.13.2"
+    "@typescript-eslint/utils" "6.13.2"
+    "@typescript-eslint/visitor-keys" "6.13.2"
+    debug "^4.3.4"
+    graphemer "^1.4.0"
+    ignore "^5.2.4"
+    natural-compare "^1.4.0"
+    semver "^7.5.4"
+    ts-api-utils "^1.0.1"
+
+"@typescript-eslint/parser@^6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz"
+  integrity sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==
+  dependencies:
+    "@typescript-eslint/scope-manager" "6.13.2"
+    "@typescript-eslint/types" "6.13.2"
+    "@typescript-eslint/typescript-estree" "6.13.2"
+    "@typescript-eslint/visitor-keys" "6.13.2"
+    debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz"
+  integrity sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==
+  dependencies:
+    "@typescript-eslint/types" "6.13.2"
+    "@typescript-eslint/visitor-keys" "6.13.2"
+
+"@typescript-eslint/type-utils@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz"
+  integrity sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==
+  dependencies:
+    "@typescript-eslint/typescript-estree" "6.13.2"
+    "@typescript-eslint/utils" "6.13.2"
+    debug "^4.3.4"
+    ts-api-utils "^1.0.1"
+
+"@typescript-eslint/types@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz"
+  integrity sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==
+
+"@typescript-eslint/typescript-estree@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz"
+  integrity sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==
+  dependencies:
+    "@typescript-eslint/types" "6.13.2"
+    "@typescript-eslint/visitor-keys" "6.13.2"
+    debug "^4.3.4"
+    globby "^11.1.0"
+    is-glob "^4.0.3"
+    semver "^7.5.4"
+    ts-api-utils "^1.0.1"
+
+"@typescript-eslint/utils@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz"
+  integrity sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==
+  dependencies:
+    "@eslint-community/eslint-utils" "^4.4.0"
+    "@types/json-schema" "^7.0.12"
+    "@types/semver" "^7.5.0"
+    "@typescript-eslint/scope-manager" "6.13.2"
+    "@typescript-eslint/types" "6.13.2"
+    "@typescript-eslint/typescript-estree" "6.13.2"
+    semver "^7.5.4"
+
+"@typescript-eslint/visitor-keys@6.13.2":
+  version "6.13.2"
+  resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz"
+  integrity sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==
+  dependencies:
+    "@typescript-eslint/types" "6.13.2"
+    eslint-visitor-keys "^3.4.1"
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+argparse@^1.0.7:
+  version "1.0.10"
+  resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
+  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  dependencies:
+    sprintf-js "~1.0.2"
+
+array-union@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
+  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
+builtin-modules@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz"
+  integrity sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==
+
+chalk@^2.3.0, chalk@^2.4.2:
+  version "2.4.2"
+  resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
+  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+commander@^2.12.1:
+  version "2.20.3"
+  resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+debug@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+  dependencies:
+    ms "2.1.2"
+
+diff@^4.0.1:
+  version "4.0.2"
+  resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz"
+  integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
+dir-glob@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
+  integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+  dependencies:
+    path-type "^4.0.0"
+
+escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
+  version "3.4.3"
+  resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
+  integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+esprima@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+fast-glob@^3.2.9:
+  version "3.3.2"
+  resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz"
+  integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fastq@^1.6.0:
+  version "1.15.0"
+  resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz"
+  integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+  dependencies:
+    reusify "^1.0.4"
+
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+function-bind@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
+  integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+glob-parent@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob@^7.1.1:
+  version "7.2.3"
+  resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.1.1"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globby@^11.1.0:
+  version "11.1.0"
+  resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
+  integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+  dependencies:
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.2.9"
+    ignore "^5.2.0"
+    merge2 "^1.4.1"
+    slash "^3.0.0"
+
+graphemer@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
+  integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
+  integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+hasown@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz"
+  integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+  dependencies:
+    function-bind "^1.1.2"
+
+ignore@^5.2.0, ignore@^5.2.4:
+  version "5.3.0"
+  resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz"
+  integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2:
+  version "2.0.4"
+  resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+is-core-module@^2.13.0:
+  version "2.13.1"
+  resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz"
+  integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+  dependencies:
+    hasown "^2.0.0"
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1, is-glob@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^3.13.1:
+  version "3.14.1"
+  resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+  integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
+merge2@^1.3.0, merge2@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4:
+  version "4.0.5"
+  resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
+  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+  dependencies:
+    braces "^3.0.2"
+    picomatch "^2.3.1"
+
+minimatch@^3.0.4, minimatch@^3.1.1:
+  version "3.1.2"
+  resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@^1.2.6:
+  version "1.2.8"
+  resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
+  integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+mkdirp@^0.5.3:
+  version "0.5.6"
+  resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz"
+  integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+  dependencies:
+    minimist "^1.2.6"
+
+ms@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
+  integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+once@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+  dependencies:
+    wrappy "1"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+resolve@^1.3.2:
+  version "1.22.8"
+  resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"
+  integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+  dependencies:
+    is-core-module "^2.13.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
+semver@^5.3.0:
+  version "5.7.2"
+  resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
+  integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@^7.5.4:
+  version "7.5.4"
+  resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
+  integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+  dependencies:
+    lru-cache "^6.0.0"
+
+slash@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
+  integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+  integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+ts-api-utils@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz"
+  integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==
+
+tslib@^1.13.0, tslib@^1.8.1:
+  version "1.14.1"
+  resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslint@^6.1.3:
+  version "6.1.3"
+  resolved "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz"
+  integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    builtin-modules "^1.1.1"
+    chalk "^2.3.0"
+    commander "^2.12.1"
+    diff "^4.0.1"
+    glob "^7.1.1"
+    js-yaml "^3.13.1"
+    minimatch "^3.0.4"
+    mkdirp "^0.5.3"
+    resolve "^1.3.2"
+    semver "^5.3.0"
+    tslib "^1.13.0"
+    tsutils "^2.29.0"
+
+tsutils@^2.29.0:
+  version "2.29.0"
+  resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz"
+  integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
+  dependencies:
+    tslib "^1.8.1"
+
+typescript-parsec@^0.3.4:
+  version "0.3.4"
+  resolved "https://registry.npmjs.org/typescript-parsec/-/typescript-parsec-0.3.4.tgz"
+  integrity sha512-6RD4xOxp26BTZLopNbqT2iErqNhQZZWb5m5F07/UwGhldGvOAKOl41pZ3fxsFp04bNL+PbgMjNfb6IvJAC/uYQ==
+
+undici-types@~5.26.4:
+  version "5.26.5"
+  resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+  integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==