@vibgrate/cli 1.0.78 → 1.0.80

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.
@@ -12589,19 +12589,19 @@ ${lanes.join("\n")}
12589
12589
  return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text));
12590
12590
  }
12591
12591
  function computeLineAndCharacterOfPosition(lineStarts, position) {
12592
- const lineNumber14 = computeLineOfPosition(lineStarts, position);
12592
+ const lineNumber15 = computeLineOfPosition(lineStarts, position);
12593
12593
  return {
12594
- line: lineNumber14,
12595
- character: position - lineStarts[lineNumber14]
12594
+ line: lineNumber15,
12595
+ character: position - lineStarts[lineNumber15]
12596
12596
  };
12597
12597
  }
12598
12598
  function computeLineOfPosition(lineStarts, position, lowerBound) {
12599
- let lineNumber14 = binarySearch(lineStarts, position, identity, compareValues, lowerBound);
12600
- if (lineNumber14 < 0) {
12601
- lineNumber14 = ~lineNumber14 - 1;
12602
- Debug.assert(lineNumber14 !== -1, "position cannot precede the beginning of the file");
12599
+ let lineNumber15 = binarySearch(lineStarts, position, identity, compareValues, lowerBound);
12600
+ if (lineNumber15 < 0) {
12601
+ lineNumber15 = ~lineNumber15 - 1;
12602
+ Debug.assert(lineNumber15 !== -1, "position cannot precede the beginning of the file");
12603
12603
  }
12604
- return lineNumber14;
12604
+ return lineNumber15;
12605
12605
  }
12606
12606
  function getLinesBetweenPositions(sourceFile, pos1, pos2) {
12607
12607
  if (pos1 === pos2)
@@ -132818,10 +132818,10 @@ ${lanes.join("\n")}
132818
132818
  /*ignoreCase*/
132819
132819
  false
132820
132820
  )) {
132821
- const basename4 = getBaseFileName(a.fileName);
132822
- if (basename4 === "lib.d.ts" || basename4 === "lib.es6.d.ts")
132821
+ const basename5 = getBaseFileName(a.fileName);
132822
+ if (basename5 === "lib.d.ts" || basename5 === "lib.es6.d.ts")
132823
132823
  return 0;
132824
- const name = removeSuffix(removePrefix(basename4, "lib."), ".d.ts");
132824
+ const name = removeSuffix(removePrefix(basename5, "lib."), ".d.ts");
132825
132825
  const index = libs.indexOf(name);
132826
132826
  if (index !== -1)
132827
132827
  return index + 1;
@@ -168938,9 +168938,9 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
168938
168938
  }
168939
168939
  });
