@weborigami/language 0.4.2 → 0.5.0

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.
@@ -72,16 +72,11 @@ describe("Origami parser", () => {
72
72
  [ops.literal, "src/"],
73
73
  [ops.literal, "assets"],
74
74
  ]);
75
- assertParse(
76
- "angleBracketLiteral",
77
- "<https://example.com/data.yaml>",
78
- [
79
- [markers.global, "https:"],
80
- [ops.literal, "example.com/"],
81
- [ops.literal, "data.yaml"],
82
- ],
83
- "jse"
84
- );
75
+ assertParse("angleBracketLiteral", "<https://example.com/data.yaml>", [
76
+ [markers.global, "https:"],
77
+ [ops.literal, "example.com/"],
78
+ [ops.literal, "data.yaml"],
79
+ ]);
85
80
  });
86
81
  });
87
82
 
@@ -313,6 +308,7 @@ describe("Origami parser", () => {
313
308
  [ops.literal, "assets"],
314
309
  ]);
315
310
  assertParse("callExpression", "<node:process>.env", [
311
+ ops.property,
316
312
  [
317
313
  [markers.global, "node:"],
318
314
  [ops.literal, "process"],
@@ -475,17 +471,21 @@ Body`,
475
471
 
476
472
  test("property acccess", () => {
477
473
  assertParse("expression", "(foo).bar", [
474
+ ops.property,
478
475
  [markers.traverse, [markers.reference, "foo"]],
479
476
  [ops.literal, "bar"],
480
477
  ]);
481
478
  assertParse("expression", "(foo).bar.baz", [
479
+ ops.property,
482
480
  [
481
+ ops.property,
483
482
  [markers.traverse, [markers.reference, "foo"]],
484
483
  [ops.literal, "bar"],
485
484
  ],
486
485
  [ops.literal, "baz"],
487
486
  ]);
488
487
  assertParse("expression", "foo[bar]", [
488
+ ops.property,
489
489
  [markers.traverse, [markers.reference, "foo"]],
490
490
  [markers.traverse, [markers.reference, "bar"]],
491
491
  ]);
@@ -500,7 +500,7 @@ Body`,
500
500
  "expression",
501
501
  "x //comment",
502
502
  [markers.traverse, [markers.reference, "x"]],
503
- "jse",
503
+ "program",
504
504
  false
505
505
  );
506
506
  });
@@ -557,7 +557,7 @@ Body`,
557
557
  [
558
558
  ops.lambda,
559
559
  [[ops.literal, "_"]],
560
- [ops.templateTree, [ops.literal, ["x"]]],
560
+ [ops.templateText, [ops.literal, ["x"]]],
561
561
  ],
562
562
  ]);
563
563
  assertParse("expression", "copy app.js(formulas), files:snapshot", [
@@ -577,7 +577,7 @@ Body`,
577
577
  ops.lambda,
578
578
  [[ops.literal, "_"]],
579
579
  [
580
- ops.templateTree,
580
+ ops.templateText,
581
581
  [ops.literal, ["<li>", "</li>"]],
582
582
  [markers.traverse, [markers.reference, "_"]],
583
583
  ],
@@ -679,7 +679,7 @@ Body`,
679
679
  [[ops.literal, "name"]],
680
680
  [[markers.traverse, [markers.reference, "_template"]], undefined],
681
681
  ],
682
- "jse",
682
+ "program",
683
683
  false
684
684
  );
685
685
  });
@@ -709,8 +709,8 @@ Body`,
709
709
  });
710
710
 
