@justmpm/supergrep 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-SENMQNTX.js → chunk-5PJJZ4CK.js} +188 -208
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +5 -2
- package/package.json +1 -1
|
@@ -6,9 +6,9 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
// src/tools/find.ts
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { findInFiles } from "@ast-grep/napi";
|
|
10
|
+
import { relative, resolve } from "path";
|
|
11
|
+
import { stat } from "fs/promises";
|
|
12
12
|
|
|
13
13
|
// src/utils/lang.ts
|
|
14
14
|
import { Lang } from "@ast-grep/napi";
|
|
@@ -65,35 +65,6 @@ function langName(lang) {
|
|
|
65
65
|
};
|
|
66
66
|
return friendly[langStr] ?? langStr;
|
|
67
67
|
}
|
|
68
|
-
function isSupportedExtension(filePath) {
|
|
69
|
-
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
70
|
-
return SUPPORTED_EXTENSIONS.has(ext);
|
|
71
|
-
}
|
|
72
|
-
var IGNORED_EXTENSIONS_SUBSTRINGS = [
|
|
73
|
-
".min.js",
|
|
74
|
-
".min.css",
|
|
75
|
-
".bundle.js",
|
|
76
|
-
".chunk.js",
|
|
77
|
-
".map",
|
|
78
|
-
".d.ts"
|
|
79
|
-
];
|
|
80
|
-
function shouldIgnoreFile(filePath) {
|
|
81
|
-
const lower = filePath.toLowerCase();
|
|
82
|
-
for (const ext of IGNORED_EXTENSIONS_SUBSTRINGS) {
|
|
83
|
-
if (lower.includes(ext)) return true;
|
|
84
|
-
}
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
var IGNORED_DIRS = [
|
|
88
|
-
"node_modules",
|
|
89
|
-
"dist",
|
|
90
|
-
"build",
|
|
91
|
-
".git",
|
|
92
|
-
".next",
|
|
93
|
-
".turbo",
|
|
94
|
-
"coverage",
|
|
95
|
-
"out"
|
|
96
|
-
];
|
|
97
68
|
|
|
98
69
|
// src/tools/find.ts
|
|
99
70
|
var MULTI_META_RE = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
|
|
@@ -102,33 +73,47 @@ async function findPattern(options) {
|
|
|
102
73
|
const startTime = Date.now();
|
|
103
74
|
const warnings = [];
|
|
104
75
|
const cwd = options.cwd ?? process.cwd();
|
|
105
|
-
|
|
106
|
-
if (
|
|
76
|
+
let lang;
|
|
77
|
+
if (options.lang) {
|
|
78
|
+
lang = resolveLang(options.lang);
|
|
79
|
+
if (!lang) {
|
|
80
|
+
warnings.push(`Linguagem "${options.lang}" nao reconhecida. Usando autodeteccao...`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const searchPath = resolve(cwd, options.path ?? ".");
|
|
84
|
+
try {
|
|
85
|
+
await stat(searchPath);
|
|
86
|
+
} catch {
|
|
87
|
+
warnings.push(`Path nao encontrado: ${searchPath}. Usando diretorio atual.`);
|
|
107
88
|
throw new LanguageNotDetectedError(options.lang ?? "desconhecida");
|
|
108
89
|
}
|
|
109
|
-
validatePattern(options.pattern, lang);
|
|
110
|
-
const searchDir = resolve(cwd, options.path ?? ".");
|
|
111
|
-
const files = await findCodeFiles(searchDir, cwd, lang);
|
|
112
|
-
warnings.push(...files.warnings);
|
|
113
90
|
const metaVars = extractMetaVarInfo(options.pattern);
|
|
91
|
+
const napiConfig = {
|
|
92
|
+
rule: { pattern: options.pattern }
|
|
93
|
+
};
|
|
94
|
+
const findConfig = {
|
|
95
|
+
paths: [searchPath],
|
|
96
|
+
matcher: napiConfig
|
|
97
|
+
};
|
|
98
|
+
if (lang) {
|
|
99
|
+
findConfig.languageGlobs = langToGlobs(lang);
|
|
100
|
+
}
|
|
101
|
+
const langForSearch = lang ?? resolveLang("typescript");
|
|
114
102
|
const matches = [];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const root = ast.root();
|
|
120
|
-
const foundNodes = root.findAll(options.pattern);
|
|
121
|
-
for (const node of foundNodes) {
|
|
103
|
+
try {
|
|
104
|
+
const fileResults = await findInFilesWrapper(langForSearch, findConfig);
|
|
105
|
+
for (const { file, nodes } of fileResults) {
|
|
106
|
+
for (const node of nodes) {
|
|
122
107
|
const range = node.range();
|
|
108
|
+
const text = node.text();
|
|
123
109
|
const match = {
|
|
124
|
-
file: relative(cwd,
|
|
110
|
+
file: relative(cwd, file).replace(/\\/g, "/"),
|
|
125
111
|
line: range.start.line,
|
|
126
112
|
column: range.start.column,
|
|
127
113
|
endLine: range.end.line,
|
|
128
114
|
endColumn: range.end.column,
|
|
129
|
-
text
|
|
130
|
-
metaVariables: {}
|
|
131
|
-
context: extractContextLines(source, range.start.line, 2)
|
|
115
|
+
text,
|
|
116
|
+
metaVariables: {}
|
|
132
117
|
};
|
|
133
118
|
for (const { name, isMulti } of metaVars) {
|
|
134
119
|
if (isMulti) {
|
|
@@ -145,19 +130,23 @@ async function findPattern(options) {
|
|
|
145
130
|
}
|
|
146
131
|
matches.push(match);
|
|
147
132
|
}
|
|
148
|
-
} catch {
|
|
149
|
-
continue;
|
|
150
133
|
}
|
|
134
|
+
} catch (err) {
|
|
135
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
if (lang) {
|
|
137
|
+
throw new PatternParseError(options.pattern, lang);
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Erro na busca: ${msg}`);
|
|
151
140
|
}
|
|
152
|
-
const
|
|
141
|
+
const filesWithMatchesSet = new Set(matches.map((m) => m.file));
|
|
153
142
|
const executionTimeMs = Date.now() - startTime;
|
|
154
143
|
return {
|
|
155
144
|
result: {
|
|
156
145
|
pattern: options.pattern,
|
|
157
|
-
lang,
|
|
146
|
+
lang: langForSearch,
|
|
158
147
|
matches,
|
|
159
|
-
filesScanned:
|
|
160
|
-
filesWithMatches:
|
|
148
|
+
filesScanned: matches.length > 0 ? filesWithMatchesSet.size : 0,
|
|
149
|
+
filesWithMatches: filesWithMatchesSet.size,
|
|
161
150
|
executionTimeMs
|
|
162
151
|
},
|
|
163
152
|
warnings
|
|
@@ -185,92 +174,56 @@ function extractMetaVarInfo(pattern) {
|
|
|
185
174
|
}
|
|
186
175
|
return result;
|
|
187
176
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
if (options.path) {
|
|
204
|
-
const ext = extname(options.path).toLowerCase();
|
|
205
|
-
if (ext && isSupportedExtension(options.path)) {
|
|
206
|
-
const detected = detectLangFromFile(options.path);
|
|
207
|
-
if (detected) return detected;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return resolveLang("typescript");
|
|
177
|
+
var IGNORED_DIR_PATTERNS = [
|
|
178
|
+
/[/\\]node_modules[/\\]/,
|
|
179
|
+
/[/\\]dist[/\\]/,
|
|
180
|
+
/[/\\]build[/\\]/,
|
|
181
|
+
/[/\\]\.git[/\\]/,
|
|
182
|
+
/[/\\]\.next[/\\]/,
|
|
183
|
+
/[/\\]\.turbo[/\\]/,
|
|
184
|
+
/[/\\]coverage[/\\]/,
|
|
185
|
+
/[/\\]out[/\\]/
|
|
186
|
+
];
|
|
187
|
+
function isIgnoredPath(filePath) {
|
|
188
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
189
|
+
const wrapped = `/${normalized}/`;
|
|
190
|
+
return IGNORED_DIR_PATTERNS.some((re) => re.test(wrapped));
|
|
211
191
|
}
|
|
212
|
-
function
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
192
|
+
async function findInFilesWrapper(lang, config) {
|
|
193
|
+
const results = [];
|
|
194
|
+
let callbacksReceived = 0;
|
|
195
|
+
const totalFiles = await findInFiles(
|
|
196
|
+
lang,
|
|
197
|
+
config,
|
|
198
|
+
(err, nodes) => {
|
|
199
|
+
callbacksReceived++;
|
|
200
|
+
if (err || nodes.length === 0) return;
|
|
201
|
+
const file = nodes[0].getRoot()?.filename() ?? "unknown";
|
|
202
|
+
if (isIgnoredPath(file)) return;
|
|
203
|
+
results.push({ file, nodes });
|
|
220
204
|
}
|
|
205
|
+
);
|
|
206
|
+
while (callbacksReceived < totalFiles) {
|
|
207
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
221
208
|
}
|
|
209
|
+
return results;
|
|
222
210
|
}
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
warnings.push(`Path nao encontrado: ${searchDir}. Usando diretorio atual.`);
|
|
239
|
-
return { paths: [], warnings };
|
|
240
|
-
}
|
|
241
|
-
const paths = [];
|
|
242
|
-
async function walk(dir) {
|
|
243
|
-
try {
|
|
244
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
245
|
-
for (const entry of entries) {
|
|
246
|
-
const fullPath = join(dir, entry.name);
|
|
247
|
-
if (entry.isDirectory()) {
|
|
248
|
-
if (IGNORED_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
await walk(fullPath);
|
|
252
|
-
} else if (entry.isFile()) {
|
|
253
|
-
if (shouldIgnoreFile(fullPath)) continue;
|
|
254
|
-
if (!isSupportedExtension(fullPath)) continue;
|
|
255
|
-
paths.push(fullPath);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
} catch {
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
await walk(searchDir);
|
|
262
|
-
if (paths.length > 5e3) {
|
|
263
|
-
warnings.push(
|
|
264
|
-
`Muitos arquivos encontrados (${paths.length}). Limitando a 5000. Use --path para focar em um diretorio.`
|
|
265
|
-
);
|
|
266
|
-
return { paths: paths.slice(0, 5e3), warnings };
|
|
267
|
-
}
|
|
268
|
-
if (paths.length === 0) {
|
|
269
|
-
warnings.push(
|
|
270
|
-
`Nenhum arquivo de codigo encontrado em: ${relative(_cwd, searchDir)}`
|
|
271
|
-
);
|
|
211
|
+
function langToGlobs(lang) {
|
|
212
|
+
const langStr = String(lang);
|
|
213
|
+
switch (langStr) {
|
|
214
|
+
case "TypeScript":
|
|
215
|
+
return ["*.ts"];
|
|
216
|
+
case "JavaScript":
|
|
217
|
+
return ["*.js", "*.jsx", "*.mjs", "*.cjs"];
|
|
218
|
+
case "Tsx":
|
|
219
|
+
return ["*.tsx"];
|
|
220
|
+
case "Css":
|
|
221
|
+
return ["*.css", "*.scss", "*.less"];
|
|
222
|
+
case "Html":
|
|
223
|
+
return ["*.html", "*.htm"];
|
|
224
|
+
default:
|
|
225
|
+
return [];
|
|
272
226
|
}
|
|
273
|
-
return { paths, warnings };
|
|
274
227
|
}
|
|
275
228
|
var PatternParseError = class extends Error {
|
|
276
229
|
pattern;
|
|
@@ -292,9 +245,9 @@ var LanguageNotDetectedError = class extends Error {
|
|
|
292
245
|
};
|
|
293
246
|
|
|
294
247
|
// src/tools/tree.ts
|
|
295
|
-
import { parse
|
|
296
|
-
import { readFile as
|
|
297
|
-
import { resolve as resolve2, relative as relative2, extname
|
|
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";
|
|
298
251
|
async function exploreTree(options) {
|
|
299
252
|
const warnings = [];
|
|
300
253
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -315,11 +268,11 @@ async function exploreTree(options) {
|
|
|
315
268
|
} else if (options.path) {
|
|
316
269
|
filePath = resolve2(cwd, options.path);
|
|
317
270
|
try {
|
|
318
|
-
await
|
|
271
|
+
await stat2(filePath);
|
|
319
272
|
} catch {
|
|
320
273
|
throw new FileNotFoundError(filePath);
|
|
321
274
|
}
|
|
322
|
-
source = await
|
|
275
|
+
source = await readFile(filePath, "utf-8");
|
|
323
276
|
if (options.lang) {
|
|
324
277
|
detectedLang = resolveLang(options.lang);
|
|
325
278
|
if (!detectedLang) {
|
|
@@ -330,7 +283,7 @@ async function exploreTree(options) {
|
|
|
330
283
|
detectedLang = detectLangFromFile(filePath);
|
|
331
284
|
if (!detectedLang) {
|
|
332
285
|
warnings.push(
|
|
333
|
-
`Nao foi possivel detectar linguagem da extensao "${
|
|
286
|
+
`Nao foi possivel detectar linguagem da extensao "${extname(filePath)}". Usando TypeScript.`
|
|
334
287
|
);
|
|
335
288
|
detectedLang = resolveLang("typescript");
|
|
336
289
|
}
|
|
@@ -341,7 +294,7 @@ async function exploreTree(options) {
|
|
|
341
294
|
const lang = detectedLang;
|
|
342
295
|
let ast;
|
|
343
296
|
try {
|
|
344
|
-
ast =
|
|
297
|
+
ast = parse(lang, source);
|
|
345
298
|
} catch (parseErr) {
|
|
346
299
|
const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
|
|
347
300
|
throw new TreeParseError(filePath, lang, msg);
|
|
@@ -393,9 +346,9 @@ var TreeParseError = class extends Error {
|
|
|
393
346
|
};
|
|
394
347
|
|
|
395
348
|
// src/tools/replace.ts
|
|
396
|
-
import {
|
|
397
|
-
import {
|
|
398
|
-
import {
|
|
349
|
+
import { findInFiles as findInFiles2 } from "@ast-grep/napi";
|
|
350
|
+
import { resolve as resolve3, relative as relative3 } from "path";
|
|
351
|
+
import { stat as stat3 } from "fs/promises";
|
|
399
352
|
var MULTI_META_RE2 = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
|
|
400
353
|
var SINGLE_META_RE2 = /(?<!\$)\$(?:\$\$)?([A-Z_][A-Z0-9_]*)/g;
|
|
401
354
|
async function replacePreview(options) {
|
|
@@ -418,18 +371,28 @@ async function replacePreview(options) {
|
|
|
418
371
|
} else {
|
|
419
372
|
lang = resolveLang("typescript");
|
|
420
373
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
374
|
+
const searchPath = resolve3(cwd, options.path ?? ".");
|
|
375
|
+
try {
|
|
376
|
+
await stat3(searchPath);
|
|
377
|
+
} catch {
|
|
378
|
+
throw new ReplaceLangError(
|
|
379
|
+
`Path nao encontrado: ${searchPath}`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
424
382
|
const metaVars = extractMetaVarInfo2(options.pattern);
|
|
383
|
+
const napiConfig = {
|
|
384
|
+
rule: { pattern: options.pattern }
|
|
385
|
+
};
|
|
386
|
+
const findConfig = {
|
|
387
|
+
paths: [searchPath],
|
|
388
|
+
matcher: napiConfig,
|
|
389
|
+
languageGlobs: langToGlobs2(lang)
|
|
390
|
+
};
|
|
425
391
|
const changes = [];
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
const root = ast.root();
|
|
431
|
-
const foundNodes = root.findAll(options.pattern);
|
|
432
|
-
for (const node of foundNodes) {
|
|
392
|
+
try {
|
|
393
|
+
const fileResults = await findInFilesWrapper2(lang, findConfig);
|
|
394
|
+
for (const { file, nodes } of fileResults) {
|
|
395
|
+
for (const node of nodes) {
|
|
433
396
|
const metaVarValues = {};
|
|
434
397
|
for (const { name, isMulti } of metaVars) {
|
|
435
398
|
if (isMulti) {
|
|
@@ -453,16 +416,16 @@ async function replacePreview(options) {
|
|
|
453
416
|
}
|
|
454
417
|
const range = node.range();
|
|
455
418
|
changes.push({
|
|
456
|
-
file: relative3(cwd,
|
|
419
|
+
file: relative3(cwd, file).replace(/\\/g, "/"),
|
|
457
420
|
line: range.start.line,
|
|
458
421
|
column: range.start.column,
|
|
459
422
|
original: node.text(),
|
|
460
423
|
replacement: interpolated
|
|
461
424
|
});
|
|
462
425
|
}
|
|
463
|
-
} catch {
|
|
464
|
-
continue;
|
|
465
426
|
}
|
|
427
|
+
} catch {
|
|
428
|
+
throw new ReplacePatternError(options.pattern, lang);
|
|
466
429
|
}
|
|
467
430
|
const uniqueFiles = new Set(changes.map((c) => c.file));
|
|
468
431
|
return {
|
|
@@ -471,7 +434,7 @@ async function replacePreview(options) {
|
|
|
471
434
|
rewrite: options.rewrite,
|
|
472
435
|
lang,
|
|
473
436
|
changes,
|
|
474
|
-
filesScanned:
|
|
437
|
+
filesScanned: changes.length > 0 ? uniqueFiles.size : 0,
|
|
475
438
|
filesAffected: uniqueFiles.size
|
|
476
439
|
},
|
|
477
440
|
warnings
|
|
@@ -499,55 +462,56 @@ function extractMetaVarInfo2(pattern) {
|
|
|
499
462
|
}
|
|
500
463
|
return result;
|
|
501
464
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
465
|
+
var IGNORED_DIR_PATTERNS2 = [
|
|
466
|
+
/[/\\]node_modules[/\\]/,
|
|
467
|
+
/[/\\]dist[/\\]/,
|
|
468
|
+
/[/\\]build[/\\]/,
|
|
469
|
+
/[/\\]\.git[/\\]/,
|
|
470
|
+
/[/\\]\.next[/\\]/,
|
|
471
|
+
/[/\\]\.turbo[/\\]/,
|
|
472
|
+
/[/\\]coverage[/\\]/,
|
|
473
|
+
/[/\\]out[/\\]/
|
|
474
|
+
];
|
|
475
|
+
function isIgnoredPath2(filePath) {
|
|
476
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
477
|
+
const wrapped = `/${normalized}/`;
|
|
478
|
+
return IGNORED_DIR_PATTERNS2.some((re) => re.test(wrapped));
|
|
512
479
|
}
|
|
513
|
-
async function
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
const entries = await readdir2(dir, { withFileTypes: true });
|
|
527
|
-
for (const entry of entries) {
|
|
528
|
-
const fullPath = join2(dir, entry.name);
|
|
529
|
-
if (entry.isDirectory()) {
|
|
530
|
-
if (IGNORED_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
await walk(fullPath);
|
|
534
|
-
} else if (entry.isFile()) {
|
|
535
|
-
if (shouldIgnoreFile(fullPath)) continue;
|
|
536
|
-
if (!isSupportedExtension(fullPath)) continue;
|
|
537
|
-
paths.push(fullPath);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
} catch {
|
|
480
|
+
async function findInFilesWrapper2(lang, config) {
|
|
481
|
+
const results = [];
|
|
482
|
+
let callbacksReceived = 0;
|
|
483
|
+
const totalFiles = await findInFiles2(
|
|
484
|
+
lang,
|
|
485
|
+
config,
|
|
486
|
+
(err, nodes) => {
|
|
487
|
+
callbacksReceived++;
|
|
488
|
+
if (err || nodes.length === 0) return;
|
|
489
|
+
const file = nodes[0].getRoot()?.filename() ?? "unknown";
|
|
490
|
+
if (isIgnoredPath2(file)) return;
|
|
491
|
+
results.push({ file, nodes });
|
|
541
492
|
}
|
|
493
|
+
);
|
|
494
|
+
while (callbacksReceived < totalFiles) {
|
|
495
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
542
496
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
497
|
+
return results;
|
|
498
|
+
}
|
|
499
|
+
function langToGlobs2(lang) {
|
|
500
|
+
const langStr = String(lang);
|
|
501
|
+
switch (langStr) {
|
|
502
|
+
case "TypeScript":
|
|
503
|
+
return ["*.ts"];
|
|
504
|
+
case "JavaScript":
|
|
505
|
+
return ["*.js", "*.jsx", "*.mjs", "*.cjs"];
|
|
506
|
+
case "Tsx":
|
|
507
|
+
return ["*.tsx"];
|
|
508
|
+
case "Css":
|
|
509
|
+
return ["*.css", "*.scss", "*.less"];
|
|
510
|
+
case "Html":
|
|
511
|
+
return ["*.html", "*.htm"];
|
|
512
|
+
default:
|
|
513
|
+
return [];
|
|
549
514
|
}
|
|
550
|
-
return { paths, warnings };
|
|
551
515
|
}
|
|
552
516
|
var ReplacePatternError = class extends Error {
|
|
553
517
|
pattern;
|
|
@@ -1052,10 +1016,18 @@ metavariaveis ($VAR, $$VAR, $$$VARS) como curingas que capturam partes dinamicas
|
|
|
1052
1016
|
\u{1F4E6} LINGUAGENS SUPORTADAS (apenas 5):
|
|
1053
1017
|
\u2022 typescript (.ts) \u2014 apenas .ts puro (sem JSX)
|
|
1054
1018
|
\u2022 javascript (.js, .jsx, .mjs, .cjs)
|
|
1055
|
-
\u2022 tsx (.tsx) \u2014 .tsx COM JSX/React
|
|
1019
|
+
\u2022 tsx (.tsx) \u2014 .tsx COM JSX/React
|
|
1056
1020
|
\u2022 css (.css, .scss, .less)
|
|
1057
1021
|
\u2022 html (.html, .htm)
|
|
1058
1022
|
|
|
1023
|
+
\u{1F916} AUTODETECCAO: Se o parametro 'lang' NAO for especificado, o motor
|
|
1024
|
+
detecta a linguagem automaticamente pela extensao de cada arquivo.
|
|
1025
|
+
Voce pode buscar em um diretorio com .ts e .tsx misturados \u2014 o motor
|
|
1026
|
+
usa o parser correto para cada arquivo.
|
|
1027
|
+
|
|
1028
|
+
Use 'lang' apenas quando quiser RESTRINGIR a busca a uma linguagem
|
|
1029
|
+
especifica (ex: forcar TSX em todo o diretorio).
|
|
1030
|
+
|
|
1059
1031
|
\u26A0\uFE0F LIMITACAO IMPORTANTE: Apenas busca SINTAXICA. Nao resolve imports, nao
|
|
1060
1032
|
entende tipos, nao segue referencias entre arquivos, nao faz analise de fluxo.
|
|
1061
1033
|
Cada arquivo e analisado isoladamente. Para analise semantica, use ai-tool.
|
|
@@ -1109,7 +1081,7 @@ Workflow recomendado: supergrep_find \u2192 supergrep_tree \u2192 supergrep_repl
|
|
|
1109
1081
|
"Padrao AST Grep na linguagem alvo. Ex: 'console.$METHOD($$$ARGS)', 'function $NAME($$$PARAMS) { $$$BODY }'"
|
|
1110
1082
|
),
|
|
1111
1083
|
lang: z.string().optional().describe(
|
|
1112
|
-
"Linguagem: 'typescript' (.ts), 'javascript' (.js), 'tsx' (.tsx), 'css' (.css), 'html' (.html).
|
|
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."
|
|
1113
1085
|
),
|
|
1114
1086
|
path: z.string().optional().describe(
|
|
1115
1087
|
"Arquivo ou diretorio onde buscar. Default: diretorio atual. Ex: 'src/', 'app/page.tsx'"
|
|
@@ -1168,6 +1140,10 @@ Cada estrutura de codigo vira um kind diferente na AST.
|
|
|
1168
1140
|
\u{1F4A1} Como usar os kinds: ao ver call_expression no tree, voce pode buscar
|
|
1169
1141
|
chamadas de funcao com o pattern: $FUNC($$$ARGS)
|
|
1170
1142
|
|
|
1143
|
+
\u{1F916} AUTODETECCAO: se usar 'path', a linguagem e detectada automaticamente
|
|
1144
|
+
pela extensao do arquivo. O parametro 'lang' so e necessario ao usar
|
|
1145
|
+
'code' (snippet inline) ou para forcar uma linguagem especifica.
|
|
1146
|
+
|
|
1171
1147
|
QUANDO USAR:
|
|
1172
1148
|
- "Quais tipos de nos existem neste arquivo TypeScript?"
|
|
1173
1149
|
- "Como escrever um pattern para capturar certas estruturas?"
|
|
@@ -1244,6 +1220,10 @@ apos a substituicao. Util para planejar refatoracoes em larga escala.
|
|
|
1244
1220
|
O supergrep faz interpolacao manual: textos dos nos sao concatenados
|
|
1245
1221
|
com ", " e injetados no lugar do $VAR no rewrite.
|
|
1246
1222
|
|
|
1223
|
+
\u{1F916} AUTODETECCAO DE LINGUAGEM: se 'lang' nao for especificado, o motor
|
|
1224
|
+
detecta automaticamente pela extensao de cada arquivo. Use 'lang' apenas
|
|
1225
|
+
para RESTRINGIR a busca a uma linguagem especifica.
|
|
1226
|
+
|
|
1247
1227
|
QUANDO USAR:
|
|
1248
1228
|
- "Como ficaria se eu trocasse console.log por logger.info?"
|
|
1249
1229
|
- "Preview de substituir var por let em todo o projeto"
|
|
@@ -1264,7 +1244,7 @@ Workflow: supergrep_find \u2192 supergrep_replace (preview) \u2192 aplicar mudan
|
|
|
1264
1244
|
"Texto de substituicao. Use $VAR para referenciar metavariaveis capturadas. Ex: 'logger.info($$$ARGS)'"
|
|
1265
1245
|
),
|
|
1266
1246
|
lang: z.string().optional().describe(
|
|
1267
|
-
"Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'.
|
|
1247
|
+
"Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'. Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo."
|
|
1268
1248
|
),
|
|
1269
1249
|
path: z.string().optional().describe(
|
|
1270
1250
|
"Arquivo ou diretorio onde buscar. Default: diretorio atual."
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
startMcpServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5PJJZ4CK.js";
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
|
-
|
|
6
|
+
import { createRequire } from "module";
|
|
7
|
+
var require2 = createRequire(import.meta.url);
|
|
8
|
+
var pkg = require2("../package.json");
|
|
9
|
+
var VERSION = pkg.version;
|
|
7
10
|
export {
|
|
8
11
|
VERSION,
|
|
9
12
|
startMcpServer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justmpm/supergrep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|