@ansi-tools/parser 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -179,6 +179,7 @@ type TOKEN = {
179
179
  pos: number;
180
180
  raw: string;
181
181
  code?: string;
182
+ intermediate?: string;
182
183
  };
183
184
  ```
184
185
 
package/dist/escaped.d.ts CHANGED
@@ -1,5 +1,8 @@
1
- import { APC, APC_OPEN, BACKSLASH, BELL, CODE, CODE_TYPES, CONTROL_CODE, CONTROL_CODE_TEXT, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN, TOKEN_TYPES, parse, parser } from "./parse-BirjVUvQ.js";
1
+ import { APC, APC_OPEN, BACKSLASH, BELL, CODE, CODE_TYPES, CONTROL_CODE, CONTROL_CODE_TEXT, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN, TOKEN_TYPES, parser } from "./parse-BtpkwNjf.js";
2
2
 
3
+ //#region src/parse.escaped.d.ts
4
+ declare function parse(input: string): CODE[];
5
+ //#endregion
3
6
  //#region src/tokenize.escaped.d.ts
4
7
  declare function tokenizer(input: string): Generator<TOKEN>;
5
8
  declare function tokenize(input: string): TOKEN[];
package/dist/escaped.js CHANGED
@@ -1,4 +1,4 @@
1
- import { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parse, parser } from "./parse-ClmKWMZx.js";
1
+ import { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parser } from "./parse-BE4NnMTj.js";
2
2
 
3
3
  //#region src/tokenize.escaped.ts
4
4
  const CSI_ESCAPED = "\\u009b";
@@ -105,10 +105,11 @@ function* tokenizer(input) {
105
105
  type: TOKEN_TYPES.INTRODUCER,
106
106
  pos: i,
107
107
  raw: sequence + nextChar,
108
- code: CSI
108
+ code: ESC,
109
+ intermediate: nextChar
109
110
  });
110
111
  i += len + 1;
111
- setState("SEQUENCE", CSI);
112
+ setState("SEQUENCE", ESC);
112
113
  } else if (nextChar) {
113
114
  yield emit({
114
115
  type: TOKEN_TYPES.INTRODUCER,
@@ -117,12 +118,7 @@ function* tokenizer(input) {
117
118
  code: ESC
118
119
  });
119
120
  i += len;
120
- yield emit({
121
- type: TOKEN_TYPES.FINAL,
122
- pos: i,
123
- raw: nextChar
124
- });
125
- i++;
121
+ setState("SEQUENCE", ESC);
126
122
  } else {
127
123
  yield emit({
128
124
  type: TOKEN_TYPES.INTRODUCER,
@@ -137,7 +133,7 @@ function* tokenizer(input) {
137
133
  }
138
134
  }
139
135
  }
140
- } else {
136
+ } else if (state === "SEQUENCE") {
141
137
  let terminator = "";
142
138
  let terminatorPos = -1;
143
139
  const pos = i;
@@ -151,6 +147,10 @@ function* tokenizer(input) {
151
147
  terminatorPos = i;
152
148
  i++;
153
149
  }
150
+ } else if (code === ESC) {
151
+ terminator = char;
152
+ terminatorPos = i;
153
+ i++;
154
154
  } else if (code) {
155
155
  if (char === BACKSLASH) {
156
156
  if (code === OSC) {
@@ -199,5 +199,11 @@ function tokenize(input) {
199
199
  return Array.from(tokenizer(input));
200
200
  }
201
201
 
202
+ //#endregion
203
+ //#region src/parse.escaped.ts
204
+ function parse(input) {
205
+ return Array.from(parser(tokenizer(input)));
206
+ }
207
+
202
208
  //#endregion
203
209
  export { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parse, parser, tokenize, tokenizer };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { APC, APC_OPEN, BACKSLASH, BELL, CODE, CODE_TYPES, CONTROL_CODE, CONTROL_CODE_TEXT, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN, TOKEN_TYPES, parse, parser } from "./parse-BirjVUvQ.js";
1
+ import { APC, APC_OPEN, BACKSLASH, BELL, CODE, CODE_TYPES, CONTROL_CODE, CONTROL_CODE_TEXT, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN, TOKEN_TYPES, parse, parser } from "./parse-BtpkwNjf.js";
2
2
 
3
3
  //#region src/tokenize.d.ts
4
4
  declare function tokenizer(input: string): Generator<TOKEN>;
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parse, parser, tokenize, tokenizer } from "./parse-ClmKWMZx.js";
1
+ import { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parse, parser, tokenize, tokenizer } from "./parse-BE4NnMTj.js";
2
2
 
3
3
  export { APC, APC_OPEN, BACKSLASH, BELL, CODE_TYPES, CSI, CSI_OPEN, DCS, DCS_OPEN, DEC_OPEN, ESC, OSC, OSC_OPEN, PM, PM_OPEN, PRIVATE_OPENERS, SOS, SOS_OPEN, ST, STRING_OPENERS, TOKEN_TYPES, parse, parser, tokenize, tokenizer };
@@ -177,10 +177,17 @@ function parseDEC(pos, raw, data, final) {
177
177
 
178
178
  //#endregion
179
179
  //#region src/parsers/esc.ts
180
- function parseESC(pos, raw, command, data) {
180
+ function parseESC(token, raw, command, data) {
181
+ if (token.intermediate) return {
182
+ type: CODE_TYPES.ESC,
183
+ pos: token.pos,
184
+ raw,
185
+ command: token.intermediate,
186
+ params: command ? [command] : []
187
+ };
181
188
  return {
182
189
  type: CODE_TYPES.ESC,
183
- pos,
190
+ pos: token.pos,
184
191
  raw,
185
192
  command,
186
193
  params: data ? [data] : []
@@ -303,16 +310,12 @@ function* tokenizer(input) {
303
310
  yield emit$1({
304
311
  type: TOKEN_TYPES.INTRODUCER,
305
312
  pos: i,
306
- raw: char,
307
- code: ESC
308
- });
309
- i += 1;
310
- yield emit$1({
311
- type: TOKEN_TYPES.FINAL,
312
- pos: i,
313
- raw: next
313
+ raw: char + next,
314
+ code: ESC,
315
+ intermediate: next
314
316
  });
315
- i++;
317
+ i += 2;
318
+ setState("SEQUENCE", ESC);
316
319
  } else if (next) {
317
320
  yield emit$1({
318
321
  type: TOKEN_TYPES.INTRODUCER,
@@ -320,12 +323,8 @@ function* tokenizer(input) {
320
323
  raw: char,
321
324
  code: ESC
322
325
  });
323
- yield emit$1({
324
- type: TOKEN_TYPES.FINAL,
325
- pos: i + 1,
326
- raw: next
327
- });
328
- i += 2;
326
+ i += 1;
327
+ setState("SEQUENCE", ESC);
329
328
  } else {
330
329
  yield emit$1({
331
330
  type: TOKEN_TYPES.INTRODUCER,
@@ -337,7 +336,7 @@ function* tokenizer(input) {
337
336
  }
338
337
  }
339
338
  }
340
- } else {
339
+ } else if (state === "SEQUENCE") {
341
340
  const pos = i;
342
341
  const code = currentCode;
343
342
  let data = "";
@@ -361,7 +360,17 @@ function* tokenizer(input) {
361
360
  data += char;
362
361
  i++;
363
362
  }
364
- else if (code) while (i < input.length) {
363
+ else if (code === ESC) {
364
+ if (i < input.length) {
365
+ const char = input[i];
366
+ yield emit$1({
367
+ type: TOKEN_TYPES.FINAL,
368
+ pos: i,
369
+ raw: char
370
+ });
371
+ i++;
372
+ }
373
+ } else if (code) while (i < input.length) {
365
374
  const char = input[i];
366
375
  let terminator;
367
376
  if (char === ST) terminator = ST;
@@ -470,10 +479,10 @@ function* parser(tokens) {
470
479
  });
471
480
  break;
472
481
  case ESC:
473
- yield emit(parseESC(pos, raw, finalToken.raw, data));
482
+ yield emit(parseESC(token, raw, finalToken.raw, data));
474
483
  break;
475
484
  }
476
- else if (token.code === ESC) yield emit(parseESC(pos, raw, "", ""));
485
+ else if (token.code === ESC) yield emit(parseESC(token, raw, "", ""));
477
486
  } else current = tokens.next();
478
487
  }
479
488
  }
@@ -42,6 +42,7 @@ type TOKEN = {
42
42
  pos: number;
43
43
  raw: string;
44
44
  code?: string;
45
+ intermediate?: string;
45
46
  };
46
47
  type CONTROL_CODE = {
47
48
  type: "CSI" | "DCS" | "DEC" | "ESC" | "OSC" | "SGR" | "STRING" | "PRIVATE";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ansi-tools/parser",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "description": "Tokenize and parse strings containing ANSI escape sequences and control codes",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -11,11 +11,14 @@
11
11
  "default": "./dist/index.js"
12
12
  },
13
13
  "./escaped": {
14
- "types": "./dist/index.d.ts",
14
+ "types": "./dist/escaped.d.ts",
15
15
  "import": "./dist/escaped.js",
16
16
  "default": "./dist/escaped.js"
17
17
  }
18
18
  },
19
+ "files": [
20
+ "dist"
21
+ ],
19
22
  "keywords": [
20
23
  "ansi",
21
24
  "escape codes",
package/src/constants.ts DELETED
@@ -1,40 +0,0 @@
1
- export const BELL = String.fromCharCode(7);
2
- export const ESC = String.fromCharCode(27);
3
- export const BACKSLASH = String.fromCharCode(92);
4
- export const DCS = String.fromCharCode(144);
5
- export const SOS = String.fromCharCode(152);
6
- export const CSI = String.fromCharCode(155);
7
- export const ST = String.fromCharCode(156);
8
- export const OSC = String.fromCharCode(157);
9
- export const PM = String.fromCharCode(158);
10
- export const APC = String.fromCharCode(159);
11
-
12
- export const CSI_OPEN = "[";
13
- export const OSC_OPEN = "]";
14
- export const DEC_OPEN = "?";
15
- export const PRIVATE_OPENERS = new Set(["<", "=", ">"]);
16
-
17
- export const DCS_OPEN = "P";
18
- export const APC_OPEN = "_";
19
- export const SOS_OPEN = "^";
20
- export const PM_OPEN = "X";
21
- export const STRING_OPENERS = new Set([DCS_OPEN, APC_OPEN, SOS_OPEN, PM_OPEN]);
22
-
23
- export const TOKEN_TYPES = {
24
- TEXT: "TEXT",
25
- INTRODUCER: "INTRODUCER",
26
- DATA: "DATA",
27
- FINAL: "FINAL",
28
- } as const;
29
-
30
- export const CODE_TYPES = {
31
- CSI: "CSI",
32
- DCS: "DCS",
33
- DEC: "DEC",
34
- ESC: "ESC",
35
- OSC: "OSC",
36
- PRIVATE: "PRIVATE",
37
- SGR: "SGR",
38
- STRING: "STRING",
39
- TEXT: "TEXT",
40
- } as const;
package/src/escaped.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./constants.ts";
2
- export { parse, parser } from "./parse.ts";
3
- export { tokenize, tokenizer } from "./tokenize.escaped.ts";
4
- export type { CODE, CONTROL_CODE, CONTROL_CODE_TEXT, TOKEN } from "./types.ts";
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./constants.ts";
2
- export { parse, parser } from "./parse.ts";
3
- export { tokenize, tokenizer } from "./tokenize.ts";
4
- export type { CODE, CONTROL_CODE, CONTROL_CODE_TEXT, TOKEN } from "./types.ts";
@@ -1,86 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { tokenizer } from "./tokenize.escaped.ts";
4
- import { parser } from "./parse.ts";
5
- import { CODE_TYPES } from "./constants.ts";
6
-
7
- test("parse simple text", () => {
8
- const input = "hello world";
9
- const tokens = tokenizer(input);
10
- const codes = [...parser(tokens)];
11
- assert.deepEqual(codes, [{ type: CODE_TYPES.TEXT, pos: 0, raw: "hello world" }]);
12
- });
13
-
14
- test("parse mixed text and csi", () => {
15
- const input = String.raw`hello \e[31mworld\e[0m`;
16
- const tokens = tokenizer(input);
17
- const codes = [...parser(tokens)];
18
- assert.deepEqual(codes, [
19
- { type: CODE_TYPES.TEXT, pos: 0, raw: "hello " },
20
- { type: CODE_TYPES.CSI, pos: 6, raw: "\\e[31m", params: ["31"], command: "m" },
21
- { type: CODE_TYPES.TEXT, pos: 12, raw: "world" },
22
- { type: CODE_TYPES.CSI, pos: 17, raw: "\\e[0m", params: ["0"], command: "m" },
23
- ]);
24
- });
25
-
26
- test("subsequent escape sequences", () => {
27
- const input = String.raw`\e[31m\e[32m\e[33m`;
28
- const tokens = tokenizer(input);
29
- const codes = [...parser(tokens)];
30
- assert.deepEqual(codes, [
31
- { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[31m", params: ["31"], command: "m" },
32
- { type: CODE_TYPES.CSI, pos: 6, raw: "\\e[32m", params: ["32"], command: "m" },
33
- { type: CODE_TYPES.CSI, pos: 12, raw: "\\e[33m", params: ["33"], command: "m" },
34
- ]);
35
- });
36
-
37
- test("parse multiple different sequence types", () => {
38
- const input = String.raw`\e[1;32m\e]0;title\a\e=\ePdata\e\\`;
39
- const tokens = tokenizer(input);
40
- const codes = [...parser(tokens)];
41
- assert.deepEqual(codes, [
42
- { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[1;32m", params: ["1", "32"], command: "m" },
43
- { type: CODE_TYPES.OSC, pos: 8, raw: "\\e]0;title\\a", params: ["title"], command: "0" },
44
- { type: CODE_TYPES.ESC, pos: 20, raw: "\\e=", command: "=", params: [] },
45
- { type: CODE_TYPES.DCS, pos: 23, raw: "\\ePdata\\e\\\\", params: ["data"], command: "" },
46
- ]);
47
- });
48
-
49
- test("parse mixed standard and private sequences", () => {
50
- const input = String.raw`\e[31m\e[<5h\e[?25l\e[>c`;
51
- const tokens = tokenizer(input);
52
- const codes = [...parser(tokens)];
53
- assert.deepEqual(codes, [
54
- { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[31m", params: ["31"], command: "m" },
55
- { type: CODE_TYPES.PRIVATE, pos: 6, raw: "\\e[<5h", params: ["5"], command: "<h" },
56
- { type: CODE_TYPES.DEC, pos: 12, raw: "\\e[?25l", params: ["25"], command: "l" },
57
- { type: CODE_TYPES.PRIVATE, pos: 19, raw: "\\e[>c", params: [], command: ">c" },
58
- ]);
59
- });
60
-
61
- test("parse complex missing parameter scenarios", () => {
62
- const input = String.raw`\e[;5;m\e[?;h\eP$q;;\e\\`;
63
- const tokens = tokenizer(input);
64
- const codes = [...parser(tokens)];
65
- assert.deepEqual(codes, [
66
- { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[;5;m", params: ["-1", "5", "-1"], command: "m" },
67
- { type: CODE_TYPES.DEC, pos: 7, raw: "\\e[?;h", params: ["-1", "-1"], command: "h" },
68
- { type: CODE_TYPES.DCS, pos: 13, raw: "\\eP$q;;\\e\\\\", params: ["-1", "-1", "-1"], command: "$q" },
69
- ]);
70
- });
71
-
72
- test("parse iTerm2 image sequence", () => {
73
- const input = String.raw`\e]1337;File=inline=1;width=1;height=1:R0lG=\a`;
74
- const tokens = tokenizer(input);
75
- const codes = [...parser(tokens)];
76
- assert.deepEqual(codes, [
77
- { type: CODE_TYPES.OSC, pos: 0, raw: input, command: "1337", params: ["File=inline=1;width=1;height=1:R0lG="] },
78
- ]);
79
- });
80
-
81
- test("parse DECUDK sequence", () => {
82
- const input = String.raw`\eP0|23/68656c6c6f\e\\`;
83
- const tokens = tokenizer(input);
84
- const codes = [...parser(tokens)];
85
- assert.deepEqual(codes, [{ type: CODE_TYPES.DCS, pos: 0, raw: input, command: "", params: ["0|23/68656c6c6f"] }]);
86
- });
package/src/parse.test.ts DELETED
@@ -1,86 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { tokenizer } from "./tokenize.ts";
4
- import { parser } from "./parse.ts";
5
- import { CODE_TYPES } from "./constants.ts";
6
-
7
- test("parse simple text", () => {
8
- const input = "hello world";
9
- const tokens = tokenizer(input);
10
- const codes = [...parser(tokens)];
11
- assert.deepEqual(codes, [{ type: CODE_TYPES.TEXT, pos: 0, raw: "hello world" }]);
12
- });
13
-
14
- test("parse mixed text and csi", () => {
15
- const input = `hello \x1b[31mworld\x1b[0m`;
16
- const tokens = tokenizer(input);
17
- const codes = [...parser(tokens)];
18
- assert.deepEqual(codes, [
19
- { type: CODE_TYPES.TEXT, pos: 0, raw: "hello " },
20
- { type: CODE_TYPES.CSI, pos: 6, raw: "\x1b[31m", params: ["31"], command: "m" },
21
- { type: CODE_TYPES.TEXT, pos: 11, raw: "world" },
22
- { type: CODE_TYPES.CSI, pos: 16, raw: "\x1b[0m", params: ["0"], command: "m" },
23
- ]);
24
- });
25
-
26
- test("subsequent escape sequences", () => {
27
- const input = `\x1b[31m\x1b[32m\x1b[33m`;
28
- const tokens = tokenizer(input);
29
- const codes = [...parser(tokens)];
30
- assert.deepEqual(codes, [
31
- { type: CODE_TYPES.CSI, pos: 0, raw: "\x1b[31m", params: ["31"], command: "m" },
32
- { type: CODE_TYPES.CSI, pos: 5, raw: "\x1b[32m", params: ["32"], command: "m" },
33
- { type: CODE_TYPES.CSI, pos: 10, raw: "\x1b[33m", params: ["33"], command: "m" },
34
- ]);
35
- });
36
-
37
- test("parse multiple different sequence types", () => {
38
- const input = `\x1b[1;32m\x1b]0;title\x07\x1b=\x1bPdata\x1b\\`;
39
- const tokens = tokenizer(input);
40
- const codes = [...parser(tokens)];
41
- assert.deepEqual(codes, [
42
- { type: CODE_TYPES.CSI, pos: 0, raw: "\x1b[1;32m", params: ["1", "32"], command: "m" },
43
- { type: CODE_TYPES.OSC, pos: 7, raw: "\x1b]0;title\x07", params: ["title"], command: "0" },
44
- { type: CODE_TYPES.ESC, pos: 17, raw: "\x1b=", command: "=", params: [] },
45
- { type: CODE_TYPES.DCS, pos: 19, raw: "\x1bPdata\x1b\\", params: ["data"], command: "" },
46
- ]);
47
- });
48
-
49
- test("parse mixed standard and private sequences", () => {
50
- const input = `\x1b[31m\x1b[<5h\x1b[?25l\x1b[>c`;
51
- const tokens = tokenizer(input);
52
- const codes = [...parser(tokens)];
53
- assert.deepEqual(codes, [
54
- { type: CODE_TYPES.CSI, pos: 0, raw: "\x1b[31m", params: ["31"], command: "m" },
55
- { type: CODE_TYPES.PRIVATE, pos: 5, raw: "\x1b[<5h", params: ["5"], command: "<h" },
56
- { type: CODE_TYPES.DEC, pos: 10, raw: "\x1b[?25l", params: ["25"], command: "l" },
57
- { type: CODE_TYPES.PRIVATE, pos: 16, raw: "\x1b[>c", params: [], command: ">c" },
58
- ]);
59
- });
60
-
61
- test("parse complex missing parameter scenarios", () => {
62
- const input = `\x1b[;5;m\x1b[?;h\x1bP$q;;\x1b\\`;
63
- const tokens = tokenizer(input);
64
- const codes = [...parser(tokens)];
65
- assert.deepEqual(codes, [
66
- { type: CODE_TYPES.CSI, pos: 0, raw: "\x1b[;5;m", params: ["-1", "5", "-1"], command: "m" },
67
- { type: CODE_TYPES.DEC, pos: 6, raw: "\x1b[?;h", params: ["-1", "-1"], command: "h" },
68
- { type: CODE_TYPES.DCS, pos: 11, raw: "\x1bP$q;;\x1b\\", params: ["-1", "-1", "-1"], command: "$q" },
69
- ]);
70
- });
71
-
72
- test("parse iTerm2 image sequence", () => {
73
- const input = `\x1b]1337;File=inline=1;width=1;height=1:R0lG=\x07`;
74
- const tokens = tokenizer(input);
75
- const codes = [...parser(tokens)];
76
- assert.deepEqual(codes, [
77
- { type: CODE_TYPES.OSC, pos: 0, raw: input, command: "1337", params: ["File=inline=1;width=1;height=1:R0lG="] },
78
- ]);
79
- });
80
-
81
- test("parse DECUDK sequence", () => {
82
- const input = `\x1bP0|23/68656c6c6f\x1b\\`;
83
- const tokens = tokenizer(input);
84
- const codes = [...parser(tokens)];
85
- assert.deepEqual(codes, [{ type: CODE_TYPES.DCS, pos: 0, raw: input, command: "", params: ["0|23/68656c6c6f"] }]);
86
- });
package/src/parse.ts DELETED
@@ -1,111 +0,0 @@
1
- import {
2
- APC_OPEN,
3
- APC,
4
- CODE_TYPES,
5
- CSI,
6
- DCS_OPEN,
7
- DCS,
8
- DEC_OPEN,
9
- ESC,
10
- OSC,
11
- PM_OPEN,
12
- PM,
13
- PRIVATE_OPENERS,
14
- SOS_OPEN,
15
- SOS,
16
- TOKEN_TYPES,
17
- } from "./constants.ts";
18
- import { parseCSI, parsePrivateCSI } from "./parsers/csi.ts";
19
- import { parseDCS } from "./parsers/dcs.ts";
20
- import { parseDEC } from "./parsers/dec.ts";
21
- import { parseESC } from "./parsers/esc.ts";
22
- import { parseOSC } from "./parsers/osc.ts";
23
- import { tokenizer } from "./tokenize.ts";
24
- import type { CODE, TOKEN } from "./types.ts";
25
-
26
- const debug = false;
27
-
28
- function emit(token: CODE) {
29
- if (debug) console.log("code", token);
30
- return token;
31
- }
32
-
33
- export function* parser(tokens: Generator<TOKEN>): Generator<CODE> {
34
- let current = tokens.next();
35
-
36
- while (!current.done) {
37
- const token = current.value;
38
-
39
- if (token.type === TOKEN_TYPES.TEXT) {
40
- yield emit({ type: CODE_TYPES.TEXT, pos: token.pos, raw: token.raw });
41
- current = tokens.next();
42
- continue;
43
- }
44
-
45
- if (token.type === TOKEN_TYPES.INTRODUCER) {
46
- const pos = token.pos;
47
- let raw = token.raw;
48
- let data = "";
49
- let finalToken: TOKEN | undefined;
50
-
51
- current = tokens.next();
52
-
53
- while (!current.done && !finalToken) {
54
- const nextToken = current.value;
55
-
56
- if (nextToken.type === TOKEN_TYPES.DATA) {
57
- data += nextToken.raw;
58
- raw += nextToken.raw;
59
- } else if (nextToken.type === TOKEN_TYPES.FINAL) {
60
- finalToken = nextToken;
61
- raw += nextToken.raw;
62
- }
63
- current = tokens.next();
64
- }
65
-
66
- if (finalToken) {
67
- switch (token.code) {
68
- case CSI:
69
- if (data.startsWith(DEC_OPEN)) {
70
- yield emit(parseDEC(pos, raw, data, finalToken.raw));
71
- } else if (PRIVATE_OPENERS.has(data[0])) {
72
- yield emit(parsePrivateCSI(pos, raw, data, finalToken.raw));
73
- } else {
74
- yield emit(parseCSI(pos, raw, data, finalToken.raw));
75
- }
76
- break;
77
- case OSC:
78
- yield emit(parseOSC(pos, raw, data));
79
- break;
80
- case DCS:
81
- case DCS_OPEN:
82
- yield emit(parseDCS(pos, raw, data));
83
- break;
84
- case APC:
85
- case APC_OPEN:
86
- yield emit({ type: CODE_TYPES.STRING, pos, raw, command: "APC", params: data ? [data] : [] });
87
- break;
88
- case PM:
89
- case PM_OPEN:
90
- yield emit({ type: CODE_TYPES.STRING, pos, raw, command: "PM", params: data ? [data] : [] });
91
- break;
92
- case SOS:
93
- case SOS_OPEN:
94
- yield emit({ type: CODE_TYPES.STRING, pos, raw, command: "SOS", params: data ? [data] : [] });
95
- break;
96
- case ESC:
97
- yield emit(parseESC(pos, raw, finalToken.raw, data));
98
- break;
99
- }
100
- } else if (token.code === ESC) {
101
- yield emit(parseESC(pos, raw, "", ""));
102
- }
103
- } else {
104
- current = tokens.next();
105
- }
106
- }
107
- }
108
-
109
- export function parse(input: string): CODE[] {
110
- return Array.from(parser(tokenizer(input)));
111
- }
@@ -1,55 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { parseCSI, parsePrivateCSI } from "./csi.ts";
4
- import { CODE_TYPES } from "../constants.ts";
5
-
6
- test("parseCSI simple command", () => {
7
- const result = parseCSI(0, "\\e[31m", "31", "m");
8
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[31m", params: ["31"], command: "m" });
9
- });
10
-
11
- test("parseCSI with multiple params", () => {
12
- const result = parseCSI(0, "\\e[1;31m", "1;31", "m");
13
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[1;31m", params: ["1", "31"], command: "m" });
14
- });
15
-
16
- test("parseCSI with missing parameters", () => {
17
- const result = parseCSI(0, "\\e[;31m", ";31", "m");
18
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[;31m", params: ["-1", "31"], command: "m" });
19
- });
20
-
21
- test("parseCSI with trailing semicolon", () => {
22
- const result = parseCSI(0, "\\e[31;m", "31;", "m");
23
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[31;m", params: ["31", "-1"], command: "m" });
24
- });
25
-
26
- test("parseCSI with leading semicolon", () => {
27
- const result = parseCSI(0, "\\e[;m", ";", "m");
28
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[;m", params: ["-1", "-1"], command: "m" });
29
- });
30
-
31
- test("parseCSI no data", () => {
32
- const result = parseCSI(0, "\\e[m", "", "m");
33
- assert.deepEqual(result, { type: CODE_TYPES.CSI, pos: 0, raw: "\\e[m", params: [], command: "m" });
34
- });
35
-
36
- test("parsePrivateCSI with < introducer", () => {
37
- const result = parsePrivateCSI(0, "\\e[<31m", "<31", "m");
38
- assert.deepEqual(result, { type: CODE_TYPES.PRIVATE, pos: 0, raw: "\\e[<31m", params: ["31"], command: "<m" });
39
- });
40
-
41
- test("parsePrivateCSI with > introducer", () => {
42
- const result = parsePrivateCSI(0, "\\e[>c", ">", "c");
43
- assert.deepEqual(result, { type: CODE_TYPES.PRIVATE, pos: 0, raw: "\\e[>c", params: [], command: ">c" });
44
- });
45
-
46
- test("parsePrivateCSI with = introducer", () => {
47
- const result = parsePrivateCSI(0, "\\e[=1;2c", "=1;2", "c");
48
- assert.deepEqual(result, {
49
- type: CODE_TYPES.PRIVATE,
50
- pos: 0,
51
- raw: "\\e[=1;2c",
52
- params: ["1", "2"],
53
- command: "=c",
54
- });
55
- });
@@ -1,54 +0,0 @@
1
- import { CODE_TYPES } from "../constants.ts";
2
- import type { CONTROL_CODE } from "../types.ts";
3
-
4
- export function parseCSI(pos: number, raw: string, data: string, final: string): CONTROL_CODE {
5
- const params = [];
6
- let intermediates = "";
7
- if (data) {
8
- let i = 0;
9
- let paramSection = "";
10
- while (i < data.length && data.charCodeAt(i) >= 0x30 && data.charCodeAt(i) <= 0x3f) {
11
- paramSection += data[i];
12
- i++;
13
- }
14
- intermediates = data.slice(i);
15
- if (paramSection) {
16
- let current = "";
17
- for (let j = 0; j < paramSection.length; j++) {
18
- if (paramSection[j] === ";") {
19
- params.push(current || "-1");
20
- current = "";
21
- } else {
22
- current += paramSection[j];
23
- }
24
- }
25
- params.push(current || "-1");
26
- }
27
- }
28
- const command = intermediates + final;
29
- return { type: CODE_TYPES.CSI, pos, raw, command, params };
30
- }
31
-
32
- export function parsePrivateCSI(pos: number, raw: string, data: string, final: string): CONTROL_CODE {
33
- const privateIndicator = data[0];
34
- const withoutIndicator = data.slice(1);
35
- const match = withoutIndicator.match(/^([\d;]*)(.*)/);
36
- const paramsRaw = match?.[1] ?? "";
37
- const intermediates = match?.[2] ?? "";
38
- const command = `${privateIndicator}${intermediates}${final}`;
39
- const params = [];
40
- if (paramsRaw) {
41
- let current = "";
42
- for (let i = 0; i < paramsRaw.length; i++) {
43
- if (paramsRaw[i] === ";") {
44
- params.push(current || "-1");
45
- current = "";
46
- } else {
47
- current += paramsRaw[i];
48
- }
49
- }
50
- params.push(current || "-1");
51
- }
52
-
53
- return { type: CODE_TYPES.PRIVATE, pos, raw, command, params };
54
- }