711
711
  test("identifier", () => {
712
- assertParse("identifier", "foo", "foo", "jse", false);
713
- assertParse("identifier", "$Δelta", "$Δelta", "jse", false);
712
+ assertParse("identifier", "foo", "foo", "program", false);
713
+ assertParse("identifier", "$Δelta", "$Δelta", "program", false);
714
714
  assertThrows(
715
715
  "identifier",
716
716
  "1stCharacterIsNumber",
@@ -841,7 +841,7 @@ Body`,
841
841
  "multiLineComment",
842
842
  "/*\nHello, world!\n*/",
843
843
  null,
844
- "jse",
844
+ "program",
845
845
  false
846
846
  );
847
847
  });
@@ -895,110 +895,87 @@ Body`,
895
895
  assertParse("numericLiteral", "123.45", [ops.literal, 123.45]);
896
896
  });
897
897
 
898
- test("objectLiteral", () => {
899
- assertParse("objectLiteral", "{}", [ops.object]);
900
- assertParse("objectLiteral", "{ a: 1, b }", [
901
- ops.object,
902
- ["a", [ops.literal, 1]],
903
- ["b", [markers.traverse, [markers.reference, "b"]]],
904
- ]);
905
- assertParse("objectLiteral", "{ sub: { a: 1 } }", [
906
- ops.object,
907
- ["sub", [ops.object, ["a", [ops.literal, 1]]]],
908
- ]);
909
- assertParse("objectLiteral", "{ sub: { a/: 1 } }", [
910
- ops.object,
911
- ["sub", [ops.object, ["a/", [ops.literal, 1]]]],
912
- ]);
913
- assertParse("objectLiteral", `{ "a": 1, "b": 2 }`, [
914
- ops.object,
915
- ["a", [ops.literal, 1]],
916
- ["b", [ops.literal, 2]],
917
- ]);
918
- assertParse("objectLiteral", "{ a = b, b = 2 }", [
919
- ops.object,
920
- ["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
921
- ["b", [ops.literal, 2]],
922
- ]);
923
- assertParse(
924
- "objectLiteral",
925
- `{
926
- a = b
927
- b = 2
928
- }`,
929
- [
898
+ describe("objectLiteral", () => {
899
+ describe("basic objects", () => {
900
+ assertParse("objectLiteral", "{}", [ops.object]);
901
+ assertParse("objectLiteral", "{ a: 1, b }", [
902
+ ops.object,
903
+ ["a", [ops.literal, 1]],
904
+ ["b", [markers.traverse, [markers.reference, "b"]]],
905
+ ]);
906
+ assertParse("objectLiteral", "{ sub: { a: 1 } }", [
907
+ ops.object,
908
+ ["sub", [ops.object, ["a", [ops.literal, 1]]]],
909
+ ]);
910
+ assertParse("objectLiteral", "{ sub: { a/: 1 } }", [
911
+ ops.object,
912
+ ["sub", [ops.object, ["a/", [ops.literal, 1]]]],
913
+ ]);
914
+ assertParse("objectLiteral", `{ "a": 1, "b": 2 }`, [
915
+ ops.object,
916
+ ["a", [ops.literal, 1]],
917
+ ["b", [ops.literal, 2]],
918
+ ]);
919
+ assertParse("objectLiteral", "{ a = b, b = 2 }", [
930
920
  ops.object,
931
921
  ["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
932
922
  ["b", [ops.literal, 2]],
933
- ]
934
- );
935
- assertParse("objectLiteral", "{ a: { b: 1 } }", [
936
- ops.object,
937
- ["a", [ops.object, ["b", [ops.literal, 1]]]],
938
- ]);
939
- assertParse("objectLiteral", "{ a: { b = 1 } }", [
940
- ops.object,
941
- ["a", [ops.object, ["b", [ops.literal, 1]]]],
942
- ]);
943
- assertParse("objectLiteral", "{ a: { b = fn() } }", [
944
- ops.object,
945
- [
946
- "a",
923
+ ]);
924
+ assertParse(
925
+ "objectLiteral",
926
+ `{
927
+ a = b
928
+ b = 2
929
+ }`,
947
930
  [
948
931
  ops.object,
932
+ ["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
933
+ ["b", [ops.literal, 2]],
934
+ ]
935
+ );
936
+ assertParse("objectLiteral", "{ a: { b: 1 } }", [
937
+ ops.object,
938
+ ["a", [ops.object, ["b", [ops.literal, 1]]]],
939
+ ]);
940
+ assertParse("objectLiteral", "{ a: { b = 1 } }", [
941
+ ops.object,
942
+ ["a", [ops.object, ["b", [ops.literal, 1]]]],
943
+ ]);
944
+ assertParse("objectLiteral", "{ a: { b = fn() } }", [
945
+ ops.object,
946
+ [
947
+ "a",
949
948
  [
950
- "b",
949
+ ops.object,
951
950
  [
952
- ops.getter,
953
- [[markers.traverse, [markers.reference, "fn"]], undefined],
951
+ "b",
952
+ [
953
+ ops.getter,
954
+ [[markers.traverse, [markers.reference, "fn"]], undefined],
955
+ ],
954
956
  ],
955
957
  ],
956
958
  ],
957
- ],
958
- ]);
959
- assertParse("objectLiteral", "{ x = fn.js('a') }", [
960
- ops.object,
961
- [
962
- "x",
963
- [
964
- ops.getter,
965
- [
966
- [markers.traverse, [markers.reference, "fn.js"]],
967
- [ops.literal, "a"],
968
- ],
969
- ],
970
- ],
971
- ]);
972
- assertParse("objectLiteral", "{ a: 1, ...more, c: a }", [
973
- [
959
+ ]);
960
+ assertParse("objectLiteral", "{ x = fn.js('a') }", [
974
961
  ops.object,
975
- ["a", [ops.literal, 1]],
976
- ["c", [markers.traverse, [markers.reference, "a"]]],
977
962
  [
978
- "_result",
963
+ "x",
979
964
  [
980
- ops.merge,
981
- [ops.object, ["a", [ops.getter, [[ops.context, 1], "a"]]]],
982
- [markers.traverse, [markers.reference, "more"]],
983
- [ops.object, ["c", [ops.getter, [[ops.context, 1], "c"]]]],
965
+ ops.getter,
966
+ [
967
+ [markers.traverse, [markers.reference, "fn.js"]],
968
+ [ops.literal, "a"],
969
+ ],
984
970
  ],
985
971
  ],
986
- ],
987
- "_result",
988
- ]);
989
- assertParse("objectLiteral", "{ a: 1, ...{ b: 2 } }", [
990
- ops.object,
991
- ["a", [ops.literal, 1]],
992
- ["b", [ops.literal, 2]],
993
- ]);
994
- assertParse("objectLiteral", "{ (a): 1 }", [
995
- ops.object,
996
- ["(a)", [ops.literal, 1]],
997
- ]);
998
- assertParse(
999
- "objectLiteral",
1000
- "{ <path/to/file.txt> }",
1001
- [
972
+ ]);
973
+
974
+ assertParse("objectLiteral", "{ (a): 1 }", [
975
+ ops.object,
976
+ ["(a)", [ops.literal, 1]],
977
+ ]);
978
+ assertParse("objectLiteral", "{ <path/to/file.txt> }", [
1002
979
  ops.object,
1003
980
  [
1004
981
  "file.txt",
@@ -1009,9 +986,37 @@ Body`,
1009
986
  [ops.literal, "file.txt"],
1010
987
  ],
1011
988
  ],
1012
- ],
1013
- "jse"
1014
- );
989
+ ]);
990
+ });
991
+
992
+ describe("spreads", () => {
993
+ assertParse("objectLiteral", "{ ...x }", [
994
+ ops.unpack,
995
+ [markers.traverse, [markers.reference, "x"]],
996
+ ]);
997
+ assertParse("objectLiteral", "{ a: 1, ...more, c: a }", [
998
+ [
999
+ ops.object,
1000
+ ["a", [ops.literal, 1]],
1001
+ ["c", [markers.traverse, [markers.reference, "a"]]],
1002
+ [
1003
+ "_result",
1004
+ [
1005
+ ops.merge,
1006
+ [ops.object, ["a", [ops.getter, [[ops.context, 1], "a"]]]],
1007
+ [markers.traverse, [markers.reference, "more"]],
1008
+ [ops.object, ["c", [ops.getter, [[ops.context, 1], "c"]]]],
1009
+ ],
1010
+ ],
1011
+ ],
1012
+ "_result",
1013
+ ]);
1014
+ assertParse("objectLiteral", "{ a: 1, ...{ b: 2 } }", [
1015
+ ops.object,
1016
+ ["a", [ops.literal, 1]],
1017
+ ["b", [ops.literal, 2]],
1018
+ ]);
1019
+ });
1015
1020
  });
1016
1021
 
1017
1022
  test("objectEntry", () => {
@@ -1027,20 +1032,15 @@ Body`,
1027
1032
  "a",
1028
1033
  [markers.traverse, [markers.reference, "a"]],
1029
1034
  ]);
1030
- assertParse(
1031
- "objectEntry",
1032
- "<path/to/file.txt>",
1035
+ assertParse("objectEntry", "<path/to/file.txt>", [
1036
+ "file.txt",
1033
1037
  [
1034
- "file.txt",
1035
- [
1036
- markers.traverse,
1037
- [markers.external, "path/"],
1038
- [ops.literal, "to/"],
1039
- [ops.literal, "file.txt"],
1040
- ],
1038
+ markers.traverse,
1039
+ [markers.external, "path/"],
1040
+ [ops.literal, "to/"],
1041
+ [ops.literal, "file.txt"],
1041
1042
  ],
1042
- "jse"
1043
- );
1043
+ ]);
1044
1044
  assertParse("objectEntry", "a: (a) => a", [
1045
1045
  "a",
1046
1046
  [
@@ -1252,7 +1252,7 @@ Body`,
1252
1252
  'Hello'
1253
1253
  `,
1254
1254
  [ops.literal, "Hello"],
1255
- "jse",
1255
+ "program",
1256
1256
  false
1257
1257
  );
1258
1258
  });
@@ -1312,7 +1312,7 @@ Body`,
1312
1312
  ops.lambda,
1313
1313
  [[ops.literal, "_"]],
1314
1314
  [
1315
- ops.templateTree,
1315
+ ops.templateText,
1316
1316
  [ops.literal, ["Hello, ", "."]],
1317
1317
  [markers.traverse, [markers.reference, "name"]],
1318
1318
  ],
@@ -1328,7 +1328,13 @@ Body`,
1328
1328
  });
1329
1329
 
1330
1330
  test("singleLineComment", () => {
1331
- assertParse("singleLineComment", "// Hello, world!", null, "jse", false);
1331
+ assertParse(
1332
+ "singleLineComment",
1333
+ "// Hello, world!",
1334
+ null,
1335
+ "program",
1336
+ false
1337
+ );
1332
1338
  });
1333
1339
 
1334
1340
  test("spreadElement", () => {
@@ -1336,10 +1342,6 @@ Body`,
1336
1342
  ops.spread,
1337
1343
  [markers.traverse, [markers.reference, "a"]],
1338
1344
  ]);
1339
- assertParse("spreadElement", "…a", [
1340
- ops.spread,
1341
- [markers.traverse, [markers.reference, "a"]],
1342
- ]);
1343
1345
  });
1344
1346
 
1345
1347
  test("stringLiteral", () => {
@@ -1386,7 +1388,6 @@ Body text`,
1386
1388
  [
1387
1389
  ops.object,
1388
1390
  ["title", [ops.literal, "Title goes here"]],
1389
- ["(@text)", [ops.templateIndent, [ops.literal, ["Body text"]]]],
1390
1391
  ["_body", [ops.templateIndent, [ops.literal, ["Body text"]]]],
1391
1392
  ]
1392
1393
  );
@@ -1398,7 +1399,7 @@ Body text`,
1398
1399
  `---
1399
1400
  {
1400
1401
  title: "Title"
1401
- @text: @template()
1402
+ _body: _template()
1402
1403
  }
1403
1404
  ---
1404
1405
  <h1>\${ title }</h1>
@@ -1407,7 +1408,7 @@ Body text`,
1407
1408
  ops.object,
1408
1409
  ["title", [ops.literal, "Title"]],
1409
1410
  [
1410
- "@text",
1411
+ "_body",
1411
1412
  [
1412
1413
  ops.templateIndent,
1413
1414
  [ops.literal, ["<h1>", "</h1>\n"]],
@@ -1441,34 +1442,31 @@ Body text`,
1441
1442
  [markers.traverse, [markers.reference, "title"]],
1442
1443
  ],
1443
1444
  ],
1444
- ],
1445
- "jse"
1445
+ ]
1446
1446
  );
1447
1447
  });
1448
1448
 
1449
1449
  test("templateLiteral", () => {
1450
1450
  assertParse("templateLiteral", "`Hello, world.`", [
1451
- ops.templateTree,
1451
+ ops.templateText,
1452
+ [ops.literal, ["Hello, world."]],
1453
+ ]);
1454
+ assertParse("templateLiteral", "`Hello, world.`", [
1455
+ ops.templateText,
1452
1456
  [ops.literal, ["Hello, world."]],
1453
1457
  ]);
1454
- assertParse(
1455
- "templateLiteral",
1456
- "`Hello, world.`",
1457
- [ops.templateTree, [ops.literal, ["Hello, world."]]],
1458
- "jse"
1459
- );
1460
1458
  assertParse("templateLiteral", "`foo ${x} bar`", [
1461
- ops.templateTree,
1459
+ ops.templateText,
1462
1460
  [ops.literal, ["foo ", " bar"]],
1463
1461
  [markers.traverse, [markers.reference, "x"]],
1464
1462
  ]);
1465
1463
  assertParse("templateLiteral", "`${`nested`}`", [
1466
- ops.templateTree,
1464
+ ops.templateText,
1467
1465
  [ops.literal, ["", ""]],
1468
- [ops.templateTree, [ops.literal, ["nested"]]],
1466
+ [ops.templateText, [ops.literal, ["nested"]]],
1469
1467
  ]);
1470
1468
  assertParse("templateLiteral", "`${ map(people, =`${name}`) }`", [
1471
- ops.templateTree,
1469
+ ops.templateText,
1472
1470
  [ops.literal, ["", ""]],
1473
1471
  [
1474
1472
  [markers.traverse, [markers.reference, "map"]],
@@ -1477,7 +1475,7 @@ Body text`,
1477
1475
  ops.lambda,
1478
1476
  [[ops.literal, "_"]],
1479
1477
  [
1480
- ops.templateTree,
1478
+ ops.templateText,
1481
1479
  [ops.literal, ["", ""]],
1482
1480
  [markers.traverse, [markers.reference, "name"]],
1483
1481
  ],
@@ -1562,7 +1560,7 @@ Body text`,
1562
1560
  // Second comment
1563
1561
  `,
1564
1562
  null,
1565
- "jse",
1563
+ "program",
1566
1564
  false
1567
1565
  );
1568
1566
  });
@@ -1596,7 +1594,7 @@ function assertParse(
1596
1594
  assertCodeEqual(code, expected);
1597
1595
  }
1598
1596
 
1599
- function assertThrows(startRule, source, message, position, mode = "shell") {
1597
+ function assertThrows(startRule, source, message, position, mode = "program") {
1600
1598
  // @ts-ignore We declare this so we can inspect it in debugger
1601
1599
  let code;
1602
1600
  try {
@@ -246,7 +246,7 @@ describe("ops", () => {
246
246
  test("ops.merge", async () => {
247
247
  // {
248
248
  // a: 1
249
- // more
249
+ // ...more
250
250
  // c: a
251
251
  // }
252
252
  const scope = new ObjectTree({
@@ -340,6 +340,13 @@ describe("ops", () => {
340
340
  assert.deepEqual(result, ["Hello", 1, "WORLD"]);
341
341
  });
342
342
 
343
+ test("ops.property returns a property if defined, otherwise traverses", async () => {
344
+ assert.equal(await ops.property({ a: 1 }, "a"), 1);
345
+ assert.equal(await ops.property({ a: 1 }, "b"), undefined);
346
+ const uppercase = (text) => text.toUpperCase();
347
+ assert.equal(await ops.property(uppercase, "a"), "A");
348
+ });
349
+
343
350
  test("ops.remainder calculates the remainder of two numbers", async () => {
344
351
  assert.strictEqual(ops.remainder(13, 5), 3);
345
352
  assert.strictEqual(ops.remainder(-13, 5), -3);
@@ -1,120 +0,0 @@
1
- import { deepText, toString, Tree } from "@weborigami/async-tree";
2
-
3
- const lastLineWhitespaceRegex = /\n(?<indent>[ \t]*)$/;
4
-
5
- const mapStringsToModifications = new Map();
6
-
7
- /**
8
- * Normalize indentation in a tagged template string
9
- *
10
- * @param {TemplateStringsArray} strings
11
- * @param {...any} values
12
- * @returns {Promise<string>}
13
- */
14
- export default async function indent(strings, ...values) {
15
- let modified = mapStringsToModifications.get(strings);
16
- if (!modified) {
17
- modified = modifyStrings(strings);
18
- mapStringsToModifications.set(strings, modified);
19
- }
20
- const { blockIndentations, strings: modifiedStrings } = modified;
21
- const valueTexts = await Promise.all(
22
- values.map((value) => (Tree.isTreelike(value) ? deepText(value) : value))
23
- );
24
- return joinBlocks(modifiedStrings, valueTexts, blockIndentations);
25
- }
26
-
27
- // Join strings and values, applying the given block indentation to the lines of
28
- // values for block placholders.
29
- function joinBlocks(strings, values, blockIndentations) {
30
- let result = strings[0];
31
- for (let i = 0; i < values.length; i++) {
32
- let text = toString(values[i]);
33
- if (text) {
34
- const blockIndentation = blockIndentations[i];
35
- if (blockIndentation) {
36
- const lines = text.split("\n");
37
- text = "";
38
- if (lines.at(-1) === "") {
39
- // Drop empty last line
40
- lines.pop();
41
- }
42
- for (let line of lines) {
43
- text += blockIndentation + line + "\n";
44
- }
45
- }
46
- result += text;
47
- }
48
- result += strings[i + 1];
49
- }
50
- return result;
51
- }
52
-
53
- // Given an array of template boilerplate strings, return an object { modified,
54
- // blockIndentations } where `strings` is the array of strings with indentation
55
- // removed, and `blockIndentations` is an array of indentation strings for each
56
- // block placeholder.
57
- function modifyStrings(strings) {
58
- // Phase one: Identify the indentation based on the first real line of the
59
- // first string (skipping the initial newline), and remove this indentation
60
- // from all lines of all strings.
61
- let indent;
62
- if (strings.length > 0 && strings[0].startsWith("\n")) {
63
- // Look for indenttation
64
- const firstLineWhitespaceRegex = /^\n(?<indent>[ \t]*)/;
65
- const match = strings[0].match(firstLineWhitespaceRegex);
66
- indent = match?.groups.indent;
67
- }
68
-
69
- // Determine the modified strings. If this invoked as a JS tagged template
70
- // literal, the `strings` argument will be an odd array-ish object that we'll
71
- // want to convert to a real array.
72
- let modified;
73
- if (indent) {
74
- // De-indent the strings.
75
- const indentationRegex = new RegExp(`\n${indent}`, "g");
76
- // The `replaceAll` also converts strings to a real array.
77
- modified = strings.map((string) =>
78
- string.replaceAll(indentationRegex, "\n")
79
- );
80
- // Remove indentation from last line of last string
81
- modified[modified.length - 1] = modified
82
- .at(-1)
83
- .replace(lastLineWhitespaceRegex, "\n");
84
- } else {
85
- // No indentation; just copy the strings so we have a real array
86
- modified = strings.slice();
87
- }
88
-
89
- // Phase two: Identify any block placholders, identify and remove their
90
- // preceding indentation, and remove the following newline. Work backward from
91
- // the end towards the start because we're modifying the strings in place and
92
- // our pattern matching won't work going forward from start to end.
93
- let blockIndentations = [];
94
- for (let i = modified.length - 2; i >= 0; i--) {
95
- // Get the modified before and after substitution with index `i`
96
- const beforeString = modified[i];
97
- const afterString = modified[i + 1];
98
- const match = beforeString.match(lastLineWhitespaceRegex);
99
- if (match && afterString.startsWith("\n")) {
100
- // The substitution between these strings is a block substitution
101
- let blockIndentation = match.groups.indent;
102
- blockIndentations[i] = blockIndentation;
103
- // Trim the before and after strings
104
- if (blockIndentation) {
105
- modified[i] = beforeString.slice(0, -blockIndentation.length);
106
- }
107
- modified[i + 1] = afterString.slice(1);
108
- }
109
- }
110
-
111
- // Remove newline from start of first string *after* removing indentation.
112
- if (modified[0].startsWith("\n")) {
113
- modified[0] = modified[0].slice(1);
114
- }
115
-
116
- return {
117
- blockIndentations,
118
- strings: modified,
119
- };
120
- }
@@ -1,44 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import indent from "../../src/runtime/templateIndent.js";
4
-
5
- describe("taggedTemplateIndent", () => {
6
- test("joins strings and values together if template isn't a block template", async () => {
7
- const result = await indent`a ${"b"} c`;
8
- assert.equal(result, "a b c");
9
- });
10
-
11
- test("removes first and last lines if template is a block template", async () => {
12
- const actual = await indent`
13
- <p>
14
- Hello, ${"Alice"}!
15
- </p>
16
- `;
17
- const expected = `
18
- <p>
19
- Hello, Alice!
20
- </p>
21
- `.trimStart();
22
- assert.equal(actual, expected);
23
- });
24
-
25
- test("indents all lines in a block substitution", async () => {
26
- const lines = `
27
- Line 1
28
- Line 2
29
- Line 3`.trimStart();
30
- const actual = await indent`
31
- <main>
32
- ${lines}
33
- </main>
34
- `;
35
- const expected = `
36
- <main>
37
- Line 1
38
- Line 2
39
- Line 3
40
- </main>
41
- `.trimStart();
42
- assert.equal(actual, expected);
43
- });
44
- });