prettier 2.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -6
  3. data/README.md +17 -16
  4. data/exe/rbprettier +2 -2
  5. data/lib/prettier/rake/task.rb +5 -5
  6. data/lib/prettier.rb +11 -11
  7. data/package.json +11 -25
  8. data/rubocop.yml +32 -12
  9. data/{dist/parser → src}/getInfo.js +0 -1
  10. data/{dist/parser → src}/netcat.js +0 -1
  11. data/src/parseSync.js +216 -0
  12. data/src/plugin.js +170 -0
  13. data/{dist/parser → src}/server.rb +50 -31
  14. metadata +94 -78
  15. data/bin/console +0 -7
  16. data/dist/haml/embed.js +0 -53
  17. data/dist/haml/parser.js +0 -31
  18. data/dist/haml/parser.rb +0 -149
  19. data/dist/haml/printer.js +0 -336
  20. data/dist/parser/parseSync.js +0 -179
  21. data/dist/plugin.js +0 -143
  22. data/dist/prettier.js +0 -15
  23. data/dist/rbs/parser.js +0 -34
  24. data/dist/rbs/parser.rb +0 -155
  25. data/dist/rbs/printer.js +0 -525
  26. data/dist/ruby/embed.js +0 -115
  27. data/dist/ruby/location.js +0 -19
  28. data/dist/ruby/nodes/alias.js +0 -60
  29. data/dist/ruby/nodes/aref.js +0 -51
  30. data/dist/ruby/nodes/args.js +0 -138
  31. data/dist/ruby/nodes/arrays.js +0 -122
  32. data/dist/ruby/nodes/assign.js +0 -37
  33. data/dist/ruby/nodes/blocks.js +0 -90
  34. data/dist/ruby/nodes/calls.js +0 -263
  35. data/dist/ruby/nodes/case.js +0 -50
  36. data/dist/ruby/nodes/class.js +0 -54
  37. data/dist/ruby/nodes/commands.js +0 -138
  38. data/dist/ruby/nodes/conditionals.js +0 -246
  39. data/dist/ruby/nodes/constants.js +0 -35
  40. data/dist/ruby/nodes/flow.js +0 -59
  41. data/dist/ruby/nodes/hashes.js +0 -126
  42. data/dist/ruby/nodes/heredocs.js +0 -30
  43. data/dist/ruby/nodes/hooks.js +0 -35
  44. data/dist/ruby/nodes/ints.js +0 -27
  45. data/dist/ruby/nodes/lambdas.js +0 -70
  46. data/dist/ruby/nodes/loops.js +0 -75
  47. data/dist/ruby/nodes/massign.js +0 -60
  48. data/dist/ruby/nodes/methods.js +0 -50
  49. data/dist/ruby/nodes/operators.js +0 -68
  50. data/dist/ruby/nodes/params.js +0 -95
  51. data/dist/ruby/nodes/patterns.js +0 -119
  52. data/dist/ruby/nodes/regexp.js +0 -45
  53. data/dist/ruby/nodes/rescue.js +0 -86
  54. data/dist/ruby/nodes/return.js +0 -100
  55. data/dist/ruby/nodes/statements.js +0 -110
  56. data/dist/ruby/nodes/strings.js +0 -220
  57. data/dist/ruby/nodes/super.js +0 -26
  58. data/dist/ruby/nodes/undef.js +0 -31
  59. data/dist/ruby/nodes.js +0 -177
  60. data/dist/ruby/parser.js +0 -35
  61. data/dist/ruby/parser.rb +0 -9134
  62. data/dist/ruby/printer.js +0 -67
  63. data/dist/ruby/toProc.js +0 -91
  64. data/dist/types/haml.js +0 -4
  65. data/dist/types/plugin.js +0 -3
  66. data/dist/types/rbs.js +0 -4
  67. data/dist/types/ruby.js +0 -4
  68. data/dist/types/utils.js +0 -2
  69. data/dist/types.js +0 -34
  70. data/dist/utils/containsAssignment.js +0 -18
  71. data/dist/utils/getChildNodes.js +0 -305
  72. data/dist/utils/getTrailingComma.js +0 -6
  73. data/dist/utils/hasAncestor.js +0 -15
  74. data/dist/utils/inlineEnsureParens.js +0 -49
  75. data/dist/utils/isEmptyBodyStmt.js +0 -10
  76. data/dist/utils/isEmptyParams.js +0 -12
  77. data/dist/utils/isEmptyStmts.js +0 -10
  78. data/dist/utils/literal.js +0 -8
  79. data/dist/utils/literallineWithoutBreakParent.js +0 -8
  80. data/dist/utils/makeCall.js +0 -14
  81. data/dist/utils/noIndent.js +0 -11
  82. data/dist/utils/printEmptyCollection.js +0 -46
  83. data/dist/utils/skipAssignIndent.js +0 -19
  84. data/dist/utils.js +0 -32