168940
168940
  function makeChange8(changes, sourceFile, position, seenLines) {
168941
- const { line: lineNumber14 } = getLineAndCharacterOfPosition(sourceFile, position);
168942
- if (!seenLines || tryAddToSet(seenLines, lineNumber14)) {
168943
- changes.insertCommentBeforeLine(sourceFile, lineNumber14, position, " @ts-ignore");
168941
+ const { line: lineNumber15 } = getLineAndCharacterOfPosition(sourceFile, position);
168942
+ if (!seenLines || tryAddToSet(seenLines, lineNumber15)) {
168943
+ changes.insertCommentBeforeLine(sourceFile, lineNumber15, position, " @ts-ignore");
168944
168944
  }
168945
168945
  }
168946
168946
  var fixName4, fixId40, errorCodes51;
@@ -184165,8 +184165,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
184165
184165
  insertModifierBefore(sourceFile, modifier, before) {
184166
184166
  return this.insertModifierAt(sourceFile, before.getStart(sourceFile), modifier, { suffix: " " });
184167
184167
  }
184168
- insertCommentBeforeLine(sourceFile, lineNumber14, position, commentText) {
184169
- const lineStartPosition = getStartPositionOfLine(lineNumber14, sourceFile);
184168
+ insertCommentBeforeLine(sourceFile, lineNumber15, position, commentText) {
184169
+ const lineStartPosition = getStartPositionOfLine(lineNumber15, sourceFile);
184170
184170
  const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition);
184171
184171
  const insertAtLineStart = isValidLocationToAddComment(sourceFile, startPosition);
184172
184172
  const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position);
@@ -191483,8 +191483,8 @@ ${options.prefix}` : "\n" : options.prefix
191483
191483
  }
191484
191484
  };
191485
191485
  for (const file of files) {
191486
- const basename4 = getBaseFileName(file);
191487
- if (basename4 === "package.json" || basename4 === "bower.json") {
191486
+ const basename5 = getBaseFileName(file);
191487
+ if (basename5 === "package.json" || basename5 === "bower.json") {
191488
191488
  createProjectWatcher(
191489
191489
  file,
191490
191490
  "FileWatcher"
@@ -194859,8 +194859,8 @@ All files are: ${JSON.stringify(names)}`,
194859
194859
  const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
194860
194860
  if (!fileOrDirectoryPath)
194861
194861
  return;
194862
- const basename4 = getBaseFileName(fileOrDirectoryPath);
194863
- if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a.size) && (basename4 === "package.json" || basename4 === "node_modules")) {
194862
+ const basename5 = getBaseFileName(fileOrDirectoryPath);
194863
+ if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? void 0 : _a.size) && (basename5 === "package.json" || basename5 === "node_modules")) {
194864
194864
  result.affectedModuleSpecifierCacheProjects.forEach((project) => {
194865
194865
  var _a2;
194866
194866
  (_a2 = project.getModuleSpecifierCache()) == null ? void 0 : _a2.clear();
@@ -210740,8 +210740,8 @@ var require_pattern = __commonJS({
210740
210740
  }
210741
210741
  exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
210742
210742
  function isAffectDepthOfReadingPattern(pattern) {
210743
- const basename4 = path2.basename(pattern);
210744
- return endsWithSlashGlobStar(pattern) || isStaticPattern(basename4);
210743
+ const basename5 = path2.basename(pattern);
210744
+ return endsWithSlashGlobStar(pattern) || isStaticPattern(basename5);
210745
210745
  }
210746
210746
  exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
210747
210747
  function expandPatternsWithBraceExpansion(patterns) {
@@ -213713,7 +213713,7 @@ var require_path_browserify = __commonJS({
213713
213713
  if (hasRoot && end === 1) return "//";
213714
213714
  return path2.slice(0, end);
213715
213715
  },
213716
- basename: function basename4(path2, ext) {
213716
+ basename: function basename5(path2, ext) {
213717
213717
  if (ext !== void 0 && typeof ext !== "string") throw new TypeError('"ext" argument must be a string');
213718
213718
  assertPath(path2);
213719
213719
  var start = 0;
@@ -316915,6 +316915,7 @@ var ComponentExtractor = class {
316915
316915
  const filePath = sf.getFilePath();
316916
316916
  const framework = this.detectFramework(sf);
316917
316917
  if (!framework) continue;
316918
+ this.extractUiSurfaceAnnotations(sf, filePath, framework, emitter);
316918
316919
  if (framework === "react" || framework === "nextjs") {
316919
316920
  this.extractReactFunctionComponents(sf, filePath, framework, emitter);
316920
316921
  this.extractReactClassComponents(sf, filePath, framework, emitter);
@@ -317161,6 +317162,47 @@ var ComponentExtractor = class {
317161
317162
  });
317162
317163
  }
317163
317164
  }
317165
+ extractUiSurfaceAnnotations(sf, filePath, framework, emitter) {
317166
+ const text = sf.getFullText();
317167
+ const emit = (annotationType, line, argumentMap) => {
317168
+ emitter.emitAnnotationFound({
317169
+ annotationType,
317170
+ targetSymbol: `${filePath}:${framework}:ui`,
317171
+ argumentMap,
317172
+ filePath,
317173
+ line
317174
+ });
317175
+ };
317176
+ const lineFor = (idx) => sf.getLineAndColumnAtPos(idx).line;
317177
+ const tableRe = /<(table|DataGrid|Table|v-data-table|el-table)\b[^>]*>/gim;
317178
+ for (const m of text.matchAll(tableRe)) {
317179
+ emit("UI:LayoutContainer", lineFor(m.index ?? 0), { kind: "table", tag: m[1] });
317180
+ }
317181
+ const nestedTableRe = /<table[\s\S]*?<table/gi;
317182
+ for (const m of text.matchAll(nestedTableRe)) {
317183
+ emit("UI:NestedLayout", lineFor(m.index ?? 0), { kind: "nested-table" });
317184
+ }
317185
+ const colRe = /<(th|column|el-table-column|Column)\b[^>]*(?:label|title|header)\s*=\s*["'`]([^"'`]+)["'`][^>]*>/gim;
317186
+ for (const m of text.matchAll(colRe)) {
317187
+ emit("UI:GridColumn", lineFor(m.index ?? 0), { columnElement: m[1], label: m[2] });
317188
+ }
317189
+ const labelRe = /<(label|FormLabel|v-label)\b[^>]*>([^<]+)</gim;
317190
+ for (const m of text.matchAll(labelRe)) {
317191
+ emit("UI:FieldLabel", lineFor(m.index ?? 0), { labelElement: m[1], text: m[2].trim() });
317192
+ }
317193
+ const hintRe = /(placeholder|title|aria-label|hint|helperText)\s*=\s*["'`]([^"'`]+)["'`]/gim;
317194
+ for (const m of text.matchAll(hintRe)) {
317195
+ emit("UI:FieldHint", lineFor(m.index ?? 0), { key: m[1], text: m[2] });
317196
+ }
317197
+ const colorRe = /(color|backgroundColor|className|class)\s*=\s*["'`]([^"'`]*(?:danger|warning|success|error|primary|secondary|red|green|amber|blue|gray)[^"'`]*)["'`]/gim;
317198
+ for (const m of text.matchAll(colorRe)) {
317199
+ emit("UI:VisualSemantic", lineFor(m.index ?? 0), { key: m[1], value: m[2] });
317200
+ }
317201
+ const menuRe = /<(nav|menu|Menu|ContextMenu|Menubar)\b[^>]*>/gim;
317202
+ for (const m of text.matchAll(menuRe)) {
317203
+ emit("UI:SystemMenu", lineFor(m.index ?? 0), { menuElement: m[1] });
317204
+ }
317205
+ }
317164
317206
  // ── Helpers ──────────────────────────────────────────────
317165
317207
  isReactComponent(fn) {
317166
317208
  const name = fn.getName();
@@ -321417,6 +321459,7 @@ var VB6FormsExtractor = class {
321417
321459
  this.extractMenuItems(file, emitter);
321418
321460
  this.extractEventHandlers(file, emitter);
321419
321461
  this.extractObjectReferences(file, emitter);
321462
+ this.extractNestedLayoutAndGridMetadata(file, emitter);
321420
321463
  }
321421
321464
  this.extractErrorHandling(file, emitter);
321422
321465
  this.extractFileIO(file, emitter);
@@ -321532,6 +321575,87 @@ var VB6FormsExtractor = class {
321532
321575
  });
321533
321576
  }
321534
321577
  }
321578
+ // ── Nested layout / grids / labels ───────────────────────
321579
+ extractNestedLayoutAndGridMetadata(file, emitter) {
321580
+ const moduleName = fileModuleName3(file);
321581
+ const stack = [];
321582
+ for (let i = 0; i < file.lines.length; i++) {
321583
+ const lineNo = i + 1;
321584
+ const line = file.lines[i] ?? "";
321585
+ const beginMatch = line.match(/^\s*Begin\s+(\w+(?:\.\w+)?)\s+(\w+)/i);
321586
+ if (beginMatch) {
321587
+ const controlType = beginMatch[1];
321588
+ const controlName = beginMatch[2];
321589
+ stack.push({ controlType, controlName });
321590
+ if (stack.length > 1 && controlType !== "VB.Form") {
321591
+ const parent = stack[stack.length - 2];
321592
+ emitter.emitAnnotationFound({
321593
+ annotationType: "VB6:ControlHierarchy",
321594
+ targetSymbol: `${moduleName}.${controlName}`,
321595
+ argumentMap: {
321596
+ controlType,
321597
+ parentControl: parent.controlName,
321598
+ parentType: parent.controlType,
321599
+ nestingDepth: String(stack.length - 1)
321600
+ },
321601
+ filePath: file.path,
321602
+ line: lineNo
321603
+ });
321604
+ }
321605
+ continue;
321606
+ }
321607
+ if (/^\s*End\s*$/i.test(line)) {
321608
+ if (stack.length > 0) stack.pop();
321609
+ continue;
321610
+ }
321611
+ if (stack.length === 0) continue;
321612
+ const current = stack[stack.length - 1];
321613
+ const textMatch = line.match(/^\s*(Caption|Text|ToolTipText|Placeholder)\s*=\s*"([^"]*)"/i);
321614
+ if (textMatch) {
321615
+ const key = textMatch[1];
321616
+ const value = textMatch[2];
321617
+ const annotationType = /^VB\.Label$/i.test(current.controlType) ? "VB6:FieldLabel" : "VB6:ControlHint";
321618
+ emitter.emitAnnotationFound({
321619
+ annotationType,
321620
+ targetSymbol: `${moduleName}.${current.controlName}`,
321621
+ argumentMap: {
321622
+ controlType: current.controlType,
321623
+ [key]: value
321624
+ },
321625
+ filePath: file.path,
321626
+ line: lineNo
321627
+ });
321628
+ }
321629
+ const colorMatch = line.match(/^\s*(BackColor|ForeColor)\s*=\s*(&H[0-9A-F]+|\d+)/i);
321630
+ if (colorMatch) {
321631
+ emitter.emitAnnotationFound({
321632
+ annotationType: "VB6:VisualSemantic",
321633
+ targetSymbol: `${moduleName}.${current.controlName}`,
321634
+ argumentMap: {
321635
+ controlType: current.controlType,
321636
+ [colorMatch[1]]: colorMatch[2]
321637
+ },
321638
+ filePath: file.path,
321639
+ line: lineNo
321640
+ });
321641
+ }
321642
+ const gridColumnMatch = line.match(/^\s*(ColumnHeader\(\d+\)\.Text|Columns\(\d+\)\.Caption|Cols)\s*=\s*"?([^"\r\n]+)"?/i);
321643
+ const isGrid = /(Grid|ListView|MSHFlexGrid|FlexGrid)/i.test(current.controlType);
321644
+ if (gridColumnMatch && isGrid) {
321645
+ emitter.emitAnnotationFound({
321646
+ annotationType: "VB6:GridColumn",
321647
+ targetSymbol: `${moduleName}.${current.controlName}`,
321648
+ argumentMap: {
321649
+ controlType: current.controlType,
321650
+ columnKey: gridColumnMatch[1],
321651
+ label: gridColumnMatch[2].trim()
321652
+ },
321653
+ filePath: file.path,
321654
+ line: lineNo
321655
+ });
321656
+ }
321657
+ }
321658
+ }
321535
321659
  // ── Event Handlers ────────────────────────────────────────
321536
321660
  extractEventHandlers(file, emitter) {
321537
321661
  const re = /^[ \t]*(Private\s+|Public\s+)?Sub\s+(\w+)_(\w+)\s*\(([^)]*)\)/gim;
@@ -393452,11 +393576,344 @@ function getBaseName(filePath) {
393452
393576
  return dotIndex > 0 ? name.substring(0, dotIndex) : name;
393453
393577
  }
393454
393578
 
393579
+ // src/extractors/web-markup-extractor.ts
393580
+ init_esm_shims();
393581
+ import { basename as basename4 } from "path";
393582
+ var ROUTE_ATTRS = /* @__PURE__ */ new Set(["href", "action", "to"]);
393583
+ var WebMarkupExtractor = class {
393584
+ async extract(files, emitter) {
393585
+ for (const file of files) {
393586
+ emitter.emitFileIndexed({
393587
+ fileId: file.path,
393588
+ filePath: file.path,
393589
+ language: inferMarkupLanguage(file.path),
393590
+ lineCount: file.lines.length,
393591
+ byteSize: Buffer.byteLength(file.content, "utf-8"),
393592
+ isTest: false,
393593
+ isMigration: false,
393594
+ isGenerated: false
393595
+ });
393596
+ const root = parseHtmlTree(file.content);
393597
+ this.emitRoutesFromTree(file.path, root, emitter);
393598
+ this.emitCustomElements(file.path, file.lines.length, root, emitter);
393599
+ if (file.path.endsWith(".vue")) {
393600
+ emitter.emitComponentDeclared({
393601
+ componentId: `${file.path}:default`,
393602
+ shortName: toComponentName(file.path),
393603
+ componentKind: "single_file_component",
393604
+ framework: "vue",
393605
+ filePath: file.path,
393606
+ startLine: 1,
393607
+ endLine: file.lines.length,
393608
+ props: [],
393609
+ slots: [],
393610
+ emits: [],
393611
+ hasChildren: true
393612
+ });
393613
+ }
393614
+ const convention = routeFromFilePath(file.path);
393615
+ if (convention) {
393616
+ emitter.emitPageRouteDeclared({
393617
+ pageRouteId: `page:web:convention:${file.path}:${convention}`,
393618
+ routePath: convention,
393619
+ routeKind: "convention",
393620
+ componentRef: file.path,
393621
+ filePath: file.path,
393622
+ isLayout: file.path.toLowerCase().includes("layout"),
393623
+ isDynamic: convention.includes(":") || convention.includes("*"),
393624
+ hasFallback: convention === "*",
393625
+ middleware: []
393626
+ });
393627
+ }
393628
+ }
393629
+ }
393630
+ emitRoutesFromTree(filePath, root, emitter) {
393631
+ const seen = /* @__PURE__ */ new Set();
393632
+ const stack = [root];
393633
+ while (stack.length > 0) {
393634
+ const node = stack.pop();
393635
+ if (!node) continue;
393636
+ for (const child of node.children) stack.push(child);
393637
+ for (const [name, value] of Object.entries(node.attrs)) {
393638
+ if (!ROUTE_ATTRS.has(name.toLowerCase())) continue;
393639
+ const route = normalizeRoute(value);
393640
+ if (!route) continue;
393641
+ const key = `${filePath}:${route}`;
393642
+ if (seen.has(key)) continue;
393643
+ seen.add(key);
393644
+ emitter.emitPageRouteDeclared({
393645
+ pageRouteId: `page:web:${key}`,
393646
+ routePath: route,
393647
+ routeKind: "config_based",
393648
+ componentRef: filePath,
393649
+ filePath,
393650
+ isLayout: false,
393651
+ isDynamic: route.includes(":") || route.includes("*"),
393652
+ hasFallback: route === "*",
393653
+ middleware: []
393654
+ });
393655
+ }
393656
+ }
393657
+ }
393658
+ emitCustomElements(filePath, lineCount, root, emitter) {
393659
+ const seen = /* @__PURE__ */ new Set();
393660
+ const stack = [root];
393661
+ while (stack.length > 0) {
393662
+ const node = stack.pop();
393663
+ if (!node) continue;
393664
+ for (const child of node.children) stack.push(child);
393665
+ if (!node.tagName.includes("-")) continue;
393666
+ const key = `${filePath}:${node.tagName}`;
393667
+ if (seen.has(key)) continue;
393668
+ seen.add(key);
393669
+ emitter.emitComponentDeclared({
393670
+ componentId: key,
393671
+ shortName: node.tagName,
393672
+ componentKind: "web_component",
393673
+ framework: "web",
393674
+ filePath,
393675
+ startLine: 1,
393676
+ endLine: lineCount,
393677
+ props: [],
393678
+ slots: [],
393679
+ emits: [],
393680
+ hasChildren: true
393681
+ });
393682
+ }
393683
+ }
393684
+ };
393685
+ function inferMarkupLanguage(path2) {
393686
+ if (path2.endsWith(".aspx")) return "aspx";
393687
+ if (path2.endsWith(".asp")) return "asp";
393688
+ if (path2.endsWith(".vue")) return "vue";
393689
+ return "html";
393690
+ }
393691
+ function normalizeRoute(raw) {
393692
+ const value = raw.trim();
393693
+ if (!value) return null;
393694
+ if (value.startsWith("#") || value.startsWith("javascript:") || value.startsWith("mailto:")) return null;
393695
+ if (value.startsWith("http://") || value.startsWith("https://")) return null;
393696
+ if (value.startsWith("/")) return value;
393697
+ if (value.startsWith("./")) return value.slice(1);
393698
+ return `/${value}`;
393699
+ }
393700
+ function parseHtmlTree(input) {
393701
+ const root = { tagName: "__root__", attrs: {}, children: [] };
393702
+ const stack = [root];
393703
+ const tokenizer = /<!--[^]*?-->|<\/?[A-Za-z][^>]*>|<%[^]*?%>/g;
393704
+ let match;
393705
+ while ((match = tokenizer.exec(input)) !== null) {
393706
+ const token = match[0];
393707
+ if (token.startsWith("<!--") || token.startsWith("<%")) continue;
393708
+ if (token.startsWith("</")) {
393709
+ if (stack.length > 1) stack.pop();
393710
+ continue;
393711
+ }
393712
+ const selfClosing = token.endsWith("/>");
393713
+ const head = token.slice(1, token.length - (selfClosing ? 2 : 1)).trim();
393714
+ const firstSpace = head.search(/\s/);
393715
+ const tagName = (firstSpace === -1 ? head : head.slice(0, firstSpace)).toLowerCase();
393716
+ const attrText = firstSpace === -1 ? "" : head.slice(firstSpace + 1);
393717
+ const attrs = parseAttributes(attrText);
393718
+ const node = { tagName, attrs, children: [] };
393719
+ stack[stack.length - 1]?.children.push(node);
393720
+ if (!selfClosing && !isVoidTag(tagName)) stack.push(node);
393721
+ }
393722
+ return root;
393723
+ }
393724
+ function parseAttributes(input) {
393725
+ const attrs = {};
393726
+ const attrRe = /([:\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+))/g;
393727
+ let match;
393728
+ while ((match = attrRe.exec(input)) !== null) {
393729
+ attrs[match[1].toLowerCase()] = match[2] ?? match[3] ?? match[4] ?? "";
393730
+ }
393731
+ return attrs;
393732
+ }
393733
+ function isVoidTag(tagName) {
393734
+ return (/* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"])).has(tagName);
393735
+ }
393736
+ function routeFromFilePath(filePath) {
393737
+ const normalized = filePath.replace(/\\/g, "/");
393738
+ const lower = normalized.toLowerCase();
393739
+ const markers = ["/pages/", "/app/", "/views/", "/wwwroot/"];
393740
+ for (const marker of markers) {
393741
+ const idx = lower.indexOf(marker);
393742
+ if (idx === -1) continue;
393743
+ const suffix = normalized.slice(idx + marker.length).replace(/\.(html?|vue|aspx|asp)$/i, "");
393744
+ const parts = suffix.split("/").filter(Boolean);
393745
+ if (parts.length === 0) return "/";
393746
+ const mapped = parts.map((segment) => {
393747
+ if (["index", "default", "page"].includes(segment.toLowerCase())) return "";
393748
+ if (segment.startsWith("[") && segment.endsWith("]")) {
393749
+ const key = segment.slice(1, -1);
393750
+ return key.startsWith("...") ? "*" : `:${key}`;
393751
+ }
393752
+ return segment;
393753
+ }).filter(Boolean);
393754
+ return `/${mapped.join("/")}` || "/";
393755
+ }
393756
+ return null;
393757
+ }
393758
+ function toComponentName(filePath) {
393759
+ const name = basename4(filePath).replace(/\.[^.]+$/, "");
393760
+ return name || "Component";
393761
+ }
393762
+
393763
+ // src/extractors/cpp-extractor.ts
393764
+ init_esm_shims();
393765
+ var CppExtractor = class {
393766
+ async extract(files, emitter) {
393767
+ for (const file of files) {
393768
+ this.extractFileIndexed(file, emitter);
393769
+ this.extractSymbols(file, emitter);
393770
+ this.extractImports(file, emitter);
393771
+ this.extractSqlUsage(file, emitter);
393772
+ this.extractTests(file, emitter);
393773
+ this.extractRoutes(file, emitter);
393774
+ }
393775
+ }
393776
+ extractFileIndexed(file, emitter) {
393777
+ const lowerPath = file.path.toLowerCase();
393778
+ const isTest = /(^|[/\\])(test|tests|__tests__)([/\\]|$)/i.test(file.path) || /_test\.|\.test\./i.test(file.path) || /\b(gtest|catch2|doctest)\b/i.test(file.content);
393779
+ const isGenerated = /\b(auto-generated|generated file|do not edit)\b/i.test(file.content) || lowerPath.includes("/generated/") || lowerPath.includes("\\generated\\");
393780
+ emitter.emitFileIndexed({
393781
+ fileId: `cpp:${file.path}`,
393782
+ filePath: file.path,
393783
+ language: "cplusplus",
393784
+ lineCount: file.lines.length,
393785
+ byteSize: Buffer.byteLength(file.content, "utf-8"),
393786
+ isTest,
393787
+ isMigration: false,
393788
+ isGenerated
393789
+ });
393790
+ }
393791
+ extractSymbols(file, emitter) {
393792
+ const patterns = [
393793
+ { re: /^\s*(?:template\s*<[^>]+>\s*)?(?:inline\s+)?(?:constexpr\s+)?(?:static\s+)?(?:virtual\s+)?(?:[\w:<>~*&\s]+?)\s+([A-Za-z_]\w*)\s*\([^;{}]*\)\s*(?:const\s*)?(?:noexcept\s*)?(?:override\s*)?\{/gm, kind: "function", nameGroup: 1 },
393794
+ { re: /^\s*(?:class|struct)\s+([A-Za-z_]\w*)\b/gm, kind: "class", nameGroup: 1 },
393795
+ { re: /^\s*enum(?:\s+class)?\s+([A-Za-z_]\w*)\b/gm, kind: "enum", nameGroup: 1 },
393796
+ { re: /^\s*namespace\s+([A-Za-z_]\w*)\b/gm, kind: "namespace", nameGroup: 1 }
393797
+ ];
393798
+ for (const { re, kind, nameGroup } of patterns) {
393799
+ let m;
393800
+ while ((m = re.exec(file.content)) !== null) {
393801
+ const name = m[nameGroup];
393802
+ const line = lineNumber14(file.content, m.index);
393803
+ emitter.emitSymbolDeclared({
393804
+ symbolId: `cpp:${file.path}:${kind}:${name}:${line}`,
393805
+ symbolKind: kind,
393806
+ qualifiedName: name,
393807
+ shortName: name,
393808
+ filePath: file.path,
393809
+ startLine: line,
393810
+ endLine: findBlockEnd2(file.lines, line),
393811
+ visibility: "public",
393812
+ isAbstract: false,
393813
+ isStatic: /\bstatic\b/.test(m[0]),
393814
+ baseType: null,
393815
+ interfaces: [],
393816
+ attributes: []
393817
+ });
393818
+ }
393819
+ }
393820
+ }
393821
+ extractImports(file, emitter) {
393822
+ const includeRe = /^\s*#include\s*[<"]([^>"]+)[>"]/gm;
393823
+ let m;
393824
+ while ((m = includeRe.exec(file.content)) !== null) {
393825
+ const target = m[1];
393826
+ const line = lineNumber14(file.content, m.index);
393827
+ emitter.emitImportObserved({
393828
+ importId: `cpp:${file.path}:${line}:${target}`,
393829
+ moduleSpecifier: target,
393830
+ importedNames: [],
393831
+ isDefault: false,
393832
+ isNamespace: false,
393833
+ isTypeOnly: false,
393834
+ filePath: file.path,
393835
+ line
393836
+ });
393837
+ }
393838
+ }
393839
+ extractSqlUsage(file, emitter) {
393840
+ const sqlRe = /\b(SELECT|INSERT|UPDATE|DELETE|MERGE|CREATE|ALTER|DROP)\b[\s\S]{0,200}/gi;
393841
+ let m;
393842
+ while ((m = sqlRe.exec(file.content)) !== null) {
393843
+ const snippet = m[0].replace(/\s+/g, " ").trim();
393844
+ const line = lineNumber14(file.content, m.index);
393845
+ emitter.emitSqlUsage({
393846
+ sqlUsageId: `cpp:${file.path}:${line}`,
393847
+ filePath: file.path,
393848
+ line,
393849
+ statementType: m[1].toUpperCase(),
393850
+ operation: "query",
393851
+ tableNames: [],
393852
+ usesParameterizedQuery: /\?|:\w+|@\w+/.test(snippet),
393853
+ queryFingerprint: snippet.slice(0, 160)
393854
+ });
393855
+ }
393856
+ }
393857
+ extractTests(file, emitter) {
393858
+ const testRe = /^\s*(TEST|TEST_F|TEST_P|SCENARIO|SECTION)\s*\(([^,\)]+)(?:,\s*([^\)]+))?\)/gm;
393859
+ let m;
393860
+ while ((m = testRe.exec(file.content)) !== null) {
393861
+ const line = lineNumber14(file.content, m.index);
393862
+ const suite = (m[2] || "").trim();
393863
+ const name = (m[3] || suite).trim();
393864
+ emitter.emitTestCaseDeclared({
393865
+ testId: `cpp:${file.path}:${line}:${suite}:${name}`,
393866
+ framework: "cpp-test",
393867
+ suiteName: suite || null,
393868
+ testName: name || "<unnamed>",
393869
+ filePath: file.path,
393870
+ line,
393871
+ isParameterized: /TEST_P/.test(m[1])
393872
+ });
393873
+ }
393874
+ }
393875
+ extractRoutes(file, emitter) {
393876
+ const routeRe = /\b(GET|POST|PUT|DELETE|PATCH)\s*\(\s*"([^"]+)"/g;
393877
+ let m;
393878
+ while ((m = routeRe.exec(file.content)) !== null) {
393879
+ const method = m[1].toUpperCase();
393880
+ const routePath = m[2];
393881
+ const line = lineNumber14(file.content, m.index);
393882
+ emitter.emitRouteDeclared({
393883
+ routeId: `cpp:${file.path}:${line}:${method}:${routePath}`,
393884
+ httpMethod: method,
393885
+ routePath,
393886
+ handlerType: "cpp-http",
393887
+ handlerName: "<unknown>",
393888
+ filePath: file.path,
393889
+ startLine: line
393890
+ });
393891
+ }
393892
+ }
393893
+ };
393894
+ function lineNumber14(content, index) {
393895
+ return content.slice(0, index).split("\n").length;
393896
+ }
393897
+ function findBlockEnd2(lines, startLine) {
393898
+ let depth = 0;
393899
+ for (let i = startLine - 1; i < lines.length; i++) {
393900
+ const line = lines[i] ?? "";
393901
+ for (const ch of line) {
393902
+ if (ch === "{") depth++;
393903
+ else if (ch === "}") {
393904
+ depth--;
393905
+ if (depth <= 0) return i + 1;
393906
+ }
393907
+ }
393908
+ }
393909
+ return startLine;
393910
+ }
393911
+
393455
393912
  // src/main.ts
393456
393913
  import { resolve as resolve2, extname as extname4 } from "path";
393457
393914
  import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
393458
393915
  var program2 = new Command();
393459
- program2.name("vibgrate-hcs-node").description("ts-morph-based HCS fact extractor for TypeScript and JavaScript").version("0.1.0").requiredOption("--project <path>", "Path to tsconfig.json or project directory").option("--output <format>", "Output format (ndjson)", "ndjson").option("--swift-project <path>", "Path to Swift project for text-based extraction").option("--vb6-project <path>", "Path to VB6 project for text-based extraction").option("--rust-project <path>", "Path to Rust project for text-based extraction").option("--ruby-project <path>", "Path to Ruby project for text-based extraction").option("--php-project <path>", "Path to PHP project for text-based extraction").option("--dart-project <path>", "Path to Dart project for text-based extraction").option("--scala-project <path>", "Path to Scala project for text-based extraction").option("--cobol-project <path>", "Path to COBOL project for text-based extraction").option("--cobol-copybook-paths <paths>", "Comma-separated copybook search paths").action(async (opts) => {
393916
+ program2.name("vibgrate-hcs-node").description("ts-morph-based HCS fact extractor for TypeScript and JavaScript").version("0.1.0").requiredOption("--project <path>", "Path to tsconfig.json or project directory").option("--output <format>", "Output format (ndjson)", "ndjson").option("--swift-project <path>", "Path to Swift project for text-based extraction").option("--vb6-project <path>", "Path to VB6 project for text-based extraction").option("--rust-project <path>", "Path to Rust project for text-based extraction").option("--ruby-project <path>", "Path to Ruby project for text-based extraction").option("--php-project <path>", "Path to PHP project for text-based extraction").option("--dart-project <path>", "Path to Dart project for text-based extraction").option("--scala-project <path>", "Path to Scala project for text-based extraction").option("--cobol-project <path>", "Path to COBOL project for text-based extraction").option("--cplusplus-project <path>", "Path to C++ project for text-based extraction").option("--cobol-copybook-paths <paths>", "Comma-separated copybook search paths").action(async (opts) => {
393460
393917
  const projectPath = resolve2(opts.project);
393461
393918
  if (!existsSync3(projectPath)) {
393462
393919
  process.stderr.write(`[error] Project path not found: ${projectPath}
@@ -393541,6 +393998,17 @@ program2.name("vibgrate-hcs-node").description("ts-morph-based HCS fact extracto
393541
393998
  await runScalaTextExtractors(scalaPath, emitter);
393542
393999
  return;
393543
394000
  }
394001
+ if (opts.cplusplusProject) {
394002
+ const cppPath = resolve2(opts.cplusplusProject);
394003
+ if (!existsSync3(cppPath)) {
394004
+ process.stderr.write(`[error] C++ project path not found: ${cppPath}
394005
+ `);
394006
+ process.exit(1);
394007
+ }
394008
+ emitter.setLanguage("cplusplus");
394009
+ await runCppTextExtractors(cppPath, emitter);
394010
+ return;
394011
+ }
393544
394012
  if (opts.cobolProject) {
393545
394013
  const cobolPath = resolve2(opts.cobolProject);
393546
394014
  if (!existsSync3(cobolPath)) {
@@ -393557,11 +394025,17 @@ program2.name("vibgrate-hcs-node").description("ts-morph-based HCS fact extracto
393557
394025
  emitProgress({ phase: "discovering", language: "typescript" });
393558
394026
  const project = createProject(projectPath);
393559
394027
  const sourceFiles = project.getSourceFiles();
393560
- if (sourceFiles.length === 0) {
394028
+ const webMarkupFiles = discoverFiles(projectPath, WEB_MARKUP_EXTENSIONS, WEB_MARKUP_SKIP_DIRS);
394029
+ if (sourceFiles.length === 0 && webMarkupFiles.length === 0) {
393561
394030
  process.stderr.write(`[warn] No source files found in: ${projectPath}
393562
394031
  `);
393563
394032
  process.exit(0);
393564
394033
  }
394034
+ if (sourceFiles.length === 0 && webMarkupFiles.length > 0) {
394035
+ emitter.setLanguage("web");
394036
+ await runWebMarkupExtractors(projectPath, emitter, webMarkupFiles);
394037
+ return;
394038
+ }
393565
394039
  const language = detectLanguage(sourceFiles);
393566
394040
  emitter.setLanguage(language);
393567
394041
  process.stderr.write(
@@ -393570,6 +394044,10 @@ program2.name("vibgrate-hcs-node").description("ts-morph-based HCS fact extracto
393570
394044
  );
393571
394045
  emitProgress({ phase: "scanning", language, fileCount: sourceFiles.length, fileIndex: 0 });
393572
394046
  await runExtractors(sourceFiles, emitter);
394047
+ if (webMarkupFiles.length > 0) {
394048
+ emitter.setLanguage("web");
394049
+ await runWebMarkupExtractors(projectPath, emitter, webMarkupFiles);
394050
+ }
393573
394051
  emitProgress({ phase: "done", language, fileCount: sourceFiles.length });
393574
394052
  } catch (err) {
393575
394053
  const error = err instanceof Error ? err : new Error(String(err));
@@ -393913,6 +394391,40 @@ async function runScalaTextExtractors(projectPath, emitter) {
393913
394391
  }
393914
394392
  emitProgress({ phase: "done", language: "scala", fileCount: files.length });
393915
394393
  }
394394
+ var CPP_SKIP_DIRS = /* @__PURE__ */ new Set([
394395
+ ".git",
394396
+ "node_modules",
394397
+ "build",
394398
+ "cmake-build-debug",
394399
+ "cmake-build-release",
394400
+ "out",
394401
+ "bin",
394402
+ "obj",
394403
+ "x64",
394404
+ "x86",
394405
+ ".vs",
394406
+ "vcpkg_installed"
394407
+ ]);
394408
+ var CPP_EXTENSIONS = /* @__PURE__ */ new Set([".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".ixx"]);
394409
+ async function runCppTextExtractors(projectPath, emitter) {
394410
+ const files = discoverFiles(projectPath, CPP_EXTENSIONS, CPP_SKIP_DIRS);
394411
+ if (files.length === 0) {
394412
+ process.stderr.write(`[warn] No C++ source files found in: ${projectPath}
394413
+ `);
394414
+ return;
394415
+ }
394416
+ process.stderr.write(
394417
+ `[info] Found ${files.length} C++ source files for text extraction
394418
+ `
394419
+ );
394420
+ emitProgress({ phase: "scanning", language: "cplusplus", fileCount: files.length, fileIndex: 0 });
394421
+ const textFiles = filesToTextFilesWithProgress(files, "cplusplus");
394422
+ const extractors = [new CppExtractor()];
394423
+ for (const extractor of extractors) {
394424
+ await extractor.extract(textFiles, emitter);
394425
+ }
394426
+ emitProgress({ phase: "done", language: "cplusplus", fileCount: files.length });
394427
+ }
393916
394428
  var COBOL_SKIP_DIRS = /* @__PURE__ */ new Set([
393917
394429
  ".git",
393918
394430
  "node_modules",
@@ -393923,6 +394435,31 @@ var COBOL_SKIP_DIRS = /* @__PURE__ */ new Set([
393923
394435
  "dist",
393924
394436
  "out"
393925
394437
  ]);
394438
+ var WEB_MARKUP_SKIP_DIRS = /* @__PURE__ */ new Set([
394439
+ ".git",
394440
+ "node_modules",
394441
+ "dist",
394442
+ "build",
394443
+ "out",
394444
+ ".next",
394445
+ ".nuxt",
394446
+ ".cache"
394447
+ ]);
394448
+ var WEB_MARKUP_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".htm", ".vue", ".asp", ".aspx"]);
394449
+ async function runWebMarkupExtractors(projectPath, emitter, preDiscoveredFiles) {
394450
+ const files = preDiscoveredFiles ?? discoverFiles(projectPath, WEB_MARKUP_EXTENSIONS, WEB_MARKUP_SKIP_DIRS);
394451
+ if (files.length === 0) return;
394452
+ process.stderr.write(
394453
+ `[info] Found ${files.length} website markup files for AST extraction
394454
+ `
394455
+ );
394456
+ emitProgress({ phase: "scanning", language: "web", fileCount: files.length, fileIndex: 0 });
394457
+ const textFiles = filesToTextFilesWithProgress(files, "web");
394458
+ const extractors = [new WebMarkupExtractor()];
394459
+ for (const extractor of extractors) {
394460
+ await extractor.extract(textFiles, emitter);
394461
+ }
394462
+ }
393926
394463
  async function runCobolTextExtractors(projectPath, copybookPaths, emitter) {
393927
394464
  const files = discoverFiles(projectPath, ALL_COBOL_EXTENSIONS, COBOL_SKIP_DIRS);
393928
394465
  if (files.length === 0) {