@graffiticode/parser 1.2.0 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graffiticode/parser",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/unparse.js CHANGED
@@ -89,7 +89,6 @@ function unparseNode(node, lexicon, indent = 0, options = {}) {
89
89
  return node.elts[0];
90
90
 
91
91
  case "LIST": {
92
- console.log("LIST");
93
92
  // Array literal [a, b, c]
94
93
  if (!node.elts || node.elts.length === 0) {
95
94
  return "[]";
@@ -213,13 +212,15 @@ function unparseNode(node, lexicon, indent = 0, options = {}) {
213
212
  // If-then-else
214
213
  if (node.elts && node.elts.length >= 2) {
215
214
  const cond = unparseNode(node.elts[0], lexicon, indent, opts);
216
- const thenExpr = unparseNode(node.elts[1], lexicon, indent, opts);
215
+ const innerIndent = indent + opts.indentSize;
216
+ const indentStr = " ".repeat(innerIndent);
217
+ const thenExpr = unparseNode(node.elts[1], lexicon, innerIndent, opts);
217
218
 
218
219
  if (node.elts.length >= 3) {
219
- const elseExpr = unparseNode(node.elts[2], lexicon, indent, opts);
220
- return `if ${cond} then ${thenExpr} else ${elseExpr}`;
220
+ const elseExpr = unparseNode(node.elts[2], lexicon, innerIndent, opts);
221
+ return `if ${cond} then\n${indentStr}${thenExpr}\nelse\n${indentStr}${elseExpr}`;
221
222
  } else {
222
- return `if ${cond} then ${thenExpr}`;
223
+ return `if ${cond} then\n${indentStr}${thenExpr}`;
223
224
  }
224
225
  }
225
226
  return "";
@@ -228,17 +229,39 @@ function unparseNode(node, lexicon, indent = 0, options = {}) {
228
229
  // Case expression
229
230
  if (node.elts && node.elts.length > 0) {
230
231
  const expr = unparseNode(node.elts[0], lexicon, indent, opts);
231
- const cases = node.elts.slice(1).map(c => unparseNode(c, lexicon, indent, opts));
232
- return `case ${expr} of ${cases.join(" | ")}`;
232
+ const innerIndent = indent + opts.indentSize;
233
+ const indentStr = " ".repeat(innerIndent);
234
+ const endIndentStr = " ".repeat(indent);
235
+
236
+ // Process each case branch with proper indentation
237
+ const cases = node.elts.slice(1).map(c => {
238
+ // Pass the inner indent to OF nodes but don't add extra indentation here
239
+ // The OF node will handle its own formatting
240
+ const caseStr = unparseNode(c, lexicon, indent, opts);
241
+ return caseStr;
242
+ });
243
+
244
+ return `case ${expr} of\n${cases.join("\n")}\n${endIndentStr}end`;
233
245
  }
234
246
  return "";
235
247
 
236
248
  case "OF":
237
249
  // Case branch
238
250
  if (node.elts && node.elts.length >= 2) {
251
+ const indentStr = " ".repeat(indent + opts.indentSize);
239
252
  const pattern = unparseNode(node.elts[0], lexicon, indent, opts);
240
- const expr = unparseNode(node.elts[1], lexicon, indent, opts);
241
- return `${pattern} => ${expr}`;
253
+
254
+ // Check if the expression is a CASE node for proper nested formatting
255
+ const exprNode = node.elts[1];
256
+ let expr;
257
+ if (exprNode && exprNode.tag === "CASE") {
258
+ // For nested case, don't add extra indent to the case keyword itself
259
+ expr = unparseNode(exprNode, lexicon, indent + opts.indentSize, opts);
260
+ } else {
261
+ expr = unparseNode(exprNode, lexicon, indent, opts);
262
+ }
263
+
264
+ return `${indentStr}${pattern}: ${expr}`;
242
265
  }
243
266
  return "";
244
267
 
@@ -16,7 +16,7 @@ describe("unparse", () => {
16
16
  it("should unparse string literals", async () => {
17
17
  const source = "'hello, world'..";
18
18
  const unparsed = await testRoundTrip(source);
19
- expect(unparsed).toBe("'hello, world'..");
19
+ expect(unparsed).toBe('"hello, world"..');
20
20
  });
21
21
 
22
22
  it.skip("should unparse string literals with escaped quotes", async () => {
@@ -218,14 +218,14 @@ describe("unparse", () => {
218
218
 
219
219
  it("should unparse if-then-else expression", async () => {
220
220
  const source = "if true then 1 else 2..";
221
- const unparsed = await testRoundTrip(source);
222
- expect(unparsed).toBe("if true then 1 else 2..");
221
+ const unparsed = await testRoundTrip(source, {}, { compact: false });
222
+ expect(unparsed).toBe("if true then\n 1\nelse\n 2..");
223
223
  });
224
224
 
225
225
  it("should unparse nested if expressions", async () => {
226
226
  const source = "if true then (if false then 1 else 2) else 3..";
227
- const unparsed = await testRoundTrip(source);
228
- expect(unparsed).toBe("if true then (if false then 1 else 2) else 3..");
227
+ const unparsed = await testRoundTrip(source, {}, { compact: false });
228
+ expect(unparsed).toBe("if true then\n (if false then\n 1\nelse\n 2)\nelse\n 3..");
229
229
  });
230
230
  });
231
231
 
@@ -328,7 +328,7 @@ describe("unparse", () => {
328
328
  it("should reformat multiple expressions", async () => {
329
329
  const source = "'hello'.[1, 2].{x: 10}..";
330
330
  const reformatted = await parser.reformat(0, source, basisLexicon);
331
- expect(reformatted).toContain("'hello'");
331
+ expect(reformatted).toContain('"hello"');
332
332
  expect(reformatted).toContain("[\n 1");
333
333
  expect(reformatted).toContain("{\n x: 10");
334
334
  expect(reformatted).toContain("..");
@@ -346,5 +346,11 @@ describe("unparse", () => {
346
346
  expect(reformatted).toContain(" 1"); // 4 spaces
347
347
  expect(reformatted).toContain(" 2"); // 4 spaces
348
348
  });
349
+
350
+ it("should preserve escaped quotes in strings", async () => {
351
+ const source = '"\\\"hello\\\""..'
352
+ const reformatted = await parser.reformat(0, source, basisLexicon, { compact: true });
353
+ expect(reformatted).toBe('"\\\"hello\\\""..'); // Should produce identical program
354
+ });
349
355
  });
350
356
  });