esrap 1.3.7 → 1.4.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
@@ -35,12 +35,29 @@ If the nodes of the input AST have `loc` properties (e.g. the AST was generated
35
35
 
36
36
  ## Options
37
37
 
38
- You can pass information that will be added to the resulting sourcemap (note that the AST is assumed to come from a single file):
38
+ You can pass the following options:
39
39
 
40
40
  ```js
41
41
  const { code, map } = print(ast, {
42
+ // Populate the `sources` field of the resulting sourcemap
43
+ // (note that the AST is assumed to come from a single file)
42
44
  sourceMapSource: 'input.js',
43
- sourceMapContent: fs.readFileSync('input.js', 'utf-8')
45
+
46
+ // Populate the `sourcesContent` field of the resulting sourcemap
47
+ sourceMapContent: fs.readFileSync('input.js', 'utf-8'),
48
+
49
+ // Whether to encode the `mappings` field of the resulting sourcemap
50
+ // as a VLQ string, rather than an unencoded array. Defaults to `true`
51
+ sourceMapEncodeMappings: false,
52
+
53
+ // String to use for indentation — defaults to '\t'
54
+ indent: ' ',
55
+
56
+ // Whether to wrap strings in single or double quotes — defaults to 'single'.
57
+ // This only applies to string literals with no `raw` value, which generally
58
+ // means the AST node was generated programmatically, rather than parsed
59
+ // from an original source
60
+ quotes: 'single'
44
61
  });
45
62
  ```
46
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esrap",
3
- "version": "1.3.7",
3
+ "version": "1.4.1",
4
4
  "description": "Parse in reverse",
5
5
  "repository": {
6
6
  "type": "git",
package/src/handlers.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** @import { TSESTree } from '@typescript-eslint/types' */
2
- /** @import { Chunk, Command, Dedent, Handlers, Indent, Newline, NodeWithComments, Sequence, State, TypeAnnotationNodes } from './types' */
2
+ /** @import { Command, Dedent, Handlers, Location, Indent, Newline, NodeWithComments, State, TypeAnnotationNodes } from './types' */
3
3
 
4
4
  /** @type {Newline} */
5
5
  const newline = { type: 'Newline' };
@@ -11,11 +11,10 @@ const indent = { type: 'Indent' };
11
11
  const dedent = { type: 'Dedent' };
12
12
 
13
13
  /**
14
- * @param {Command[]} children
15
- * @returns {Sequence}
14
+ * @returns {Command[]}
16
15
  */
17
- function create_sequence(...children) {
18
- return { type: 'Sequence', children };
16
+ function create_sequence() {
17
+ return [];
19
18
  }
20
19
 
21
20
  /**
@@ -30,11 +29,11 @@ function measure(commands, from, to = commands.length) {
30
29
  const command = commands[i];
31
30
  if (typeof command === 'string') {
32
31
  total += command.length;
33
- } else if (command.type === 'Chunk') {
34
- total += command.content.length;
35
- } else if (command.type === 'Sequence') {
36
- // assume this is ', '
37
- total += 2;
32
+ } else if (Array.isArray(command)) {
33
+ total +=
34
+ command.length === 0
35
+ ? 2 // assume this is ', '
36
+ : measure(command, 0);
38
37
  }
39
38
  }
40
39
 
@@ -66,17 +65,32 @@ export function handle(node, state) {
66
65
  }
67
66
  }
68
67
 
68
+ /**
69
+ * @param {number} line
70
+ * @param {number} column
71
+ * @returns {Location}
72
+ */
73
+ function l(line, column) {
74
+ return {
75
+ type: 'Location',
76
+ line,
77
+ column
78
+ };
79
+ }
80
+
69
81
  /**
70
82
  * @param {string} content
71
83
  * @param {TSESTree.Node} node
72
- * @returns {Chunk}
84
+ * @returns {string | Command[]}
73
85
  */
74
86
  function c(content, node) {
75
- return {
76
- type: 'Chunk',
77
- content,
78
- loc: node?.loc ?? null
79
- };
87
+ return node.loc
88
+ ? [
89
+ l(node.loc.start.line, node.loc.start.column),
90
+ content,
91
+ l(node.loc.end.line, node.loc.end.column)
92
+ ]
93
+ : content;
80
94
  }
81
95
 
82
96
  /**
@@ -96,6 +110,33 @@ function prepend_comments(comments, state, newlines) {
96
110
  }
97
111
  }
98
112
 
113
+ /**
114
+ * @param {string} string
115
+ * @param {'\'' | '"'} char
116
+ */
117
+ function quote(string, char) {
118
+ let out = char;
119
+ let escaped = false;
120
+
121
+ for (const c of string) {
122
+ if (escaped) {
123
+ out += c;
124
+ escaped = false;
125
+ } else if (c === '\\') {
126
+ out += '\\\\';
127
+ escaped = true;
128
+ } else if (c === char) {
129
+ out += '\\' + c;
130
+ } else if (c === '\n') {
131
+ out += '\\n';
132
+ } else {
133
+ out += c;
134
+ }
135
+ }
136
+
137
+ return out + char;
138
+ }
139
+
99
140
  const OPERATOR_PRECEDENCE = {
100
141
  '||': 2,
101
142
  '&&': 3,
@@ -280,7 +321,7 @@ const handle_body = (nodes, state) => {
280
321
  grouped_expression_types.includes(last_statement.type)) &&
281
322
  last_statement.type !== statement.type)
282
323
  ) {
283
- margin.children.push('\n');
324
+ margin.push('\n');
284
325
  }
285
326
 
286
327
  let add_newline = false;
@@ -324,11 +365,11 @@ const handle_var_declaration = (node, state) => {
324
365
 
325
366
  if (multiline) {
326
367
  state.multiline = true;
327
- if (node.declarations.length > 1) open.children.push(indent);
328
- join.children.push(',', newline);
368
+ if (node.declarations.length > 1) open.push(indent);
369
+ join.push(',', newline);
329
370
  if (node.declarations.length > 1) state.commands.push(dedent);
330
371
  } else {
331
- join.children.push(', ');
372
+ join.push(', ');
332
373
  }
333
374
  };
334
375
 
@@ -400,13 +441,13 @@ function sequence(nodes, state, spaces, fn, separator = ',') {
400
441
  if (multiline) {
401
442
  state.multiline = true;
402
443
 
403
- open.children.push(indent, newline);
404
- join.children.push(newline);
405
- close.children.push(dedent, newline);
444
+ open.push(indent, newline);
445
+ join.push(newline);
446
+ close.push(dedent, newline);
406
447
  } else {
407
- if (spaces) open.children.push(' ');
408
- join.children.push(' ');
409
- if (spaces) close.children.push(' ');
448
+ if (spaces) open.push(' ');
449
+ join.push(' ');
450
+ if (spaces) close.push(' ');
410
451
  }
411
452
  }
412
453
 
@@ -702,11 +743,11 @@ const shared = {
702
743
  }
703
744
 
704
745
  if (multiline) {
705
- open.children.push(indent, newline);
706
- join.children.push(',', newline);
707
- close.children.push(dedent, newline);
746
+ open.push(indent, newline);
747
+ join.push(',', newline);
748
+ close.push(dedent, newline);
708
749
  } else {
709
- join.children.push(', ');
750
+ join.push(', ');
710
751
  }
711
752
  },
712
753
 
@@ -898,12 +939,12 @@ const handlers = {
898
939
  const multiline = child_state.multiline;
899
940
 
900
941
  if (multiline) {
901
- if_true.children.push(indent, newline, '? ');
902
- if_false.children.push(newline, ': ');
942
+ if_true.push(indent, newline, '? ');
943
+ if_false.push(newline, ': ');
903
944
  state.commands.push(dedent);
904
945
  } else {
905
- if_true.children.push(' ? ');
906
- if_false.children.push(' : ');
946
+ if_true.push(' ? ');
947
+ if_false.push(' : ');
907
948
  }
908
949
  },
909
950
 
@@ -1125,9 +1166,9 @@ const handlers = {
1125
1166
  // TODO do we need to handle weird unicode characters somehow?
1126
1167
  // str.replace(/\\u(\d{4})/g, (m, n) => String.fromCharCode(+n))
1127
1168
 
1128
- let value = node.raw;
1129
- if (!value)
1130
- value = typeof node.value === 'string' ? JSON.stringify(node.value) : String(node.value);
1169
+ const value =
1170
+ node.raw ||
1171
+ (typeof node.value === 'string' ? quote(node.value, state.quote) : String(node.value));
1131
1172
 
1132
1173
  state.commands.push(c(value, node));
1133
1174
  },
package/src/index.js CHANGED
@@ -37,7 +37,8 @@ export function print(node, opts = {}) {
37
37
  const state = {
38
38
  commands: [],
39
39
  comments: [],
40
- multiline: false
40
+ multiline: false,
41
+ quote: opts.quotes === 'double' ? '"' : "'"
41
42
  };
42
43
 
43
44
  handle(/** @type {TSESTree.Node} */ (node), state);
@@ -69,6 +70,7 @@ export function print(node, opts = {}) {
69
70
  }
70
71
 
71
72
  let newline = '\n';
73
+ const indent = opts.indent ?? '\t';
72
74
 
73
75
  /** @param {Command} command */
74
76
  function run(command) {
@@ -77,30 +79,21 @@ export function print(node, opts = {}) {
77
79
  return;
78
80
  }
79
81
 
80
- switch (command.type) {
81
- case 'Chunk':
82
- const loc = command.loc;
83
-
84
- if (loc) {
85
- current_line.push([
86
- current_column,
87
- 0, // source index is always zero
88
- loc.start.line - 1,
89
- loc.start.column
90
- ]);
91
- }
92
-
93
- append(command.content);
94
-
95
- if (loc) {
96
- current_line.push([
97
- current_column,
98
- 0, // source index is always zero
99
- loc.end.line - 1,
100
- loc.end.column
101
- ]);
102
- }
82
+ if (Array.isArray(command)) {
83
+ for (let i = 0; i < command.length; i += 1) {
84
+ run(command[i]);
85
+ }
86
+ return;
87
+ }
103
88
 
89
+ switch (command.type) {
90
+ case 'Location':
91
+ current_line.push([
92
+ current_column,
93
+ 0, // source index is always zero
94
+ command.line - 1,
95
+ command.column
96
+ ]);
104
97
  break;
105
98
 
106
99
  case 'Newline':
@@ -108,18 +101,11 @@ export function print(node, opts = {}) {
108
101
  break;
109
102
 
110
103
  case 'Indent':
111
- newline += '\t';
104
+ newline += indent;
112
105
  break;
113
106
 
114
107
  case 'Dedent':
115
- newline = newline.slice(0, -1);
116
- break;
117
-
118
- case 'Sequence':
119
- for (let i = 0; i < command.children.length; i += 1) {
120
- run(command.children[i]);
121
- }
122
-
108
+ newline = newline.slice(0, -indent.length);
123
109
  break;
124
110
 
125
111
  case 'Comment':
package/src/types.d.ts CHANGED
@@ -35,15 +35,13 @@ export interface State {
35
35
  commands: Command[];
36
36
  comments: TSESTree.Comment[];
37
37
  multiline: boolean;
38
+ quote: "'" | '"';
38
39
  }
39
40
 
40
- export interface Chunk {
41
- type: 'Chunk';
42
- content: string;
43
- loc: null | {
44
- start: { line: number; column: number };
45
- end: { line: number; column: number };
46
- };
41
+ export interface Location {
42
+ type: 'Location';
43
+ line: number;
44
+ column: number;
47
45
  }
48
46
 
49
47
  export interface Newline {
@@ -63,20 +61,17 @@ export interface IndentChange {
63
61
  offset: number;
64
62
  }
65
63
 
66
- export interface Sequence {
67
- type: 'Sequence';
68
- children: Command[];
69
- }
70
-
71
64
  export interface CommentChunk {
72
65
  type: 'Comment';
73
66
  comment: TSESTree.Comment;
74
67
  }
75
68
 
76
- export type Command = string | Chunk | Newline | Indent | Dedent | Sequence | CommentChunk;
69
+ export type Command = string | Location | Newline | Indent | Dedent | CommentChunk | Command[];
77
70
 
78
71
  export interface PrintOptions {
79
72
  sourceMapSource?: string;
80
73
  sourceMapContent?: string;
81
74
  sourceMapEncodeMappings?: boolean; // default true
75
+ indent?: string; // default tab
76
+ quotes?: 'single' | 'double'; // default single
82
77
  }
package/types/index.d.ts CHANGED
@@ -3,6 +3,8 @@ declare module 'esrap' {
3
3
  sourceMapSource?: string;
4
4
  sourceMapContent?: string;
5
5
  sourceMapEncodeMappings?: boolean; // default true
6
+ indent?: string; // default tab
7
+ quotes?: 'single' | 'double'; // default single
6
8
  }
7
9
  /**
8
10
  * @returns // TODO
@@ -13,6 +13,6 @@
13
13
  null,
14
14
  null
15
15
  ],
16
- "mappings": ";kBA6EiBA,YAAYA;;;;;;;;iBCtDbC,KAAKA",
16
+ "mappings": ";kBAsEiBA,YAAYA;;;;;;;;;;iBC/CbC,KAAKA",
17
17
  "ignoreList": []
18
18
  }