@jbearak/sight 0.14.6 → 0.15.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.
@@ -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.14.6",
55
+ version: "0.15.1",
56
56
  type: "module",
57
57
  workspaces: [
58
58
  "client"
@@ -115,6 +115,7 @@ var init_package = __esm(() => {
115
115
  license: "GPL-3.0",
116
116
  dependencies: {
117
117
  "@jbearak/dta-parser": "^0.6.0",
118
+ ignore: "7.0.5",
118
119
  picomatch: "^4.0.2",
119
120
  "smol-toml": "^1.6.1",
120
121
  "vscode-languageserver": "^9.0.1",
@@ -917,7 +918,10 @@ function map_public_config_to_partial_config(raw, warn) {
917
918
  }
918
919
  const workspace = object_value(raw, "workspace", "workspace", warn);
919
920
  if (workspace) {
920
- warn_unknown_keys(workspace, ["exclude"], "workspace", warn);
921
+ warn_unknown_keys(workspace, ["exclude", "respectGitignore"], "workspace", warn);
922
+ const mapped_workspace = {};
923
+ assign_boolean(mapped_workspace, "respectGitignore", workspace, "respectGitignore", "workspace.respectGitignore", warn);
924
+ maybe_assign_object(root, "workspace", mapped_workspace);
921
925
  }
922
926
  const canonical_exclude = workspace ? pick_key(workspace, "exclude", warn, "workspace.exclude") : undefined;
923
927
  const legacy_exclude = pick_key(raw, "exclude", warn, "exclude");
@@ -2353,6 +2357,9 @@ function ascii_to_lower(c) {
2353
2357
  return String.fromCharCode(code + 32);
2354
2358
  return c;
2355
2359
  }
2360
+ function ascii_case_fold(text) {
2361
+ return text.replace(ASCII_UPPERCASE_PATTERN, ascii_to_lower);
2362
+ }
2356
2363
  function ascii_ci_equal(a, b) {
2357
2364
  if (a.length !== b.length)
2358
2365
  return false;
@@ -2421,12 +2428,17 @@ function resolve_path_rich(resolved_fs_path, options) {
2421
2428
  return { kind: "exact", path: chosen_root };
2422
2429
  }
2423
2430
  const the_components = remainder.split(sep2);
2424
- let current_dir = chosen_root;
2425
- let had_case_mismatch = false;
2426
2431
  const join_path = (dir, name) => dir.endsWith(sep2) ? `${dir}${name}` : `${dir}${sep2}${name}`;
2427
- for (let comp_idx = 0;comp_idx < the_components.length; comp_idx++) {
2432
+ let directory_reads_left = the_components.length + MAX_CASE_VARIANT_BACKTRACK_READS;
2433
+ let budget_exhausted = false;
2434
+ const walk = (current_dir, comp_idx, had_case_mismatch) => {
2428
2435
  const my_component = the_components[comp_idx];
2429
2436
  const my_is_final = comp_idx === the_components.length - 1;
2437
+ if (directory_reads_left <= 0) {
2438
+ budget_exhausted = true;
2439
+ return { kind: "missing", requested: resolved_fs_path };
2440
+ }
2441
+ directory_reads_left--;
2430
2442
  let my_entries;
2431
2443
  try {
2432
2444
  my_entries = the_fs.readdirSync(current_dir, {
@@ -2438,20 +2450,43 @@ function resolve_path_rich(resolved_fs_path, options) {
2438
2450
  if (!my_is_final) {
2439
2451
  const my_exact = my_entries.find((e) => e.name === my_component && entry_is_dir(e, join_path(current_dir, e.name), the_fs));
2440
2452
  if (my_exact !== undefined) {
2441
- current_dir = join_path(current_dir, my_exact.name);
2442
- continue;
2453
+ const my_outcome = walk(join_path(current_dir, my_exact.name), comp_idx + 1, had_case_mismatch);
2454
+ if (my_outcome.kind !== "missing") {
2455
+ return my_outcome;
2456
+ }
2443
2457
  }
2444
- const the_ci_dirs = my_entries.filter((e) => ascii_ci_equal(e.name, my_component) && entry_is_dir(e, join_path(current_dir, e.name), the_fs));
2445
- if (the_ci_dirs.length === 1) {
2446
- had_case_mismatch = true;
2447
- current_dir = join_path(current_dir, the_ci_dirs[0].name);
2448
- continue;
2458
+ const the_hits = [];
2459
+ for (const my_entry of my_entries) {
2460
+ if (my_entry.name === my_component || !ascii_ci_equal(my_entry.name, my_component) || !entry_is_dir(my_entry, join_path(current_dir, my_entry.name), the_fs)) {
2461
+ continue;
2462
+ }
2463
+ const my_outcome = walk(join_path(current_dir, my_entry.name), comp_idx + 1, true);
2464
+ if (my_outcome.kind === "ambiguous") {
2465
+ the_hits.push(...my_outcome.matches);
2466
+ } else if (my_outcome.kind !== "missing") {
2467
+ the_hits.push(my_outcome.path);
2468
+ }
2469
+ if (the_hits.length > 1) {
2470
+ return {
2471
+ kind: "ambiguous",
2472
+ requested: resolved_fs_path,
2473
+ matches: the_hits
2474
+ };
2475
+ }
2449
2476
  }
2450
- if (the_ci_dirs.length > 1) {
2477
+ if (budget_exhausted) {
2451
2478
  return {
2452
2479
  kind: "ambiguous",
2453
2480
  requested: resolved_fs_path,
2454
- matches: the_ci_dirs.map((e) => join_path(current_dir, e.name))
2481
+ matches: the_hits,
2482
+ truncated: true
2483
+ };
2484
+ }
2485
+ if (the_hits.length === 1) {
2486
+ return {
2487
+ kind: "case_only",
2488
+ path: the_hits[0],
2489
+ requested: resolved_fs_path
2455
2490
  };
2456
2491
  }
2457
2492
  return { kind: "missing", requested: resolved_fs_path };
@@ -2500,8 +2535,8 @@ function resolve_path_rich(resolved_fs_path, options) {
2500
2535
  };
2501
2536
  }
2502
2537
  return { kind: "missing", requested: resolved_fs_path };
2503
- }
2504
- return { kind: "missing", requested: resolved_fs_path };
2538
+ };
2539
+ return walk(chosen_root, 0, false);
2505
2540
  }
2506
2541
  function host_is_case_sensitive(seed_existing_dir, fs3) {
2507
2542
  if (fs3 !== undefined) {
@@ -2571,6 +2606,31 @@ function is_resolvable_static_call(call) {
2571
2606
  function outcome_fs_path(outcome) {
2572
2607
  return outcome.kind === "exact" || outcome.kind === "case_only" ? outcome.path : outcome.requested;
2573
2608
  }
2609
+ function case_only_matched_directory(outcome) {
2610
+ const dir_of = (fs_path) => node_path.posix.dirname(fs_path.replace(/\\/g, "/"));
2611
+ return dir_of(outcome.path) !== dir_of(outcome.requested);
2612
+ }
2613
+ function case_mismatch_display_paths(raw_path, outcome, display_dir) {
2614
+ const my_normalized_raw = raw_path.replace(/\\/g, "/");
2615
+ const my_is_abs = node_path.isAbsolute(my_normalized_raw) || /^[a-zA-Z]:\//.test(my_normalized_raw);
2616
+ const the_raw_parts = my_normalized_raw.split("/").filter((my_part) => my_part.length > 0);
2617
+ const my_count = the_raw_parts.length;
2618
+ const the_requested_parts = outcome.requested.replace(/\\/g, "/").split("/");
2619
+ const the_real_parts = outcome.path.replace(/\\/g, "/").split("/");
2620
+ const my_base_count = the_requested_parts.length - my_count;
2621
+ const my_pairs = !my_is_abs && my_count > 0 && the_raw_parts.every((my_part) => my_part !== "." && my_part !== "..") && my_base_count >= 0 && the_real_parts.length === the_requested_parts.length && the_requested_parts.slice(my_base_count).join("/") === the_raw_parts.join("/") && the_requested_parts.slice(0, my_base_count).join("/") === the_real_parts.slice(0, my_base_count).join("/");
2622
+ if (my_pairs) {
2623
+ return {
2624
+ requested: the_raw_parts.join("/"),
2625
+ on_disk: the_real_parts.slice(-my_count).join("/")
2626
+ };
2627
+ }
2628
+ const relative_to_display_dir = (fs_path) => node_path.relative(display_dir, fs_path).replace(/\\/g, "/") || fs_path;
2629
+ return {
2630
+ requested: relative_to_display_dir(outcome.requested),
2631
+ on_disk: relative_to_display_dir(outcome.path)
2632
+ };
2633
+ }
2574
2634
  function resolve_forward_call_rich(raw_path, caller_dir, working_directory, options) {
2575
2635
  const my_normalized_raw = raw_path.replace(/\\/g, "/");
2576
2636
  const my_is_abs = node_path.isAbsolute(my_normalized_raw) || /^[a-zA-Z]:\//.test(my_normalized_raw);
@@ -2653,6 +2713,7 @@ function build_cd_timeline(params) {
2653
2713
  const { starting_wd, caller_dir, cd_commands, workspace_roots, fs: fs3 } = params;
2654
2714
  const the_diagnostics = [];
2655
2715
  const the_entries = [];
2716
+ let depends_on_directory_casing = false;
2656
2717
  const the_statics = (cd_commands ?? []).filter((c) => c.is_static && c.raw_path.length > 0).sort((a, b) => position_before(a.range.start, b.range.start) ? -1 : position_before(b.range.start, a.range.start) ? 1 : 0);
2657
2718
  let current_wd = starting_wd;
2658
2719
  for (const my_cd of the_statics) {
@@ -2668,6 +2729,7 @@ function build_cd_timeline(params) {
2668
2729
  current_wd = my_outcome.path;
2669
2730
  } else if (my_outcome.kind === "case_only") {
2670
2731
  current_wd = my_outcome.path;
2732
+ depends_on_directory_casing = true;
2671
2733
  the_diagnostics.push(make_cd_case_mismatch_diagnostic(my_cd, my_outcome, caller_dir, workspace_roots));
2672
2734
  } else if (my_outcome.kind === "missing") {
2673
2735
  current_wd = my_outcome.requested;
@@ -2679,8 +2741,9 @@ function build_cd_timeline(params) {
2679
2741
  code: "CROSS_FILE_MISSING_FILE" /* CROSS_FILE_MISSING_FILE */
2680
2742
  });
2681
2743
  } else {
2744
+ depends_on_directory_casing = true;
2682
2745
  the_diagnostics.push({
2683
- message: `Ambiguous directory for cd: "${my_cd.raw_path}" ` + `(multiple case-insensitive matches)`,
2746
+ message: `Ambiguous directory for cd: "${my_cd.raw_path}" ` + (my_outcome.truncated ? `(too many case-variant directories to search)` : `(multiple case-insensitive matches)`),
2684
2747
  range: my_cd.range,
2685
2748
  severity: "warning",
2686
2749
  kind: "missing_directory",
@@ -2691,15 +2754,15 @@ function build_cd_timeline(params) {
2691
2754
  }
2692
2755
  return {
2693
2756
  timeline: { starting_wd, entries: the_entries },
2694
- diagnostics: the_diagnostics
2757
+ diagnostics: the_diagnostics,
2758
+ depends_on_directory_casing
2695
2759
  };
2696
2760
  }
2697
2761
  function make_cd_case_mismatch_diagnostic(cd, outcome, caller_dir, workspace_roots) {
2698
- const my_req_disp = node_path.relative(caller_dir, outcome.requested).replace(/\\/g, "/") || outcome.requested;
2699
- const my_real_disp = node_path.relative(caller_dir, outcome.path).replace(/\\/g, "/") || outcome.path;
2762
+ const my_display = case_mismatch_display_paths(cd.raw_path, outcome, caller_dir);
2700
2763
  const my_seed = workspace_roots ? get_workspace_root_for_path(workspace_roots, outcome.path) ?? node_path.dirname(outcome.path) : node_path.dirname(outcome.path);
2701
2764
  return {
2702
- message: `Path "${my_req_disp}" does not match the directory on disk ` + `"${my_real_disp}"; Stata will not find it on case-sensitive ` + `filesystems (Linux). Update the path to match.`,
2765
+ message: `Path "${my_display.requested}" does not match the directory ` + `on disk "${my_display.on_disk}"; Stata will not find it on ` + `case-sensitive filesystems (Linux). Update the path to match.`,
2703
2766
  range: cd.range,
2704
2767
  severity: "warning",
2705
2768
  kind: "path_case_mismatch",
@@ -2718,7 +2781,7 @@ function apply_cd_timeline(forward_calls, timeline) {
2718
2781
  };
2719
2782
  });
2720
2783
  }
2721
- var FILE_COMMANDS, PATH_DIRECTIVES, STATA_FILE_EXTENSIONS, VCS_METADATA_DIRS, entry_is_dir, entry_is_file, case_sensitivity_cache;
2784
+ var FILE_COMMANDS, PATH_DIRECTIVES, STATA_FILE_EXTENSIONS, VCS_METADATA_DIRS, MAX_CASE_VARIANT_BACKTRACK_READS = 256, ASCII_UPPERCASE_PATTERN, entry_is_dir, entry_is_file, case_sensitivity_cache;
2722
2785
  var init_file_path_utils = __esm(() => {
2723
2786
  init_types();
2724
2787
  init_workspace_roots();
@@ -2751,6 +2814,7 @@ var init_file_path_utils = __esm(() => {
2751
2814
  ]);
2752
2815
  STATA_FILE_EXTENSIONS = [".do", ".ado", ".doh", ".mata"];
2753
2816
  VCS_METADATA_DIRS = new Set([".git", ".hg", ".svn"]);
2817
+ ASCII_UPPERCASE_PATTERN = /[A-Z]/g;
2754
2818
  entry_is_dir = entry_is_directory_sync;
2755
2819
  entry_is_file = entry_is_file_sync;
2756
2820
  case_sensitivity_cache = new Map;
@@ -13310,6 +13374,8 @@ var init_parser = __esm(() => {
13310
13374
  pending_trivia = [];
13311
13375
  context_tracker = null;
13312
13376
  inside_program = false;
13377
+ if_brace_scan_end = -1;
13378
+ if_brace_scan_result = false;
13313
13379
  static OPENING_DELIMITER_PATTERN = /^(`")+$/;
13314
13380
  static CLOSING_DELIMITER_PATTERN = /^("')+$/;
13315
13381
  parse(tokens, context_tracker) {
@@ -13317,6 +13383,8 @@ var init_parser = __esm(() => {
13317
13383
  this.current = 0;
13318
13384
  this.errors = [];
13319
13385
  this.pending_trivia = [];
13386
+ this.if_brace_scan_end = -1;
13387
+ this.if_brace_scan_result = false;
13320
13388
  this.context_tracker = context_tracker || null;
13321
13389
  const nodes = [];
13322
13390
  while (!this.isAtEnd()) {
@@ -13346,7 +13414,7 @@ var init_parser = __esm(() => {
13346
13414
  errors: this.errors
13347
13415
  };
13348
13416
  }
13349
- parseStatement() {
13417
+ parseStatement(consume_terminator = true) {
13350
13418
  const leading_trivia = [...this.pending_trivia, ...this.collectTrivia()];
13351
13419
  this.pending_trivia = [];
13352
13420
  if (this.isAtEnd()) {
@@ -13433,7 +13501,7 @@ var init_parser = __esm(() => {
13433
13501
  if (node && this.isNodeWithTrivia(node) && trailing_trivia.length > 0) {
13434
13502
  node.trailingTrivia = trailing_trivia;
13435
13503
  }
13436
- if (this.check("STATEMENT_TERMINATOR")) {
13504
+ if (consume_terminator && this.check("STATEMENT_TERMINATOR")) {
13437
13505
  this.advance();
13438
13506
  }
13439
13507
  return node;
@@ -14650,13 +14718,31 @@ var init_parser = __esm(() => {
14650
14718
  }
14651
14719
  return false;
14652
14720
  }
14721
+ hasIfBrace() {
14722
+ if (this.current <= this.if_brace_scan_end) {
14723
+ return this.if_brace_scan_result;
14724
+ }
14725
+ for (let i = this.current;i < this.tokens.length; i++) {
14726
+ const token = this.tokens[i];
14727
+ if (token.type === "LBRACE" || token.type === "EOF" || token.type === "STATEMENT_TERMINATOR" && !is_swallowed_continuation_terminator(token, this.tokens[i - 1]?.type === "CONTINUATION")) {
14728
+ this.if_brace_scan_end = i;
14729
+ this.if_brace_scan_result = token.type === "LBRACE";
14730
+ return this.if_brace_scan_result;
14731
+ }
14732
+ }
14733
+ return false;
14734
+ }
14653
14735
  parseIfStatement() {
14654
14736
  const ifToken = this.advance();
14737
+ const has_brace = this.hasIfBrace();
14655
14738
  const condition_tokens = [];
14656
14739
  const preceded_by_continuation = [];
14657
14740
  const continuation = new ContinuationTracker;
14658
14741
  const condition_start_line = ifToken.range.start.line;
14659
14742
  let paren_depth = 0;
14743
+ let bracket_depth = 0;
14744
+ let previous_operand;
14745
+ let is_single_statement = false;
14660
14746
  while (!this.check("LBRACE") && !this.isAtEnd()) {
14661
14747
  if (this.check("CONTINUATION")) {
14662
14748
  const cont_token = this.peek();
@@ -14668,7 +14754,15 @@ var init_parser = __esm(() => {
14668
14754
  if (this.check("STATEMENT_TERMINATOR")) {
14669
14755
  break;
14670
14756
  }
14671
- const token = this.advance();
14757
+ const token = this.peek();
14758
+ const follows_continuation = continuation.collect(token);
14759
+ const joins_operand = previous_operand && previous_operand.type !== "RPAREN" && previous_operand.type !== "RBRACKET" && (this.isAdjacentToken(previous_operand, token) || follows_continuation && token.range.start.character === 0);
14760
+ const starts_nested_if = this.checkWord("if");
14761
+ if ((!has_brace || starts_nested_if) && paren_depth === 0 && bracket_depth === 0 && previous_operand && !joins_operand && (token.type === "WORD" || this.isMacroRefToken(token) || token.type === "MATA_INLINE" || token.type === "PYTHON_INLINE")) {
14762
+ is_single_statement = true;
14763
+ break;
14764
+ }
14765
+ this.advance();
14672
14766
  if (token.type === "LPAREN") {
14673
14767
  paren_depth++;
14674
14768
  } else if (token.type === "RPAREN") {
@@ -14678,8 +14772,16 @@ var init_parser = __esm(() => {
14678
14772
  paren_depth = 0;
14679
14773
  }
14680
14774
  }
14775
+ if (token.type === "LBRACKET") {
14776
+ bracket_depth++;
14777
+ } else if (token.type === "RBRACKET") {
14778
+ bracket_depth = Math.max(0, bracket_depth - 1);
14779
+ }
14780
+ if (token.type !== "COMMENT_LINE" && token.type !== "COMMENT_BLOCK") {
14781
+ previous_operand = token.type === "WORD" || token.type === "NUMBER" || token.type === "STRING" || this.isMacroRefToken(token) || token.type === "RPAREN" || token.type === "RBRACKET" ? token : undefined;
14782
+ }
14681
14783
  condition_tokens.push(token);
14682
- preceded_by_continuation.push(continuation.collect(token));
14784
+ preceded_by_continuation.push(follows_continuation);
14683
14785
  }
14684
14786
  const condition = this.reconstruct_value_tokens(condition_tokens, preceded_by_continuation).trim();
14685
14787
  if (paren_depth > 0) {
@@ -14690,7 +14792,11 @@ var init_parser = __esm(() => {
14690
14792
  }
14691
14793
  const body = [];
14692
14794
  let blockEndingTrivia;
14693
- if (this.check("LBRACE")) {
14795
+ if (is_single_statement) {
14796
+ const statement = this.parseStatement(false);
14797
+ if (statement)
14798
+ body.push(statement);
14799
+ } else if (this.check("LBRACE")) {
14694
14800
  const lbrace_index = this.current;
14695
14801
  const lbrace_token = this.advance();
14696
14802
  const has_condition_before = lbrace_token.range.start.line === condition_start_line;
@@ -14708,9 +14814,10 @@ var init_parser = __esm(() => {
14708
14814
  }
14709
14815
  return {
14710
14816
  type: "if",
14817
+ ...is_single_statement ? { is_single_statement: true } : {},
14711
14818
  condition: condition.trim(),
14712
14819
  body,
14713
- range: this.makeRange(ifToken.range.start, this.previous().range.end),
14820
+ range: this.makeRange(ifToken.range.start, is_single_statement && body.length > 0 ? body[body.length - 1].range.end : this.previous().range.end),
14714
14821
  blockEndingTrivia
14715
14822
  };
14716
14823
  }
@@ -20742,6 +20849,61 @@ async function with_parse_timeout(operation, timeout_ms = PARSE_TIMEOUT_MS) {
20742
20849
  }
20743
20850
  var PARSE_TIMEOUT_MS = 5000;
20744
20851
 
20852
+ // src/source-analysis/index.ts
20853
+ import * as path4 from "path";
20854
+ function analyze_source(content, uri) {
20855
+ const lexer = new StataLexer;
20856
+ const parser = new StataParser;
20857
+ const analyzer = new SemanticAnalyzer;
20858
+ const directive_parser = new DirectiveParser;
20859
+ const lex_result = lexer.tokenize(content);
20860
+ const directive_result = directive_parser.parse(content, uri, lex_result.tokens);
20861
+ const parse_result = parser.parse(lex_result.tokens);
20862
+ const analysis = analyzer.analyze(parse_result.ast, uri, undefined, undefined, lex_result.tokens);
20863
+ return {
20864
+ tokens: lex_result.tokens,
20865
+ analysis,
20866
+ directives: directive_result
20867
+ };
20868
+ }
20869
+ function prepare_forward_calls(options) {
20870
+ let command_calls = options.command_calls;
20871
+ try {
20872
+ const caller_dir = path4.dirname(URI.parse(options.uri).fsPath);
20873
+ const { timeline } = build_cd_timeline({
20874
+ starting_wd: options.working_directory,
20875
+ caller_dir,
20876
+ cd_commands: options.cd_commands,
20877
+ workspace_roots: options.workspace_roots,
20878
+ fs: options.fs
20879
+ });
20880
+ command_calls = apply_cd_timeline(command_calls, timeline);
20881
+ } catch (error) {
20882
+ if (!options.recover_command_projection) {
20883
+ throw error;
20884
+ }
20885
+ }
20886
+ const directive_calls = options.directive_calls.map((my_directive) => ({
20887
+ type: my_directive.type,
20888
+ raw_path: my_directive.raw_path,
20889
+ call_site_line: my_directive.call_site_line,
20890
+ range: my_directive.range,
20891
+ source: "directive",
20892
+ is_static: true,
20893
+ caller_uri: options.uri,
20894
+ working_directory: options.working_directory
20895
+ }));
20896
+ return [...command_calls, ...directive_calls];
20897
+ }
20898
+ var init_source_analysis = __esm(() => {
20899
+ init_esm();
20900
+ init_analyzer();
20901
+ init_directive_parser();
20902
+ init_lexer();
20903
+ init_parser();
20904
+ init_file_path_utils();
20905
+ });
20906
+
20745
20907
  // src/utils/polling-cancellation-token.ts
20746
20908
  function polling_cancellation_token(should_continue, parent) {
20747
20909
  return {
@@ -20757,7 +20919,6 @@ var no_op_cancellation_event = () => ({ dispose: () => {
20757
20919
 
20758
20920
  // src/document-store.ts
20759
20921
  import * as fs4 from "fs";
20760
- import * as path4 from "path";
20761
20922
 
20762
20923
  class DocumentStore {
20763
20924
  documents = new Map;
@@ -21156,17 +21317,16 @@ class DocumentStore {
21156
21317
  const directive_parser = new DirectiveParser;
21157
21318
  let resolved_working_directory;
21158
21319
  let staged_effects;
21320
+ let parsed_directives;
21159
21321
  try {
21160
21322
  const directive_result = directive_parser.parse(content, uri, lex_result.result.tokens);
21323
+ parsed_directives = directive_result;
21161
21324
  staged_effects = this.stage_cross_file_effects(directive_result, effective_scope_resolver_config);
21162
21325
  if (directive_result.working_directory) {
21163
21326
  resolved_working_directory = this.resolve_working_directory(directive_result.working_directory, uri);
21164
21327
  } else if (this.scope_resolver) {
21165
21328
  try {
21166
- const scope_result = await this.scope_resolver.resolve(uri, content, effective_scope_resolver_config, cancellation_token, { register_dependencies: false });
21167
- if (scope_result.inherited_working_directory) {
21168
- resolved_working_directory = scope_result.inherited_working_directory;
21169
- }
21329
+ resolved_working_directory = await this.scope_resolver.resolve_document_working_directory(uri, directive_result, effective_scope_resolver_config, cancellation_token);
21170
21330
  } catch {}
21171
21331
  }
21172
21332
  } catch {}
@@ -21220,36 +21380,19 @@ class DocumentStore {
21220
21380
  };
21221
21381
  }
21222
21382
  const diagnostics = this.build_diagnostics(lex_result.result.errors, parse_result.result.errors, analyze_result.result.diagnostics);
21223
- let restamped_command_calls = analyze_result.result.forward_calls;
21383
+ let the_forward_directives = [];
21224
21384
  try {
21225
- const my_caller_dir = path4.dirname(URI.parse(uri).fsPath);
21226
- const { timeline: cd_timeline } = build_cd_timeline({
21227
- starting_wd: resolved_working_directory,
21228
- caller_dir: my_caller_dir,
21229
- cd_commands: analyze_result.result.cd_commands,
21230
- workspace_roots: this.workspace_roots
21231
- });
21232
- restamped_command_calls = apply_cd_timeline(analyze_result.result.forward_calls, cd_timeline);
21233
- } catch {}
21234
- let all_forward_calls = restamped_command_calls;
21235
- try {
21236
- const directive_parser2 = new DirectiveParser;
21237
- const directive_result = directive_parser2.parse_forward_call_directives(content, uri, lex_result.result.tokens);
21238
- const directive_forward_calls = directive_result.forward_calls.map((d) => ({
21239
- type: d.type,
21240
- raw_path: d.raw_path,
21241
- call_site_line: d.call_site_line,
21242
- range: d.range,
21243
- source: "directive",
21244
- is_static: true,
21245
- caller_uri: uri,
21246
- working_directory: resolved_working_directory
21247
- }));
21248
- all_forward_calls = [
21249
- ...restamped_command_calls,
21250
- ...directive_forward_calls
21251
- ];
21385
+ the_forward_directives = parsed_directives ? parsed_directives.forward_calls ?? [] : directive_parser.parse_forward_call_directives(content, uri, lex_result.result.tokens).forward_calls;
21252
21386
  } catch {}
21387
+ const all_forward_calls = prepare_forward_calls({
21388
+ uri,
21389
+ command_calls: analyze_result.result.forward_calls,
21390
+ directive_calls: the_forward_directives,
21391
+ cd_commands: analyze_result.result.cd_commands,
21392
+ working_directory: resolved_working_directory,
21393
+ workspace_roots: this.workspace_roots,
21394
+ recover_command_projection: true
21395
+ });
21253
21396
  return {
21254
21397
  state: {
21255
21398
  uri,
@@ -21415,8 +21558,7 @@ var init_document_store = __esm(() => {
21415
21558
  init_context_tracker();
21416
21559
  init_directive_parser();
21417
21560
  init_workspace_roots();
21418
- init_file_path_utils();
21419
- init_esm();
21561
+ init_source_analysis();
21420
21562
  import_vscode_languageserver = __toESM(require_main4(), 1);
21421
21563
  });
21422
21564
 
@@ -21928,6 +22070,11 @@ function build_forward_closure_key(inputs) {
21928
22070
  inputs.dep_graph_version
21929
22071
  ]);
21930
22072
  }
22073
+ function mark_directory_casing(collector) {
22074
+ if (collector !== undefined) {
22075
+ collector.depends_on_directory_casing = true;
22076
+ }
22077
+ }
21931
22078
 
21932
22079
  class ForwardScopeResolver {
21933
22080
  scope_resolver;
@@ -21952,6 +22099,7 @@ class ForwardScopeResolver {
21952
22099
  };
21953
22100
  standalone_in_flight = new Set;
21954
22101
  active_probe_collectors = [];
22102
+ collector_by_visited = new WeakMap;
21955
22103
  dependency_graph;
21956
22104
  constructor(scope_resolver, config = {}) {
21957
22105
  this.scope_resolver = scope_resolver;
@@ -21984,7 +22132,7 @@ class ForwardScopeResolver {
21984
22132
  }
21985
22133
  invalidate_forward_closure_for_uri(uri) {
21986
22134
  this.memo_invalidation_epoch++;
21987
- const the_keys = this.memo_uri_to_keys.get(uri);
22135
+ const the_keys = this.memo_uri_to_keys.get(this.memo_index_key(uri));
21988
22136
  if (!the_keys) {
21989
22137
  return 0;
21990
22138
  }
@@ -22014,15 +22162,19 @@ class ForwardScopeResolver {
22014
22162
  }
22015
22163
  prune_memo_uri_to_keys_for_entry(key, entry) {
22016
22164
  for (const my_dep_uri of entry.dependent_uris) {
22017
- const my_key_set = this.memo_uri_to_keys.get(my_dep_uri);
22165
+ const my_index_key = this.memo_index_key(my_dep_uri);
22166
+ const my_key_set = this.memo_uri_to_keys.get(my_index_key);
22018
22167
  if (my_key_set) {
22019
22168
  my_key_set.delete(key);
22020
22169
  if (my_key_set.size === 0) {
22021
- this.memo_uri_to_keys.delete(my_dep_uri);
22170
+ this.memo_uri_to_keys.delete(my_index_key);
22022
22171
  }
22023
22172
  }
22024
22173
  }
22025
22174
  }
22175
+ memo_index_key(uri) {
22176
+ return ascii_case_fold(uri);
22177
+ }
22026
22178
  set_forward_closure_memo_capacity(max_entries) {
22027
22179
  this.forward_closure_memo.set_max_size(max_entries);
22028
22180
  }
@@ -22036,7 +22188,7 @@ class ForwardScopeResolver {
22036
22188
  for (const my_fs_path of fs_paths) {
22037
22189
  const my_probe_uri = URI.file(my_fs_path).toString();
22038
22190
  for (const my_collector of this.active_probe_collectors) {
22039
- my_collector.add(my_probe_uri);
22191
+ my_collector.probes.add(my_probe_uri);
22040
22192
  }
22041
22193
  }
22042
22194
  }
@@ -22055,7 +22207,7 @@ class ForwardScopeResolver {
22055
22207
  const resolved = path5.resolve(fs_path);
22056
22208
  return this.workspace_roots.some((root) => resolved.startsWith(root + path5.sep) || resolved === root);
22057
22209
  }
22058
- resolve_call_path(raw_path, caller_uri, working_directory) {
22210
+ resolve_call_path(raw_path, caller_uri, working_directory, casing_collector) {
22059
22211
  const my_caller_dir = path5.dirname(URI.parse(caller_uri).fsPath);
22060
22212
  const my_missed_candidates = this.active_probe_collectors.length > 0 ? [] : undefined;
22061
22213
  const my_outcome = resolve_forward_call_rich(raw_path, my_caller_dir, working_directory, {
@@ -22073,6 +22225,9 @@ class ForwardScopeResolver {
22073
22225
  };
22074
22226
  }
22075
22227
  if (my_outcome.kind === "case_only") {
22228
+ if (case_only_matched_directory(my_outcome)) {
22229
+ mark_directory_casing(casing_collector);
22230
+ }
22076
22231
  const my_seed = this.find_seed_dir(my_outcome.path);
22077
22232
  return {
22078
22233
  resolved_path: my_outcome.path,
@@ -22089,13 +22244,16 @@ class ForwardScopeResolver {
22089
22244
  find_seed_dir(fs_path) {
22090
22245
  return get_workspace_root_for_path(this.workspace_roots, fs_path) ?? path5.dirname(fs_path);
22091
22246
  }
22092
- resolve_call_path_simple(raw_path, caller_uri, working_directory) {
22247
+ resolve_call_path_simple(raw_path, caller_uri, working_directory, casing_collector) {
22093
22248
  const my_caller_dir = path5.dirname(URI.parse(caller_uri).fsPath);
22094
22249
  const my_outcome = resolve_forward_call_rich(raw_path, my_caller_dir, working_directory, {
22095
22250
  workspace_roots: this.workspace_roots.length > 0 ? this.workspace_roots : undefined,
22096
22251
  fs: this.resolve_fs
22097
22252
  });
22098
22253
  if (my_outcome.kind === "exact" || my_outcome.kind === "case_only") {
22254
+ if (my_outcome.kind === "case_only" && case_only_matched_directory(my_outcome)) {
22255
+ mark_directory_casing(casing_collector);
22256
+ }
22099
22257
  return my_outcome.path;
22100
22258
  }
22101
22259
  return null;
@@ -22123,13 +22281,21 @@ class ForwardScopeResolver {
22123
22281
  const the_call_sites = [];
22124
22282
  let accumulated_symbols = create_empty_symbol_table();
22125
22283
  const my_caller_dir = path5.dirname(URI.parse(file_uri).fsPath);
22126
- const { timeline: cd_timeline, diagnostics: cd_diagnostics } = build_cd_timeline({
22284
+ const my_casing_collector = this.collector_by_visited.get(my_context.visited);
22285
+ const {
22286
+ timeline: cd_timeline,
22287
+ diagnostics: cd_diagnostics,
22288
+ depends_on_directory_casing
22289
+ } = build_cd_timeline({
22127
22290
  starting_wd: my_context.working_directory,
22128
22291
  caller_dir: my_caller_dir,
22129
22292
  cd_commands: my_context.cd_commands ?? [],
22130
22293
  workspace_roots: this.workspace_roots.length > 0 ? this.workspace_roots : undefined,
22131
22294
  fs: this.resolve_fs
22132
22295
  });
22296
+ if (depends_on_directory_casing) {
22297
+ mark_directory_casing(my_casing_collector);
22298
+ }
22133
22299
  if (my_context.diagnostic_owner_uri !== undefined && file_uri === my_context.diagnostic_owner_uri && my_context.depth === 0) {
22134
22300
  const my_source_filename = path5.basename(URI.parse(file_uri).fsPath);
22135
22301
  for (const my_cd_diag of cd_diagnostics) {
@@ -22176,16 +22342,16 @@ class ForwardScopeResolver {
22176
22342
  break;
22177
22343
  }
22178
22344
  const my_effective_type = this.compute_effective_call_type(my_call.type, my_context.effective_call_type);
22179
- const my_path_result = this.resolve_call_path(my_call.raw_path, file_uri, effective_call_wd);
22345
+ const my_path_result = this.resolve_call_path(my_call.raw_path, file_uri, effective_call_wd, my_casing_collector);
22180
22346
  const resolved_path = my_path_result.resolved_path;
22181
22347
  const callee_uri = URI.file(resolved_path).toString();
22182
22348
  if (my_path_result.outcome_kind === "case_only" && my_context.diagnostic_owner_uri !== undefined && file_uri === my_context.diagnostic_owner_uri && my_context.depth === 0) {
22183
- const my_requested = my_path_result.requested_path ?? my_call.raw_path;
22184
- const my_real = my_path_result.resolved_path;
22185
- const my_req_disp = path5.relative(path5.dirname(URI.parse(file_uri).fsPath), my_requested).replace(/\\/g, "/") || my_requested;
22186
- const my_real_disp = path5.relative(path5.dirname(URI.parse(file_uri).fsPath), my_real).replace(/\\/g, "/") || my_real;
22349
+ const my_display = case_mismatch_display_paths(my_call.raw_path, {
22350
+ path: my_path_result.resolved_path,
22351
+ requested: my_path_result.requested_path ?? my_call.raw_path
22352
+ }, path5.dirname(URI.parse(file_uri).fsPath));
22187
22353
  my_context.diagnostics.push({
22188
- message: `Path "${my_req_disp}" does not match the file ` + `on disk "${my_real_disp}"; Stata will not find ` + `it on case-sensitive filesystems (Linux). ` + `Update the path to match.`,
22354
+ message: `Path "${my_display.requested}" does not match ` + `the file on disk "${my_display.on_disk}"; ` + `Stata will not find ` + `it on case-sensitive filesystems (Linux). ` + `Update the path to match.`,
22189
22355
  range: my_call.range,
22190
22356
  severity: "warning",
22191
22357
  kind: "path_case_mismatch",
@@ -22233,7 +22399,7 @@ class ForwardScopeResolver {
22233
22399
  if ("error" in callee_result) {
22234
22400
  continue;
22235
22401
  }
22236
- const effective_end_state = await this.compute_effective_end_state_locals(callee_uri, resolved_path, callee_result.working_directory ?? effective_call_wd, new Set(my_stack), my_context.depth + 1, resolved_config, token);
22402
+ const effective_end_state = await this.compute_effective_end_state_locals(callee_uri, resolved_path, callee_result.working_directory ?? effective_call_wd, new Set(my_stack), my_context.depth + 1, resolved_config, token, my_casing_collector);
22237
22403
  const boundary_excluded = effective_end_state.size > 0 ? effective_end_state : undefined;
22238
22404
  the_call_sites.push({
22239
22405
  callee_uri,
@@ -22281,7 +22447,7 @@ class ForwardScopeResolver {
22281
22447
  }
22282
22448
  let excluded_locals;
22283
22449
  if (my_call.type !== "include" && my_effective_type === "do" && my_context.depth === 0) {
22284
- const effective_end_state = await this.compute_effective_end_state_locals(callee_uri, resolved_path, callee_result.working_directory ?? effective_call_wd, new Set(my_stack), my_context.depth + 1, resolved_config, token);
22450
+ const effective_end_state = await this.compute_effective_end_state_locals(callee_uri, resolved_path, callee_result.working_directory ?? effective_call_wd, new Set(my_stack), my_context.depth + 1, resolved_config, token, my_casing_collector);
22285
22451
  if (effective_end_state.size > 0) {
22286
22452
  excluded_locals = effective_end_state;
22287
22453
  }
@@ -22383,8 +22549,12 @@ class ForwardScopeResolver {
22383
22549
  const fresh_diagnostics = [];
22384
22550
  this.memo_metrics.misses++;
22385
22551
  this.standalone_in_flight.add(callee_uri);
22386
- const my_probe_collector = new Set;
22552
+ const my_probe_collector = {
22553
+ probes: new Set,
22554
+ depends_on_directory_casing: false
22555
+ };
22387
22556
  this.active_probe_collectors.push(my_probe_collector);
22557
+ this.collector_by_visited.set(fresh_visited, my_probe_collector);
22388
22558
  let standalone;
22389
22559
  try {
22390
22560
  standalone = await this.resolve(callee_uri, forward_calls, effective_call_type, {
@@ -22407,6 +22577,7 @@ class ForwardScopeResolver {
22407
22577
  if (my_collector_index >= 0) {
22408
22578
  this.active_probe_collectors.splice(my_collector_index, 1);
22409
22579
  }
22580
+ this.collector_by_visited.delete(fresh_visited);
22410
22581
  }
22411
22582
  if (token?.isCancellationRequested) {
22412
22583
  return;
@@ -22420,9 +22591,9 @@ class ForwardScopeResolver {
22420
22591
  const dependent_uris = new Set([
22421
22592
  callee_uri,
22422
22593
  ...fresh_visited.keys(),
22423
- ...my_probe_collector
22594
+ ...my_probe_collector.probes
22424
22595
  ]);
22425
- if (fresh_diagnostics.length > 0) {
22596
+ if (fresh_diagnostics.length > 0 || my_probe_collector.depends_on_directory_casing) {
22426
22597
  return this.store_memo_entry(key, {
22427
22598
  kind: "unservable",
22428
22599
  dependent_uris
@@ -22443,10 +22614,11 @@ class ForwardScopeResolver {
22443
22614
  }
22444
22615
  this.forward_closure_memo.set(key, entry);
22445
22616
  for (const my_dep_uri of entry.dependent_uris) {
22446
- let my_key_set = this.memo_uri_to_keys.get(my_dep_uri);
22617
+ const my_index_key = this.memo_index_key(my_dep_uri);
22618
+ let my_key_set = this.memo_uri_to_keys.get(my_index_key);
22447
22619
  if (!my_key_set) {
22448
22620
  my_key_set = new Set;
22449
- this.memo_uri_to_keys.set(my_dep_uri, my_key_set);
22621
+ this.memo_uri_to_keys.set(my_index_key, my_key_set);
22450
22622
  }
22451
22623
  my_key_set.add(key);
22452
22624
  }
@@ -22499,7 +22671,7 @@ class ForwardScopeResolver {
22499
22671
  }
22500
22672
  return result;
22501
22673
  }
22502
- async compute_effective_end_state_locals(callee_uri, callee_fs_path, working_directory, stack, depth, resolved_config, token) {
22674
+ async compute_effective_end_state_locals(callee_uri, callee_fs_path, working_directory, stack, depth, resolved_config, token, casing_collector) {
22503
22675
  if (token?.isCancellationRequested)
22504
22676
  return new Map;
22505
22677
  if (stack.has(callee_uri))
@@ -22551,13 +22723,19 @@ class ForwardScopeResolver {
22551
22723
  the_events.sort((a, b) => a.line - b.line || a.character - b.character);
22552
22724
  const the_effective = new Map;
22553
22725
  const nested_base_wd = callee_result.working_directory ?? working_directory;
22554
- const { timeline: nested_cd_timeline } = build_cd_timeline({
22726
+ const {
22727
+ timeline: nested_cd_timeline,
22728
+ depends_on_directory_casing: nested_depends_on_casing
22729
+ } = build_cd_timeline({
22555
22730
  starting_wd: nested_base_wd,
22556
22731
  caller_dir: path5.dirname(URI.parse(callee_uri).fsPath),
22557
22732
  cd_commands: callee_result.cd_commands,
22558
22733
  workspace_roots: this.workspace_roots.length > 0 ? this.workspace_roots : undefined,
22559
22734
  fs: this.resolve_fs
22560
22735
  });
22736
+ if (nested_depends_on_casing) {
22737
+ mark_directory_casing(casing_collector);
22738
+ }
22561
22739
  for (const my_event of the_events) {
22562
22740
  if (token?.isCancellationRequested)
22563
22741
  break;
@@ -22565,12 +22743,12 @@ class ForwardScopeResolver {
22565
22743
  the_effective.set(my_event.name, my_event.symbol);
22566
22744
  } else {
22567
22745
  const event_wd = wd_for_position(nested_cd_timeline, my_event.call.range.start);
22568
- const nested_resolved = this.resolve_call_path_simple(my_event.call.raw_path, callee_uri, event_wd);
22746
+ const nested_resolved = this.resolve_call_path_simple(my_event.call.raw_path, callee_uri, event_wd, casing_collector);
22569
22747
  if (nested_resolved === null) {
22570
22748
  continue;
22571
22749
  }
22572
22750
  const nested_uri = URI.file(nested_resolved).toString();
22573
- const nested_effective = await this.compute_effective_end_state_locals(nested_uri, nested_resolved, event_wd, stack, depth + 1, resolved_config, token);
22751
+ const nested_effective = await this.compute_effective_end_state_locals(nested_uri, nested_resolved, event_wd, stack, depth + 1, resolved_config, token, casing_collector);
22574
22752
  for (const [my_name, my_symbol] of nested_effective) {
22575
22753
  the_effective.set(my_name, my_symbol);
22576
22754
  }
@@ -22665,9 +22843,6 @@ function scope_resolver_config_for(config) {
22665
22843
 
22666
22844
  class ScopeResolver {
22667
22845
  directive_parser;
22668
- lexer;
22669
- parser;
22670
- analyzer;
22671
22846
  file_cache;
22672
22847
  scope_cache;
22673
22848
  uri_to_cache_keys;
@@ -22682,9 +22857,6 @@ class ScopeResolver {
22682
22857
  resolve_fs;
22683
22858
  constructor(logger2, content_provider, cache_capacities) {
22684
22859
  this.directive_parser = new DirectiveParser;
22685
- this.lexer = new StataLexer;
22686
- this.parser = new StataParser;
22687
- this.analyzer = new SemanticAnalyzer;
22688
22860
  this.file_cache = new BoundedLruMap(cache_capacities?.max_cached_files ?? DEFAULT_MAX_CACHED_FILES, {
22689
22861
  on_evict: (_key, entry) => {
22690
22862
  this.cache_metrics.file.evictions++;
@@ -23364,6 +23536,16 @@ class ScopeResolver {
23364
23536
  };
23365
23537
  return this.discover_working_directory(the_backward_directives, new Set, 0, my_config, new Map, current_uri, undefined, true);
23366
23538
  }
23539
+ async resolve_document_working_directory(file_uri, directive_result, config = {}, token) {
23540
+ if (token?.isCancellationRequested || directive_result.working_directory) {
23541
+ return;
23542
+ }
23543
+ const my_config = { ...DEFAULT_CONFIG2, ...config };
23544
+ const { directives: effective_directives } = this.get_effective_backward_directives(file_uri, directive_result.directives, my_config, directive_result.standalone !== undefined);
23545
+ const normalized_directives = this.normalize_directives(effective_directives, []);
23546
+ const working_directory = await this.discover_working_directory(normalized_directives, new Set([file_uri]), 1, my_config, new Map, file_uri, token, true);
23547
+ return token?.isCancellationRequested ? undefined : working_directory;
23548
+ }
23367
23549
  async discover_working_directory(directives, visited, depth, config, request_cache, current_uri, token, skip_backward_registration) {
23368
23550
  if (depth > config.max_backward_depth) {
23369
23551
  return;
@@ -23733,9 +23915,10 @@ class ScopeResolver {
23733
23915
  }
23734
23916
  }
23735
23917
  parse_content(uri, content, inherited_working_directory) {
23736
- const my_directive_result = this.directive_parser.parse(content, uri);
23737
- const my_lex_result = this.lexer.tokenize(content);
23738
- const my_parse_result = this.parser.parse(my_lex_result.tokens);
23918
+ const {
23919
+ directives: my_directive_result,
23920
+ analysis: my_analysis
23921
+ } = analyze_source(content, uri);
23739
23922
  const my_workspace_root = get_workspace_root_for_uri(this.workspace_roots, uri);
23740
23923
  let own_working_directory;
23741
23924
  if (my_directive_result.working_directory) {
@@ -23748,32 +23931,15 @@ class ScopeResolver {
23748
23931
  }
23749
23932
  }
23750
23933
  const effective_working_directory = own_working_directory ?? inherited_working_directory;
23751
- const my_analysis = this.analyzer.analyze(my_parse_result.ast, uri, undefined, {
23752
- working_directory: effective_working_directory
23753
- }, my_lex_result.tokens);
23754
- const my_caller_dir = path6.dirname(URI.parse(uri).fsPath);
23755
- const { timeline: cd_timeline } = build_cd_timeline({
23756
- starting_wd: effective_working_directory,
23757
- caller_dir: my_caller_dir,
23934
+ const all_forward_calls = prepare_forward_calls({
23935
+ uri,
23936
+ command_calls: my_analysis.forward_calls,
23937
+ directive_calls: my_directive_result.forward_calls ?? [],
23758
23938
  cd_commands: my_analysis.cd_commands,
23939
+ working_directory: effective_working_directory,
23759
23940
  workspace_roots: this.workspace_roots,
23760
23941
  fs: this.resolve_fs
23761
23942
  });
23762
- const restamped_command_calls = apply_cd_timeline(my_analysis.forward_calls, cd_timeline);
23763
- const directive_forward_calls = (my_directive_result.forward_calls ?? []).map((d) => ({
23764
- type: d.type,
23765
- raw_path: d.raw_path,
23766
- call_site_line: d.call_site_line,
23767
- range: d.range,
23768
- source: "directive",
23769
- is_static: true,
23770
- caller_uri: uri,
23771
- working_directory: effective_working_directory
23772
- }));
23773
- const all_forward_calls = [
23774
- ...restamped_command_calls,
23775
- ...directive_forward_calls
23776
- ];
23777
23943
  return {
23778
23944
  symbols: my_analysis.symbols,
23779
23945
  directives: my_directive_result.directives,
@@ -24607,9 +24773,8 @@ var init_scope_resolver = __esm(() => {
24607
24773
  init_esm();
24608
24774
  init_types();
24609
24775
  init_directive_parser();
24610
- init_lexer();
24611
- init_parser();
24612
24776
  init_analyzer();
24777
+ init_source_analysis();
24613
24778
  init_logger();
24614
24779
  init_lru_cache();
24615
24780
  init_dofile_locals();
@@ -25062,6 +25227,476 @@ var init_source_discovery_policy = __esm(() => {
25062
25227
  init_workspace_roots();
25063
25228
  });
25064
25229
 
25230
+ // node_modules/ignore/index.js
25231
+ var require_ignore = __commonJS((exports, module) => {
25232
+ function makeArray(subject) {
25233
+ return Array.isArray(subject) ? subject : [subject];
25234
+ }
25235
+ var UNDEFINED = undefined;
25236
+ var EMPTY = "";
25237
+ var SPACE = " ";
25238
+ var ESCAPE = "\\";
25239
+ var REGEX_TEST_BLANK_LINE = /^\s+$/;
25240
+ var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
25241
+ var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
25242
+ var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
25243
+ var REGEX_SPLITALL_CRLF = /\r?\n/g;
25244
+ var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
25245
+ var REGEX_TEST_TRAILING_SLASH = /\/$/;
25246
+ var SLASH = "/";
25247
+ var TMP_KEY_IGNORE = "node-ignore";
25248
+ if (typeof Symbol !== "undefined") {
25249
+ TMP_KEY_IGNORE = Symbol.for("node-ignore");
25250
+ }
25251
+ var KEY_IGNORE = TMP_KEY_IGNORE;
25252
+ var define2 = (object, key, value) => {
25253
+ Object.defineProperty(object, key, { value });
25254
+ return value;
25255
+ };
25256
+ var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
25257
+ var RETURN_FALSE = () => false;
25258
+ var sanitizeRange = (range) => range.replace(REGEX_REGEXP_RANGE, (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY);
25259
+ var cleanRangeBackSlash = (slashes) => {
25260
+ const { length } = slashes;
25261
+ return slashes.slice(0, length - length % 2);
25262
+ };
25263
+ var REPLACERS = [
25264
+ [
25265
+ /^\uFEFF/,
25266
+ () => EMPTY
25267
+ ],
25268
+ [
25269
+ /((?:\\\\)*?)(\\?\s+)$/,
25270
+ (_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
25271
+ ],
25272
+ [
25273
+ /(\\+?)\s/g,
25274
+ (_, m1) => {
25275
+ const { length } = m1;
25276
+ return m1.slice(0, length - length % 2) + SPACE;
25277
+ }
25278
+ ],
25279
+ [
25280
+ /[\\$.|*+(){^]/g,
25281
+ (match) => `\\${match}`
25282
+ ],
25283
+ [
25284
+ /(?!\\)\?/g,
25285
+ () => "[^/]"
25286
+ ],
25287
+ [
25288
+ /^\//,
25289
+ () => "^"
25290
+ ],
25291
+ [
25292
+ /\//g,
25293
+ () => "\\/"
25294
+ ],
25295
+ [
25296
+ /^\^*\\\*\\\*\\\//,
25297
+ () => "^(?:.*\\/)?"
25298
+ ],
25299
+ [
25300
+ /^(?=[^^])/,
25301
+ function startingReplacer() {
25302
+ return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
25303
+ }
25304
+ ],
25305
+ [
25306
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
25307
+ (_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
25308
+ ],
25309
+ [
25310
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
25311
+ (_, p1, p2) => {
25312
+ const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
25313
+ return p1 + unescaped;
25314
+ }
25315
+ ],
25316
+ [
25317
+ /\\\\\\(?=[$.|*+(){^])/g,
25318
+ () => ESCAPE
25319
+ ],
25320
+ [
25321
+ /\\\\/g,
25322
+ () => ESCAPE
25323
+ ],
25324
+ [
25325
+ /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
25326
+ (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` : close === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
25327
+ ],
25328
+ [
25329
+ /(?:[^*])$/,
25330
+ (match) => /\/$/.test(match) ? `${match}$` : `${match}(?=$|\\/$)`
25331
+ ]
25332
+ ];
25333
+ var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
25334
+ var MODE_IGNORE = "regex";
25335
+ var MODE_CHECK_IGNORE = "checkRegex";
25336
+ var UNDERSCORE = "_";
25337
+ var TRAILING_WILD_CARD_REPLACERS = {
25338
+ [MODE_IGNORE](_, p1) {
25339
+ const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
25340
+ return `${prefix}(?=$|\\/$)`;
25341
+ },
25342
+ [MODE_CHECK_IGNORE](_, p1) {
25343
+ const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
25344
+ return `${prefix}(?=$|\\/$)`;
25345
+ }
25346
+ };
25347
+ var makeRegexPrefix = (pattern) => REPLACERS.reduce((prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)), pattern);
25348
+ var isString = (subject) => typeof subject === "string";
25349
+ var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
25350
+ var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
25351
+
25352
+ class IgnoreRule {
25353
+ constructor(pattern, mark, body, ignoreCase, negative, prefix) {
25354
+ this.pattern = pattern;
25355
+ this.mark = mark;
25356
+ this.negative = negative;
25357
+ define2(this, "body", body);
25358
+ define2(this, "ignoreCase", ignoreCase);
25359
+ define2(this, "regexPrefix", prefix);
25360
+ }
25361
+ get regex() {
25362
+ const key = UNDERSCORE + MODE_IGNORE;
25363
+ if (this[key]) {
25364
+ return this[key];
25365
+ }
25366
+ return this._make(MODE_IGNORE, key);
25367
+ }
25368
+ get checkRegex() {
25369
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
25370
+ if (this[key]) {
25371
+ return this[key];
25372
+ }
25373
+ return this._make(MODE_CHECK_IGNORE, key);
25374
+ }
25375
+ _make(mode, key) {
25376
+ const str = this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, TRAILING_WILD_CARD_REPLACERS[mode]);
25377
+ const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
25378
+ return define2(this, key, regex);
25379
+ }
25380
+ }
25381
+ var createRule = ({
25382
+ pattern,
25383
+ mark
25384
+ }, ignoreCase) => {
25385
+ let negative = false;
25386
+ let body = pattern;
25387
+ if (body.indexOf("!") === 0) {
25388
+ negative = true;
25389
+ body = body.substr(1);
25390
+ }
25391
+ body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
25392
+ const regexPrefix = makeRegexPrefix(body);
25393
+ return new IgnoreRule(pattern, mark, body, ignoreCase, negative, regexPrefix);
25394
+ };
25395
+
25396
+ class RuleManager {
25397
+ constructor(ignoreCase) {
25398
+ this._ignoreCase = ignoreCase;
25399
+ this._rules = [];
25400
+ }
25401
+ _add(pattern) {
25402
+ if (pattern && pattern[KEY_IGNORE]) {
25403
+ this._rules = this._rules.concat(pattern._rules._rules);
25404
+ this._added = true;
25405
+ return;
25406
+ }
25407
+ if (isString(pattern)) {
25408
+ pattern = {
25409
+ pattern
25410
+ };
25411
+ }
25412
+ if (checkPattern(pattern.pattern)) {
25413
+ const rule = createRule(pattern, this._ignoreCase);
25414
+ this._added = true;
25415
+ this._rules.push(rule);
25416
+ }
25417
+ }
25418
+ add(pattern) {
25419
+ this._added = false;
25420
+ makeArray(isString(pattern) ? splitPattern(pattern) : pattern).forEach(this._add, this);
25421
+ return this._added;
25422
+ }
25423
+ test(path10, checkUnignored, mode) {
25424
+ let ignored = false;
25425
+ let unignored = false;
25426
+ let matchedRule;
25427
+ this._rules.forEach((rule) => {
25428
+ const { negative } = rule;
25429
+ if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
25430
+ return;
25431
+ }
25432
+ const matched = rule[mode].test(path10);
25433
+ if (!matched) {
25434
+ return;
25435
+ }
25436
+ ignored = !negative;
25437
+ unignored = negative;
25438
+ matchedRule = negative ? UNDEFINED : rule;
25439
+ });
25440
+ const ret = {
25441
+ ignored,
25442
+ unignored
25443
+ };
25444
+ if (matchedRule) {
25445
+ ret.rule = matchedRule;
25446
+ }
25447
+ return ret;
25448
+ }
25449
+ }
25450
+ var throwError = (message, Ctor) => {
25451
+ throw new Ctor(message);
25452
+ };
25453
+ var checkPath = (path10, originalPath, doThrow) => {
25454
+ if (!isString(path10)) {
25455
+ return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
25456
+ }
25457
+ if (!path10) {
25458
+ return doThrow(`path must not be empty`, TypeError);
25459
+ }
25460
+ if (checkPath.isNotRelative(path10)) {
25461
+ const r = "`path.relative()`d";
25462
+ return doThrow(`path should be a ${r} string, but got "${originalPath}"`, RangeError);
25463
+ }
25464
+ return true;
25465
+ };
25466
+ var isNotRelative = (path10) => REGEX_TEST_INVALID_PATH.test(path10);
25467
+ checkPath.isNotRelative = isNotRelative;
25468
+ checkPath.convert = (p) => p;
25469
+
25470
+ class Ignore {
25471
+ constructor({
25472
+ ignorecase = true,
25473
+ ignoreCase = ignorecase,
25474
+ allowRelativePaths = false
25475
+ } = {}) {
25476
+ define2(this, KEY_IGNORE, true);
25477
+ this._rules = new RuleManager(ignoreCase);
25478
+ this._strictPathCheck = !allowRelativePaths;
25479
+ this._initCache();
25480
+ }
25481
+ _initCache() {
25482
+ this._ignoreCache = Object.create(null);
25483
+ this._testCache = Object.create(null);
25484
+ }
25485
+ add(pattern) {
25486
+ if (this._rules.add(pattern)) {
25487
+ this._initCache();
25488
+ }
25489
+ return this;
25490
+ }
25491
+ addPattern(pattern) {
25492
+ return this.add(pattern);
25493
+ }
25494
+ _test(originalPath, cache, checkUnignored, slices) {
25495
+ const path10 = originalPath && checkPath.convert(originalPath);
25496
+ checkPath(path10, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
25497
+ return this._t(path10, cache, checkUnignored, slices);
25498
+ }
25499
+ checkIgnore(path10) {
25500
+ if (!REGEX_TEST_TRAILING_SLASH.test(path10)) {
25501
+ return this.test(path10);
25502
+ }
25503
+ const slices = path10.split(SLASH).filter(Boolean);
25504
+ slices.pop();
25505
+ if (slices.length) {
25506
+ const parent = this._t(slices.join(SLASH) + SLASH, this._testCache, true, slices);
25507
+ if (parent.ignored) {
25508
+ return parent;
25509
+ }
25510
+ }
25511
+ return this._rules.test(path10, false, MODE_CHECK_IGNORE);
25512
+ }
25513
+ _t(path10, cache, checkUnignored, slices) {
25514
+ if (path10 in cache) {
25515
+ return cache[path10];
25516
+ }
25517
+ if (!slices) {
25518
+ slices = path10.split(SLASH).filter(Boolean);
25519
+ }
25520
+ slices.pop();
25521
+ if (!slices.length) {
25522
+ return cache[path10] = this._rules.test(path10, checkUnignored, MODE_IGNORE);
25523
+ }
25524
+ const parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);
25525
+ return cache[path10] = parent.ignored ? parent : this._rules.test(path10, checkUnignored, MODE_IGNORE);
25526
+ }
25527
+ ignores(path10) {
25528
+ return this._test(path10, this._ignoreCache, false).ignored;
25529
+ }
25530
+ createFilter() {
25531
+ return (path10) => !this.ignores(path10);
25532
+ }
25533
+ filter(paths) {
25534
+ return makeArray(paths).filter(this.createFilter());
25535
+ }
25536
+ test(path10) {
25537
+ return this._test(path10, this._testCache, true);
25538
+ }
25539
+ }
25540
+ var factory = (options) => new Ignore(options);
25541
+ var isPathValid = (path10) => checkPath(path10 && checkPath.convert(path10), path10, RETURN_FALSE);
25542
+ var setupWindows = () => {
25543
+ const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
25544
+ checkPath.convert = makePosix;
25545
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
25546
+ checkPath.isNotRelative = (path10) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path10) || isNotRelative(path10);
25547
+ };
25548
+ if (typeof process !== "undefined" && process.platform === "win32") {
25549
+ setupWindows();
25550
+ }
25551
+ module.exports = factory;
25552
+ factory.default = factory;
25553
+ module.exports.isPathValid = isPathValid;
25554
+ define2(module.exports, Symbol.for("setupWindows"), setupWindows);
25555
+ });
25556
+
25557
+ // src/utils/gitignore-matcher.ts
25558
+ import * as fs9 from "fs";
25559
+ import * as path10 from "path";
25560
+ function rebase_patterns(content, relative_directory) {
25561
+ const pattern_content = content.startsWith("\uFEFF") ? content.slice(1) : content;
25562
+ const the_lines = pattern_content.split(IGNORE_LINE_BREAK);
25563
+ if (relative_directory === "")
25564
+ return the_lines;
25565
+ LITERAL_DIRECTORY_METACHARACTERS.lastIndex = 0;
25566
+ const prefix = relative_directory.replace(LITERAL_DIRECTORY_METACHARACTERS, "\\$&");
25567
+ const the_patterns = [];
25568
+ for (const my_line of the_lines) {
25569
+ if (BLANK_PATTERN.test(my_line) || my_line.startsWith("#"))
25570
+ continue;
25571
+ const negative = my_line.startsWith("!");
25572
+ const body = negative ? my_line.slice(1) : my_line;
25573
+ const shape = body.replace(TRAILING_PATTERN_WHITESPACE, "");
25574
+ if (shape === "" || shape === "/")
25575
+ continue;
25576
+ const anchored = body.startsWith("/") || MIDDLE_SLASH.test(shape);
25577
+ const relative_pattern = (body.startsWith("/") ? body.slice(1) : body).replace(ESCAPED_PATTERN_PREFIX, "$1");
25578
+ the_patterns.push(`${negative ? "!" : ""}/${prefix}/` + `${anchored ? "" : "**/"}${relative_pattern}`);
25579
+ }
25580
+ return the_patterns;
25581
+ }
25582
+ function is_missing(error) {
25583
+ return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
25584
+ }
25585
+ function contains_path(root, target) {
25586
+ const relative5 = path10.relative(root, target);
25587
+ return relative5 !== ".." && !relative5.startsWith(`..${path10.sep}`) && !path10.isAbsolute(relative5);
25588
+ }
25589
+ function create_gitignore_matcher(workspace_roots, respect_gitignore = true) {
25590
+ if (!respect_gitignore || workspace_roots.length === 0) {
25591
+ return DISABLED_MATCHER;
25592
+ }
25593
+ let warned = false;
25594
+ function warn_unreadable(file_path, error) {
25595
+ if (warned || is_missing(error))
25596
+ return;
25597
+ warned = true;
25598
+ const detail = error instanceof Error ? error.message : String(error);
25599
+ logger.warn(`Cannot read Gitignore rules at ${file_path}: ${detail}. ` + "Continuing with the available rules.");
25600
+ }
25601
+ function find_rule_root(workspace_root) {
25602
+ let directory = workspace_root;
25603
+ while (true) {
25604
+ const marker_path = path10.join(directory, ".git");
25605
+ try {
25606
+ const marker = fs9.lstatSync(marker_path);
25607
+ if (marker.isDirectory() || marker.isFile())
25608
+ return directory;
25609
+ } catch (error) {
25610
+ warn_unreadable(marker_path, error);
25611
+ }
25612
+ const parent = path10.dirname(directory);
25613
+ if (parent === directory)
25614
+ return workspace_root;
25615
+ directory = parent;
25616
+ }
25617
+ }
25618
+ function read_rules(scope, directory, inherited_rules) {
25619
+ const ignore_path = path10.join(directory, ".gitignore");
25620
+ try {
25621
+ if (fs9.lstatSync(ignore_path).isFile()) {
25622
+ const content = fs9.readFileSync(ignore_path, "utf8");
25623
+ const relative_directory = path10.relative(scope.rule_root, directory).split(path10.sep).join("/");
25624
+ return import_ignore.default({ ignorecase: false }).add(inherited_rules ?? []).add(rebase_patterns(content, relative_directory));
25625
+ }
25626
+ } catch (error) {
25627
+ warn_unreadable(ignore_path, error);
25628
+ }
25629
+ return inherited_rules ?? import_ignore.default({ ignorecase: false });
25630
+ }
25631
+ function matches_rules(context, absolute_path, kind) {
25632
+ if (context.ignored)
25633
+ return true;
25634
+ const relative5 = path10.relative(context.rule_root, absolute_path).split(path10.sep).join("/");
25635
+ return context.rules.ignores(kind === "directory" ? `${relative5}/` : relative5);
25636
+ }
25637
+ function directory_context(scope, directory) {
25638
+ const cached = scope.directories.get(directory);
25639
+ if (cached)
25640
+ return cached;
25641
+ const parent = path10.relative(scope.rule_root, directory) === "" ? undefined : directory_context(scope, path10.dirname(directory));
25642
+ const ignored = parent !== undefined && matches_rules(parent, directory, "directory");
25643
+ const context = {
25644
+ rule_root: scope.rule_root,
25645
+ ignored,
25646
+ rules: ignored && parent ? parent.rules : read_rules(scope, directory, parent?.rules)
25647
+ };
25648
+ scope.directories.set(directory, context);
25649
+ return context;
25650
+ }
25651
+ const the_scopes = Array.from(new Set(workspace_roots.map((my_root) => path10.resolve(my_root)))).sort((a, b) => b.length - a.length).map((workspace_root) => ({
25652
+ workspace_root,
25653
+ rule_root: find_rule_root(workspace_root),
25654
+ directories: new Map
25655
+ }));
25656
+ const the_watch_directories = new Map;
25657
+ for (const my_scope of the_scopes) {
25658
+ the_watch_directories.set(my_scope.workspace_root, true);
25659
+ let directory = my_scope.workspace_root;
25660
+ while (directory !== my_scope.rule_root) {
25661
+ directory = path10.dirname(directory);
25662
+ if (!the_watch_directories.has(directory)) {
25663
+ the_watch_directories.set(directory, false);
25664
+ }
25665
+ }
25666
+ }
25667
+ return {
25668
+ watch_directories: Array.from(the_watch_directories, ([directory, recursive]) => ({ directory, recursive })),
25669
+ is_ignored(absolute_path, kind) {
25670
+ const target = path10.resolve(absolute_path);
25671
+ for (const my_scope of the_scopes) {
25672
+ if (!contains_path(my_scope.workspace_root, target))
25673
+ continue;
25674
+ if (path10.relative(my_scope.workspace_root, target) === "") {
25675
+ return false;
25676
+ }
25677
+ const context = directory_context(my_scope, path10.dirname(target));
25678
+ return matches_rules(context, target, kind);
25679
+ }
25680
+ return false;
25681
+ }
25682
+ };
25683
+ }
25684
+ var import_ignore, DISABLED_MATCHER, IGNORE_LINE_BREAK, BLANK_PATTERN, TRAILING_PATTERN_WHITESPACE, MIDDLE_SLASH, LITERAL_DIRECTORY_METACHARACTERS, ESCAPED_PATTERN_PREFIX;
25685
+ var init_gitignore_matcher = __esm(() => {
25686
+ init_logger();
25687
+ import_ignore = __toESM(require_ignore(), 1);
25688
+ DISABLED_MATCHER = {
25689
+ is_ignored: () => false,
25690
+ watch_directories: []
25691
+ };
25692
+ IGNORE_LINE_BREAK = /\r?\n/;
25693
+ BLANK_PATTERN = /^\s*$/;
25694
+ TRAILING_PATTERN_WHITESPACE = /\s+$/;
25695
+ MIDDLE_SLASH = /\/(?!$)/;
25696
+ LITERAL_DIRECTORY_METACHARACTERS = /[\\*[\]]/g;
25697
+ ESCAPED_PATTERN_PREFIX = /^\\([!#])/;
25698
+ });
25699
+
25065
25700
  // node_modules/picomatch/lib/constants.js
25066
25701
  var require_constants = __commonJS((exports, module) => {
25067
25702
  var WIN_SLASH = "\\\\/";
@@ -25260,8 +25895,8 @@ var require_utils = __commonJS((exports) => {
25260
25895
  }
25261
25896
  return output;
25262
25897
  };
25263
- exports.basename = (path10, { windows } = {}) => {
25264
- const segs = path10.split(windows ? /[\\/]/ : "/");
25898
+ exports.basename = (path11, { windows } = {}) => {
25899
+ const segs = path11.split(windows ? /[\\/]/ : "/");
25265
25900
  const last = segs[segs.length - 1];
25266
25901
  if (last === "") {
25267
25902
  return segs[segs.length - 2];
@@ -26089,9 +26724,9 @@ var require_parse = __commonJS((exports, module) => {
26089
26724
  const idx = prev.value.lastIndexOf("[");
26090
26725
  const pre = prev.value.slice(0, idx);
26091
26726
  const rest2 = prev.value.slice(idx + 2);
26092
- const posix3 = POSIX_REGEX_SOURCE[rest2];
26093
- if (posix3) {
26094
- prev.value = pre + posix3;
26727
+ const posix4 = POSIX_REGEX_SOURCE[rest2];
26728
+ if (posix4) {
26729
+ prev.value = pre + posix4;
26095
26730
  state.backtrack = true;
26096
26731
  advance();
26097
26732
  if (!bos.output && tokens.indexOf(prev) === 1) {
@@ -26612,7 +27247,7 @@ var require_picomatch = __commonJS((exports, module) => {
26612
27247
  throw new TypeError("Expected pattern to be a non-empty string");
26613
27248
  }
26614
27249
  const opts = options || {};
26615
- const posix3 = opts.windows;
27250
+ const posix4 = opts.windows;
26616
27251
  const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
26617
27252
  const state = regex.state;
26618
27253
  delete regex.state;
@@ -26622,8 +27257,8 @@ var require_picomatch = __commonJS((exports, module) => {
26622
27257
  isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
26623
27258
  }
26624
27259
  const matcher = (input, returnObject = false) => {
26625
- const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix: posix3 });
26626
- const result = { glob, state, regex, posix: posix3, input, output, match, isMatch };
27260
+ const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix: posix4 });
27261
+ const result = { glob, state, regex, posix: posix4, input, output, match, isMatch };
26627
27262
  if (typeof opts.onResult === "function") {
26628
27263
  opts.onResult(result);
26629
27264
  }
@@ -26648,7 +27283,7 @@ var require_picomatch = __commonJS((exports, module) => {
26648
27283
  }
26649
27284
  return matcher;
26650
27285
  };
26651
- picomatch.test = (input, regex, options, { glob, posix: posix3 } = {}) => {
27286
+ picomatch.test = (input, regex, options, { glob, posix: posix4 } = {}) => {
26652
27287
  if (typeof input !== "string") {
26653
27288
  throw new TypeError("Expected input to be a string");
26654
27289
  }
@@ -26656,7 +27291,7 @@ var require_picomatch = __commonJS((exports, module) => {
26656
27291
  return { isMatch: false, output: "" };
26657
27292
  }
26658
27293
  const opts = options || {};
26659
- const format = opts.format || (posix3 ? utils.toPosixSlashes : null);
27294
+ const format = opts.format || (posix4 ? utils.toPosixSlashes : null);
26660
27295
  let match = input === glob;
26661
27296
  let output = match && format ? format(input) : input;
26662
27297
  if (match === false) {
@@ -26665,7 +27300,7 @@ var require_picomatch = __commonJS((exports, module) => {
26665
27300
  }
26666
27301
  if (match === false || opts.capture === true) {
26667
27302
  if (opts.matchBase === true || opts.basename === true) {
26668
- match = picomatch.matchBase(input, regex, options, posix3);
27303
+ match = picomatch.matchBase(input, regex, options, posix4);
26669
27304
  } else {
26670
27305
  match = regex.exec(output);
26671
27306
  }
@@ -26742,7 +27377,7 @@ var require_picomatch2 = __commonJS((exports, module) => {
26742
27377
  });
26743
27378
 
26744
27379
  // src/utils/exclude-matcher.ts
26745
- import path10 from "path";
27380
+ import path11 from "path";
26746
27381
  function normalize_pattern(raw) {
26747
27382
  const trimmed = raw.trim();
26748
27383
  if (trimmed === "")
@@ -26764,13 +27399,13 @@ function derive_dir_pattern(pattern) {
26764
27399
  return stripped === "" ? pattern : stripped;
26765
27400
  }
26766
27401
  function relative_to_containing_root(abs_path, workspace_roots) {
26767
- const target = path10.resolve(abs_path);
27402
+ const target = path11.resolve(abs_path);
26768
27403
  let best = null;
26769
27404
  let best_root_length = -1;
26770
27405
  for (const my_root of workspace_roots) {
26771
- const root = path10.resolve(my_root);
26772
- const my_relative = path10.relative(root, target);
26773
- const contained = my_relative === "" || my_relative !== ".." && !my_relative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(my_relative);
27406
+ const root = path11.resolve(my_root);
27407
+ const my_relative = path11.relative(root, target);
27408
+ const contained = my_relative === "" || my_relative !== ".." && !my_relative.startsWith(`..${path11.sep}`) && !path11.isAbsolute(my_relative);
26774
27409
  if (contained && root.length > best_root_length) {
26775
27410
  best = my_relative;
26776
27411
  best_root_length = root.length;
@@ -26778,7 +27413,7 @@ function relative_to_containing_root(abs_path, workspace_roots) {
26778
27413
  }
26779
27414
  if (best === null)
26780
27415
  return null;
26781
- return best.split(path10.sep).join("/");
27416
+ return best.split(path11.sep).join("/");
26782
27417
  }
26783
27418
  function create_exclude_matcher(patterns) {
26784
27419
  const compiled = [];
@@ -26849,15 +27484,13 @@ var init_exclude_matcher = __esm(() => {
26849
27484
  });
26850
27485
 
26851
27486
  // src/indexer/index.ts
26852
- import * as fs9 from "fs";
26853
- import * as path11 from "path";
27487
+ import * as fs10 from "fs";
27488
+ import * as path12 from "path";
26854
27489
  var MAX_PARALLEL = 4, YIELD_INTERVAL_MS = 100, INDEX_DEBOUNCE_MS = 200, WorkspaceIndexer;
26855
27490
  var init_indexer = __esm(() => {
26856
27491
  init_esm();
26857
- init_lexer();
26858
- init_parser();
26859
27492
  init_analyzer();
26860
- init_directive_parser();
27493
+ init_source_analysis();
26861
27494
  init_scope_resolver();
26862
27495
  init_context_tracker();
26863
27496
  init_logger();
@@ -26867,6 +27500,7 @@ var init_indexer = __esm(() => {
26867
27500
  init_findalias_resolver();
26868
27501
  init_file_path_utils();
26869
27502
  init_source_discovery_policy();
27503
+ init_gitignore_matcher();
26870
27504
  init_exclude_matcher();
26871
27505
  WorkspaceIndexer = class WorkspaceIndexer {
26872
27506
  symbol_index = new Map;
@@ -26874,10 +27508,6 @@ var init_indexer = __esm(() => {
26874
27508
  token_index = new Map;
26875
27509
  context_ranges_index = new Map;
26876
27510
  enabled = true;
26877
- lexer = new StataLexer;
26878
- parser = new StataParser;
26879
- analyzer = new SemanticAnalyzer;
26880
- directive_parser = new DirectiveParser;
26881
27511
  ado_paths = [];
26882
27512
  help_search_paths = [];
26883
27513
  findalias_resolver = new FindaliasResolver;
@@ -26892,6 +27522,8 @@ var init_indexer = __esm(() => {
26892
27522
  cancelled = false;
26893
27523
  size_threshold_bytes = 512 * 1024;
26894
27524
  exclude_matcher = create_exclude_matcher([]);
27525
+ respect_gitignore = true;
27526
+ gitignore_matcher = create_gitignore_matcher([]);
26895
27527
  skipped_files = new Map;
26896
27528
  max_indexed_files = 1000;
26897
27529
  max_files_reached = false;
@@ -27001,16 +27633,17 @@ var init_indexer = __esm(() => {
27001
27633
  async initialize(workspace_folders, ado_paths = []) {
27002
27634
  const generation = ++this.scan_generation;
27003
27635
  this.cancelled = false;
27004
- if (!this.enabled) {
27005
- this.dependency_graph?.mark_scan_complete();
27006
- return;
27007
- }
27008
27636
  this.ado_paths = ado_paths;
27009
- this.workspace_roots = workspace_folders.map((f) => path11.resolve(f));
27637
+ this.workspace_roots = workspace_folders.map((f) => path12.resolve(f));
27010
27638
  this.scan_roots = [
27011
27639
  ...this.workspace_roots,
27012
- ...ado_paths.map((my_path) => path11.resolve(my_path))
27640
+ ...ado_paths.map((my_path) => path12.resolve(my_path))
27013
27641
  ];
27642
+ this.gitignore_matcher = create_gitignore_matcher(this.workspace_roots, this.respect_gitignore);
27643
+ if (!this.enabled) {
27644
+ this.dependency_graph?.mark_scan_complete();
27645
+ return;
27646
+ }
27014
27647
  this.help_search_paths = discover_stata_ado_paths();
27015
27648
  const start_time = Date.now();
27016
27649
  for (const folder of [...workspace_folders, ...this.ado_paths]) {
@@ -27032,8 +27665,10 @@ var init_indexer = __esm(() => {
27032
27665
  async scan_directory(dir_path, generation) {
27033
27666
  if (!this.is_active_generation(generation))
27034
27667
  return;
27668
+ if (this.gitignore_matcher.is_ignored(dir_path, "directory"))
27669
+ return;
27035
27670
  try {
27036
- const entries = await fs9.promises.readdir(dir_path, {
27671
+ const entries = await fs10.promises.readdir(dir_path, {
27037
27672
  withFileTypes: true
27038
27673
  });
27039
27674
  if (!this.is_active_generation(generation))
@@ -27042,7 +27677,7 @@ var init_indexer = __esm(() => {
27042
27677
  for (const entry of entries) {
27043
27678
  if (!this.is_active_generation(generation))
27044
27679
  break;
27045
- const entry_path = path11.join(dir_path, entry.name);
27680
+ const entry_path = path12.join(dir_path, entry.name);
27046
27681
  if (entry.isDirectory()) {
27047
27682
  if (entry.name.startsWith(".")) {
27048
27683
  continue;
@@ -27052,6 +27687,8 @@ var init_indexer = __esm(() => {
27052
27687
  }
27053
27688
  await this.scan_directory(entry_path, generation);
27054
27689
  } else if (entry.isFile() && hasStataExtension(entry.name)) {
27690
+ if (this.is_gitignored(entry_path))
27691
+ continue;
27055
27692
  if (!this.exclude_matcher.is_empty && this.exclude_matcher.is_excluded_file(entry_path, this.workspace_roots)) {
27056
27693
  continue;
27057
27694
  }
@@ -27074,7 +27711,7 @@ var init_indexer = __esm(() => {
27074
27711
  const now = Date.now();
27075
27712
  if (now - last_yield_time.value > YIELD_INTERVAL_MS) {
27076
27713
  last_yield_time.value = now;
27077
- await new Promise((resolve10) => setImmediate(resolve10));
27714
+ await new Promise((resolve11) => setImmediate(resolve11));
27078
27715
  }
27079
27716
  }
27080
27717
  };
@@ -27120,6 +27757,8 @@ var init_indexer = __esm(() => {
27120
27757
  const file_uri = URI.file(file_path).toString();
27121
27758
  if (is_hidden_source_path(file_path, this.scan_roots))
27122
27759
  return;
27760
+ if (this.is_gitignored(file_path))
27761
+ return;
27123
27762
  if (!this.exclude_matcher.is_empty && this.exclude_matcher.is_excluded_file(file_path, this.workspace_roots)) {
27124
27763
  this.clear_stale_entry(file_uri);
27125
27764
  return;
@@ -27128,7 +27767,7 @@ var init_indexer = __esm(() => {
27128
27767
  if (!already_indexed && this.should_skip_for_max_indexed_files(file_uri))
27129
27768
  return;
27130
27769
  try {
27131
- const stats = await fs9.promises.stat(file_path);
27770
+ const stats = await fs10.promises.stat(file_path);
27132
27771
  if (!this.is_active_generation(generation))
27133
27772
  return;
27134
27773
  if (stats.size > this.size_threshold_bytes) {
@@ -27138,56 +27777,41 @@ var init_indexer = __esm(() => {
27138
27777
  this.metrics.files_skipped++;
27139
27778
  return;
27140
27779
  }
27141
- const content = await fs9.promises.readFile(file_path, "utf8");
27780
+ const content = await fs10.promises.readFile(file_path, "utf8");
27142
27781
  if (!this.is_active_generation(generation))
27143
27782
  return;
27144
27783
  if (!already_indexed && this.should_skip_for_max_indexed_files(file_uri))
27145
27784
  return;
27146
- if (path11.extname(file_path).toLowerCase() === ".mata") {
27785
+ if (path12.extname(file_path).toLowerCase() === ".mata") {
27147
27786
  await this.index_mata_file(content, file_uri, generation);
27148
27787
  return;
27149
27788
  }
27150
- const directive_result = this.directive_parser.parse(content, file_uri);
27151
- const lexResult = this.lexer.tokenize(content);
27152
- const parseResult = this.parser.parse(lexResult.tokens);
27789
+ const source_analysis = analyze_source(content, file_uri);
27790
+ const directive_result = source_analysis.directives;
27791
+ const analyzeResult = source_analysis.analysis;
27153
27792
  const workspace_root = get_workspace_root_for_path(this.workspace_roots, file_path);
27154
- const analyzeResult = this.analyzer.analyze(parseResult.ast, file_uri, undefined, undefined, lexResult.tokens);
27155
27793
  const own_working_directory = directive_result.working_directory ? resolve_working_directory_directive(directive_result.working_directory, workspace_root) : undefined;
27156
27794
  let effective_working_directory = own_working_directory;
27157
27795
  if (own_working_directory === undefined && this.scope_resolver) {
27158
27796
  effective_working_directory = await this.scope_resolver.resolve_inherited_working_directory(directive_result.directives, file_uri, directive_result.standalone !== undefined, this.scope_resolver_config);
27159
27797
  }
27160
- const my_caller_dir = path11.dirname(file_path);
27161
- const { timeline: cd_timeline } = build_cd_timeline({
27162
- starting_wd: effective_working_directory,
27163
- caller_dir: my_caller_dir,
27798
+ const all_forward_calls = prepare_forward_calls({
27799
+ uri: file_uri,
27800
+ command_calls: analyzeResult.forward_calls,
27801
+ directive_calls: directive_result.forward_calls ?? [],
27164
27802
  cd_commands: analyzeResult.cd_commands,
27803
+ working_directory: effective_working_directory,
27165
27804
  workspace_roots: this.workspace_roots
27166
27805
  });
27167
- const stamped_analyzer_calls = apply_cd_timeline(analyzeResult.forward_calls, cd_timeline);
27168
27806
  const context_tracker = new ContextTracker;
27169
- context_tracker.initialize_from_tokens(lexResult.tokens, content);
27807
+ context_tracker.initialize_from_tokens(source_analysis.tokens, content);
27170
27808
  const context_ranges = context_tracker.get_all_context_ranges();
27171
27809
  if (!this.is_active_generation(generation))
27172
27810
  return;
27173
27811
  if (!already_indexed && this.should_skip_for_max_indexed_files(file_uri))
27174
27812
  return;
27175
- let all_forward_calls = stamped_analyzer_calls;
27176
- if (directive_result.forward_calls && directive_result.forward_calls.length > 0) {
27177
- const directive_forward_calls = directive_result.forward_calls.map((d) => ({
27178
- type: d.type,
27179
- raw_path: d.raw_path,
27180
- call_site_line: d.call_site_line,
27181
- range: d.range,
27182
- source: "directive",
27183
- is_static: true,
27184
- caller_uri: file_uri,
27185
- working_directory: effective_working_directory
27186
- }));
27187
- all_forward_calls = [
27188
- ...stamped_analyzer_calls,
27189
- ...directive_forward_calls
27190
- ].sort((a, b) => a.call_site_line - b.call_site_line);
27813
+ if ((directive_result.forward_calls?.length ?? 0) > 0) {
27814
+ all_forward_calls.sort((a, b) => a.call_site_line - b.call_site_line);
27191
27815
  }
27192
27816
  if (this.dependency_graph) {
27193
27817
  const graph_result = this.dependency_graph.update_caller(file_uri, all_forward_calls);
@@ -27195,7 +27819,7 @@ var init_indexer = __esm(() => {
27195
27819
  this.on_graph_change_callback(graph_result.changed_callees);
27196
27820
  }
27197
27821
  }
27198
- this.token_index.set(file_uri, lexResult.tokens);
27822
+ this.token_index.set(file_uri, source_analysis.tokens);
27199
27823
  this.context_ranges_index.set(file_uri, context_ranges);
27200
27824
  const is_new_entry = !this.symbol_index.has(file_uri);
27201
27825
  this.symbol_index.set(file_uri, {
@@ -27274,6 +27898,8 @@ var init_indexer = __esm(() => {
27274
27898
  return;
27275
27899
  if (is_hidden_source_path(file_path, this.scan_roots))
27276
27900
  return;
27901
+ if (this.is_gitignored(file_path))
27902
+ return;
27277
27903
  const existing = this.pending_updates.get(file_path);
27278
27904
  if (existing) {
27279
27905
  clearTimeout(existing);
@@ -27298,7 +27924,7 @@ var init_indexer = __esm(() => {
27298
27924
  break;
27299
27925
  this.update_queue.delete(file_path);
27300
27926
  await this.index_file(file_path, generation);
27301
- await new Promise((resolve10) => setImmediate(resolve10));
27927
+ await new Promise((resolve11) => setImmediate(resolve11));
27302
27928
  }
27303
27929
  } finally {
27304
27930
  this.is_processing_queue = false;
@@ -27330,10 +27956,12 @@ var init_indexer = __esm(() => {
27330
27956
  this.version = 0;
27331
27957
  this.cancelled = false;
27332
27958
  this.workspace_roots = [];
27959
+ this.gitignore_matcher = create_gitignore_matcher([]);
27333
27960
  }
27334
27961
  configure(config) {
27335
27962
  this.scope_resolver_config = scope_resolver_config_for(config);
27336
27963
  this.exclude_matcher = create_exclude_matcher(config.exclude ?? []);
27964
+ this.respect_gitignore = config.workspace?.respectGitignore !== false;
27337
27965
  const threshold = config?.indexing?.maxFileSizeBytes;
27338
27966
  if (typeof threshold === "number" && threshold > 0) {
27339
27967
  this.size_threshold_bytes = threshold;
@@ -27348,6 +27976,9 @@ var init_indexer = __esm(() => {
27348
27976
  this.enabled = true;
27349
27977
  }
27350
27978
  }
27979
+ is_gitignored(file_path) {
27980
+ return this.gitignore_matcher.is_ignored(file_path, "file");
27981
+ }
27351
27982
  get_skipped_files() {
27352
27983
  return new Map(this.skipped_files);
27353
27984
  }
@@ -27557,17 +28188,17 @@ var init_indexer = __esm(() => {
27557
28188
  ...this.help_search_paths
27558
28189
  ];
27559
28190
  for (const my_dir of the_search_dirs) {
27560
- const my_subdir_path = path11.join(my_dir, my_first_letter, my_basename);
28191
+ const my_subdir_path = path12.join(my_dir, my_first_letter, my_basename);
27561
28192
  try {
27562
- await fs9.promises.access(my_subdir_path);
28193
+ await fs10.promises.access(my_subdir_path);
27563
28194
  return my_subdir_path;
27564
28195
  } catch {}
27565
- const my_direct_path = path11.join(my_dir, my_basename);
28196
+ const my_direct_path = path12.join(my_dir, my_basename);
27566
28197
  try {
27567
- await fs9.promises.access(my_direct_path);
28198
+ await fs10.promises.access(my_direct_path);
27568
28199
  return my_direct_path;
27569
28200
  } catch {}
27570
- if (!this.workspace_roots.includes(path11.resolve(my_dir))) {
28201
+ if (!this.workspace_roots.includes(path12.resolve(my_dir))) {
27571
28202
  continue;
27572
28203
  }
27573
28204
  const my_recursive_match = await this.find_sthlp_file_recursive(my_dir, my_basename);
@@ -27591,14 +28222,14 @@ var init_indexer = __esm(() => {
27591
28222
  ...this.help_search_paths
27592
28223
  ];
27593
28224
  for (const my_dir of the_search_dirs) {
27594
- const my_subdir_path = path11.join(my_dir, my_first_letter, my_basename);
28225
+ const my_subdir_path = path12.join(my_dir, my_first_letter, my_basename);
27595
28226
  try {
27596
- await fs9.promises.access(my_subdir_path);
28227
+ await fs10.promises.access(my_subdir_path);
27597
28228
  return my_subdir_path;
27598
28229
  } catch {}
27599
- const my_direct_path = path11.join(my_dir, my_basename);
28230
+ const my_direct_path = path12.join(my_dir, my_basename);
27600
28231
  try {
27601
- await fs9.promises.access(my_direct_path);
28232
+ await fs10.promises.access(my_direct_path);
27602
28233
  return my_direct_path;
27603
28234
  } catch {}
27604
28235
  }
@@ -27606,9 +28237,9 @@ var init_indexer = __esm(() => {
27606
28237
  }
27607
28238
  async list_matching_sthlp(dir, prefix) {
27608
28239
  try {
27609
- const the_entries = await fs9.promises.readdir(dir);
28240
+ const the_entries = await fs10.promises.readdir(dir);
27610
28241
  const the_matches = the_entries.filter((my_entry) => my_entry.startsWith(prefix) && my_entry.endsWith(".sthlp")).sort();
27611
- return the_matches.map((my_entry) => path11.join(dir, my_entry));
28242
+ return the_matches.map((my_entry) => path12.join(dir, my_entry));
27612
28243
  } catch {
27613
28244
  return [];
27614
28245
  }
@@ -27632,7 +28263,7 @@ var init_indexer = __esm(() => {
27632
28263
  const my_prefix = `${my_variant}_`;
27633
28264
  const my_first_letter = my_variant.charAt(0).toLowerCase();
27634
28265
  for (const my_dir of the_search_dirs) {
27635
- const my_subdir = path11.join(my_dir, my_first_letter);
28266
+ const my_subdir = path12.join(my_dir, my_first_letter);
27636
28267
  const the_subdir_matches = await this.list_matching_sthlp(my_subdir, my_prefix);
27637
28268
  for (const my_match of the_subdir_matches) {
27638
28269
  if (!the_seen.has(my_match)) {
@@ -27670,14 +28301,14 @@ var init_indexer = __esm(() => {
27670
28301
  }
27671
28302
  let the_entries;
27672
28303
  try {
27673
- the_entries = await fs9.promises.readdir(my_entry.path, {
28304
+ the_entries = await fs10.promises.readdir(my_entry.path, {
27674
28305
  withFileTypes: true
27675
28306
  });
27676
28307
  } catch {
27677
28308
  continue;
27678
28309
  }
27679
28310
  for (const my_dirent of the_entries) {
27680
- const my_path = path11.join(my_entry.path, my_dirent.name);
28311
+ const my_path = path12.join(my_entry.path, my_dirent.name);
27681
28312
  if (my_dirent.isDirectory()) {
27682
28313
  if (!WorkspaceIndexer.EXCLUDED_DIRS.has(my_dirent.name)) {
27683
28314
  the_dirs.push({
@@ -27687,7 +28318,7 @@ var init_indexer = __esm(() => {
27687
28318
  }
27688
28319
  continue;
27689
28320
  }
27690
- if (my_dirent.name === basename6 && await entry_is_file_async(my_dirent, my_path, fs9.promises)) {
28321
+ if (my_dirent.name === basename6 && await entry_is_file_async(my_dirent, my_path, fs10.promises)) {
27691
28322
  return my_path;
27692
28323
  }
27693
28324
  }
@@ -27696,9 +28327,9 @@ var init_indexer = __esm(() => {
27696
28327
  }
27697
28328
  resolve_program(name, referring_uri) {
27698
28329
  const referring_path = URI.parse(referring_uri).fsPath;
27699
- const current_dir = path11.dirname(referring_path);
27700
- const local_ado = path11.join(current_dir, `${name}.ado`);
27701
- if (fs9.existsSync(local_ado)) {
28330
+ const current_dir = path12.dirname(referring_path);
28331
+ const local_ado = path12.join(current_dir, `${name}.ado`);
28332
+ if (fs10.existsSync(local_ado)) {
27702
28333
  const local_uri = URI.file(local_ado).toString();
27703
28334
  const entry = this.symbol_index.get(local_uri);
27704
28335
  return entry?.symbols.programs.get(name);
@@ -27717,7 +28348,7 @@ var init_indexer = __esm(() => {
27717
28348
  }
27718
28349
  try {
27719
28350
  const file_path = URI.parse(file_uri).fsPath;
27720
- const content = await fs9.promises.readFile(file_path, "utf8");
28351
+ const content = await fs10.promises.readFile(file_path, "utf8");
27721
28352
  const resolve_config = build_scope_resolver_config(cross_file_config);
27722
28353
  const resolved_scope = await scope_resolver.resolve(file_uri, content, resolve_config);
27723
28354
  return resolved_scope.symbols;
@@ -28005,8 +28636,7 @@ class IndentationDiagnosticAnalyzer {
28005
28636
  }
28006
28637
  return;
28007
28638
  }
28008
- const is_control_flow = node.type === "program" || node.type === "if" || node.type === "else" || node.type === "foreach" || node.type === "forvalues" || node.type === "while" || node.type === "frame";
28009
- if (is_control_flow && node.body) {
28639
+ if (this.is_block_node_type(node) && "body" in node && node.body) {
28010
28640
  for (const child of node.body) {
28011
28641
  const child_start_line = child.range.start.line;
28012
28642
  if (child_start_line === start_line) {
@@ -28052,9 +28682,8 @@ class IndentationDiagnosticAnalyzer {
28052
28682
  }
28053
28683
  return;
28054
28684
  }
28055
- if (this.is_block_node_type(node)) {
28056
- const block_node = node;
28057
- for (const my_child of block_node.body) {
28685
+ if (this.is_block_node_type(node) && "body" in node && node.body) {
28686
+ for (const my_child of node.body) {
28058
28687
  const child_start_line = my_child.range.start.line;
28059
28688
  if (child_start_line === start_line) {
28060
28689
  walk_node(my_child, depth);
@@ -28067,6 +28696,10 @@ class IndentationDiagnosticAnalyzer {
28067
28696
  expected_depths.set(end_line, depth);
28068
28697
  }
28069
28698
  }
28699
+ } else if ("body" in node && node.body) {
28700
+ for (const my_child of node.body) {
28701
+ walk_node(my_child, depth);
28702
+ }
28070
28703
  }
28071
28704
  };
28072
28705
  for (const my_node of document.ast.nodes) {
@@ -28080,7 +28713,7 @@ class IndentationDiagnosticAnalyzer {
28080
28713
  return expected_depths;
28081
28714
  }
28082
28715
  is_block_node_type(node) {
28083
- return node.type === "program" || node.type === "if" || node.type === "else" || node.type === "foreach" || node.type === "forvalues" || node.type === "while" || node.type === "frame";
28716
+ return node.type === "program" || node.type === "if" && !node.is_single_statement || node.type === "else" || node.type === "foreach" || node.type === "forvalues" || node.type === "while" || node.type === "frame";
28084
28717
  }
28085
28718
  should_skip_unnecessary_check(line, lineIndex, block_comment_lines2, continuation_lines) {
28086
28719
  if (block_comment_lines2.has(lineIndex)) {
@@ -31502,8 +32135,8 @@ function format_help_link(topic, display) {
31502
32135
  }
31503
32136
 
31504
32137
  // src/providers/completion.ts
31505
- import * as fs10 from "fs";
31506
- import * as path12 from "path";
32138
+ import * as fs11 from "fs";
32139
+ import * as path13 from "path";
31507
32140
  function coerce_macro_map(value) {
31508
32141
  if (value instanceof Map) {
31509
32142
  return value;
@@ -32269,15 +32902,15 @@ class CompletionProvider {
32269
32902
  const path_parts = clean_path.split("/");
32270
32903
  search_prefix = path_parts.pop() || "";
32271
32904
  const dir_path = path_parts.join("/");
32272
- base_dir = path12.resolve(workspace_root, dir_path);
32905
+ base_dir = path13.resolve(workspace_root, dir_path);
32273
32906
  } else {
32274
32907
  search_prefix = clean_path;
32275
32908
  }
32276
32909
  }
32277
- if (!fs10.existsSync(base_dir) || !fs10.statSync(base_dir).isDirectory()) {
32910
+ if (!fs11.existsSync(base_dir) || !fs11.statSync(base_dir).isDirectory()) {
32278
32911
  return completions;
32279
32912
  }
32280
- const entries = fs10.readdirSync(base_dir, { withFileTypes: true });
32913
+ const entries = fs11.readdirSync(base_dir, { withFileTypes: true });
32281
32914
  for (const entry of entries) {
32282
32915
  if (entry.name.startsWith(".")) {
32283
32916
  continue;
@@ -32285,7 +32918,7 @@ class CompletionProvider {
32285
32918
  if (search_prefix && !entry.name.toLowerCase().startsWith(search_prefix.toLowerCase())) {
32286
32919
  continue;
32287
32920
  }
32288
- const entry_kind = classify_entry_sync(entry, path12.join(base_dir, entry.name), fs10);
32921
+ const entry_kind = classify_entry_sync(entry, path13.join(base_dir, entry.name), fs11);
32289
32922
  if (entry_kind === "directory") {
32290
32923
  completions.push({
32291
32924
  label: entry.name + "/",
@@ -32313,17 +32946,17 @@ class CompletionProvider {
32313
32946
  get_workspace_root(document_uri) {
32314
32947
  try {
32315
32948
  const file_path = document_uri.replace(/^file:\/\//, "");
32316
- let current_dir = path12.dirname(file_path);
32317
- while (current_dir !== path12.dirname(current_dir)) {
32949
+ let current_dir = path13.dirname(file_path);
32950
+ while (current_dir !== path13.dirname(current_dir)) {
32318
32951
  const markers = [".git", "sight.toml", ".sight.json", "package.json", ".vscode"];
32319
32952
  for (const marker of markers) {
32320
- if (fs10.existsSync(path12.join(current_dir, marker))) {
32953
+ if (fs11.existsSync(path13.join(current_dir, marker))) {
32321
32954
  return current_dir;
32322
32955
  }
32323
32956
  }
32324
- current_dir = path12.dirname(current_dir);
32957
+ current_dir = path13.dirname(current_dir);
32325
32958
  }
32326
- return path12.dirname(file_path);
32959
+ return path13.dirname(file_path);
32327
32960
  } catch {
32328
32961
  return null;
32329
32962
  }
@@ -33581,7 +34214,7 @@ var init_help_resolver = __esm(() => {
33581
34214
  });
33582
34215
 
33583
34216
  // src/server-handlers.ts
33584
- import * as fs11 from "fs";
34217
+ import * as fs12 from "fs";
33585
34218
  function create_initialize_handler(on_capabilities_detected, on_initialization_options_detected, on_root_uri_detected) {
33586
34219
  return (params) => {
33587
34220
  const capabilities = params.capabilities;
@@ -33808,7 +34441,7 @@ function create_shutdown_handler(deps, disposables) {
33808
34441
  const SHUTDOWN_TIMEOUT_MS = 500;
33809
34442
  await Promise.race([
33810
34443
  deps.document_store.dispose(),
33811
- new Promise((resolve11) => setTimeout(resolve11, SHUTDOWN_TIMEOUT_MS))
34444
+ new Promise((resolve12) => setTimeout(resolve12, SHUTDOWN_TIMEOUT_MS))
33812
34445
  ]);
33813
34446
  }
33814
34447
  deps?.scope_resolver?.dispose();
@@ -33825,10 +34458,14 @@ function create_exit_handler(on_exit) {
33825
34458
  }
33826
34459
  };
33827
34460
  }
33828
- function create_did_change_watched_files_handler(deps, parse_uri, on_file_changed, on_project_config_changed) {
34461
+ function create_did_change_watched_files_handler(deps, parse_uri, on_file_changed, on_project_config_changed, on_gitignore_changed) {
33829
34462
  return (params) => {
33830
34463
  for (const my_event of params.changes) {
33831
34464
  const file_path = parse_uri(my_event.uri);
34465
+ if (GITIGNORE_PATH.test(file_path)) {
34466
+ on_gitignore_changed?.(my_event.uri);
34467
+ continue;
34468
+ }
33832
34469
  if (is_project_config_event_path(file_path)) {
33833
34470
  on_project_config_changed?.(my_event.uri);
33834
34471
  continue;
@@ -33911,7 +34548,7 @@ function create_shared_ihlp_resolver(deps, max_size = MAX_IHLP_CACHE_SIZE) {
33911
34548
  const my_cached = the_cache.get(my_path);
33912
34549
  if (my_cached !== undefined) {
33913
34550
  try {
33914
- const my_stat = await fs11.promises.stat(my_path);
34551
+ const my_stat = await fs12.promises.stat(my_path);
33915
34552
  if (my_stat.mtimeMs === my_cached.mtime_ms) {
33916
34553
  the_cache.delete(my_path);
33917
34554
  the_cache.set(my_path, my_cached);
@@ -33924,8 +34561,8 @@ function create_shared_ihlp_resolver(deps, max_size = MAX_IHLP_CACHE_SIZE) {
33924
34561
  }
33925
34562
  }
33926
34563
  try {
33927
- const my_stat = await fs11.promises.stat(my_path);
33928
- const my_content = await fs11.promises.readFile(my_path, "utf-8");
34564
+ const my_stat = await fs12.promises.stat(my_path);
34565
+ const my_content = await fs12.promises.readFile(my_path, "utf-8");
33929
34566
  if (the_cache.size >= max_size) {
33930
34567
  const my_first = the_cache.keys().next().value;
33931
34568
  if (my_first !== undefined) {
@@ -33962,7 +34599,7 @@ function create_resolve_sthlp_file_handler(deps, shared_ihlp) {
33962
34599
  if (!deps.workspace_indexer)
33963
34600
  return null;
33964
34601
  try {
33965
- const my_content = await fs11.promises.readFile(file_path, "utf-8");
34602
+ const my_content = await fs12.promises.readFile(file_path, "utf-8");
33966
34603
  return await expand_includes(my_content, my_ihlp_resolver);
33967
34604
  } catch {
33968
34605
  return null;
@@ -34041,7 +34678,7 @@ function create_expand_includes_handler(deps, shared_ihlp) {
34041
34678
  return { content: my_result };
34042
34679
  };
34043
34680
  }
34044
- var import_node7, DEFAULT_SETTINGS, MAX_IHLP_CACHE_SIZE = 500, MAX_RESOLVE_STHLP_NEGATIVE_CACHE_SIZE = 1000;
34681
+ var import_node7, DEFAULT_SETTINGS, GITIGNORE_PATH, MAX_IHLP_CACHE_SIZE = 500, MAX_RESOLVE_STHLP_NEGATIVE_CACHE_SIZE = 1000;
34045
34682
  var init_server_handlers = __esm(() => {
34046
34683
  init_completion();
34047
34684
  init_context_tracker();
@@ -34090,6 +34727,9 @@ var init_server_handlers = __esm(() => {
34090
34727
  adoPaths: [],
34091
34728
  indexWorkspace: true,
34092
34729
  exclude: [],
34730
+ workspace: {
34731
+ respectGitignore: true
34732
+ },
34093
34733
  cross_file: {
34094
34734
  index_workspace: true,
34095
34735
  max_indexed_files: 1000,
@@ -34110,6 +34750,7 @@ var init_server_handlers = __esm(() => {
34110
34750
  },
34111
34751
  debug: false
34112
34752
  };
34753
+ GITIGNORE_PATH = /(?:^|[/\\])\.gitignore$/;
34113
34754
  });
34114
34755
 
34115
34756
  // src/utils/config-validator.ts
@@ -34251,6 +34892,13 @@ function validate_comment_formatting_config(config, log_warning) {
34251
34892
  if (typeof config.indexWorkspace === "boolean") {
34252
34893
  validated_config.indexWorkspace = config.indexWorkspace;
34253
34894
  }
34895
+ if (config.workspace?.respectGitignore !== undefined) {
34896
+ if (typeof config.workspace.respectGitignore === "boolean") {
34897
+ validated_config.workspace.respectGitignore = config.workspace.respectGitignore;
34898
+ } else {
34899
+ log_warning?.("Invalid workspace.respectGitignore: " + `${config.workspace.respectGitignore}. ` + "Using default: " + `${DEFAULT_SETTINGS.workspace.respectGitignore}`);
34900
+ }
34901
+ }
34254
34902
  if (typeof config.debug === "boolean") {
34255
34903
  validated_config.debug = config.debug;
34256
34904
  }
@@ -34562,15 +35210,15 @@ var init_shared = __esm(() => {
34562
35210
  });
34563
35211
 
34564
35212
  // src/cli/source-files.ts
34565
- import * as fs12 from "fs";
34566
- import * as path13 from "path";
35213
+ import * as fs13 from "fs";
35214
+ import * as path14 from "path";
34567
35215
  import { TextDecoder } from "util";
34568
35216
  function canonicalize_existing_path(file_path) {
34569
- return fs12.realpathSync.native(file_path);
35217
+ return fs13.realpathSync.native(file_path);
34570
35218
  }
34571
35219
  function workspace_relative(workspace_root, file_path) {
34572
- const relative6 = path13.relative(workspace_root, file_path);
34573
- const inside = relative6 !== ".." && !relative6.startsWith(`..${path13.sep}`) && !path13.isAbsolute(relative6);
35220
+ const relative6 = path14.relative(workspace_root, file_path);
35221
+ const inside = relative6 !== ".." && !relative6.startsWith(`..${path14.sep}`) && !path14.isAbsolute(relative6);
34574
35222
  return { relative: relative6, inside };
34575
35223
  }
34576
35224
  function relative_path(workspace_root, file_path) {
@@ -34578,30 +35226,34 @@ function relative_path(workspace_root, file_path) {
34578
35226
  if (relative6 === "") {
34579
35227
  return ".";
34580
35228
  }
34581
- return path13.isAbsolute(relative6) ? file_path : relative6.split(path13.sep).join("/");
35229
+ return path14.isAbsolute(relative6) ? file_path : relative6.split(path14.sep).join("/");
34582
35230
  }
34583
35231
  function is_within_workspace(workspace_root, file_path) {
34584
35232
  const { relative: relative6, inside } = workspace_relative(workspace_root, file_path);
34585
35233
  return relative6 === "" || relative6.length > 0 && inside;
34586
35234
  }
34587
- function walk_sources(dir_path, out, operator_errors, workspace_roots, exclude_matcher) {
35235
+ function walk_sources(dir_path, out, operator_errors, workspace_roots, exclude_matcher, gitignore_matcher) {
35236
+ if (gitignore_matcher.is_ignored(dir_path, "directory"))
35237
+ return;
34588
35238
  let entries;
34589
35239
  try {
34590
- entries = fs12.readdirSync(dir_path, { withFileTypes: true });
35240
+ entries = fs13.readdirSync(dir_path, { withFileTypes: true });
34591
35241
  } catch (error) {
34592
35242
  operator_errors.push(`cannot read directory: ${dir_path}: ${error_message(error)}`);
34593
35243
  return;
34594
35244
  }
34595
35245
  for (const entry of entries) {
34596
- const entry_path = path13.join(dir_path, entry.name);
35246
+ const entry_path = path14.join(dir_path, entry.name);
34597
35247
  if (entry.isDirectory()) {
34598
35248
  if (entry.name.startsWith("."))
34599
35249
  continue;
34600
35250
  if (!exclude_matcher.is_empty && exclude_matcher.is_excluded_dir(entry_path, workspace_roots)) {
34601
35251
  continue;
34602
35252
  }
34603
- walk_sources(entry_path, out, operator_errors, workspace_roots, exclude_matcher);
35253
+ walk_sources(entry_path, out, operator_errors, workspace_roots, exclude_matcher, gitignore_matcher);
34604
35254
  } else if (entry.isFile() && hasStataExtension(entry.name)) {
35255
+ if (gitignore_matcher.is_ignored(entry_path, "file"))
35256
+ continue;
34605
35257
  if (!exclude_matcher.is_empty && exclude_matcher.is_excluded_file(entry_path, workspace_roots)) {
34606
35258
  continue;
34607
35259
  }
@@ -34609,20 +35261,21 @@ function walk_sources(dir_path, out, operator_errors, workspace_roots, exclude_m
34609
35261
  }
34610
35262
  }
34611
35263
  }
34612
- function collect_report_targets(input_paths, workspace_root, cwd, exclude_patterns = []) {
35264
+ function collect_report_targets(input_paths, workspace_root, cwd, exclude_patterns = [], respect_gitignore = true) {
34613
35265
  const operator_errors = [];
34614
35266
  const source_paths = [];
34615
- let normalized_root = path13.resolve(workspace_root);
35267
+ let normalized_root = path14.resolve(workspace_root);
34616
35268
  try {
34617
35269
  normalized_root = canonicalize_existing_path(normalized_root);
34618
35270
  } catch {}
34619
35271
  const exclude_matcher = create_exclude_matcher(exclude_patterns);
34620
35272
  const exclude_roots = [normalized_root];
35273
+ const gitignore_matcher = create_gitignore_matcher(exclude_roots, respect_gitignore);
34621
35274
  const has_explicit_paths = input_paths.length > 0;
34622
35275
  const paths_to_collect = input_paths.length > 0 ? input_paths : [normalized_root];
34623
35276
  for (const input_path of paths_to_collect) {
34624
- const resolved_path = path13.resolve(cwd, input_path);
34625
- if (!fs12.existsSync(resolved_path)) {
35277
+ const resolved_path = path14.resolve(cwd, input_path);
35278
+ if (!fs13.existsSync(resolved_path)) {
34626
35279
  operator_errors.push(`path does not exist: ${input_path}`);
34627
35280
  continue;
34628
35281
  }
@@ -34635,13 +35288,13 @@ function collect_report_targets(input_paths, workspace_root, cwd, exclude_patter
34635
35288
  }
34636
35289
  let stat;
34637
35290
  try {
34638
- stat = fs12.statSync(absolute_path);
35291
+ stat = fs13.statSync(absolute_path);
34639
35292
  } catch (error) {
34640
35293
  operator_errors.push(`cannot stat path: ${input_path}: ${error_message(error)}`);
34641
35294
  continue;
34642
35295
  }
34643
35296
  if (stat.isDirectory()) {
34644
- walk_sources(absolute_path, source_paths, operator_errors, exclude_roots, exclude_matcher);
35297
+ walk_sources(absolute_path, source_paths, operator_errors, exclude_roots, exclude_matcher, gitignore_matcher);
34645
35298
  } else if (stat.isFile() && hasStataExtension(absolute_path)) {
34646
35299
  source_paths.push(absolute_path);
34647
35300
  }
@@ -34730,7 +35383,7 @@ function decode_error_diagnostic(offset) {
34730
35383
  function read_source_file(file_path) {
34731
35384
  let bytes;
34732
35385
  try {
34733
- bytes = fs12.readFileSync(file_path);
35386
+ bytes = fs13.readFileSync(file_path);
34734
35387
  } catch (error) {
34735
35388
  return {
34736
35389
  kind: "read-error",
@@ -34754,6 +35407,7 @@ var init_source_files = __esm(() => {
34754
35407
  init_file_path_utils();
34755
35408
  init_exclude_matcher();
34756
35409
  init_diagnostic_code_description();
35410
+ init_gitignore_matcher();
34757
35411
  init_shared();
34758
35412
  import_vscode_languageserver6 = __toESM(require_main4(), 1);
34759
35413
  });
@@ -34768,8 +35422,8 @@ __export(exports_check, {
34768
35422
  collect_check_diagnostics: () => collect_check_diagnostics,
34769
35423
  build_check_context: () => build_check_context
34770
35424
  });
34771
- import * as fs13 from "fs";
34772
- import * as path14 from "path";
35425
+ import * as fs14 from "fs";
35426
+ import * as path15 from "path";
34773
35427
  function parse_required_option_value(argv, index, flag, value_kind, inline_value) {
34774
35428
  if (inline_value !== undefined) {
34775
35429
  if (inline_value.length === 0) {
@@ -34935,7 +35589,7 @@ function load_check_config(options) {
34935
35589
  warnings: validation_warnings
34936
35590
  };
34937
35591
  }
34938
- const loaded = options.config_path ? load_toml_file(path14.resolve(options.cwd, options.config_path)) : discover_and_load_project_config(options.workspace_root);
35592
+ const loaded = options.config_path ? load_toml_file(path15.resolve(options.cwd, options.config_path)) : discover_and_load_project_config(options.workspace_root);
34939
35593
  if (loaded.kind === "load-failed") {
34940
35594
  return {
34941
35595
  kind: "operator-error",
@@ -35031,7 +35685,7 @@ async function collect_check_diagnostics(context, workspace_root, config, target
35031
35685
  const uri = URI.file(target.path).toString();
35032
35686
  let stats;
35033
35687
  try {
35034
- stats = fs13.statSync(target.path);
35688
+ stats = fs14.statSync(target.path);
35035
35689
  } catch (error) {
35036
35690
  records.push(diagnostic_record(target.relative_path, unreadable_diagnostic(read_error_detail(error))));
35037
35691
  return records;
@@ -35042,7 +35696,7 @@ async function collect_check_diagnostics(context, workspace_root, config, target
35042
35696
  }
35043
35697
  return records;
35044
35698
  }
35045
- if (is_within_workspace(workspace_root, target.path) && files_indexed >= config.cross_file.max_indexed_files && !context.workspace_indexer.has_indexed_file(uri) && !is_hidden_source_path(target.path, scan_roots) && !exclude_matcher.is_excluded_file(target.path, [workspace_root])) {
35699
+ if (is_within_workspace(workspace_root, target.path) && files_indexed >= config.cross_file.max_indexed_files && !context.workspace_indexer.has_indexed_file(uri) && !context.workspace_indexer.is_gitignored(target.path) && !is_hidden_source_path(target.path, scan_roots) && !exclude_matcher.is_excluded_file(target.path, [workspace_root])) {
35046
35700
  records.push(diagnostic_record(target.relative_path, index_limit_diagnostic()));
35047
35701
  return records;
35048
35702
  }
@@ -35126,10 +35780,10 @@ async function run_check_with_cwd(argv, cwd, output = DEFAULT_OUTPUT) {
35126
35780
  `);
35127
35781
  return EXIT_OK;
35128
35782
  }
35129
- const resolved_workspace_root = path14.resolve(cwd, result.args.workspace ?? ".");
35783
+ const resolved_workspace_root = path15.resolve(cwd, result.args.workspace ?? ".");
35130
35784
  let is_workspace_directory = false;
35131
35785
  try {
35132
- is_workspace_directory = fs13.statSync(resolved_workspace_root).isDirectory();
35786
+ is_workspace_directory = fs14.statSync(resolved_workspace_root).isDirectory();
35133
35787
  } catch {
35134
35788
  is_workspace_directory = false;
35135
35789
  }
@@ -35161,7 +35815,7 @@ async function run_check_with_cwd(argv, cwd, output = DEFAULT_OUTPUT) {
35161
35815
  `);
35162
35816
  return EXIT_OPERATOR_ERROR;
35163
35817
  }
35164
- const target_result = collect_report_targets(result.args.paths, workspace_root, cwd, config_result.config.exclude);
35818
+ const target_result = collect_report_targets(result.args.paths, workspace_root, cwd, config_result.config.exclude, config_result.config.workspace.respectGitignore);
35165
35819
  if (target_result.operator_errors.length > 0) {
35166
35820
  for (const message of target_result.operator_errors) {
35167
35821
  output.stderr(`sight check: ${message}
@@ -35490,7 +36144,7 @@ function is_position_in_range3(position, range) {
35490
36144
  }
35491
36145
 
35492
36146
  // src/providers/hover.ts
35493
- import * as path15 from "path";
36147
+ import * as path16 from "path";
35494
36148
  function has_definition_index(hit) {
35495
36149
  return typeof hit.definition_index === "number";
35496
36150
  }
@@ -36840,7 +37494,7 @@ ${source_info}${footer}`
36840
37494
  if (this.looks_like_uri_scheme(uri_or_path)) {
36841
37495
  return null;
36842
37496
  }
36843
- return path15.resolve(uri_or_path);
37497
+ return path16.resolve(uri_or_path);
36844
37498
  }
36845
37499
  escape_markdown_link_text(text) {
36846
37500
  return text.replace(/[\\[\]()]/g, "\\$&");
@@ -36860,8 +37514,8 @@ ${source_info}${footer}`
36860
37514
  if (workspace_fs_path === null) {
36861
37515
  return fs_path;
36862
37516
  }
36863
- const relative7 = path15.relative(workspace_fs_path, fs_path);
36864
- if (relative7.startsWith("..") || path15.isAbsolute(relative7)) {
37517
+ const relative7 = path16.relative(workspace_fs_path, fs_path);
37518
+ if (relative7.startsWith("..") || path16.isAbsolute(relative7)) {
36865
37519
  return fs_path;
36866
37520
  }
36867
37521
  return relative7;
@@ -37215,7 +37869,7 @@ var init_hover = __esm(() => {
37215
37869
  });
37216
37870
 
37217
37871
  // src/providers/definition.ts
37218
- import * as path16 from "path";
37872
+ import * as path17 from "path";
37219
37873
 
37220
37874
  class DefinitionProvider {
37221
37875
  workspace_roots = [];
@@ -37960,7 +38614,7 @@ class DefinitionProvider {
37960
38614
  if (!the_call) {
37961
38615
  return { matched: false, path: null };
37962
38616
  }
37963
- const current_dir = path16.dirname(URI.parse(document.uri).fsPath);
38617
+ const current_dir = path17.dirname(URI.parse(document.uri).fsPath);
37964
38618
  const my_outcome = resolve_forward_call_rich(file_path, current_dir, the_call.working_directory, { workspace_roots: this.workspace_roots });
37965
38619
  if (my_outcome.kind === "exact" || my_outcome.kind === "case_only") {
37966
38620
  return { matched: true, path: my_outcome.path };
@@ -37969,8 +38623,8 @@ class DefinitionProvider {
37969
38623
  }
37970
38624
  resolve_file_path(current_uri, file_path) {
37971
38625
  const current_path = URI.parse(current_uri).fsPath;
37972
- const current_dir = path16.dirname(current_path);
37973
- const resolved_path = path16.resolve(current_dir, file_path);
38626
+ const current_dir = path17.dirname(current_path);
38627
+ const resolved_path = path17.resolve(current_dir, file_path);
37974
38628
  const the_roots_set = new Set(this.workspace_roots);
37975
38629
  the_roots_set.add(current_dir);
37976
38630
  const the_roots = Array.from(the_roots_set);
@@ -38544,7 +39198,7 @@ class ReferencesProvider {
38544
39198
  }
38545
39199
  file_count++;
38546
39200
  if (file_count % 10 === 0) {
38547
- await new Promise((resolve15) => setTimeout(resolve15, 0));
39201
+ await new Promise((resolve16) => setTimeout(resolve16, 0));
38548
39202
  if (cancellation_token?.isCancellationRequested) {
38549
39203
  break;
38550
39204
  }
@@ -38970,7 +39624,7 @@ var init_section_detector = __esm(() => {
38970
39624
  });
38971
39625
 
38972
39626
  // src/providers/symbols.ts
38973
- import * as path17 from "path";
39627
+ import * as path18 from "path";
38974
39628
  function is_position_in_range4(position, range) {
38975
39629
  if (position.line < range.start.line) {
38976
39630
  return false;
@@ -39366,7 +40020,7 @@ class SymbolProvider {
39366
40020
  }
39367
40021
  }
39368
40022
  for (const document of all_documents) {
39369
- const my_basename = path17.basename(document.uri);
40023
+ const my_basename = path18.basename(document.uri);
39370
40024
  for (const my_program of document.symbols.programs.values()) {
39371
40025
  if (my_program.name.toLowerCase().includes(lower_query)) {
39372
40026
  symbols.push({
@@ -39623,6 +40277,13 @@ class IndentationAnalyzer {
39623
40277
  this.process_embedded_block_node(node);
39624
40278
  return;
39625
40279
  }
40280
+ if (node.type === "if" && node.is_single_statement) {
40281
+ this.process_regular_node(node);
40282
+ for (const my_child of node.body) {
40283
+ this.walk_node(my_child);
40284
+ }
40285
+ return;
40286
+ }
39626
40287
  if (this.is_block_node(node)) {
39627
40288
  if (node.type === "command") {
39628
40289
  const cmd = node;
@@ -41297,6 +41958,12 @@ class PrettyPrinter {
41297
41958
  return spaced.replace(/\(\s+/g, "(").replace(/\s+\)/g, ")");
41298
41959
  }
41299
41960
  printControlFlow(node) {
41961
+ if (node.type === "if" && node.is_single_statement) {
41962
+ const body_node = node.body[0];
41963
+ const body = body_node ? this.printNode(body_node) : "";
41964
+ const inline_body = body.trimStart().slice(0, -this.getStatementTerminator().length);
41965
+ return `${this.getIndent()}if ${node.condition || ""} ${inline_body}`;
41966
+ }
41300
41967
  const the_lines = [];
41301
41968
  let header = this.getIndent();
41302
41969
  switch (node.type) {
@@ -41339,7 +42006,7 @@ class PrettyPrinter {
41339
42006
  }
41340
42007
  printEmbeddedBlock(node) {
41341
42008
  if (node.is_single_line) {
41342
- return `${this.getIndent()}${node.start_command} ${node.content}${this.getStatementTerminator()}`;
42009
+ return `${this.getIndent()}${node.start_command} ${node.content}`;
41343
42010
  }
41344
42011
  const the_lines = [];
41345
42012
  the_lines.push(`${this.getIndent()}${node.start_command}`);
@@ -41811,8 +42478,8 @@ class DocumentDebounceManager {
41811
42478
  if (prev_resolver) {
41812
42479
  prev_resolver();
41813
42480
  }
41814
- const promise = new Promise((resolve15) => {
41815
- this.pending_resolvers.set(uri, resolve15);
42481
+ const promise = new Promise((resolve16) => {
42482
+ this.pending_resolvers.set(uri, resolve16);
41816
42483
  });
41817
42484
  this.pending_promises.set(uri, promise);
41818
42485
  const timer = setTimeout(() => {
@@ -41838,9 +42505,9 @@ class DocumentDebounceManager {
41838
42505
  if (this.parse_queue.length >= this.MAX_QUEUE_LENGTH) {
41839
42506
  logger.warn(`Parse queue full, dropping ${uri} v${version}`);
41840
42507
  this.metrics.dropped_parses++;
41841
- const resolve15 = this.pending_resolvers.get(uri);
41842
- if (resolve15) {
41843
- resolve15();
42508
+ const resolve16 = this.pending_resolvers.get(uri);
42509
+ if (resolve16) {
42510
+ resolve16();
41844
42511
  this.pending_resolvers.delete(uri);
41845
42512
  this.pending_promises.delete(uri);
41846
42513
  }
@@ -41863,7 +42530,7 @@ class DocumentDebounceManager {
41863
42530
  }
41864
42531
  this.active_parses++;
41865
42532
  try {
41866
- await new Promise((resolve15) => setImmediate(resolve15));
42533
+ await new Promise((resolve16) => setImmediate(resolve16));
41867
42534
  await callback();
41868
42535
  } catch (error) {
41869
42536
  logger.error(`Parse error for ${uri}: ${error}`);
@@ -41895,9 +42562,9 @@ class DocumentDebounceManager {
41895
42562
  clearTimeout(existing);
41896
42563
  this.pending_timers.delete(uri);
41897
42564
  }
41898
- const resolve15 = this.pending_resolvers.get(uri);
41899
- if (resolve15) {
41900
- resolve15();
42565
+ const resolve16 = this.pending_resolvers.get(uri);
42566
+ if (resolve16) {
42567
+ resolve16();
41901
42568
  this.pending_resolvers.delete(uri);
41902
42569
  this.pending_promises.delete(uri);
41903
42570
  }
@@ -72719,7 +73386,8 @@ __export(exports_server_factory, {
72719
73386
  create_server: () => create_server,
72720
73387
  build_non_capability_settings_from_sources: () => build_non_capability_settings_from_sources
72721
73388
  });
72722
- import * as fs14 from "fs";
73389
+ import * as fs15 from "fs";
73390
+ import * as path19 from "path";
72723
73391
  function create_transport_connection(transport) {
72724
73392
  if (transport === "stdio") {
72725
73393
  return import_node8.createConnection(process.stdin, process.stdout);
@@ -72755,6 +73423,7 @@ function indexing_affecting_signature(config) {
72755
73423
  return JSON.stringify({
72756
73424
  adoPaths: config?.adoPaths ?? null,
72757
73425
  exclude: config?.exclude ?? null,
73426
+ respectGitignore: config?.workspace?.respectGitignore ?? true,
72758
73427
  indexWorkspace: config?.indexWorkspace ?? null,
72759
73428
  index_workspace: config?.cross_file?.index_workspace ?? null,
72760
73429
  max_indexed_files: config?.cross_file?.max_indexed_files ?? null,
@@ -72797,6 +73466,13 @@ async function create_server(options) {
72797
73466
  let project_config_candidate_dirs = [];
72798
73467
  let active_workspace_roots = [];
72799
73468
  let project_config_watch_registration = undefined;
73469
+ let gitignore_watch_registration;
73470
+ let gitignore_watch_seq = 0;
73471
+ let gitignore_watch_directories = [];
73472
+ let gitignore_refresh_pending = false;
73473
+ let gitignore_refresh_scheduled = false;
73474
+ let gitignore_change_seq = 0;
73475
+ let workspace_indexing_seq = 0;
72800
73476
  let last_applied_indexing_signature = "";
72801
73477
  let config_change_seq = 0;
72802
73478
  let init_options_config = undefined;
@@ -72898,6 +73574,65 @@ async function create_server(options) {
72898
73574
  }
72899
73575
  previous_registration?.dispose();
72900
73576
  }
73577
+ async function refresh_gitignore_watchers() {
73578
+ const my_seq = ++gitignore_watch_seq;
73579
+ if (!server_capabilities.has_watched_files_dynamic_registration_capability) {
73580
+ return;
73581
+ }
73582
+ const watchers = gitignore_watch_directories.map(({ directory, recursive }) => ({
73583
+ globPattern: {
73584
+ baseUri: URI.file(directory).toString(),
73585
+ pattern: recursive ? "**/.gitignore" : ".gitignore"
73586
+ },
73587
+ kind: import_node8.WatchKind.Create | import_node8.WatchKind.Change | import_node8.WatchKind.Delete
73588
+ }));
73589
+ const registration = watchers.length > 0 ? await connection.client.register(import_node8.DidChangeWatchedFilesNotification.type, { watchers }) : undefined;
73590
+ if (my_seq !== gitignore_watch_seq || shutdown_requested) {
73591
+ registration?.dispose();
73592
+ return;
73593
+ }
73594
+ const previous_registration = gitignore_watch_registration;
73595
+ gitignore_watch_registration = registration;
73596
+ previous_registration?.dispose();
73597
+ }
73598
+ function is_relevant_gitignore(uri) {
73599
+ const directory = path19.dirname(URI.parse(uri).fsPath);
73600
+ return gitignore_watch_directories.some((watch) => {
73601
+ const relative8 = path19.relative(watch.directory, directory);
73602
+ return relative8 === "" || watch.recursive && relative8 !== ".." && !relative8.startsWith(`..${path19.sep}`) && !path19.isAbsolute(relative8);
73603
+ });
73604
+ }
73605
+ function schedule_gitignore_refresh() {
73606
+ if (gitignore_refresh_scheduled || shutdown_requested)
73607
+ return;
73608
+ gitignore_refresh_scheduled = true;
73609
+ queueMicrotask(() => {
73610
+ const my_change_seq = gitignore_change_seq;
73611
+ const my_config_seq = config_change_seq;
73612
+ get_document_settings("").then((settings) => {
73613
+ if (shutdown_requested || !gitignore_refresh_pending || my_change_seq !== gitignore_change_seq || my_config_seq !== config_change_seq) {
73614
+ return;
73615
+ }
73616
+ configure_workspace_indexing(settings, active_workspace_roots, true);
73617
+ }).catch((error) => {
73618
+ connection.console.log(`[indexer] Gitignore refresh failed: ${error_message(error)}`);
73619
+ }).finally(() => {
73620
+ gitignore_refresh_scheduled = false;
73621
+ if (gitignore_refresh_pending && (my_change_seq !== gitignore_change_seq || my_config_seq !== config_change_seq)) {
73622
+ schedule_gitignore_refresh();
73623
+ }
73624
+ });
73625
+ });
73626
+ }
73627
+ function on_gitignore_changed(uri) {
73628
+ if (shutdown_requested || !is_relevant_gitignore(uri))
73629
+ return;
73630
+ gitignore_refresh_pending = true;
73631
+ gitignore_change_seq++;
73632
+ workspace_indexing_seq++;
73633
+ workspace_indexer?.cancel();
73634
+ schedule_gitignore_refresh();
73635
+ }
72901
73636
  function build_non_capability_settings() {
72902
73637
  return build_non_capability_settings_from_sources({
72903
73638
  init_options_config,
@@ -73106,10 +73841,16 @@ async function create_server(options) {
73106
73841
  scope_resolver?.reset_reverse_deps();
73107
73842
  }
73108
73843
  function configure_workspace_indexing(settings, folder_paths, reset_indexes) {
73844
+ const my_indexing_seq = ++workspace_indexing_seq;
73845
+ gitignore_refresh_pending = false;
73109
73846
  if (reset_indexes) {
73110
73847
  reset_workspace_indexing_state();
73111
73848
  }
73112
73849
  last_applied_indexing_signature = indexing_affecting_signature(settings);
73850
+ gitignore_watch_directories = create_gitignore_matcher(folder_paths, settings.workspace.respectGitignore).watch_directories;
73851
+ refresh_gitignore_watchers().catch((error) => {
73852
+ connection.console.log(`[indexer] Gitignore watcher registration failed: ` + error_message(error));
73853
+ });
73113
73854
  configure_completion_provider(settings);
73114
73855
  apply_cache_capacities(settings);
73115
73856
  if (workspace_indexer) {
@@ -73117,8 +73858,13 @@ async function create_server(options) {
73117
73858
  workspace_indexer.set_max_indexed_files(settings.cross_file?.max_indexed_files ?? 1000);
73118
73859
  }
73119
73860
  const indexing_enabled = settings.indexWorkspace !== false && settings.cross_file?.index_workspace !== false;
73120
- if (indexing_enabled && workspace_indexer && folder_paths.length > 0) {
73861
+ if (workspace_indexer && folder_paths.length > 0) {
73862
+ if (!indexing_enabled) {
73863
+ workspace_indexer.set_help_search_paths(discover_stata_ado_paths());
73864
+ }
73121
73865
  workspace_indexer.initialize(folder_paths, settings.adoPaths || []).then(() => {
73866
+ if (my_indexing_seq !== workspace_indexing_seq || shutdown_requested)
73867
+ return;
73122
73868
  resolve_sthlp_handler?.clear_negative_cache();
73123
73869
  if (dependency_graph?.is_scan_complete()) {
73124
73870
  revalidate_all_open_docs();
@@ -73160,7 +73906,7 @@ async function create_server(options) {
73160
73906
  global_settings = build_non_capability_settings();
73161
73907
  }
73162
73908
  const settings = await get_document_settings("");
73163
- const indexing_changed = indexing_affecting_signature(settings) !== last_applied_indexing_signature;
73909
+ const indexing_changed = gitignore_refresh_pending || indexing_affecting_signature(settings) !== last_applied_indexing_signature;
73164
73910
  if (indexing_changed) {
73165
73911
  configure_workspace_indexing(settings, active_workspace_roots, true);
73166
73912
  } else {
@@ -73415,14 +74161,14 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
73415
74161
  return open_doc.getText();
73416
74162
  }
73417
74163
  const fs_path = URI.parse(uri).fsPath;
73418
- return fs14.promises.readFile(fs_path, "utf8");
74164
+ return fs15.promises.readFile(fs_path, "utf8");
73419
74165
  },
73420
74166
  exists: async (uri) => {
73421
74167
  if (documents.get(uri))
73422
74168
  return true;
73423
74169
  const fs_path = URI.parse(uri).fsPath;
73424
74170
  try {
73425
- await fs14.promises.access(fs_path);
74171
+ await fs15.promises.access(fs_path);
73426
74172
  return true;
73427
74173
  } catch {
73428
74174
  return false;
@@ -73504,7 +74250,7 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
73504
74250
  }));
73505
74251
  function apply_runtime_settings_change(settings) {
73506
74252
  const new_signature = indexing_affecting_signature(settings);
73507
- if (new_signature !== last_applied_indexing_signature) {
74253
+ if (gitignore_refresh_pending || new_signature !== last_applied_indexing_signature) {
73508
74254
  configure_workspace_indexing(settings, active_workspace_roots, true);
73509
74255
  } else {
73510
74256
  configure_completion_provider(settings);
@@ -73580,6 +74326,9 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
73580
74326
  }
73581
74327
  if (dependency_graph) {
73582
74328
  const affected_callees = new Set(dependency_graph.get_callees(e.document.uri));
74329
+ if (workspace_indexer?.is_gitignored(URI.parse(e.document.uri).fsPath)) {
74330
+ dependency_graph.remove_caller(e.document.uri);
74331
+ }
73583
74332
  if (affected_callees.size > 0) {
73584
74333
  invalidate_and_revalidate_callees(affected_callees);
73585
74334
  }
@@ -73601,7 +74350,7 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
73601
74350
  }
73602
74351
  }, async () => {
73603
74352
  await reload_project_config_from_active_root();
73604
- }));
74353
+ }, on_gitignore_changed));
73605
74354
  connection.onNotification(DIAGNOSTIC_RESOURCES_CHANGED_NOTIFICATION, (params) => {
73606
74355
  const next = diagnostic_uris_from_notification(params);
73607
74356
  if (next !== undefined) {
@@ -73636,6 +74385,9 @@ ${scope_resolver.get_reverse_deps_debug_info()}`);
73636
74385
  });
73637
74386
  connection.onShutdown(() => {
73638
74387
  shutdown_requested = true;
74388
+ gitignore_watch_seq++;
74389
+ workspace_indexing_seq++;
74390
+ gitignore_watch_registration?.dispose();
73639
74391
  return shutdown_handler();
73640
74392
  });
73641
74393
  connection.onExit(create_exit_handler());
@@ -73673,6 +74425,7 @@ var init_server_factory = __esm(() => {
73673
74425
  init_file_path_utils();
73674
74426
  init_dependency_graph();
73675
74427
  init_esm();
74428
+ init_gitignore_matcher();
73676
74429
  init_stata_install_paths();
73677
74430
  init_diagnostic_resources();
73678
74431
  init_v18();
@@ -73869,4 +74622,4 @@ export {
73869
74622
  is_cli_entry_point
73870
74623
  };
73871
74624
 
73872
- //# debugId=A1706D274D80E2DC64756E2164756E21
74625
+ //# debugId=7D74EF27B76852CD64756E2164756E21