data/dist/rbs/printer.js DELETED
@@ -1,525 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const prettier_1 = __importDefault(require("../prettier"));
7
- const { group, hardline, indent, makeString, join, line, softline } = prettier_1.default;
8
- // For some lists of entities in the AST, the parser returns them as an unsorted
9
- // object (presumably because Ruby hashes have implicit ordering). We do not
10
- // have that in JavaScript, so here we sort each object by its position in the
11
- // source string.
12
- function getSortedKeys(object) {
13
- return Object.keys(object).sort((left, right) => object[left].type.location.start_pos -
14
- object[right].type.location.start_pos);
15
- }
16
- // In some cases, we want to just defer to whatever was in the source.
17
- function getSource(node, opts) {
18
- const { location } = node;
19
- return opts.originalText.slice(location.start_pos, location.end_pos);
20
- }
21
- const printer = {
22
- // This is the generic node print function, used to convert any node in the
23
- // AST into its equivalent Doc representation.
24
- print(path, opts, print) {
25
- const node = path.getValue();
26
- let doc = null;
27
- if (node.declarations) {
28
- // Prints out the root of the tree, which includes zero or more
29
- // declarations.
30
- return [
31
- join([hardline, hardline], path.map(print, "declarations")),
32
- hardline
33
- ];
34
- }
35
- /* istanbul ignore else */
36
- if (node.declaration) {
37
- switch (node.declaration) {
38
- // Prints out a type alias, which is a declaration that looks like:
39
- // type foo = String
40
- case "alias": {
41
- doc = group([
42
- "type ",
43
- node.name,
44
- " =",
45
- indent(group([line, path.call(printType, "type")]))
46
- ]);
47
- break;
48
- }
49
- // Prints out a class declarations, which looks like:
50
- // class Foo end
51
- case "class": {
52
- const nodePath = path;
53
- const parts = [
54
- "class ",
55
- printNameAndTypeParams(nodePath, node)
56
- ];
57
- if (node.super_class) {
58
- const superPath = nodePath;
59
- parts.push(" < ", superPath.call(printNameAndArgs, "super_class"));
60
- }
61
- parts.push(indent(printMembers(nodePath)), hardline, "end");
62
- doc = group(parts);
63
- break;
64
- }
65
- // Prints out a constant or a global declaration, which looks like:
66
- // Foo: String
67
- // $foo: String
68
- case "constant":
69
- case "global": {
70
- doc = group([node.name, ": ", path.call(printType, "type")]);
71
- break;
72
- }
73
- // Prints out an interface declaration, which looks like:
74
- // interface _Foo end
75
- case "interface": {
76
- const nodePath = path;
77
- doc = group([
78
- "interface ",
79
- printNameAndTypeParams(nodePath, node),
80
- indent(printMembers(nodePath)),
81
- hardline,
82
- "end"
83
- ]);
84
- break;
85
- }
86
- // Prints out a module declaration, which looks like:
87
- // module Foo end
88
- case "module": {
89
- const nodePath = path;
90
- const parts = [
91
- "module ",
92
- printNameAndTypeParams(nodePath, node)
93
- ];
94
- if (node.self_types.length > 0) {
95
- parts.push(" : ", join(", ", nodePath.map(printNameAndArgs, "self_types")));
96
- }
97
- parts.push(indent(printMembers(nodePath)), hardline, "end");
98
- doc = group(parts);
99
- break;
100
- }
101
- /* istanbul ignore next */
102
- default:
103
- throw new Error(`unknown declaration: ${node.declaration}`);
104
- }
105
- }
106
- else if (node.member) {
107
- switch (node.member) {
108
- // Prints out an alias within a declaration, which looks like:
109
- // alias foo bar
110
- // alias self.foo self.bar
111
- case "alias": {
112
- if (node.kind === "singleton") {
113
- doc = ["alias self.", node.new_name, " self.", node.old_name];
114
- }
115
- else {
116
- doc = ["alias ", node.new_name, " ", node.old_name];
117
- }
118
- break;
119
- }
120
- // Prints out an attr_* meta method, which looks like:
121
- // attr_accessor foo
122
- // attr_reader self.foo()
123
- // attr_writer self.foo(@bar): String
124
- case "attr_accessor":
125
- case "attr_reader":
126
- case "attr_writer": {
127
- const parts = [node.member, " "];
128
- if (node.kind === "singleton") {
129
- parts.push("self.");
130
- }
131
- parts.push(node.name);
132
- if (node.ivar_name === false) {
133
- parts.push("()");
134
- }
135
- else if (node.ivar_name) {
136
- parts.push("(", node.ivar_name, ")");
137
- }
138
- parts.push(": ", path.call(printType, "type"));
139
- doc = group(parts);
140
- break;
141
- }
142
- // Prints out a class or instance variable member, which looks like:
143
- // @foo: String
144
- // @@foo: String
145
- case "class_variable":
146
- case "instance_variable": {
147
- doc = group([node.name, ": ", path.call(printType, "type")]);
148
- break;
149
- }
150
- // Prints out a class instance variable member, which looks like:
151
- // self.@foo: String
152
- case "class_instance_variable": {
153
- doc = ["self.", node.name, ": ", path.call(printType, "type")];
154
- break;
155
- }
156
- // Prints out a mixin, which looks like:
157
- // include Foo
158
- // prepend Foo
159
- // extend Foo
160
- case "include":
161
- case "extend":
162
- case "prepend": {
163
- const nodePath = path;
164
- doc = group([node.member, " ", printNameAndArgs(nodePath)]);
165
- break;
166
- }
167
- case "public":
168
- case "private": {
169
- doc = node.member;
170
- break;
171
- }
172
- case "method_definition": {
173
- const nodePath = path;
174
- doc = printMethodDefinition(nodePath, node);
175
- break;
176
- }
177
- /* istanbul ignore next */
178
- default:
179
- throw new Error(`unknown member: ${node.member}`);
180
- }
181
- }
182
- else {
183
- const ast = JSON.stringify(node, null, 2);
184
- throw new Error(`Unsupported node encountered:\n${ast}`);
185
- }
186
- // An annotation can be attached to most kinds of nodes, and should be
187
- // printed using %a{}. Certain nodes can't have annotations at all.
188
- if (node.annotations && node.annotations.length > 0) {
189
- const annotationsPath = path;
190
- doc = [
191
- join(hardline, annotationsPath.map((annotationPath) => {
192
- const annotationNode = annotationPath.getValue();
193
- // If there are already braces inside the annotation, then we're
194
- // just going to print out the original string to avoid having to
195
- // escape anything.
196
- if (/[{}]/.test(annotationNode.string)) {
197
- return getSource(annotationNode, opts);
198
- }
199
- return ["%a{", annotationNode.string, "}"];
200
- }, "annotations")),
201
- hardline,
202
- doc
203
- ];
204
- }
205
- // Comments come in as one whole string, so here we split it up into
206
- // multiple lines and then prefix it with the pound sign.
207
- if (node.comment) {
208
- doc = [
209
- join(hardline, node.comment.string
210
- .slice(0, -1)
211
- .split("\n")
212
- .map((segment) => `# ${segment}`)),
213
- hardline,
214
- doc
215
- ];
216
- }
217
- return doc;
218
- // Prints out a string in the source, which looks like:
219
- // 'foo'
220
- function printString(node) {
221
- // We're going to go straight to the source here, as if we don't then
222
- // we're going to end up with the result of String#inspect, which does
223
- // weird things to escape sequences.
224
- const value = getSource(node, opts);
225
- // Get the quote that was used in the source and the quote that we want to
226
- // be using.
227
- const originalQuote = value[0];
228
- const preferredQuote = opts.rubySingleQuote ? "'" : '"';
229
- // Determine if we're allowed to change the quote based on whether or not
230
- // there is an escape sequence in the source string.
231
- const quote = value.match(new RegExp(`\\\\[^${originalQuote}]`))
232
- ? originalQuote
233
- : preferredQuote;
234
- return makeString(value.slice(1, -1), quote, false);
235
- }
236
- // Certain nodes are names with optional arguments attached, as in Array[A].
237
- // We handle all of that printing centralized here.
238
- function printNameAndArgs(path) {
239
- const node = path.getValue();
240
- if (node.args.length === 0) {
241
- return node.name;
242
- }
243
- return group([
244
- node.name,
245
- "[",
246
- join(", ", path.map(printType, "args")),
247
- "]"
248
- ]);
249
- }
250
- // This is the big function that prints out any individual type, which can
251
- // look like all kinds of things, listed in the case statement below.
252
- function printType(path, options) {
253
- const node = path.getValue();
254
- const forceParens = typeof options === "object" && options.forceParens;
255
- switch (node.class) {
256
- case "literal":
257
- if (node.literal[0] === '"') {
258
- return printString(node);
259
- }
260
- return node.literal;
261
- case "optional": {
262
- const nodePath = path;
263
- return [
264
- nodePath.call((typePath) => printType(typePath, { forceParens: true }), "type"),
265
- "?"
266
- ];
267
- }
268
- case "tuple": {
269
- // If we don't have any sub types, we explicitly need the space in
270
- // between the brackets to not confuse the parser.
271
- if (node.types.length === 0) {
272
- return "[ ]";
273
- }
274
- const nodePath = path;
275
- return group([
276
- "[",
277
- join(", ", nodePath.map(printType, "types")),
278
- "]"
279
- ]);
280
- }
281
- case "union": {
282
- const nodePath = path;
283
- const doc = group(join([line, "| "], nodePath.map(printType, "types")));
284
- if (forceParens) {
285
- return ["(", doc, ")"];
286
- }
287
- return doc;
288
- }
289
- case "intersection": {
290
- const nodePath = path;
291
- const doc = group(join([line, "& "], nodePath.map((typePath) => printType(typePath, { forceParens: true }), "types")));
292
- if (forceParens) {
293
- return ["(", doc, ")"];
294
- }
295
- return doc;
296
- }
297
- case "class_singleton":
298
- return ["singleton(", node.name, ")"];
299
- case "proc":
300
- return [
301
- "^",
302
- printMethodSignature(path)
303
- ];
304
- case "record": {
305
- const nodePath = path;
306
- const parts = [];
307
- getSortedKeys(node.fields).forEach((field) => {
308
- const fieldParts = [];
309
- if (node.fields[field].joiner === "rocket") {
310
- fieldParts.push(`${field} => `);
311
- }
312
- else {
313
- fieldParts.push(`${field}: `);
314
- }
315
- fieldParts.push(nodePath.call(printType, "fields", field, "type"));
316
- parts.push(fieldParts);
317
- });
318
- return group([
319
- "{",
320
- indent([line, join([",", line], parts)]),
321
- line,
322
- "}"
323
- ]);
324
- }
325
- case "class_instance":
326
- case "interface": {
327
- const nodePath = path;
328
- return printNameAndArgs(nodePath);
329
- }
330
- case "alias":
331
- case "variable":
332
- return node.name;
333
- case "bool":
334
- case "bot":
335
- case "class":
336
- case "instance":
337
- case "nil":
338
- case "self":
339
- case "top":
340
- case "untyped":
341
- case "void":
342
- return node.class;
343
- /* istanbul ignore next */
344
- default:
345
- throw new Error(`unknown type: ${node.class}`);
346
- }
347
- }
348
- // Prints out the members of a class, module, or interface.
349
- function printMembers(path) {
350
- let lastLine = null;
351
- const docs = [];
352
- path.each((memberPath) => {
353
- const memberNode = memberPath.getValue();
354
- if (lastLine !== null &&
355
- memberNode.location.start.line - lastLine >= 2) {
356
- docs.push([hardline, hardline]);
357
- }
358
- else {
359
- docs.push(hardline);
360
- }
361
- docs.push(print(memberPath));
362
- lastLine = memberNode.location.end.line;
363
- }, "members");
364
- return docs;
365
- }
366
- // Prints out the name of a class, interface, or module declaration.
367
- // Additionally loops through each type parameter if there are any and print
368
- // them out joined by commas. Checks for validation and variance.
369
- function printNameAndTypeParams(path, node) {
370
- if (node.type_params.length === 0) {
371
- return node.name;
372
- }
373
- const docs = path.map((paramPath) => {
374
- const node = paramPath.getValue();
375
- const parts = [];
376
- if (node.unchecked) {
377
- parts.push("unchecked");
378
- }
379
- if (node.variance === "covariant") {
380
- parts.push("out");
381
- }
382
- else if (node.variance === "contravariant") {
383
- parts.push("in");
384
- }
385
- if (node.upper_bound) {
386
- const path = paramPath;
387
- const upperBound = path.call(printType, "upper_bound");
388
- return join(" ", [...parts, node.name, "<", upperBound]);
389
- }
390
- else {
391
- return join(" ", [...parts, node.name]);
392
- }
393
- }, "type_params");
394
- return [node.name, "[", join(", ", docs), "]"];
395
- }
396
- // Returns an array of printed parameters so that the calling function can
397
- // join them together in whatever way.
398
- function printMethodParams(path) {
399
- const node = path.getValue();
400
- let parts = [];
401
- // required positionals, as in (A)
402
- parts = parts.concat(path.map(printMethodParam, "required_positionals"));
403
- // optional positionals, as in (?A)
404
- parts = parts.concat(path.map((paramPath) => ["?", printMethodParam(paramPath)], "optional_positionals"));
405
- // rest positional, as in (*A)
406
- if (node.rest_positionals) {
407
- const restPositionalsPath = path;
408
- parts.push([
409
- "*",
410
- restPositionalsPath.call(printMethodParam, "rest_positionals")
411
- ]);
412
- }
413
- // trailing positionals are required positionals after a rest
414
- parts = parts.concat(path.map(printMethodParam, "trailing_positionals"));
415
- // required keywords, as in (a: A)
416
- getSortedKeys(node.required_keywords).forEach((name) => {
417
- parts.push([
418
- name,
419
- ": ",
420
- path.call(printMethodParam, "required_keywords", name)
421
- ]);
422
- });
423
- // optional keywords, as in (?a: A)
424
- getSortedKeys(node.optional_keywords).forEach((name) => {
425
- parts.push([
426
- "?",
427
- name,
428
- ": ",
429
- path.call(printMethodParam, "optional_keywords", name)
430
- ]);
431
- });
432
- // rest keyword, as in (**A)
433
- if (node.rest_keywords) {
434
- const restKeywordsPath = path;
435
- parts.push([
436
- "**",
437
- restKeywordsPath.call(printMethodParam, "rest_keywords")
438
- ]);
439
- }
440
- return parts;
441
- // Prints out a method parameter at a given path. Handles printing out the
442
- // name if there is one (and whether or not it's escaped).
443
- function printMethodParam(path) {
444
- const node = path.getValue();
445
- const parts = [path.call(printType, "type")];
446
- if (node.name) {
447
- parts.push(" ");
448
- if (node.escaped) {
449
- parts.push("`", node.name, "`");
450
- }
451
- else {
452
- parts.push(node.name);
453
- }
454
- }
455
- return parts;
456
- }
457
- }
458
- // Prints out a specific method signature, which looks like:
459
- // (T t) -> void
460
- function printMethodSignature(path) {
461
- const node = path.getValue();
462
- const parts = [];
463
- // We won't have a type_params key if we're printing a block
464
- if (node.type_params && node.type_params.length > 0) {
465
- const typeParamNames = node.type_params.map((tp) => tp.name);
466
- parts.push("[", join(", ", typeParamNames), "] ");
467
- }
468
- const params = path.call(printMethodParams, "type");
469
- if (params.length > 0) {
470
- parts.push("(", indent([softline, join([",", line], params)]), softline, ") ");
471
- }
472
- if (node.block) {
473
- if (!node.block.required) {
474
- parts.push("?");
475
- }
476
- parts.push("{", indent([line, path.call(printMethodSignature, "block")]), line, "} ");
477
- }
478
- parts.push("-> ", path.call((typePath) => printType(typePath, { forceParens: true }), "type", "return_type"));
479
- return group(parts);
480
- }
481
- // Prints out a method definition, which looks like:
482
- // def t: (T t) -> void
483
- function printMethodDefinition(path, node) {
484
- let typeDocs = path.map(printMethodSignature, "types");
485
- if (node.overload) {
486
- typeDocs.push("...");
487
- }
488
- if (typeDocs.length === 1) {
489
- typeDocs = [" ", typeDocs[0]];
490
- }
491
- else {
492
- typeDocs = indent(group([line, join([line, "| "], typeDocs)]));
493
- }
494
- const parts = ["def "];
495
- if (node.kind === "singleton") {
496
- parts.push("self.");
497
- }
498
- else if (node.kind === "singleton_instance") {
499
- parts.push("self?.");
500
- }
501
- const escaped = isMethodNameEscaped();
502
- parts.push(escaped ? `\`${node.name}\`` : node.name, ":", typeDocs);
503
- return group(parts);
504
- // Determine if a method name is escaped in the original source.
505
- function isMethodNameEscaped() {
506
- const pos = node.location.start_pos + 4;
507
- const name = opts.originalText.slice(pos, pos + 2).trimStart();
508
- return name[0] === "`" && name[1] !== ":";
509
- }
510
- }
511
- },
512
- // This is an escape-hatch to ignore nodes in the tree. If you have a comment
513
- // that includes this pattern, then the entire node will be ignored and just
514
- // the original source will be printed out.
515
- hasPrettierIgnore(path) {
516
- const node = path.getValue();
517
- return ((node.comment && node.comment.string.includes("prettier-ignore")) || false);
518
- },
519
- // This function handles adding the format pragma to a source string. This is
520
- // an optional workflow for incremental adoption.
521
- insertPragma(text) {
522
- return `# @format${text[0] === "#" ? "\n" : "\n\n"}${text}`;
523
- }
524
- };
525
- exports.default = printer;
data/dist/ruby/embed.js DELETED
@@ -1,115 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const prettier_1 = __importDefault(require("../prettier"));
7
- const utils_1 = require("../utils");
8
- const { group, indent, dedent, lineSuffix, mapDoc, markAsRoot, stripTrailingHardline } = prettier_1.default;
9
- const parsers = {
10
- css: "css",
11
- javascript: "babel",
12
- js: "babel",
13
- less: "less",
14
- markdown: "markdown",
15
- ruby: "ruby",
16
- scss: "scss"
17
- };
18
- // This function is in here because it handles embedded parser values. I don't
19
- // have a test that exercises it because I'm not sure for which parser it is
20
- // necessary, but since it's in prettier core I'm keeping it here.
21
- /* istanbul ignore next */
22
- function replaceNewlines(doc) {
23
- return mapDoc(doc, (currentDoc) => typeof currentDoc === "string" && currentDoc.includes("\n")
24
- ? currentDoc
25
- .split(/(\n)/g)
26
- .map((v, i) => (i % 2 === 0 ? v : utils_1.literallineWithoutBreakParent))
27
- : currentDoc);
28
- }
29
- // Returns a number that represents the minimum amount of leading whitespace
30
- // that is present on every line in the given string. So for example if you have
31
- // the following heredoc:
32
- //
33
- // <<~HERE
34
- // my
35
- // content
36
- // here
37
- // HERE
38
- //
39
- // then the return value of this function would be 2. If you indented every line
40
- // of the inner content 2 more spaces then this function would return 4.
41
- function getCommonLeadingWhitespace(content) {
42
- const pattern = /^\s+/;
43
- return content
44
- .split("\n")
45
- .slice(0, -1)
46
- .filter((line) => line.trim().length > 0)
47
- .reduce((minimum, line) => {
48
- const matched = pattern.exec(line);
49
- const length = matched ? matched[0].length : 0;
50
- return minimum === null ? length : Math.min(minimum, length);
51
- }, content.length);
52
- }
53
- // Returns a new string with the common whitespace stripped out. Effectively it
54
- // emulates what a squiggly heredoc does in Ruby.
55
- function stripCommonLeadingWhitespace(content) {
56
- const lines = content.split("\n");
57
- const minimum = getCommonLeadingWhitespace(content);
58
- return lines.map((line) => line.slice(minimum)).join("\n");
59
- }
60
- // A type assertion so that TypeScript knows we're working with an array of
61
- // exclusively plain string content.
62
- function isTStringContentArray(body) {
63
- return body.every((part) => part.type === "tstring_content");
64
- }
65
- const embed = (path, print, textToDoc) => {
66
- const node = path.getValue();
67
- // Currently we only support embedded formatting on heredoc nodes
68
- if (node.type !== "heredoc") {
69
- return null;
70
- }
71
- // First, ensure that we don't have any interpolation
72
- const { beging, parts, ending } = node;
73
- const isSquiggly = beging.value[2] === "~";
74
- if (!isTStringContentArray(parts)) {
75
- return null;
76
- }
77
- // Next, find the parser associated with this heredoc (if there is one). For
78
- // example, if you use <<~CSS, we'd hook it up to the css parser.
79
- const parser = parsers[beging.value.slice(3).toLowerCase()];
80
- if (!parser) {
81
- return null;
82
- }
83
- // Get the content as if it were a source string.
84
- let content = parts.map((part) => part.value).join("");
85
- // If we're using a squiggly heredoc, then we're going to manually strip off
86
- // the leading whitespace of each line up to the minimum leading whitespace so
87
- // that the embedded parser can handle that for us.
88
- if (isSquiggly) {
89
- content = stripCommonLeadingWhitespace(content);
90
- }
91
- // Pass that content into the embedded parser. Get back the doc node.
92
- const formatted = [
93
- utils_1.literallineWithoutBreakParent,
94
- replaceNewlines(stripTrailingHardline(textToDoc(content, { parser })))
95
- ];
96
- // If we're using a squiggly heredoc, then we can properly handle indentation
97
- // ourselves.
98
- if (isSquiggly) {
99
- return [
100
- path.call(print, "beging"),
101
- lineSuffix(dedent([
102
- indent(markAsRoot(formatted)),
103
- { type: "line", hard: true },
104
- ending.trim()
105
- ]))
106
- ];
107
- }
108
- // Otherwise, we need to just assume it's formatted correctly and return the
109
- // content as it is.
110
- return markAsRoot([
111
- path.call(print, "beging"),
112
- lineSuffix(group([formatted, utils_1.literallineWithoutBreakParent, ending.trim()]))
113
- ]);
114
- };
115
- exports.default = embed;
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEndChar = exports.getEndLine = exports.getStartChar = exports.getStartLine = void 0;
4
- function getStartLine(location) {
5
- return location[0];
6
- }
7
- exports.getStartLine = getStartLine;
8
- function getStartChar(location) {
9
- return location[1];
10
- }
11
- exports.getStartChar = getStartChar;
12
- function getEndLine(location) {
13
- return location[2];
14
- }
15
- exports.getEndLine = getEndLine;
16
- function getEndChar(location) {
17
- return location[3];
18
- }
19
- exports.getEndChar = getEndChar;