@justmpm/supergrep 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ import { z } from "zod";
7
7
 
8
8
  // src/tools/find.ts
9
9
  import { findInFiles } from "@ast-grep/napi";
10
- import { relative, resolve } from "path";
10
+ import { relative, resolve as resolve2 } from "path";
11
11
  import { stat } from "fs/promises";
12
12
 
13
13
  // src/utils/lang.ts
@@ -65,8 +65,115 @@ function langName(lang) {
65
65
  };
66
66
  return friendly[langStr] ?? langStr;
67
67
  }
68
+ var IGNORED_EXTENSIONS_SUBSTRINGS = [
69
+ ".min.js",
70
+ ".min.css",
71
+ ".bundle.js",
72
+ ".chunk.js",
73
+ ".map",
74
+ ".d.ts"
75
+ ];
76
+ function shouldIgnoreFile(filePath) {
77
+ const lower = filePath.toLowerCase();
78
+ for (const ext of IGNORED_EXTENSIONS_SUBSTRINGS) {
79
+ if (lower.includes(ext)) return true;
80
+ }
81
+ return false;
82
+ }
83
+
84
+ // src/utils/find-fallback.ts
85
+ import { parse } from "@ast-grep/napi";
86
+ import { readdir, readFile, stat as fsStat } from "fs/promises";
87
+ import { join, extname, resolve } from "path";
88
+ var LANG_EXTENSIONS = {
89
+ Html: [".html", ".htm"],
90
+ Css: [".css", ".scss", ".less"]
91
+ };
92
+ var IGNORED_DIRS = /* @__PURE__ */ new Set([
93
+ "node_modules",
94
+ ".git",
95
+ "dist",
96
+ "build",
97
+ ".next",
98
+ ".turbo",
99
+ "coverage",
100
+ "out"
101
+ ]);
102
+ async function findInFilesFallback(lang, config) {
103
+ const langStr = String(lang);
104
+ const extensions = LANG_EXTENSIONS[langStr];
105
+ if (!extensions) {
106
+ return [];
107
+ }
108
+ const results = [];
109
+ for (const searchPath of config.paths) {
110
+ const absPath = resolve(searchPath);
111
+ try {
112
+ const pathStat = await fsStat(absPath);
113
+ if (pathStat.isFile()) {
114
+ const ext = extname(absPath).toLowerCase();
115
+ if (extensions.some((e) => ext === e)) {
116
+ await processFile(absPath, lang, config.matcher, results);
117
+ }
118
+ } else if (pathStat.isDirectory()) {
119
+ await walkDir(absPath, lang, extensions, config.matcher, results);
120
+ }
121
+ } catch {
122
+ continue;
123
+ }
124
+ }
125
+ return results;
126
+ }
127
+ async function processFile(filePath, lang, matcher, results) {
128
+ if (shouldIgnoreFile(filePath)) return;
129
+ let source;
130
+ try {
131
+ source = await readFile(filePath, "utf-8");
132
+ } catch {
133
+ return;
134
+ }
135
+ let ast;
136
+ try {
137
+ ast = parse(lang, source);
138
+ } catch {
139
+ return;
140
+ }
141
+ try {
142
+ const nodes = [...ast.root().findAll(matcher)];
143
+ if (nodes.length > 0) {
144
+ results.push({ file: filePath, nodes });
145
+ }
146
+ } catch {
147
+ return;
148
+ }
149
+ }
150
+ async function walkDir(dirPath, lang, extensions, matcher, results) {
151
+ let entries;
152
+ try {
153
+ entries = await readdir(dirPath, { withFileTypes: true });
154
+ } catch {
155
+ return;
156
+ }
157
+ for (const entry of entries) {
158
+ const fullPath = join(dirPath, entry.name);
159
+ if (entry.isDirectory()) {
160
+ if (IGNORED_DIRS.has(entry.name)) continue;
161
+ if (entry.name.startsWith(".")) continue;
162
+ await walkDir(fullPath, lang, extensions, matcher, results);
163
+ } else if (entry.isFile()) {
164
+ const ext = extname(entry.name).toLowerCase();
165
+ if (extensions.includes(ext)) {
166
+ await processFile(fullPath, lang, matcher, results);
167
+ }
168
+ }
169
+ }
170
+ }
68
171
 
69
172
  // src/tools/find.ts
