@jbearak/sight 0.10.0 → 0.11.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.
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "@jbearak/sight",
55
- version: "0.10.0",
55
+ version: "0.11.0",
56
56
  type: "module",
57
57
  workspaces: [
58
58
  "client"
@@ -926,7 +926,9 @@ var init_schema = __esm(() => {
926
926
  "spacedCompoundOperator",
927
927
  "invalidOperatorSequence",
928
928
  "cStyleLogicalInControlFlow",
929
- "mixedLogicalOperators"
929
+ "mixedLogicalOperators",
930
+ "chainedComparison",
931
+ "literalMacroAdjacency"
930
932
  ];
931
933
  INDENT_STYLES = ["spaces", "tabs"];
932
934
  FORMATTER_MODES = ["source-preserving", "ast"];
@@ -2203,6 +2205,8 @@ var init_types = __esm(() => {
2203
2205
  StataDiagnosticCode2["CSTYLE_LOGICAL_IN_CONTROL_FLOW"] = "CSTYLE_LOGICAL_IN_CONTROL_FLOW";
2204
2206
  StataDiagnosticCode2["MIXED_LOGICAL_OPERATORS"] = "MIXED_LOGICAL_OPERATORS";
2205
2207
  StataDiagnosticCode2["SPACED_COMPOUND_OPERATOR"] = "SPACED_COMPOUND_OPERATOR";
2208
+ StataDiagnosticCode2["CHAINED_COMPARISON"] = "CHAINED_COMPARISON";
2209
+ StataDiagnosticCode2["LITERAL_MACRO_ADJACENCY"] = "LITERAL_MACRO_ADJACENCY";
2206
2210
  StataDiagnosticCode2["PATH_CASE_MISMATCH"] = "PATH_CASE_MISMATCH";
2207
2211
  StataDiagnosticCode2["CROSS_FILE_MISSING_FILE"] = "CROSS_FILE_MISSING_FILE";
2208
2212
  StataDiagnosticCode2["CROSS_FILE_TRUNCATED"] = "CROSS_FILE_TRUNCATED";
@@ -26568,7 +26572,31 @@ var init_indentation_diagnostics = __esm(() => {
26568
26572
  FIRST_WORD_RE = /^(\w+)\b/;
26569
26573
  });
26570
26574
 
26575
+ // src/utils/diagnostic-severity.ts
26576
+ function resolve_diagnostic_severity(my_config_severity, fallback = import_node2.DiagnosticSeverity.Warning) {
26577
+ switch (my_config_severity) {
26578
+ case "error":
26579
+ return import_node2.DiagnosticSeverity.Error;
26580
+ case "warning":
26581
+ return import_node2.DiagnosticSeverity.Warning;
26582
+ case "information":
26583
+ return import_node2.DiagnosticSeverity.Information;
26584
+ case "hint":
26585
+ return import_node2.DiagnosticSeverity.Hint;
26586
+ default:
26587
+ return fallback;
26588
+ }
26589
+ }
26590
+ var import_node2;
26591
+ var init_diagnostic_severity = __esm(() => {
26592
+ import_node2 = __toESM(require_main4(), 1);
26593
+ });
26594
+
26571
26595
  // src/providers/operator-sequence-diagnostics.ts
26596
+ function is_invalid_operator_sequence_pair(first_value, second_value) {
26597
+ return INVALID_PAIRS.has(`${first_value} ${second_value}`);
26598
+ }
26599
+
26572
26600
  class OperatorSequenceAnalyzer {
26573
26601
  analyze(document, config) {
26574
26602
  const malformed_severity = config.diagnostics?.severity?.malformedOperator ?? "warning";
@@ -26629,7 +26657,7 @@ class OperatorSequenceAnalyzer {
26629
26657
  }
26630
26658
  const severity = this.resolve_severity(config_severity, pair_result.default_severity);
26631
26659
  const diagnostic = {
26632
- range: import_node2.Range.create(first_token.range.start, second_token.range.end),
26660
+ range: import_node3.Range.create(first_token.range.start, second_token.range.end),
26633
26661
  message: pair_result.message,
26634
26662
  severity,
26635
26663
  source: "sight",
@@ -26680,7 +26708,7 @@ class OperatorSequenceAnalyzer {
26680
26708
  second_token,
26681
26709
  pair_key,
26682
26710
  message: `Spaced compound operator '${pair_key}'. Stata treats this as ` + `'${spaced_compound}'; consider writing '${spaced_compound}'.`,
26683
- default_severity: import_node2.DiagnosticSeverity.Information,
26711
+ default_severity: import_node3.DiagnosticSeverity.Information,
26684
26712
  code: "SPACED_COMPOUND_OPERATOR" /* SPACED_COMPOUND_OPERATOR */
26685
26713
  };
26686
26714
  }
@@ -26692,7 +26720,7 @@ class OperatorSequenceAnalyzer {
26692
26720
  second_token,
26693
26721
  pair_key,
26694
26722
  message: `Malformed operator '${pair_key}'. Did you mean '${malformed_suggestion}'?`,
26695
- default_severity: import_node2.DiagnosticSeverity.Warning,
26723
+ default_severity: import_node3.DiagnosticSeverity.Warning,
26696
26724
  code: "MALFORMED_OPERATOR" /* MALFORMED_OPERATOR */
26697
26725
  };
26698
26726
  }
@@ -26706,7 +26734,7 @@ class OperatorSequenceAnalyzer {
26706
26734
  second_token,
26707
26735
  pair_key,
26708
26736
  message,
26709
- default_severity: import_node2.DiagnosticSeverity.Information,
26737
+ default_severity: import_node3.DiagnosticSeverity.Information,
26710
26738
  code: "CSTYLE_LOGICAL_IN_CONTROL_FLOW" /* CSTYLE_LOGICAL_IN_CONTROL_FLOW */
26711
26739
  };
26712
26740
  } else {
@@ -26718,7 +26746,7 @@ class OperatorSequenceAnalyzer {
26718
26746
  second_token,
26719
26747
  pair_key,
26720
26748
  message,
26721
- default_severity: import_node2.DiagnosticSeverity.Error,
26749
+ default_severity: import_node3.DiagnosticSeverity.Error,
26722
26750
  code: "INVALID_OPERATOR_SEQUENCE" /* INVALID_OPERATOR_SEQUENCE */
26723
26751
  };
26724
26752
  }
@@ -26732,7 +26760,7 @@ class OperatorSequenceAnalyzer {
26732
26760
  second_token,
26733
26761
  pair_key,
26734
26762
  message,
26735
- default_severity: import_node2.DiagnosticSeverity.Error,
26763
+ default_severity: import_node3.DiagnosticSeverity.Error,
26736
26764
  code: "INVALID_OPERATOR_SEQUENCE" /* INVALID_OPERATOR_SEQUENCE */
26737
26765
  };
26738
26766
  }
@@ -26837,27 +26865,21 @@ class OperatorSequenceAnalyzer {
26837
26865
  return false;
26838
26866
  }
26839
26867
  resolve_severity(config_severity, default_severity) {
26840
- switch (config_severity) {
26841
- case "error":
26842
- return import_node2.DiagnosticSeverity.Error;
26843
- case "warning":
26844
- return import_node2.DiagnosticSeverity.Warning;
26845
- case "information":
26846
- return import_node2.DiagnosticSeverity.Information;
26847
- case "hint":
26848
- return import_node2.DiagnosticSeverity.Hint;
26849
- case "off":
26850
- throw new Error('resolve_severity called with "off" - caller must filter before calling');
26851
- default:
26852
- return default_severity;
26868
+ if (config_severity === undefined) {
26869
+ return default_severity;
26870
+ }
26871
+ if (config_severity === "off") {
26872
+ throw new Error('resolve_severity called with "off" - caller must filter before calling');
26853
26873
  }
26874
+ return resolve_diagnostic_severity(config_severity, default_severity);
26854
26875
  }
26855
26876
  }
26856
- var import_node2, SPACED_COMPOUND_PAIRS, MALFORMED_OPERATOR_PAIRS, INVALID_PAIRS, CSTYLE_LOGICAL_PAIRS, SPECIAL_MESSAGES, CSTYLE_QUALIFIER_MESSAGES, CSTYLE_CONTROL_FLOW_MESSAGES, ARITHMETIC_OPS, COMPARISON_OPS, NEGATION_OPS, TRIVIA_TYPES, ADJACENCY_BREAKERS;
26877
+ var import_node3, SPACED_COMPOUND_PAIRS, MALFORMED_OPERATOR_PAIRS, INVALID_PAIRS, CSTYLE_LOGICAL_PAIRS, SPECIAL_MESSAGES, CSTYLE_QUALIFIER_MESSAGES, CSTYLE_CONTROL_FLOW_MESSAGES, ARITHMETIC_OPS, COMPARISON_OPS, NEGATION_OPS, TRIVIA_TYPES, ADJACENCY_BREAKERS;
26857
26878
  var init_operator_sequence_diagnostics = __esm(() => {
26858
26879
  init_types();
26859
26880
  init_diagnostic_code_description();
26860
- import_node2 = __toESM(require_main4(), 1);
26881
+ init_diagnostic_severity();
26882
+ import_node3 = __toESM(require_main4(), 1);
26861
26883
  SPACED_COMPOUND_PAIRS = new Map([
26862
26884
  ["< =", "<="],
26863
26885
  ["> =", ">="],
@@ -26902,11 +26924,14 @@ var init_operator_sequence_diagnostics = __esm(() => {
26902
26924
  ARITHMETIC_OPS = new Set(["+", "-", "*", "/", "^"]);
26903
26925
  COMPARISON_OPS = new Set(["<", ">"]);
26904
26926
  NEGATION_OPS = new Set(["!", "~"]);
26905
- TRIVIA_TYPES = new Set(["WHITESPACE", "CONTINUATION"]);
26927
+ TRIVIA_TYPES = new Set([
26928
+ "WHITESPACE",
26929
+ "CONTINUATION",
26930
+ "COMMENT_BLOCK",
26931
+ "COMMENT_LINE"
26932
+ ]);
26906
26933
  ADJACENCY_BREAKERS = new Set([
26907
- "STATEMENT_TERMINATOR",
26908
- "COMMENT_LINE",
26909
- "COMMENT_BLOCK"
26934
+ "STATEMENT_TERMINATOR"
26910
26935
  ]);
26911
26936
  });
26912
26937
 
@@ -26929,7 +26954,7 @@ class MixedLogicalOperatorAnalyzer {
26929
26954
  return [];
26930
26955
  }
26931
26956
  const my_ignored_lines = document.ignored_lines ?? new Set;
26932
- const my_severity = this.resolve_severity(my_config_severity);
26957
+ const my_severity = resolve_diagnostic_severity(my_config_severity);
26933
26958
  const my_diagnostics = [];
26934
26959
  let my_state = this.fresh_state();
26935
26960
  let my_in_continuation = false;
@@ -27065,7 +27090,7 @@ class MixedLogicalOperatorAnalyzer {
27065
27090
  continue;
27066
27091
  }
27067
27092
  my_diagnostics.push({
27068
- range: import_node3.Range.create(my_first_token.range.start, my_last_token.range.end),
27093
+ range: import_node4.Range.create(my_first_token.range.start, my_last_token.range.end),
27069
27094
  message: "Mixed '&' and '|' without parentheses. " + "Use parentheses to clarify precedence " + "(e.g., '(x & y) | z' or 'x & (y | z)')",
27070
27095
  severity: my_severity,
27071
27096
  source: "sight",
@@ -27074,24 +27099,13 @@ class MixedLogicalOperatorAnalyzer {
27074
27099
  });
27075
27100
  }
27076
27101
  }
27077
- resolve_severity(my_config_severity) {
27078
- switch (my_config_severity) {
27079
- case "error":
27080
- return import_node3.DiagnosticSeverity.Error;
27081
- case "warning":
27082
- return import_node3.DiagnosticSeverity.Warning;
27083
- case "information":
27084
- return import_node3.DiagnosticSeverity.Information;
27085
- case "hint":
27086
- return import_node3.DiagnosticSeverity.Hint;
27087
- }
27088
- }
27089
27102
  }
27090
- var import_node3, LOGICAL_OPS, QUALIFIER_BREAKERS, EXPRESSION_BREAKERS;
27103
+ var import_node4, LOGICAL_OPS, QUALIFIER_BREAKERS, EXPRESSION_BREAKERS;
27091
27104
  var init_mixed_logical_diagnostics = __esm(() => {
27092
27105
  init_types();
27093
27106
  init_diagnostic_code_description();
27094
- import_node3 = __toESM(require_main4(), 1);
27107
+ init_diagnostic_severity();
27108
+ import_node4 = __toESM(require_main4(), 1);
27095
27109
  LOGICAL_OPS = new Set(["&", "|"]);
27096
27110
  QUALIFIER_BREAKERS = new Set(["if", "in"]);
27097
27111
  EXPRESSION_BREAKERS = new Set([
@@ -27102,6 +27116,362 @@ var init_mixed_logical_diagnostics = __esm(() => {
27102
27116
  ]);
27103
27117
  });
27104
27118
 
27119
+ // src/providers/diagnostic-token-stream.ts
27120
+ function normalized_spaced_comparison_operator(first, second) {
27121
+ if (first.type !== "OPERATOR" || second?.type !== "OPERATOR") {
27122
+ return;
27123
+ }
27124
+ const my_compact_operator = SPACED_COMPARISON_OPERATOR_PAIRS.get(`${first.value} ${second.value}`);
27125
+ if (!my_compact_operator) {
27126
+ return;
27127
+ }
27128
+ return {
27129
+ type: "OPERATOR",
27130
+ value: my_compact_operator,
27131
+ range: {
27132
+ start: first.range.start,
27133
+ end: second.range.end
27134
+ }
27135
+ };
27136
+ }
27137
+ function collect_significant_tokens(tokens) {
27138
+ const the_unfiltered_significant = [];
27139
+ let my_in_continuation = false;
27140
+ for (const my_token of tokens) {
27141
+ if (my_token.type === "STATEMENT_TERMINATOR" && my_in_continuation) {
27142
+ my_in_continuation = false;
27143
+ continue;
27144
+ }
27145
+ if (my_token.type === "WHITESPACE") {
27146
+ continue;
27147
+ }
27148
+ if (my_token.type === "CONTINUATION") {
27149
+ my_in_continuation = true;
27150
+ continue;
27151
+ }
27152
+ if (my_token.type === "COMMENT_BLOCK" || my_token.type === "COMMENT_LINE") {
27153
+ continue;
27154
+ }
27155
+ my_in_continuation = false;
27156
+ the_unfiltered_significant.push(my_token);
27157
+ }
27158
+ const the_significant = [];
27159
+ for (let i = 0;i < the_unfiltered_significant.length; i++) {
27160
+ const my_token = the_unfiltered_significant[i];
27161
+ const my_normalized_operator = normalized_spaced_comparison_operator(my_token, the_unfiltered_significant[i + 1]);
27162
+ if (my_normalized_operator) {
27163
+ the_significant.push(my_normalized_operator);
27164
+ i++;
27165
+ continue;
27166
+ }
27167
+ the_significant.push(my_token);
27168
+ }
27169
+ return the_significant;
27170
+ }
27171
+ function is_adjacent(first, second) {
27172
+ return first.range.end.line === second.range.start.line && first.range.end.character === second.range.start.character;
27173
+ }
27174
+ var COMPARISON_OPERATORS, LOGICAL_OPERATORS, SPACED_COMPARISON_OPERATOR_PAIRS;
27175
+ var init_diagnostic_token_stream = __esm(() => {
27176
+ COMPARISON_OPERATORS = new Set([
27177
+ "==",
27178
+ "!=",
27179
+ "~=",
27180
+ "<",
27181
+ "<=",
27182
+ ">",
27183
+ ">="
27184
+ ]);
27185
+ LOGICAL_OPERATORS = new Set(["&", "|"]);
27186
+ SPACED_COMPARISON_OPERATOR_PAIRS = new Map([
27187
+ ["< =", "<="],
27188
+ ["> =", ">="],
27189
+ ["! =", "!="],
27190
+ ["~ =", "~="]
27191
+ ]);
27192
+ });
27193
+
27194
+ // src/providers/chained-comparison-diagnostics.ts
27195
+ class ChainedComparisonAnalyzer {
27196
+ analyze(document, config) {
27197
+ const my_config_severity = config.diagnostics?.severity?.chainedComparison ?? "warning";
27198
+ if (my_config_severity === "off") {
27199
+ return [];
27200
+ }
27201
+ const the_tokens = document.tokens;
27202
+ if (!the_tokens || the_tokens.length === 0) {
27203
+ return [];
27204
+ }
27205
+ const the_significant = collect_significant_tokens(the_tokens);
27206
+ const my_ignored_lines = document.ignored_lines ?? new Set;
27207
+ const my_severity = resolve_diagnostic_severity(my_config_severity);
27208
+ const the_chains = [];
27209
+ let run_stack = [[]];
27210
+ let prev_significant = undefined;
27211
+ const incomplete_tail_operators = new WeakSet;
27212
+ const close_run = (my_run) => {
27213
+ if (my_run.length >= 2) {
27214
+ const last_operator = my_run[my_run.length - 1];
27215
+ the_chains.push({
27216
+ first: my_run[0],
27217
+ last: last_operator,
27218
+ incomplete_tail: incomplete_tail_operators.has(last_operator)
27219
+ });
27220
+ }
27221
+ my_run.length = 0;
27222
+ };
27223
+ const flush_all = () => {
27224
+ for (const my_run of run_stack) {
27225
+ close_run(my_run);
27226
+ }
27227
+ run_stack = [[]];
27228
+ prev_significant = undefined;
27229
+ };
27230
+ const is_missing_rhs_after_comparison = (my_next_token) => {
27231
+ if (!my_next_token) {
27232
+ return true;
27233
+ }
27234
+ return EXPRESSION_BREAKERS2.has(my_next_token.type) || my_next_token.type === "COMMA" || my_next_token.type === "EOF" || my_next_token.type === "RPAREN" || my_next_token.type === "RBRACKET";
27235
+ };
27236
+ for (let i = 0;i < the_significant.length; i++) {
27237
+ const my_token = the_significant[i];
27238
+ const next_significant = the_significant[i + 1];
27239
+ if (run_stack.length === 1 && my_token.type === "WORD" && QUALIFIER_BREAKERS2.has(my_token.value)) {
27240
+ flush_all();
27241
+ continue;
27242
+ }
27243
+ if (EXPRESSION_BREAKERS2.has(my_token.type)) {
27244
+ flush_all();
27245
+ continue;
27246
+ }
27247
+ const current_run = run_stack[run_stack.length - 1];
27248
+ if (my_token.type === "COMMA") {
27249
+ close_run(current_run);
27250
+ prev_significant = my_token;
27251
+ continue;
27252
+ }
27253
+ if (my_token.type === "LPAREN" || my_token.type === "LBRACKET") {
27254
+ run_stack.push([]);
27255
+ prev_significant = my_token;
27256
+ continue;
27257
+ }
27258
+ if (my_token.type === "RPAREN" || my_token.type === "RBRACKET") {
27259
+ if (run_stack.length > 1) {
27260
+ const my_closed = run_stack.pop();
27261
+ close_run(my_closed);
27262
+ }
27263
+ prev_significant = my_token;
27264
+ continue;
27265
+ }
27266
+ if (my_token.type === "OPERATOR") {
27267
+ if (LOGICAL_OPERATORS.has(my_token.value)) {
27268
+ close_run(current_run);
27269
+ prev_significant = my_token;
27270
+ continue;
27271
+ }
27272
+ if (COMPARISON_OPERATORS.has(my_token.value)) {
27273
+ if (prev_significant && OPERAND_END_TYPES.has(prev_significant.type)) {
27274
+ if (next_significant?.type === "OPERATOR" && is_invalid_operator_sequence_pair(my_token.value, next_significant.value)) {
27275
+ close_run(current_run);
27276
+ } else {
27277
+ if (is_missing_rhs_after_comparison(next_significant)) {
27278
+ incomplete_tail_operators.add(my_token);
27279
+ }
27280
+ current_run.push(my_token);
27281
+ }
27282
+ } else {
27283
+ close_run(current_run);
27284
+ }
27285
+ prev_significant = my_token;
27286
+ continue;
27287
+ }
27288
+ prev_significant = my_token;
27289
+ continue;
27290
+ }
27291
+ if (prev_significant && OPERAND_END_TYPES.has(prev_significant.type) && !is_adjacent(prev_significant, my_token)) {
27292
+ close_run(current_run);
27293
+ }
27294
+ prev_significant = my_token;
27295
+ }
27296
+ for (const my_run of run_stack) {
27297
+ close_run(my_run);
27298
+ }
27299
+ const the_diagnostics = [];
27300
+ for (const my_chain of the_chains) {
27301
+ if (this.is_range_ignored(my_chain.first.range.start.line, my_chain.last.range.end.line, my_ignored_lines)) {
27302
+ continue;
27303
+ }
27304
+ the_diagnostics.push({
27305
+ range: import_node5.Range.create(my_chain.first.range.start, my_chain.last.range.end),
27306
+ message: my_chain.incomplete_tail ? "Incomplete chained comparison. A later comparison " + "operator has no right-hand operand; complete the " + "comparison or replace the chain with an explicit " + "logical operator (`&`/`|`)." : "Chained comparison is suspicious. Stata evaluates " + "comparisons left-to-right (e.g. `a < b < c` becomes " + "`(a < b) < c`), not as a mathematical chain. Use an " + "explicit logical operator (`&`/`|`) or parentheses to " + "make the intended evaluation clear.",
27307
+ severity: my_severity,
27308
+ source: "sight",
27309
+ code: "CHAINED_COMPARISON" /* CHAINED_COMPARISON */,
27310
+ ...diagnostic_code_description_fields("CHAINED_COMPARISON" /* CHAINED_COMPARISON */)
27311
+ });
27312
+ }
27313
+ return the_diagnostics;
27314
+ }
27315
+ is_range_ignored(start_line, end_line, ignored_lines) {
27316
+ for (let my_line = start_line;my_line <= end_line; my_line++) {
27317
+ if (ignored_lines.has(my_line)) {
27318
+ return true;
27319
+ }
27320
+ }
27321
+ return false;
27322
+ }
27323
+ }
27324
+ var import_node5, OPERAND_END_TYPES, EXPRESSION_BREAKERS2, QUALIFIER_BREAKERS2;
27325
+ var init_chained_comparison_diagnostics = __esm(() => {
27326
+ init_types();
27327
+ init_diagnostic_code_description();
27328
+ init_diagnostic_severity();
27329
+ init_diagnostic_token_stream();
27330
+ init_operator_sequence_diagnostics();
27331
+ import_node5 = __toESM(require_main4(), 1);
27332
+ OPERAND_END_TYPES = new Set([
27333
+ "WORD",
27334
+ "NUMBER",
27335
+ "STRING",
27336
+ "MACRO_REF_LOCAL",
27337
+ "MACRO_REF_GLOBAL",
27338
+ "RPAREN",
27339
+ "RBRACKET"
27340
+ ]);
27341
+ EXPRESSION_BREAKERS2 = new Set([
27342
+ "STATEMENT_TERMINATOR",
27343
+ "LBRACE",
27344
+ "RBRACE"
27345
+ ]);
27346
+ QUALIFIER_BREAKERS2 = new Set(["if", "in"]);
27347
+ });
27348
+
27349
+ // src/providers/literal-macro-adjacency-diagnostics.ts
27350
+ function is_complete_string(my_token) {
27351
+ const my_value = my_token.value;
27352
+ if (my_value.startsWith('`"') && my_value.endsWith(`"'`)) {
27353
+ return my_value.length >= 4;
27354
+ }
27355
+ return my_value.length >= 2 && my_value.startsWith('"') && my_value.endsWith('"');
27356
+ }
27357
+ function is_qualifying_literal(my_token) {
27358
+ if (my_token.type === "NUMBER") {
27359
+ return true;
27360
+ }
27361
+ if (my_token.type === "STRING") {
27362
+ return is_complete_string(my_token);
27363
+ }
27364
+ return false;
27365
+ }
27366
+ function is_expression_operator(my_token) {
27367
+ return my_token !== undefined && my_token.type === "OPERATOR" && (COMPARISON_OPERATORS.has(my_token.value) || LOGICAL_OPERATORS.has(my_token.value));
27368
+ }
27369
+ function governing_before(the_significant, index) {
27370
+ let my_group_opens = 0;
27371
+ for (let my_i = index - 1;my_i >= 0; my_i--) {
27372
+ const my_token = the_significant[my_i];
27373
+ if (GROUP_OPEN_TYPES.has(my_token.type)) {
27374
+ const my_before_paren = my_i - 1 >= 0 ? the_significant[my_i - 1] : undefined;
27375
+ if (is_call_opener(my_before_paren, my_token)) {
27376
+ return {
27377
+ token: my_before_paren,
27378
+ group_opens: my_group_opens
27379
+ };
27380
+ }
27381
+ my_group_opens++;
27382
+ continue;
27383
+ }
27384
+ if (my_token.type === "OPERATOR" && UNARY_PREFIX_OPERATORS.has(my_token.value)) {
27385
+ continue;
27386
+ }
27387
+ return { token: my_token, group_opens: my_group_opens };
27388
+ }
27389
+ return { token: undefined, group_opens: my_group_opens };
27390
+ }
27391
+ function is_call_opener(my_token, my_paren) {
27392
+ if (my_token === undefined) {
27393
+ return false;
27394
+ }
27395
+ if (!is_adjacent(my_token, my_paren)) {
27396
+ return false;
27397
+ }
27398
+ if (my_token.type === "RPAREN" || my_token.type === "RBRACKET") {
27399
+ return true;
27400
+ }
27401
+ return my_token.type === "WORD" && !CONDITION_KEYWORDS.has(my_token.value);
27402
+ }
27403
+ function governing_after(the_significant, index, max_group_closes) {
27404
+ let my_remaining_closes = max_group_closes;
27405
+ for (let my_i = index + 1;my_i < the_significant.length; my_i++) {
27406
+ const my_token = the_significant[my_i];
27407
+ if (GROUP_CLOSE_TYPES.has(my_token.type)) {
27408
+ if (my_remaining_closes > 0) {
27409
+ my_remaining_closes--;
27410
+ continue;
27411
+ }
27412
+ return my_token;
27413
+ }
27414
+ return my_token;
27415
+ }
27416
+ return;
27417
+ }
27418
+
27419
+ class LiteralMacroAdjacencyAnalyzer {
27420
+ analyze(document, config) {
27421
+ const my_config_severity = config.diagnostics?.severity?.literalMacroAdjacency ?? "hint";
27422
+ if (my_config_severity === "off") {
27423
+ return [];
27424
+ }
27425
+ const the_tokens = document.tokens;
27426
+ if (!the_tokens || the_tokens.length === 0) {
27427
+ return [];
27428
+ }
27429
+ const the_significant = collect_significant_tokens(the_tokens);
27430
+ const my_ignored_lines = document.ignored_lines ?? new Set;
27431
+ const my_severity = resolve_diagnostic_severity(my_config_severity);
27432
+ const the_diagnostics = [];
27433
+ for (let i = 1;i < the_significant.length; i++) {
27434
+ const my_macro = the_significant[i];
27435
+ const my_literal = the_significant[i - 1];
27436
+ if (!MACRO_REF_TYPES.has(my_macro.type) || !is_qualifying_literal(my_literal) || !is_adjacent(my_literal, my_macro)) {
27437
+ continue;
27438
+ }
27439
+ const before = governing_before(the_significant, i - 1);
27440
+ const governor_after = governing_after(the_significant, i, before.group_opens);
27441
+ const operator_before = is_expression_operator(before.token);
27442
+ const operator_after = is_expression_operator(governor_after);
27443
+ const leads_condition = before.token !== undefined && before.token.type === "WORD" && CONDITION_KEYWORDS.has(before.token.value);
27444
+ if ((operator_before || operator_after || leads_condition) && !my_ignored_lines.has(my_literal.range.start.line)) {
27445
+ the_diagnostics.push({
27446
+ range: import_node6.Range.create(my_literal.range.start, my_macro.range.end),
27447
+ message: "Literal adjacent to macro reference in an " + "expression. Stata concatenates these during macro " + "expansion; add an operator, whitespace, or " + "parentheses if that was not intended.",
27448
+ severity: my_severity,
27449
+ source: "sight",
27450
+ code: "LITERAL_MACRO_ADJACENCY" /* LITERAL_MACRO_ADJACENCY */,
27451
+ ...diagnostic_code_description_fields("LITERAL_MACRO_ADJACENCY" /* LITERAL_MACRO_ADJACENCY */)
27452
+ });
27453
+ }
27454
+ }
27455
+ return the_diagnostics;
27456
+ }
27457
+ }
27458
+ var import_node6, MACRO_REF_TYPES, CONDITION_KEYWORDS, GROUP_OPEN_TYPES, GROUP_CLOSE_TYPES, UNARY_PREFIX_OPERATORS;
27459
+ var init_literal_macro_adjacency_diagnostics = __esm(() => {
27460
+ init_types();
27461
+ init_diagnostic_code_description();
27462
+ init_diagnostic_severity();
27463
+ init_diagnostic_token_stream();
27464
+ import_node6 = __toESM(require_main4(), 1);
27465
+ MACRO_REF_TYPES = new Set([
27466
+ "MACRO_REF_LOCAL",
27467
+ "MACRO_REF_GLOBAL"
27468
+ ]);
27469
+ CONDITION_KEYWORDS = new Set(["if", "while"]);
27470
+ GROUP_OPEN_TYPES = new Set(["LPAREN", "LBRACKET"]);
27471
+ GROUP_CLOSE_TYPES = new Set(["RPAREN", "RBRACKET"]);
27472
+ UNARY_PREFIX_OPERATORS = new Set(["-", "+", "!", "~"]);
27473
+ });
27474
+
27105
27475
  // src/providers/diagnostics.ts
27106
27476
  import { createHash } from "crypto";
27107
27477
  function is_lexer_error_code(code) {
@@ -27120,6 +27490,8 @@ class DiagnosticsProvider {
27120
27490
  indentation_analyzer = new IndentationDiagnosticAnalyzer;
27121
27491
  operator_sequence_analyzer = new OperatorSequenceAnalyzer;
27122
27492
  mixed_logical_analyzer = new MixedLogicalOperatorAnalyzer;
27493
+ chained_comparison_analyzer = new ChainedComparisonAnalyzer;
27494
+ literal_macro_adjacency_analyzer = new LiteralMacroAdjacencyAnalyzer;
27123
27495
  dependency_graph;
27124
27496
  published_versions = new Map;
27125
27497
  filtered_cache = new Map;
@@ -27299,6 +27671,18 @@ class DiagnosticsProvider {
27299
27671
  the_diagnostics.push(my_mixed_diag);
27300
27672
  }
27301
27673
  }
27674
+ const chained_comparison_diagnostics = this.chained_comparison_analyzer.analyze(document, config);
27675
+ for (const my_chained_diag of chained_comparison_diagnostics) {
27676
+ if (!this.is_in_embedded_context(my_chained_diag.range.start, the_context_ranges)) {
27677
+ the_diagnostics.push(my_chained_diag);
27678
+ }
27679
+ }
27680
+ const literal_macro_adjacency_diagnostics = this.literal_macro_adjacency_analyzer.analyze(document, config);
27681
+ for (const my_adjacency_diag of literal_macro_adjacency_diagnostics) {
27682
+ if (!this.is_in_embedded_context(my_adjacency_diag.range.start, the_context_ranges)) {
27683
+ the_diagnostics.push(my_adjacency_diag);
27684
+ }
27685
+ }
27302
27686
  if (resolved_scope) {
27303
27687
  for (const my_directive_diag of resolved_scope.diagnostics) {
27304
27688
  const converted = this.convert_directive_diagnostic(my_directive_diag, config);
@@ -27833,6 +28217,8 @@ var init_diagnostics = __esm(() => {
27833
28217
  init_indentation_diagnostics();
27834
28218
  init_operator_sequence_diagnostics();
27835
28219
  init_mixed_logical_diagnostics();
28220
+ init_chained_comparison_diagnostics();
28221
+ init_literal_macro_adjacency_diagnostics();
27836
28222
  import_vscode_languageserver2 = __toESM(require_main4(), 1);
27837
28223
  LEXER_ERROR_CODES = new Set(Object.values(LexerErrorCode));
27838
28224
  PARSER_ERROR_CODES = new Set(Object.values(ParseErrorCode));
@@ -31011,7 +31397,7 @@ function create_initialize_handler(on_capabilities_detected, on_initialization_o
31011
31397
  }
31012
31398
  const result = {
31013
31399
  capabilities: {
31014
- textDocumentSync: import_node4.TextDocumentSyncKind.Incremental,
31400
+ textDocumentSync: import_node7.TextDocumentSyncKind.Incremental,
31015
31401
  completionProvider: {
31016
31402
  triggerCharacters: [":", "`", '"', "$", "{", ",", " "],
31017
31403
  resolveProvider: false
@@ -31442,7 +31828,7 @@ function create_expand_includes_handler(deps, shared_ihlp) {
31442
31828
  return { content: my_result };
31443
31829
  };
31444
31830
  }
31445
- var import_node4, DEFAULT_SETTINGS, MAX_IHLP_CACHE_SIZE = 500, MAX_RESOLVE_STHLP_NEGATIVE_CACHE_SIZE = 1000;
31831
+ var import_node7, DEFAULT_SETTINGS, MAX_IHLP_CACHE_SIZE = 500, MAX_RESOLVE_STHLP_NEGATIVE_CACHE_SIZE = 1000;
31446
31832
  var init_server_handlers = __esm(() => {
31447
31833
  init_completion();
31448
31834
  init_context_tracker();
@@ -31451,7 +31837,7 @@ var init_server_handlers = __esm(() => {
31451
31837
  init_marker_scanner();
31452
31838
  init_help_resolver();
31453
31839
  init_config_file();
31454
- import_node4 = __toESM(require_main4(), 1);
31840
+ import_node7 = __toESM(require_main4(), 1);
31455
31841
  DEFAULT_SETTINGS = {
31456
31842
  diagnostics: {
31457
31843
  enabled: true,
@@ -31463,7 +31849,9 @@ var init_server_handlers = __esm(() => {
31463
31849
  spacedCompoundOperator: "information",
31464
31850
  invalidOperatorSequence: "error",
31465
31851
  cStyleLogicalInControlFlow: "information",
31466
- mixedLogicalOperators: "warning"
31852
+ mixedLogicalOperators: "warning",
31853
+ chainedComparison: "warning",
31854
+ literalMacroAdjacency: "hint"
31467
31855
  },
31468
31856
  indentation: false
31469
31857
  },
@@ -31607,6 +31995,12 @@ function validate_comment_formatting_config(config, log_warning) {
31607
31995
  if (diagnostics.severity.mixedLogicalOperators && valid_severities.includes(diagnostics.severity.mixedLogicalOperators)) {
31608
31996
  validated_config.diagnostics.severity.mixedLogicalOperators = diagnostics.severity.mixedLogicalOperators;
31609
31997
  }
31998
+ if (diagnostics.severity.chainedComparison && valid_severities.includes(diagnostics.severity.chainedComparison)) {
31999
+ validated_config.diagnostics.severity.chainedComparison = diagnostics.severity.chainedComparison;
32000
+ }
32001
+ if (diagnostics.severity.literalMacroAdjacency && valid_severities.includes(diagnostics.severity.literalMacroAdjacency)) {
32002
+ validated_config.diagnostics.severity.literalMacroAdjacency = diagnostics.severity.literalMacroAdjacency;
32003
+ }
31610
32004
  }
31611
32005
  if (typeof diagnostics.indentation === "boolean") {
31612
32006
  validated_config.diagnostics.indentation = diagnostics.indentation;
@@ -69870,9 +70264,9 @@ __export(exports_server_factory, {
69870
70264
  import * as fs14 from "fs";
69871
70265
  function create_transport_connection(transport) {
69872
70266
  if (transport === "stdio") {
69873
- return import_node5.createConnection(process.stdin, process.stdout);
70267
+ return import_node8.createConnection(process.stdin, process.stdout);
69874
70268
  } else {
69875
- return import_node5.createConnection(import_node5.ProposedFeatures.all);
70269
+ return import_node8.createConnection(import_node8.ProposedFeatures.all);
69876
70270
  }
69877
70271
  }
69878
70272
  function map_public_settings(raw, log_warning) {
@@ -69913,7 +70307,7 @@ function indexing_affecting_signature(config) {
69913
70307
  async function create_server(options) {
69914
70308
  const { transport, quiet, log_channel } = options;
69915
70309
  const connection = create_transport_connection(transport);
69916
- const documents = new import_node5.TextDocuments(TextDocument);
70310
+ const documents = new import_node8.TextDocuments(TextDocument);
69917
70311
  const document_store = new DocumentStore;
69918
70312
  const debounce_manager = new DocumentDebounceManager;
69919
70313
  let diagnostics_provider = null;
@@ -69990,7 +70384,7 @@ async function create_server(options) {
69990
70384
  for (const my_pattern of [PROJECT_CONFIG_FILE, STALE_JSON_CONFIG_FILE]) {
69991
70385
  watchers.push({
69992
70386
  globPattern: { baseUri, pattern: my_pattern },
69993
- kind: import_node5.WatchKind.Create | import_node5.WatchKind.Change | import_node5.WatchKind.Delete
70387
+ kind: import_node8.WatchKind.Create | import_node8.WatchKind.Change | import_node8.WatchKind.Delete
69994
70388
  });
69995
70389
  }
69996
70390
  }
@@ -70005,7 +70399,7 @@ async function create_server(options) {
70005
70399
  if (watchers.length === 0) {
70006
70400
  project_config_watch_registration = undefined;
70007
70401
  } else {
70008
- project_config_watch_registration = await connection.client.register(import_node5.DidChangeWatchedFilesNotification.type, { watchers });
70402
+ project_config_watch_registration = await connection.client.register(import_node8.DidChangeWatchedFilesNotification.type, { watchers });
70009
70403
  }
70010
70404
  previous_registration?.dispose();
70011
70405
  }
@@ -70561,7 +70955,7 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
70561
70955
  }
70562
70956
  });
70563
70957
  if (server_capabilities.has_configuration_capability) {
70564
- connection.client.register(import_node5.DidChangeConfigurationNotification.type, undefined);
70958
+ connection.client.register(import_node8.DidChangeConfigurationNotification.type, undefined);
70565
70959
  }
70566
70960
  if (server_capabilities.has_workspace_folder_capability) {
70567
70961
  connection.workspace.onDidChangeWorkspaceFolders(async (_event) => {
@@ -70681,7 +71075,7 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
70681
71075
  documents.listen(connection);
70682
71076
  connection.listen();
70683
71077
  }
70684
- var import_node5, embedded_cache;
71078
+ var import_node8, embedded_cache;
70685
71079
  var init_server_factory = __esm(() => {
70686
71080
  init_main();
70687
71081
  init_document_store();
@@ -70707,7 +71101,7 @@ var init_server_factory = __esm(() => {
70707
71101
  init_stata_install_paths();
70708
71102
  init_v18();
70709
71103
  init_server_handlers();
70710
- import_node5 = __toESM(require_main4(), 1);
71104
+ import_node8 = __toESM(require_main4(), 1);
70711
71105
  embedded_cache = v18_default;
70712
71106
  });
70713
71107
 
@@ -70899,4 +71293,4 @@ export {
70899
71293
  is_cli_entry_point
70900
71294
  };
70901
71295
 
70902
- //# debugId=A1927913CBC66B5464756E2164756E21
71296
+ //# debugId=6FDB62323EDE1B8464756E2164756E21
@@ -1 +1 @@
1
- ba04e86fe7a6ff3104e6dcc4fd46966bd59d1b2d47c0dcf2c505ecd6789bfae1 sight-server.js
1
+ 4bf15e7be7e980d82d2126fba5074822b8d22cc4aeb9b9c5a51db7409db926bc sight-server.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbearak/sight",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  "client"