prettier-plugin-wolfram 0.7.13 → 0.7.15

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,11 +1,15 @@
1
1
  {
2
2
  "name": "prettier-plugin-wolfram",
3
- "version": "0.7.13",
3
+ "version": "0.7.15",
4
4
  "description": "Prettier plugin for Wolfram Language using tree-sitter",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git://github.com/ToneAr/prettier-plugin-wolfram.git"
8
+ "url": "https://github.com/ToneAr/prettier-plugin-wolfram.git"
9
+ },
10
+ "homepage": "https://github.com/ToneAr/prettier-plugin-wolfram#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/ToneAr/prettier-plugin-wolfram/issues"
9
13
  },
10
14
  "keywords": [
11
15
  "prettier",
@@ -55,8 +59,5 @@
55
59
  },
56
60
  "workspaces": [
57
61
  "vscode-extension"
58
- ],
59
- "engines": {
60
- "vscode": "^1.105.0"
61
- }
62
+ ]
62
63
  }
package/src/options.js CHANGED
@@ -15,6 +15,9 @@ function wolframOptionDefinition(definition) {
15
15
  return {
16
16
  type: definition.type,
17
17
  category: "Wolfram",
18
+ ...(hasOwn(definition, "exception")
19
+ ? { exception: definition.exception }
20
+ : {}),
18
21
  ...(hasOwn(definition, "default")
19
22
  ? { default: definition.default }
20
23
  : {}),
@@ -22,42 +25,61 @@ function wolframOptionDefinition(definition) {
22
25
  };
23
26
  }
24
27
 
28
+ function isBlankLineRange(value) {
29
+ return (
30
+ isPlainObject(value) &&
31
+ Number.isInteger(value.min) &&
32
+ Number.isInteger(value.max) &&
33
+ value.min >= 0 &&
34
+ value.max >= value.min
35
+ );
36
+ }
37
+
38
+ function blankLineRangeOption(defaultValue, description) {
39
+ return {
40
+ type: "int",
41
+ ...(defaultValue == null ? {} : { default: defaultValue }),
42
+ exception: (value) =>
43
+ (Number.isInteger(value) && value >= 0) || isBlankLineRange(value),
44
+ description,
45
+ };
46
+ }
47
+
25
48
  export const wolframOptions = {
26
49
  newlinesBetweenDefinitions: {
27
- type: "int",
28
- default: 1,
29
- minimum: 0,
50
+ ...blankLineRangeOption(
51
+ { min: 1, max: 1 },
52
+ "Allowed blank lines between adjacent definitions.",
53
+ ),
30
54
  legacyName: "wolframNewlinesBetweenDefinitions",
31
- description: "Blank lines inserted between adjacent definitions.",
32
55
  },
33
56
  newlinesBetweenSetDefinitions: {
34
- type: "int",
35
- minimum: 0,
57
+ ...blankLineRangeOption(
58
+ null,
59
+ "Allowed blank lines between adjacent Set-family definitions. Inherits newlinesBetweenDefinitions when unset.",
60
+ ),
36
61
  legacyName: "wolframNewlinesBetweenSetDefinitions",
37
- description:
38
- "Blank lines inserted between adjacent Set-family definitions. Inherits newlinesBetweenDefinitions when unset.",
39
62
  },
40
63
  newlinesBetweenSetDelayedDefinitions: {
41
- type: "int",
42
- minimum: 0,
64
+ ...blankLineRangeOption(
65
+ null,
66
+ "Allowed blank lines between adjacent SetDelayed-family definitions. Inherits newlinesBetweenDefinitions when unset.",
67
+ ),
43
68
  legacyName: "wolframNewlinesBetweenSetDelayedDefinitions",
44
- description:
45
- "Blank lines inserted between adjacent SetDelayed-family definitions. Inherits newlinesBetweenDefinitions when unset.",
46
69
  },
47
70
  newlinesBetweenSetAndSetDelayedDefinitions: {
48
- type: "int",
49
- minimum: 0,
71
+ ...blankLineRangeOption(
72
+ null,
73
+ "Allowed blank lines between mixed Set-family and SetDelayed-family definitions. Inherits newlinesBetweenDefinitions when unset.",
74
+ ),
50
75
  legacyName: "wolframNewlinesBetweenSetAndSetDelayedDefinitions",
51
- description:
52
- "Blank lines inserted between mixed Set-family and SetDelayed-family definitions. Inherits newlinesBetweenDefinitions when unset.",
53
76
  },
54
77
  newlinesBetweenSameNameDefinitions: {
55
- type: "int",
56
- default: 0,
57
- minimum: 0,
78
+ ...blankLineRangeOption(
79
+ { min: 0, max: 0 },
80
+ "Allowed blank lines between adjacent definitions that belong to the same symbol.",
81
+ ),
58
82
  legacyName: "wolframNewlinesBetweenSameNameDefinitions",
59
- description:
60
- "Blank lines inserted between adjacent definitions that belong to the same symbol.",
61
83
  },
62
84
  maxBlankLinesBetweenCode: {
63
85
  type: "int",
@@ -10,6 +10,7 @@ import {
10
10
  withMarkedTrailingCommentDocs,
11
11
  } from "../docComments.js";
12
12
  import { normalizeWolframOptions } from "../../options.js";
13
+ import { buildDispatchSets } from "../specialForms.js";
13
14
  const { group, indent, softline, line, hardline } = builders;
14
15
 
15
16
  const BRACKET_KINDS = new Set(["Token`OpenSquare", "Token`CloseSquare"]);
@@ -40,6 +41,24 @@ function hasCommentBoundary(leftEntry, rightEntry) {
40
41
  return isComment(leftEntry?.node) || isComment(rightEntry?.node);
41
42
  }
42
43
 
44
+ function callHeadName(node) {
45
+ return node.head?.type === "LeafNode" && node.head.kind === "Symbol"
46
+ ? node.head.value
47
+ : null;
48
+ }
49
+
50
+ function shouldBreakCommentedSpecialCall(node, options, entries) {
51
+ if (!entries.some((entry) => isComment(entry.node))) return false;
52
+ const name = callHeadName(node);
53
+ if (!name) return false;
54
+ const sets = buildDispatchSets(options);
55
+ return (
56
+ sets.conditionFirst.has(name) ||
57
+ sets.blockStructure.has(name) ||
58
+ sets.caseStructure.has(name)
59
+ );
60
+ }
61
+
43
62
  function commentBoundary(leftEntry, rightEntry, options, fallback = line) {
44
63
  if (!leftEntry || !rightEntry) return fallback;
45
64
  return commentBoundarySeparator(
@@ -321,5 +340,8 @@ export function printCall(path, options, print, node) {
321
340
  );
322
341
  const contents = [head, "[", indent([softline, ...docs]), softline, "]"];
323
342
 
324
- return grouped(contents, alignmentGroupId);
343
+ const shouldBreak = shouldBreakCommentedSpecialCall(node, options, entries);
344
+ return alignmentGroupId
345
+ ? group(contents, { id: alignmentGroupId, shouldBreak })
346
+ : group(contents, { shouldBreak });
325
347
  }
@@ -95,6 +95,10 @@ function isCommaToken(node) {
95
95
  return node?.type === "LeafNode" && node.kind === "Token`Comma";
96
96
  }
97
97
 
98
+ function isCommentNode(node) {
99
+ return node?.type === "LeafNode" && node.kind === "Token`Comment";
100
+ }
101
+
98
102
  function isStringJoinOperatorToken(node) {
99
103
  return node?.type === "LeafNode" && node.kind === "Token`LessGreater";
100
104
  }
@@ -459,7 +463,7 @@ function semanticGroupEntries(callNode, groupNode) {
459
463
  ) {
460
464
  const commaWrapperIdx = groupNode.children.indexOf(semanticChildren[0]);
461
465
  return semanticChildren[0].children.reduce((entries, child, idx) => {
462
- if (isTrivia(child)) return entries;
466
+ if (isTrivia(child) || isCommentNode(child)) return entries;
463
467
  if (child.type === "LeafNode" && child.kind === "Token`Comma")
464
468
  return entries;
465
469
  entries.push({
@@ -477,7 +481,7 @@ function semanticGroupEntries(callNode, groupNode) {
477
481
  }
478
482
 
479
483
  return (groupNode.children ?? []).reduce((entries, child, idx) => {
480
- if (isTrivia(child)) return entries;
484
+ if (isTrivia(child) || isCommentNode(child)) return entries;
481
485
  if (
482
486
  child.type === "LeafNode" &&
483
487
  (child.kind === "Token`OpenCurly" ||
@@ -35,6 +35,27 @@ export function nonNegativeIntegerOption(value, fallback) {
35
35
  return Math.max(0, Math.floor(numeric));
36
36
  }
37
37
 
38
+ function blankLineRangeOption(value, fallback) {
39
+ if (value == null) return fallback;
40
+ if (typeof value === "object" && !Array.isArray(value)) {
41
+ const min = nonNegativeIntegerOption(value.min, fallback.min);
42
+ const max = nonNegativeIntegerOption(value.max, fallback.max);
43
+ return { min, max: Math.max(min, max) };
44
+ }
45
+
46
+ const exact = nonNegativeIntegerOption(value, fallback.min);
47
+ return { min: exact, max: exact };
48
+ }
49
+
50
+ function exactBlankLineRange(value) {
51
+ return { min: value, max: value };
52
+ }
53
+
54
+ function blankLinesFromRange(observedBlankLines, range) {
55
+ const observed = nonNegativeIntegerOption(observedBlankLines, 0);
56
+ return Math.min(range.max, Math.max(range.min, observed));
57
+ }
58
+
38
59
  export function maxBlankLinesBetweenCode(options = {}) {
39
60
  options = normalizeWolframOptions(options);
40
61
  return nonNegativeIntegerOption(
@@ -44,47 +65,72 @@ export function maxBlankLinesBetweenCode(options = {}) {
44
65
  }
45
66
 
46
67
  export function blankLinesBetweenDefinitions(options = {}) {
68
+ const range = blankLineRangeBetweenDefinitions(options);
69
+ return range.min;
70
+ }
71
+
72
+ function blankLineRangeBetweenDefinitions(options = {}) {
47
73
  options = normalizeWolframOptions(options);
48
- return nonNegativeIntegerOption(
74
+ return blankLineRangeOption(
49
75
  options.wolframNewlinesBetweenDefinitions,
50
- DEFAULT_BLANK_LINES_BETWEEN_DEFINITIONS,
76
+ exactBlankLineRange(DEFAULT_BLANK_LINES_BETWEEN_DEFINITIONS),
51
77
  );
52
78
  }
53
79
 
54
- function optionalBlankLinesOption(value, fallback) {
80
+ function optionalBlankLineRangeOption(value, fallback) {
55
81
  if (value == null) return fallback;
56
- return nonNegativeIntegerOption(value, fallback);
82
+ return blankLineRangeOption(value, fallback);
57
83
  }
58
84
 
59
85
  export function blankLinesBetweenSetDefinitions(options = {}) {
86
+ const range = blankLineRangeBetweenSetDefinitions(options);
87
+ return range.min;
88
+ }
89
+
90
+ function blankLineRangeBetweenSetDefinitions(options = {}) {
60
91
  options = normalizeWolframOptions(options);
61
- return optionalBlankLinesOption(
92
+ return optionalBlankLineRangeOption(
62
93
  options.wolframNewlinesBetweenSetDefinitions,
63
- blankLinesBetweenDefinitions(options),
94
+ blankLineRangeBetweenDefinitions(options),
64
95
  );
65
96
  }
66
97
 
67
98
  export function blankLinesBetweenSetDelayedDefinitions(options = {}) {
99
+ const range = blankLineRangeBetweenSetDelayedDefinitions(options);
100
+ return range.min;
101
+ }
102
+
103
+ function blankLineRangeBetweenSetDelayedDefinitions(options = {}) {
68
104
  options = normalizeWolframOptions(options);
69
- return optionalBlankLinesOption(
105
+ return optionalBlankLineRangeOption(
70
106
  options.wolframNewlinesBetweenSetDelayedDefinitions,
71
- blankLinesBetweenDefinitions(options),
107
+ blankLineRangeBetweenDefinitions(options),
72
108
  );
73
109
  }
74
110
 
75
111
  export function blankLinesBetweenSetAndSetDelayedDefinitions(options = {}) {
112
+ const range = blankLineRangeBetweenSetAndSetDelayedDefinitions(options);
113
+ return range.min;
114
+ }
115
+
116
+ function blankLineRangeBetweenSetAndSetDelayedDefinitions(options = {}) {
76
117
  options = normalizeWolframOptions(options);
77
- return optionalBlankLinesOption(
118
+ return optionalBlankLineRangeOption(
78
119
  options.wolframNewlinesBetweenSetAndSetDelayedDefinitions,
79
- blankLinesBetweenDefinitions(options),
120
+ blankLineRangeBetweenDefinitions(options),
80
121
  );
81
122
  }
82
123
 
83
124
  export function blankLinesBetweenSameNameDefinitions(options = {}) {
125
+ const range = blankLineRangeBetweenSameNameDefinitions(options);
126
+ return range.min;
127
+ }
128
+
129
+ function blankLineRangeBetweenSameNameDefinitions(options = {}) {
84
130
  options = normalizeWolframOptions(options);
85
- return nonNegativeIntegerOption(
131
+ return blankLineRangeOption(
86
132
  options.wolframNewlinesBetweenSameNameDefinitions,
87
- DEFAULT_BLANK_LINES_BETWEEN_SAME_NAME_DEFINITIONS,
133
+ exactBlankLineRange(DEFAULT_BLANK_LINES_BETWEEN_SAME_NAME_DEFINITIONS),
88
134
  );
89
135
  }
90
136
 
@@ -187,6 +233,48 @@ function blankLinesBetweenDeclarationKinds(
187
233
  return null;
188
234
  }
189
235
 
236
+ function blankLineRangeBetweenDeclarationKinds(
237
+ prevKind,
238
+ nextKind,
239
+ options,
240
+ { requireSpecificOption = false } = {},
241
+ ) {
242
+ if (prevKind === "set" && nextKind === "set") {
243
+ if (
244
+ requireSpecificOption &&
245
+ options.wolframNewlinesBetweenSetDefinitions == null
246
+ ) {
247
+ return null;
248
+ }
249
+ return blankLineRangeBetweenSetDefinitions(options);
250
+ }
251
+
252
+ if (prevKind === "setDelayed" && nextKind === "setDelayed") {
253
+ if (
254
+ requireSpecificOption &&
255
+ options.wolframNewlinesBetweenSetDelayedDefinitions == null
256
+ ) {
257
+ return null;
258
+ }
259
+ return blankLineRangeBetweenSetDelayedDefinitions(options);
260
+ }
261
+
262
+ if (
263
+ (prevKind === "set" && nextKind === "setDelayed") ||
264
+ (prevKind === "setDelayed" && nextKind === "set")
265
+ ) {
266
+ if (
267
+ requireSpecificOption &&
268
+ options.wolframNewlinesBetweenSetAndSetDelayedDefinitions == null
269
+ ) {
270
+ return null;
271
+ }
272
+ return blankLineRangeBetweenSetAndSetDelayedDefinitions(options);
273
+ }
274
+
275
+ return null;
276
+ }
277
+
190
278
  function blankLinesBetweenDeclarationNodes(
191
279
  prevNode,
192
280
  nextNode,
@@ -201,6 +289,20 @@ function blankLinesBetweenDeclarationNodes(
201
289
  );
202
290
  }
203
291
 
292
+ function blankLineRangeBetweenDeclarationNodes(
293
+ prevNode,
294
+ nextNode,
295
+ options,
296
+ requireSpecificOption = false,
297
+ ) {
298
+ return blankLineRangeBetweenDeclarationKinds(
299
+ declarationSpacingKind(prevNode),
300
+ declarationSpacingKind(nextNode),
301
+ options,
302
+ { requireSpecificOption },
303
+ );
304
+ }
305
+
204
306
  function firstSemanticChild(node) {
205
307
  return semanticChildren(node)[0] ?? null;
206
308
  }
@@ -396,14 +498,17 @@ export function blankLinesForCodeGap(
396
498
  if (topLevel && mode === "none") return 0;
397
499
 
398
500
  if (hasSharedDefinitionSubject(prevNode, nextNode)) {
399
- return blankLinesBetweenSameNameDefinitions(options);
501
+ return blankLinesFromRange(
502
+ observedBlankLines,
503
+ blankLineRangeBetweenSameNameDefinitions(options),
504
+ );
400
505
  }
401
506
 
402
507
  if (isDeclarationNode(prevNode) && isDeclarationNode(nextNode)) {
403
- return (
404
- blankLinesBetweenDeclarationNodes(prevNode, nextNode, options) ??
405
- blankLinesBetweenDefinitions(options)
406
- );
508
+ const range =
509
+ blankLineRangeBetweenDeclarationNodes(prevNode, nextNode, options) ??
510
+ blankLineRangeBetweenDefinitions(options);
511
+ return blankLinesFromRange(observedBlankLines, range);
407
512
  }
408
513
 
409
514
  const maxBlankLines = maxBlankLinesBetweenCode(options);