173
+ function isHtmlCssLang(lang) {
174
+ const langStr = String(lang);
175
+ return langStr === "Html" || langStr === "Css";
176
+ }
70
177
  var MULTI_META_RE = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
71
178
  var SINGLE_META_RE = /(?<!\$)\$(?:\$\$)?([A-Z_][A-Z0-9_]*)/g;
72
179
  async function findPattern(options) {
@@ -80,7 +187,7 @@ async function findPattern(options) {
80
187
  warnings.push(`Linguagem "${options.lang}" nao reconhecida. Usando autodeteccao...`);
81
188
  }
82
189
  }
83
- const searchPath = resolve(cwd, options.path ?? ".");
190
+ const searchPath = resolve2(cwd, options.path ?? ".");
84
191
  try {
85
192
  await stat(searchPath);
86
193
  } catch {
@@ -100,8 +207,9 @@ async function findPattern(options) {
100
207
  }
101
208
  const langForSearch = lang ?? resolveLang("typescript");
102
209
  const matches = [];
210
+ const useFallback = lang !== void 0 && isHtmlCssLang(lang);
103
211
  try {
104
- const fileResults = await findInFilesWrapper(langForSearch, findConfig);
212
+ const fileResults = useFallback ? await findInFilesFallback(lang, { paths: [searchPath], matcher: napiConfig }) : await findInFilesWrapper(langForSearch, findConfig);
105
213
  for (const { file, nodes } of fileResults) {
106
214
  for (const node of nodes) {
107
215
  const range = node.range();
@@ -245,9 +353,9 @@ var LanguageNotDetectedError = class extends Error {
245
353
  };
246
354
 
247
355
  // src/tools/tree.ts
248
- import { parse } from "@ast-grep/napi";
249
- import { readFile, stat as stat2 } from "fs/promises";
250
- import { resolve as resolve2, relative as relative2, extname } from "path";
356
+ import { parse as parse2 } from "@ast-grep/napi";
357
+ import { readFile as readFile2, stat as stat2 } from "fs/promises";
358
+ import { resolve as resolve3, relative as relative2, extname as extname2 } from "path";
251
359
  async function exploreTree(options) {
252
360
  const warnings = [];
253
361
  const cwd = options.cwd ?? process.cwd();
@@ -266,13 +374,13 @@ async function exploreTree(options) {
266
374
  detectedLang = resolveLang("typescript");
267
375
  }
268
376
  } else if (options.path) {
269
- filePath = resolve2(cwd, options.path);
377
+ filePath = resolve3(cwd, options.path);
270
378
  try {
271
379
  await stat2(filePath);
272
380
  } catch {
273
381
  throw new FileNotFoundError(filePath);
274
382
  }
275
- source = await readFile(filePath, "utf-8");
383
+ source = await readFile2(filePath, "utf-8");
276
384
  if (options.lang) {
277
385
  detectedLang = resolveLang(options.lang);
278
386
  if (!detectedLang) {
@@ -283,7 +391,7 @@ async function exploreTree(options) {
283
391
  detectedLang = detectLangFromFile(filePath);
284
392
  if (!detectedLang) {
285
393
  warnings.push(
286
- `Nao foi possivel detectar linguagem da extensao "${extname(filePath)}". Usando TypeScript.`
394
+ `Nao foi possivel detectar linguagem da extensao "${extname2(filePath)}". Usando TypeScript.`
287
395
  );
288
396
  detectedLang = resolveLang("typescript");
289
397
  }
@@ -294,7 +402,7 @@ async function exploreTree(options) {
294
402
  const lang = detectedLang;
295
403
  let ast;
296
404
  try {
297
- ast = parse(lang, source);
405
+ ast = parse2(lang, source);
298
406
  } catch (parseErr) {
299
407
  const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
300
408
  throw new TreeParseError(filePath, lang, msg);
@@ -347,8 +455,12 @@ var TreeParseError = class extends Error {
347
455
 
348
456
  // src/tools/replace.ts
349
457
  import { findInFiles as findInFiles2 } from "@ast-grep/napi";
350
- import { resolve as resolve3, relative as relative3 } from "path";
458
+ import { resolve as resolve4, relative as relative3 } from "path";
351
459
  import { stat as stat3 } from "fs/promises";
460
+ function isHtmlCssLang2(lang) {
461
+ const langStr = String(lang);
462
+ return langStr === "Html" || langStr === "Css";
463
+ }
352
464
  var MULTI_META_RE2 = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
353
465
  var SINGLE_META_RE2 = /(?<!\$)\$(?:\$\$)?([A-Z_][A-Z0-9_]*)/g;
354
466
  async function replacePreview(options) {
@@ -371,7 +483,7 @@ async function replacePreview(options) {
371
483
  } else {
372
484
  lang = resolveLang("typescript");
373
485
  }
374
- const searchPath = resolve3(cwd, options.path ?? ".");
486
+ const searchPath = resolve4(cwd, options.path ?? ".");
375
487
  try {
376
488
  await stat3(searchPath);
377
489
  } catch {
@@ -389,8 +501,9 @@ async function replacePreview(options) {
389
501
  languageGlobs: langToGlobs2(lang)
390
502
  };
391
503
  const changes = [];
504
+ const useFallback = isHtmlCssLang2(lang);
392
505
  try {
393
- const fileResults = await findInFilesWrapper2(lang, findConfig);
506
+ const fileResults = useFallback ? await findInFilesFallback(lang, { paths: [searchPath], matcher: napiConfig }) : await findInFilesWrapper2(lang, findConfig);
394
507
  for (const { file, nodes } of fileResults) {
395
508
  for (const node of nodes) {
396
509
  const metaVarValues = {};
@@ -410,7 +523,7 @@ async function replacePreview(options) {
410
523
  let interpolated = options.rewrite;
411
524
  for (const [name, value] of Object.entries(metaVarValues)) {
412
525
  interpolated = interpolated.replaceAll(
413
- new RegExp(`\\$${name}\\b`, "g"),
526
+ new RegExp(`\\$+${name}\\b`, "g"),
414
527
  value
415
528
  );
416
529
  }
@@ -1017,8 +1130,8 @@ metavariaveis ($VAR, $$VAR, $$$VARS) como curingas que capturam partes dinamicas
1017
1130
  \u2022 typescript (.ts) \u2014 apenas .ts puro (sem JSX)
1018
1131
  \u2022 javascript (.js, .jsx, .mjs, .cjs)
1019
1132
  \u2022 tsx (.tsx) \u2014 .tsx COM JSX/React
1020
- \u2022 css (.css, .scss, .less)
1021
- \u2022 html (.html, .htm)
1133
+ \u2022 css (.css, .scss, .less) \u26A0\uFE0F Motor usa fallback manual (findInFiles napi nao suporta nativamente)
1134
+ \u2022 html (.html, .htm) \u26A0\uFE0F Motor usa fallback manual (findInFiles napi nao suporta nativamente)
1022
1135
 
1023
1136
  \u{1F916} AUTODETECCAO: Se o parametro 'lang' NAO for especificado, o motor
1024
1137
  detecta a linguagem automaticamente pela extensao de cada arquivo.
@@ -1057,12 +1170,30 @@ Cada arquivo e analisado isoladamente. Para analise semantica, use ai-tool.
1057
1170
  \u{1F4DD} EXEMPLOS DE PATTERNS:
1058
1171
  \u2022 console.$METHOD($MSG) \u2192 captura metodo e 1 argumento
1059
1172
  \u2022 console.$METHOD($$$ARGS) \u2192 captura metodo e todos os argumentos
1060
- \u2022 function $NAME($$$PARAMS) { $$$BODY } \u2192 captura funcoes completas
1173
+ \u2022 $FUNC($$$ARGS) \u2192 captura qualquer chamada de funcao (use para call_expression)
1061
1174
  \u2022 import { $$$ITEMS } from '$MODULE' \u2192 captura imports
1062
- \u2022 const $VAR = $VALUE \u2192 captura declaracoes
1175
+ \u2022 const $VAR = $VALUE \u2192 captura declaracoes simples
1176
+ \u2022 const $VAR: $TYPE = $VALUE \u2192 captura declaracoes com tipo (sempre inclua o =)
1063
1177
  \u2022 try { $$$ } catch ($ERR) { $$$ } \u2192 captura try-catch
1064
1178
  \u2022 await $FUNC($$$ARGS) \u2192 captura chamadas assincronas
1065
1179
 
1180
+ \u26A0\uFE0F PATTERNS PARA FUNCOES TYPESCRIPT (IMPORTANTE):
1181
+ Funcoes TS frequentemente tem tipo de retorno (: Type) como no nomeado extra.
1182
+ Se o pattern nao incluir o tipo de retorno, o match FALHA. Use:
1183
+ \u2705 function $NAME($$$PARAMS): $_RET { $$$BODY }
1184
+ \u2705 function $NAME($$$PARAMS): $_RET_TYPE { $$$BODY }
1185
+ \u2705 const $NAME = ($PARAM: $TYPE): $_RET => { $$$BODY }
1186
+ \u274C function $NAME($$$PARAMS) { $$$BODY } \u2014 falha se houver tipo de retorno
1187
+ O $_RET (com underscore) age como "coringa nao-capturador" para o tipo de retorno.
1188
+
1189
+ \u26A0\uFE0F PATTERNS CSS PRECISAM DE CONTEXTO:
1190
+ Padroes CSS sem contexto sao ambiguos para o parser. Use:
1191
+ \u2705 $SELECTOR { $$$ } \u2014 captura qualquer regra CSS completa
1192
+ \u2705 $PROP: $VALUE \u2014 captura propriedade (dentro de uma regra)
1193
+ \u2705 * { $$$ } \u2014 qualquer regra CSS
1194
+ \u274C .className { $$$ } \u2014 falha (ponto no inicio e ambiguo)
1195
+ \u274C margin: 0 \u2014 sem contexto, use $PROP: $VALUE
1196
+
1066
1197
  \u{1F524} METAVARIAVEIS:
1067
1198
  \u2022 $VAR \u2192 captura UM no nomeado (ex: um identificador, uma string, um numero)
1068
1199
  \u2022 $$VAR \u2192 captura UM no (incluindo nos nao-nomeados como operadores +, -)
@@ -1081,7 +1212,7 @@ Workflow recomendado: supergrep_find \u2192 supergrep_tree \u2192 supergrep_repl
1081
1212
  "Padrao AST Grep na linguagem alvo. Ex: 'console.$METHOD($$$ARGS)', 'function $NAME($$$PARAMS) { $$$BODY }'"
1082
1213
  ),
1083
1214
  lang: z.string().optional().describe(
1084
- "Linguagem: 'typescript' (.ts), 'javascript' (.js), 'tsx' (.tsx), 'css' (.css), 'html' (.html). Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo."
1215
+ "Linguagem: 'typescript' (.ts), 'javascript' (.js), 'tsx' (.tsx), 'css' (.css), 'html' (.html). Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo. Para HTML/CSS, o motor usa fallback parse direto (findInFiles nao suporta nativamente)."
1085
1216
  ),
1086
1217
  path: z.string().optional().describe(
1087
1218
  "Arquivo ou diretorio onde buscar. Default: diretorio atual. Ex: 'src/', 'app/page.tsx'"
@@ -1244,7 +1375,7 @@ Workflow: supergrep_find \u2192 supergrep_replace (preview) \u2192 aplicar mudan
1244
1375
  "Texto de substituicao. Use $VAR para referenciar metavariaveis capturadas. Ex: 'logger.info($$$ARGS)'"
1245
1376
  ),
1246
1377
  lang: z.string().optional().describe(
1247
- "Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'. Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo."
1378
+ "Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'. Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo. Para HTML/CSS, o motor usa fallback parse direto (findInFiles nao suporta nativamente)."
1248
1379
  ),
1249
1380
  path: z.string().optional().describe(
1250
1381
  "Arquivo ou diretorio onde buscar. Default: diretorio atual."
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startMcpServer
4
- } from "./chunk-5PJJZ4CK.js";
4
+ } from "./chunk-LUKDYG3I.js";
5
5
 
6
6
  // src/cli.ts
7
7
  startMcpServer().catch((err) => {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startMcpServer
3
- } from "./chunk-5PJJZ4CK.js";
3
+ } from "./chunk-LUKDYG3I.js";
4
4
 
5
5
  // src/index.ts
6
6
  import { createRequire } from "module";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/supergrep",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server para busca estrutural de código com AST Grep. Encontra padrões de código com precisão sintática, ignorando formatação e comentários. Suporta 20+ linguagens via Tree-sitter.",
5
5
  "keywords": [
6
6
  "ast-grep",