sigmap 6.10.9 → 6.10.11
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/AGENTS.md +89 -129
- package/CHANGELOG.md +29 -0
- package/README.md +15 -14
- package/gen-context.js +409 -85
- package/package.json +3 -3
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/discovery/r-manifest.js +176 -0
- package/src/extractors/deps.js +30 -1
- package/src/extractors/r.js +182 -45
- package/src/graph/builder.js +133 -24
- package/src/graph/impact.js +6 -1
- package/src/mcp/handlers.js +60 -93
- package/src/mcp/server.js +1 -1
- package/src/retrieval/ranker.js +80 -6
package/gen-context.js
CHANGED
|
@@ -2761,7 +2761,27 @@ __factories["./src/extractors/deps"] = function(module, exports) {
|
|
|
2761
2761
|
return reverse;
|
|
2762
2762
|
}
|
|
2763
2763
|
|
|
2764
|
-
|
|
2764
|
+
const R_BASE_PKGS = new Set([
|
|
2765
|
+
'base', 'stats', 'utils', 'graphics', 'grDevices', 'methods', 'datasets',
|
|
2766
|
+
'parallel', 'splines', 'stats4', 'tools', 'tcltk', 'grid', 'compiler',
|
|
2767
|
+
]);
|
|
2768
|
+
|
|
2769
|
+
function extractRDeps(src) {
|
|
2770
|
+
const deps = new Set();
|
|
2771
|
+
const stripped = (src || '').replace(/#.*$/gm, '');
|
|
2772
|
+
for (const m of stripped.matchAll(/\b(?:library|require)\s*\(\s*["']?([\w.]+)["']?\s*\)/g)) {
|
|
2773
|
+
if (m[1] && !R_BASE_PKGS.has(m[1])) deps.add(m[1]);
|
|
2774
|
+
}
|
|
2775
|
+
for (const m of stripped.matchAll(/\brequireNamespace\s*\(\s*["']([\w.]+)["']/g)) {
|
|
2776
|
+
if (m[1] && !R_BASE_PKGS.has(m[1])) deps.add(m[1]);
|
|
2777
|
+
}
|
|
2778
|
+
for (const m of stripped.matchAll(/\b([A-Za-z][\w.]*)::[A-Za-z]/g)) {
|
|
2779
|
+
if (m[1] && !R_BASE_PKGS.has(m[1])) deps.add(m[1]);
|
|
2780
|
+
}
|
|
2781
|
+
return [...deps].slice(0, 5);
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
module.exports = { extractPythonDeps, extractTSDeps, extractRDeps, buildReverseDepMap };
|
|
2765
2785
|
|
|
2766
2786
|
};
|
|
2767
2787
|
|
|
@@ -3063,67 +3083,169 @@ __factories["./src/extractors/r"] = function(module, exports) {
|
|
|
3063
3083
|
|
|
3064
3084
|
'use strict';
|
|
3065
3085
|
|
|
3066
|
-
/**
|
|
3067
|
-
* Extract signatures from R source code.
|
|
3068
|
-
* @param {string} src - Raw file content
|
|
3069
|
-
* @returns {string[]} Array of signature strings
|
|
3070
|
-
*/
|
|
3071
3086
|
function extract(src) {
|
|
3072
3087
|
if (!src || typeof src !== 'string') return [];
|
|
3073
3088
|
const sigs = [];
|
|
3074
|
-
|
|
3075
|
-
// Strip line comments. R uses # comments. Roxygen2 (#') comments are
|
|
3076
|
-
// stripped along with regular ones; Phase 2 may parse them.
|
|
3089
|
+
const docHints = collectRoxygenHints(src);
|
|
3077
3090
|
const stripped = src.replace(/#.*$/gm, '');
|
|
3091
|
+
const consumedRanges = [];
|
|
3078
3092
|
|
|
3079
|
-
|
|
3080
|
-
// name <- function(args) { ... }
|
|
3081
|
-
// name = function(args) { ... }
|
|
3082
|
-
// name <<- function(args) { ... }
|
|
3083
|
-
// Args may span multiple lines and contain default values, so we need to
|
|
3084
|
-
// match a balanced parenthesis group rather than a single line.
|
|
3085
|
-
const funcRe = /^(?:[ \t]*)([\w.]+)\s*(?:<<-|<-|=)\s*function\s*\(/gm;
|
|
3093
|
+
const r6Re = /([\w.]+)\s*(?:<<-|<-|=)\s*(?:R6::)?R6Class\s*\(/g;
|
|
3086
3094
|
let m;
|
|
3087
|
-
while ((m =
|
|
3095
|
+
while ((m = r6Re.exec(stripped)) !== null && sigs.length < 30) {
|
|
3096
|
+
const name = m[1];
|
|
3097
|
+
if (name.startsWith('.')) continue;
|
|
3098
|
+
const openIdx = r6Re.lastIndex - 1;
|
|
3099
|
+
const body = readBalancedParens(stripped, openIdx);
|
|
3100
|
+
if (body === null) continue;
|
|
3101
|
+
const closeIdx = openIdx + body.length + 1;
|
|
3102
|
+
const classNameLit = readFirstStringArg(body) || name;
|
|
3103
|
+
sigs.push(`${name} <- R6Class("${classNameLit}")` + applyHint(docHints, name));
|
|
3104
|
+
for (const memberSig of extractListMethods(body, 8)) {
|
|
3105
|
+
sigs.push(' ' + memberSig);
|
|
3106
|
+
if (sigs.length >= 30) break;
|
|
3107
|
+
}
|
|
3108
|
+
consumedRanges.push([m.index, closeIdx]);
|
|
3109
|
+
r6Re.lastIndex = closeIdx;
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
const s7Classes = new Set();
|
|
3113
|
+
const s7Re = /([\w.]+)\s*(?:<<-|<-|=)\s*(?:S7::)?new_class\s*\(/g;
|
|
3114
|
+
while ((m = s7Re.exec(stripped)) !== null && sigs.length < 30) {
|
|
3088
3115
|
const name = m[1];
|
|
3089
|
-
if (name.startsWith('.')) continue;
|
|
3090
|
-
const
|
|
3091
|
-
const
|
|
3116
|
+
if (name.startsWith('.')) continue;
|
|
3117
|
+
const openIdx = s7Re.lastIndex - 1;
|
|
3118
|
+
const body = readBalancedParens(stripped, openIdx);
|
|
3119
|
+
if (body === null) continue;
|
|
3120
|
+
const closeIdx = openIdx + body.length + 1;
|
|
3121
|
+
const classNameLit = readFirstStringArg(body) || name;
|
|
3122
|
+
s7Classes.add(classNameLit);
|
|
3123
|
+
s7Classes.add(name);
|
|
3124
|
+
sigs.push(`${name} <- new_class("${classNameLit}")` + applyHint(docHints, name));
|
|
3125
|
+
consumedRanges.push([m.index, closeIdx]);
|
|
3126
|
+
s7Re.lastIndex = closeIdx;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
const s7MethodRe = /^[ \t]*method\s*\(\s*([\w.]+)\s*,\s*([\w.]+)\s*\)\s*(?:<<-|<-|=)\s*function\s*\(/gm;
|
|
3130
|
+
while ((m = s7MethodRe.exec(stripped)) !== null && sigs.length < 30) {
|
|
3131
|
+
if (!s7Classes.has(m[2])) continue;
|
|
3132
|
+
const argsStart = s7MethodRe.lastIndex - 1;
|
|
3133
|
+
const args = readBalancedParens(stripped, argsStart);
|
|
3092
3134
|
if (args === null) continue;
|
|
3093
|
-
sigs.push(
|
|
3135
|
+
sigs.push(` method(${m[1]}, ${m[2]}) <- function(${normalizeParams(args)})`);
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
const funcRe = /^(?:[ \t]*)([\w.]+)\s*(?:<<-|<-|=)\s*function\s*\(/gm;
|
|
3139
|
+
while ((m = funcRe.exec(stripped)) !== null && sigs.length < 30) {
|
|
3140
|
+
const name = m[1];
|
|
3141
|
+
if (name.startsWith('.')) continue;
|
|
3142
|
+
if (inAnyRange(m.index, consumedRanges)) continue;
|
|
3143
|
+
const argsStart = funcRe.lastIndex - 1;
|
|
3144
|
+
const args = readBalancedParens(stripped, argsStart);
|
|
3145
|
+
if (args === null) continue;
|
|
3146
|
+
sigs.push(`${name} <- function(${normalizeParams(args)})` + applyHint(docHints, name));
|
|
3094
3147
|
}
|
|
3095
3148
|
|
|
3096
|
-
// S4 setMethod / setGeneric:
|
|
3097
|
-
// setGeneric("name", function(args) standardGeneric("name"))
|
|
3098
|
-
// setMethod("name", "ClassName", function(args) { ... })
|
|
3099
3149
|
for (const sm of stripped.matchAll(/^[ \t]*setGeneric\s*\(\s*["']([\w.]+)["']/gm)) {
|
|
3150
|
+
if (sigs.length >= 30) break;
|
|
3100
3151
|
sigs.push(`setGeneric("${sm[1]}")`);
|
|
3101
3152
|
}
|
|
3102
3153
|
for (const sm of stripped.matchAll(/^[ \t]*setMethod\s*\(\s*["']([\w.]+)["']\s*,\s*["']([\w.]+)["']/gm)) {
|
|
3154
|
+
if (sigs.length >= 30) break;
|
|
3103
3155
|
sigs.push(`setMethod("${sm[1]}", "${sm[2]}")`);
|
|
3104
3156
|
}
|
|
3105
|
-
|
|
3106
|
-
// S4 class definitions:
|
|
3107
|
-
// setClass("Name", representation(...), ...)
|
|
3108
3157
|
for (const sm of stripped.matchAll(/^[ \t]*setClass\s*\(\s*["']([\w.]+)["']/gm)) {
|
|
3158
|
+
if (sigs.length >= 30) break;
|
|
3109
3159
|
sigs.push(`setClass("${sm[1]}")`);
|
|
3110
3160
|
}
|
|
3111
3161
|
|
|
3112
3162
|
return sigs.slice(0, 30);
|
|
3113
3163
|
}
|
|
3114
3164
|
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3165
|
+
function collectRoxygenHints(src) {
|
|
3166
|
+
const hints = new Map();
|
|
3167
|
+
const lines = src.split('\n');
|
|
3168
|
+
let block = [];
|
|
3169
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3170
|
+
const line = lines[i];
|
|
3171
|
+
if (/^\s*#'/.test(line)) {
|
|
3172
|
+
block.push(line.replace(/^\s*#'\s?/, ''));
|
|
3173
|
+
continue;
|
|
3174
|
+
}
|
|
3175
|
+
if (block.length > 0) {
|
|
3176
|
+
const mm = line.match(/^[ \t]*([\w.]+)\s*(?:<<-|<-|=)\s*(?:R6::)?R6Class\b/)
|
|
3177
|
+
|| line.match(/^[ \t]*([\w.]+)\s*(?:<<-|<-|=)\s*(?:S7::)?new_class\b/)
|
|
3178
|
+
|| line.match(/^[ \t]*([\w.]+)\s*(?:<<-|<-|=)\s*function\b/);
|
|
3179
|
+
if (mm) {
|
|
3180
|
+
const name = mm[1];
|
|
3181
|
+
let hint = pickRoxygenLine(block, '@title')
|
|
3182
|
+
|| pickRoxygenLine(block, '@description')
|
|
3183
|
+
|| pickRoxygenLine(block, null);
|
|
3184
|
+
if (hint) {
|
|
3185
|
+
hint = hint.replace(/\s+/g, ' ').trim().slice(0, 60).replace(/[.,;:!?]+$/, '').trim();
|
|
3186
|
+
if (hint) hints.set(name, hint);
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
block = [];
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
return hints;
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
function pickRoxygenLine(block, tag) {
|
|
3196
|
+
for (const raw of block) {
|
|
3197
|
+
const b = raw.trim();
|
|
3198
|
+
if (!b) continue;
|
|
3199
|
+
if (tag) {
|
|
3200
|
+
if (b.startsWith(tag)) {
|
|
3201
|
+
const rest = b.slice(tag.length).trim();
|
|
3202
|
+
if (rest) return rest;
|
|
3203
|
+
}
|
|
3204
|
+
} else if (!b.startsWith('@')) {
|
|
3205
|
+
return b;
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
return null;
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3211
|
+
function applyHint(hints, name) {
|
|
3212
|
+
const h = hints.get(name);
|
|
3213
|
+
return h ? ` # ${h}` : '';
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
function extractListMethods(body, cap) {
|
|
3217
|
+
const out = [];
|
|
3218
|
+
const re = /(?:^|[\n,])\s*([\w.]+)\s*=\s*function\s*\(/g;
|
|
3219
|
+
let m;
|
|
3220
|
+
while ((m = re.exec(body)) !== null && out.length < cap) {
|
|
3221
|
+
const name = m[1];
|
|
3222
|
+
if (name.startsWith('.')) continue;
|
|
3223
|
+
const argsStart = re.lastIndex - 1;
|
|
3224
|
+
const args = readBalancedParens(body, argsStart);
|
|
3225
|
+
if (args === null) continue;
|
|
3226
|
+
out.push(`${name} <- function(${normalizeParams(args)})`);
|
|
3227
|
+
}
|
|
3228
|
+
return out;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
function inAnyRange(pos, ranges) {
|
|
3232
|
+
for (const [s, e] of ranges) {
|
|
3233
|
+
if (pos >= s && pos < e) return true;
|
|
3234
|
+
}
|
|
3235
|
+
return false;
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
function readFirstStringArg(body) {
|
|
3239
|
+
const m = body.match(/^\s*["']([\w.]+)["']/);
|
|
3240
|
+
return m ? m[1] : null;
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
function readBalancedParens(src, openIdx, cap = 16384) {
|
|
3122
3244
|
if (src[openIdx] !== '(') return null;
|
|
3123
3245
|
let depth = 1;
|
|
3124
3246
|
let i = openIdx + 1;
|
|
3125
3247
|
const end = Math.min(src.length, openIdx + cap);
|
|
3126
|
-
let inString = null;
|
|
3248
|
+
let inString = null;
|
|
3127
3249
|
while (i < end) {
|
|
3128
3250
|
const ch = src[i];
|
|
3129
3251
|
if (inString) {
|
|
@@ -3143,38 +3265,14 @@ __factories["./src/extractors/r"] = function(module, exports) {
|
|
|
3143
3265
|
return null;
|
|
3144
3266
|
}
|
|
3145
3267
|
|
|
3146
|
-
/**
|
|
3147
|
-
* Compress whitespace inside a parameter list, collapse multi-line default
|
|
3148
|
-
* expressions onto a single line, and trim. The goal is one-line readable
|
|
3149
|
-
* signatures, not a faithful AST.
|
|
3150
|
-
*
|
|
3151
|
-
* String literals are protected so that commas/equals inside default values
|
|
3152
|
-
* like sep = "," don't get respaced.
|
|
3153
|
-
*/
|
|
3154
3268
|
function normalizeParams(raw) {
|
|
3155
|
-
|
|
3156
|
-
let buf = '';
|
|
3269
|
+
let out = '';
|
|
3157
3270
|
let inString = null;
|
|
3158
3271
|
for (let i = 0; i < raw.length; i++) {
|
|
3159
3272
|
const ch = raw[i];
|
|
3160
|
-
if (inString) {
|
|
3161
|
-
buf += ch;
|
|
3162
|
-
if (ch === '\\' && i + 1 < raw.length) { buf += raw[i + 1]; i++; continue; }
|
|
3163
|
-
if (ch === inString) inString = null;
|
|
3164
|
-
continue;
|
|
3165
|
-
}
|
|
3166
|
-
if (ch === '"' || ch === "'") { inString = ch; buf += ch; continue; }
|
|
3167
|
-
buf += ch;
|
|
3168
|
-
}
|
|
3169
|
-
// Now buf === raw with strings preserved character-for-character.
|
|
3170
|
-
// Walk again: collapse non-string runs of whitespace, normalize ', ' and ' = '.
|
|
3171
|
-
let out = '';
|
|
3172
|
-
inString = null;
|
|
3173
|
-
for (let i = 0; i < buf.length; i++) {
|
|
3174
|
-
const ch = buf[i];
|
|
3175
3273
|
if (inString) {
|
|
3176
3274
|
out += ch;
|
|
3177
|
-
if (ch === '\\' && i + 1 <
|
|
3275
|
+
if (ch === '\\' && i + 1 < raw.length) { out += raw[i + 1]; i++; continue; }
|
|
3178
3276
|
if (ch === inString) inString = null;
|
|
3179
3277
|
continue;
|
|
3180
3278
|
}
|
|
@@ -4916,13 +5014,33 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
4916
5014
|
const RS_EXTS = new Set(['.rs']);
|
|
4917
5015
|
const JVM_EXTS = new Set(['.java', '.kt', '.kts', '.scala', '.sc']);
|
|
4918
5016
|
const RB_EXTS = new Set(['.rb', '.rake']);
|
|
5017
|
+
const R_EXTS = new Set(['.r', '.R']);
|
|
4919
5018
|
function resolveJsPath(dir, importStr, fileSet) {
|
|
4920
5019
|
const base = path.resolve(dir, importStr);
|
|
4921
5020
|
const candidates = [base, base+'.ts', base+'.tsx', base+'.js', base+'.jsx', base+'.mjs', base+'.cjs', path.join(base,'index.ts'), path.join(base,'index.js')];
|
|
4922
5021
|
for (const c of candidates) { if (fileSet.has(c)) return c; }
|
|
4923
5022
|
return null;
|
|
4924
5023
|
}
|
|
4925
|
-
function
|
|
5024
|
+
function normalizePath(p) {
|
|
5025
|
+
return path.normalize(p).toLowerCase();
|
|
5026
|
+
}
|
|
5027
|
+
function resolveRPath(dir, importStr, fileSet, cwd) {
|
|
5028
|
+
const tried = new Set();
|
|
5029
|
+
const bases = [path.resolve(dir, importStr)];
|
|
5030
|
+
if (cwd) bases.push(path.resolve(cwd, importStr));
|
|
5031
|
+
for (const base of bases) {
|
|
5032
|
+
for (const c of [base, base + '.R', base + '.r']) {
|
|
5033
|
+
const normC = normalizePath(c);
|
|
5034
|
+
if (tried.has(normC)) continue;
|
|
5035
|
+
tried.add(normC);
|
|
5036
|
+
if (fileSet.has(c)) return c;
|
|
5037
|
+
if (fileSet.has(normC)) return normC;
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
return null;
|
|
5041
|
+
}
|
|
5042
|
+
function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
|
|
5043
|
+
function extractFileDeps(filePath, content, fileSet, cwd, ctx) {
|
|
4926
5044
|
const ext = path.extname(filePath).toLowerCase();
|
|
4927
5045
|
const dir = path.dirname(filePath);
|
|
4928
5046
|
const found = [];
|
|
@@ -4941,7 +5059,13 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
4941
5059
|
const modPart = m[1].slice(dotCount).replace(/\./g,'/');
|
|
4942
5060
|
let base = dir; for (let i=1;i<dotCount;i++) base=path.dirname(base);
|
|
4943
5061
|
const candidate = modPart ? path.join(base,modPart+'.py') : null;
|
|
4944
|
-
if (candidate
|
|
5062
|
+
if (candidate) { const normC = normalizePath(candidate); if (fileSet.has(normC)) found.push(normC); }
|
|
5063
|
+
}
|
|
5064
|
+
const reAbs = /^[ \t]*from\s+([\w.]+)\s+import/gm;
|
|
5065
|
+
while ((m = reAbs.exec(content)) !== null) {
|
|
5066
|
+
const modulePath = m[1].replace(/\./g,'/');
|
|
5067
|
+
const candidates = [path.join(dir,modulePath+'.py'),path.join(dir,modulePath,'__init__.py'),path.resolve(dir,'..',modulePath+'.py'),path.resolve(dir,'..',modulePath,'__init__.py')];
|
|
5068
|
+
for (const c of candidates) { const normC = normalizePath(c); if (fileSet.has(normC)) { found.push(normC); break; } }
|
|
4945
5069
|
}
|
|
4946
5070
|
}
|
|
4947
5071
|
if (GO_EXTS.has(ext)) {
|
|
@@ -4952,14 +5076,14 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
4952
5076
|
while ((m = reInline.exec(content)) !== null) imports.push(m[1]);
|
|
4953
5077
|
for (const imp of imports) {
|
|
4954
5078
|
const suffix = imp.split('/').pop();
|
|
4955
|
-
for (const f of fileSet) { if (
|
|
5079
|
+
for (const f of fileSet) { const normF = normalizePath(f); if (normF.endsWith(path.sep+suffix+'.go')||normF.includes(path.sep+suffix+path.sep)) { found.push(normF); break; } }
|
|
4956
5080
|
}
|
|
4957
5081
|
}
|
|
4958
5082
|
if (RS_EXTS.has(ext)) {
|
|
4959
5083
|
const reMod = /^\s*(?:pub\s+)?mod\s+(\w+)\s*;/gm; let m;
|
|
4960
5084
|
while ((m = reMod.exec(content)) !== null) {
|
|
4961
|
-
const c1 = path.join(dir,m[1]+'.rs'); if (fileSet.has(
|
|
4962
|
-
const c2 = path.join(dir,m[1],'mod.rs'); if (fileSet.has(
|
|
5085
|
+
const c1 = path.join(dir,m[1]+'.rs'); const normC1 = normalizePath(c1); if (fileSet.has(normC1)) found.push(normC1);
|
|
5086
|
+
const c2 = path.join(dir,m[1],'mod.rs'); const normC2 = normalizePath(c2); if (fileSet.has(normC2)) found.push(normC2);
|
|
4963
5087
|
}
|
|
4964
5088
|
}
|
|
4965
5089
|
if (JVM_EXTS.has(ext)) {
|
|
@@ -4967,7 +5091,7 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
4967
5091
|
while ((m = re.exec(content)) !== null) {
|
|
4968
5092
|
const asPath = m[1].replace(/\./g,path.sep);
|
|
4969
5093
|
for (const jvmExt of ['.java','.kt','.kts','.scala','.sc']) {
|
|
4970
|
-
for (const f of fileSet) { if (
|
|
5094
|
+
for (const f of fileSet) { const normF = normalizePath(f); if (normF.endsWith(normalizePath(asPath+jvmExt))) { found.push(normF); break; } }
|
|
4971
5095
|
}
|
|
4972
5096
|
}
|
|
4973
5097
|
}
|
|
@@ -4976,27 +5100,90 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
4976
5100
|
while ((m = re.exec(content)) !== null) {
|
|
4977
5101
|
const base = path.resolve(dir,m[1]);
|
|
4978
5102
|
const candidate = base.endsWith('.rb') ? base : base+'.rb';
|
|
4979
|
-
|
|
5103
|
+
const normC = normalizePath(candidate);
|
|
5104
|
+
if (fileSet.has(normC)) found.push(normC);
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
if (R_EXTS.has(ext)) {
|
|
5108
|
+
const stripped = content.replace(/#.*$/gm, '');
|
|
5109
|
+
const reSrc = /(?:^|[^\w.])source\s*\(\s*["']([^"']+)["']/g; let m;
|
|
5110
|
+
while ((m = reSrc.exec(stripped)) !== null) {
|
|
5111
|
+
const r = resolveRPath(dir, m[1], fileSet, cwd); if (r) found.push(r);
|
|
5112
|
+
}
|
|
5113
|
+
if (ctx && ctx.rPackage && ctx.rLocalDefs && ctx.rLocalDefs.size > 0) {
|
|
5114
|
+
const reNs = new RegExp('\\b' + escapeRegex(ctx.rPackage) + ':::?([A-Za-z][\\w.]*)', 'g');
|
|
5115
|
+
while ((m = reNs.exec(stripped)) !== null) {
|
|
5116
|
+
const target = ctx.rLocalDefs.get(m[1]);
|
|
5117
|
+
if (!target) continue;
|
|
5118
|
+
const normTarget = normalizePath(target);
|
|
5119
|
+
const normFilePath = normalizePath(filePath);
|
|
5120
|
+
if (normTarget === normFilePath) continue;
|
|
5121
|
+
if (fileSet.has(target)) {
|
|
5122
|
+
found.push(target);
|
|
5123
|
+
} else if (fileSet.has(normTarget)) {
|
|
5124
|
+
found.push(normTarget);
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
4980
5127
|
}
|
|
4981
5128
|
}
|
|
4982
5129
|
return [...new Set(found)];
|
|
4983
5130
|
}
|
|
4984
|
-
function build(files, cwd) {
|
|
5131
|
+
function build(files, cwd, ctx) {
|
|
4985
5132
|
const fileSet = new Set(files.map((f) => path.resolve(f)));
|
|
4986
|
-
const
|
|
4987
|
-
|
|
5133
|
+
const fileSetNormalized = new Set([...fileSet].map(normalizePath));
|
|
5134
|
+
const forward = new Map();
|
|
5135
|
+
const reverse = new Map();
|
|
5136
|
+
for (const f of fileSet) {
|
|
5137
|
+
const normF = normalizePath(f);
|
|
5138
|
+
if (!forward.has(normF)) forward.set(normF, []);
|
|
5139
|
+
if (!reverse.has(normF)) reverse.set(normF, []);
|
|
5140
|
+
}
|
|
4988
5141
|
for (const filePath of fileSet) {
|
|
4989
|
-
let content;
|
|
4990
|
-
|
|
5142
|
+
let content;
|
|
5143
|
+
try { content = fs.readFileSync(filePath,'utf8'); } catch(_) { continue; }
|
|
5144
|
+
const normFilePath = normalizePath(filePath);
|
|
5145
|
+
const deps = extractFileDeps(filePath, content, fileSetNormalized, cwd, ctx);
|
|
4991
5146
|
if (deps.length > 0) {
|
|
4992
|
-
forward.set(
|
|
4993
|
-
for (const dep of deps) {
|
|
5147
|
+
forward.set(normFilePath, deps);
|
|
5148
|
+
for (const dep of deps) {
|
|
5149
|
+
if (!reverse.has(dep)) reverse.set(dep, []);
|
|
5150
|
+
reverse.get(dep).push(normFilePath);
|
|
5151
|
+
}
|
|
4994
5152
|
}
|
|
4995
5153
|
}
|
|
4996
5154
|
return { forward, reverse };
|
|
4997
5155
|
}
|
|
5156
|
+
function _readDescriptionPackage(cwd) {
|
|
5157
|
+
try {
|
|
5158
|
+
const raw = fs.readFileSync(path.join(cwd, 'DESCRIPTION'), 'utf8');
|
|
5159
|
+
const m = raw.match(/^Package\s*:\s*(\S+)/m);
|
|
5160
|
+
return m ? m[1] : null;
|
|
5161
|
+
} catch (_) { return null; }
|
|
5162
|
+
}
|
|
5163
|
+
function _collectRLocalDefs(rFiles) {
|
|
5164
|
+
const defs = new Map();
|
|
5165
|
+
const reAssign = /^(?:[ \t]*)([\w.]+)\s*(?:<<-|<-|=)\s*(?:(?:R6::)?R6Class|(?:S7::)?new_class|function)\b/gm;
|
|
5166
|
+
const reS4Generic = /^[ \t]*setGeneric\s*\(\s*["']([\w.]+)["']/gm;
|
|
5167
|
+
const reS4Class = /^[ \t]*setClass\s*\(\s*["']([\w.]+)["']/gm;
|
|
5168
|
+
for (const filePath of rFiles) {
|
|
5169
|
+
let content; try { content = fs.readFileSync(filePath, 'utf8'); } catch (_) { continue; }
|
|
5170
|
+
const stripped = content.replace(/#.*$/gm, '');
|
|
5171
|
+
let m;
|
|
5172
|
+
while ((m = reAssign.exec(stripped)) !== null) {
|
|
5173
|
+
if (m[1].startsWith('.')) continue;
|
|
5174
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
5175
|
+
}
|
|
5176
|
+
while ((m = reS4Generic.exec(stripped)) !== null) {
|
|
5177
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
5178
|
+
}
|
|
5179
|
+
while ((m = reS4Class.exec(stripped)) !== null) {
|
|
5180
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
return defs;
|
|
5184
|
+
}
|
|
4998
5185
|
function buildFromCwd(cwd, opts) {
|
|
4999
|
-
const { srcDirs=['src','app','lib'], exclude=['node_modules','.git','dist','build'] } = opts||{};
|
|
5186
|
+
const { srcDirs=['src','app','lib','R','inst'], exclude=['node_modules','.git','dist','build'] } = opts||{};
|
|
5000
5187
|
const excludeSet = new Set(exclude);
|
|
5001
5188
|
function walkDir(dir,depth) {
|
|
5002
5189
|
if (depth>8) return [];
|
|
@@ -5008,19 +5195,25 @@ __factories["./src/graph/builder"] = function(module, exports) {
|
|
|
5008
5195
|
if (e.isDirectory()) out.push(...walkDir(full,depth+1));
|
|
5009
5196
|
else if (e.isFile()) {
|
|
5010
5197
|
const ext = path.extname(e.name).toLowerCase();
|
|
5011
|
-
if (JS_EXTS.has(ext)||PY_EXTS.has(ext)||GO_EXTS.has(ext)||RS_EXTS.has(ext)||JVM_EXTS.has(ext)||RB_EXTS.has(ext)) out.push(full);
|
|
5198
|
+
if (JS_EXTS.has(ext)||PY_EXTS.has(ext)||GO_EXTS.has(ext)||RS_EXTS.has(ext)||JVM_EXTS.has(ext)||RB_EXTS.has(ext)||R_EXTS.has(ext)) out.push(full);
|
|
5012
5199
|
}
|
|
5013
5200
|
}
|
|
5014
5201
|
return out;
|
|
5015
5202
|
}
|
|
5016
5203
|
const files=[];
|
|
5017
5204
|
for (const sd of srcDirs) { const absDir=path.resolve(cwd,sd); if (fs.existsSync(absDir)) files.push(...walkDir(absDir,0)); }
|
|
5018
|
-
for (const rootFile of ['gen-context.js','index.js','main.js','app.js']) {
|
|
5205
|
+
for (const rootFile of ['gen-context.js','index.js','main.js','app.js','app.R','server.R','ui.R','global.R']) {
|
|
5019
5206
|
const abs=path.resolve(cwd,rootFile); if (fs.existsSync(abs)) files.push(abs);
|
|
5020
5207
|
}
|
|
5021
|
-
|
|
5208
|
+
let ctx;
|
|
5209
|
+
const rPackage = _readDescriptionPackage(cwd);
|
|
5210
|
+
if (rPackage) {
|
|
5211
|
+
const rFiles = files.filter((f) => R_EXTS.has(path.extname(f).toLowerCase()));
|
|
5212
|
+
if (rFiles.length > 0) ctx = { rPackage, rLocalDefs: _collectRLocalDefs(rFiles) };
|
|
5213
|
+
}
|
|
5214
|
+
return build(files, cwd, ctx);
|
|
5022
5215
|
}
|
|
5023
|
-
module.exports = { build, buildFromCwd, extractFileDeps };
|
|
5216
|
+
module.exports = { build, buildFromCwd, extractFileDeps, normalizePath };
|
|
5024
5217
|
};
|
|
5025
5218
|
|
|
5026
5219
|
// ── ./src/graph/impact ──
|
|
@@ -5032,6 +5225,7 @@ __factories["./src/graph/impact"] = function(module, exports) {
|
|
|
5032
5225
|
const ROUTE_PATTERNS = [/router?\.[jt]sx?$/i,/routes?\.[jt]sx?$/i,/controller\.[jt]sx?$/i,/views?\.[jt]sx?$/i,/handlers?\.[jt]sx?$/i];
|
|
5033
5226
|
function isTestFile(f) { return TEST_PATTERNS.some((re) => re.test(f.replace(/\\/g,'/'))); }
|
|
5034
5227
|
function isRouteFile(f) { return ROUTE_PATTERNS.some((re) => re.test(f.replace(/\\/g,'/'))); }
|
|
5228
|
+
function normalizePath(p) { return path.normalize(p).toLowerCase(); }
|
|
5035
5229
|
function bfs(startFile, reverseGraph, maxDepth) {
|
|
5036
5230
|
const direct=new Set(); const transitive=new Set(); const visited=new Set([startFile]);
|
|
5037
5231
|
const firstLevel = reverseGraph.get(startFile)||[];
|
|
@@ -5050,7 +5244,7 @@ __factories["./src/graph/impact"] = function(module, exports) {
|
|
|
5050
5244
|
}
|
|
5051
5245
|
function getImpact(changedFile, graph, opts) {
|
|
5052
5246
|
const {depth=0,cwd=process.cwd()} = opts||{};
|
|
5053
|
-
const absChanged = path.resolve(cwd,changedFile);
|
|
5247
|
+
const absChanged = normalizePath(path.resolve(cwd,changedFile));
|
|
5054
5248
|
if (!graph||!graph.reverse) return {changed:changedFile,direct:[],transitive:[],tests:[],routes:[],totalImpact:0};
|
|
5055
5249
|
const {direct,transitive} = bfs(absChanged,graph.reverse,depth);
|
|
5056
5250
|
const allImpacted=[...direct,...transitive];
|
|
@@ -5707,7 +5901,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
|
|
|
5707
5901
|
|
|
5708
5902
|
const SERVER_INFO = {
|
|
5709
5903
|
name: 'sigmap',
|
|
5710
|
-
version: '6.10.
|
|
5904
|
+
version: '6.10.11',
|
|
5711
5905
|
description: 'SigMap MCP server — code signatures on demand',
|
|
5712
5906
|
};
|
|
5713
5907
|
|
|
@@ -6727,6 +6921,21 @@ __factories["./src/retrieval/ranker"] = function(module, exports) {
|
|
|
6727
6921
|
if (learnedWeights && score > 0) score *= learnedWeights[file] || 1.0;
|
|
6728
6922
|
scored.push({ file, score, sigs, tokens: Math.ceil(sigs.join('\n').length / 4) });
|
|
6729
6923
|
}
|
|
6924
|
+
// Compute confidence levels based on score distribution
|
|
6925
|
+
if (scored.length > 0) {
|
|
6926
|
+
const scores = scored.map(s => s.score);
|
|
6927
|
+
const maxScore = Math.max(...scores);
|
|
6928
|
+
const minScore = Math.min(...scores);
|
|
6929
|
+
const scoreRange = maxScore - minScore || 1;
|
|
6930
|
+
for (const entry of scored) {
|
|
6931
|
+
if (entry.score <= 0) {
|
|
6932
|
+
entry.confidence = 'low';
|
|
6933
|
+
} else {
|
|
6934
|
+
const normalized = (entry.score - minScore) / scoreRange;
|
|
6935
|
+
entry.confidence = normalized > 0.66 ? 'high' : normalized > 0.33 ? 'medium' : 'low';
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6730
6939
|
scored.sort((a, b) => b.score - a.score || a.file.localeCompare(b.file));
|
|
6731
6940
|
return scored.slice(0, topK);
|
|
6732
6941
|
}
|
|
@@ -6894,6 +7103,7 @@ __factories["./src/eval/analyzer"] = function(module, exports) {
|
|
|
6894
7103
|
'.swift': 'swift',
|
|
6895
7104
|
'.dart': 'dart',
|
|
6896
7105
|
'.scala': 'scala', '.sc': 'scala',
|
|
7106
|
+
'.r': 'r', '.R': 'r',
|
|
6897
7107
|
'.vue': 'vue_sfc',
|
|
6898
7108
|
'.svelte': 'svelte',
|
|
6899
7109
|
'.html': 'html', '.htm': 'html',
|
|
@@ -7934,7 +8144,7 @@ __factories["./src/discovery/language-detector"] = function(module, exports) {
|
|
|
7934
8144
|
if (e.isDirectory()) {
|
|
7935
8145
|
_walkDepth(path.join(dir, e.name), depth - 1, extCount);
|
|
7936
8146
|
} else if (e.isFile()) {
|
|
7937
|
-
const EXT_TO_LANG = {'.js': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript', '.ts': 'typescript', '.tsx': 'typescript', '.jsx': 'javascript', '.py': 'python', '.rb': 'ruby', '.go': 'go', '.rs': 'rust', '.java': 'java', '.kt': 'kotlin', '.cs': 'csharp', '.cpp': 'cpp', '.c': 'cpp', '.h': 'cpp', '.hpp': 'cpp', '.swift': 'swift', '.dart': 'dart', '.scala': 'scala', '.php': 'php'};
|
|
8147
|
+
const EXT_TO_LANG = {'.js': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript', '.ts': 'typescript', '.tsx': 'typescript', '.jsx': 'javascript', '.py': 'python', '.rb': 'ruby', '.go': 'go', '.rs': 'rust', '.java': 'java', '.kt': 'kotlin', '.cs': 'csharp', '.cpp': 'cpp', '.c': 'cpp', '.h': 'cpp', '.hpp': 'cpp', '.swift': 'swift', '.dart': 'dart', '.scala': 'scala', '.php': 'php', '.r': 'r', '.R': 'r'};
|
|
7938
8148
|
const ext = path.extname(e.name).toLowerCase();
|
|
7939
8149
|
if (EXT_TO_LANG[ext]) extCount[ext] = (extCount[ext] || 0) + 1;
|
|
7940
8150
|
}
|
|
@@ -8233,6 +8443,117 @@ __factories["./src/discovery/source-root-resolver"] = function(module, exports)
|
|
|
8233
8443
|
module.exports = { resolveSourceRoots };
|
|
8234
8444
|
};
|
|
8235
8445
|
|
|
8446
|
+
// ── ./src/discovery/r-manifest ──
|
|
8447
|
+
__factories["./src/discovery/r-manifest"] = function(module, exports) {
|
|
8448
|
+
'use strict';
|
|
8449
|
+
const fs = require('fs');
|
|
8450
|
+
const path = require('path');
|
|
8451
|
+
module.exports = { readDescription, readNamespace, collectLocalDefs };
|
|
8452
|
+
function readDescription(cwd) {
|
|
8453
|
+
const p = path.join(cwd, 'DESCRIPTION');
|
|
8454
|
+
if (!fs.existsSync(p)) return null;
|
|
8455
|
+
let raw;
|
|
8456
|
+
try { raw = fs.readFileSync(p, 'utf8'); } catch (_) { return null; }
|
|
8457
|
+
const fields = {};
|
|
8458
|
+
let currentKey = null;
|
|
8459
|
+
for (const rawLine of raw.split('\n')) {
|
|
8460
|
+
if (/^\s/.test(rawLine) && currentKey) {
|
|
8461
|
+
fields[currentKey] += ' ' + rawLine.trim();
|
|
8462
|
+
continue;
|
|
8463
|
+
}
|
|
8464
|
+
const m = rawLine.match(/^([A-Za-z][\w.]*)\s*:\s*(.*)$/);
|
|
8465
|
+
if (m) {
|
|
8466
|
+
currentKey = m[1];
|
|
8467
|
+
fields[currentKey] = m[2].trim();
|
|
8468
|
+
} else {
|
|
8469
|
+
currentKey = null;
|
|
8470
|
+
}
|
|
8471
|
+
}
|
|
8472
|
+
return {
|
|
8473
|
+
package: fields.Package || null,
|
|
8474
|
+
version: fields.Version || null,
|
|
8475
|
+
imports: splitDeps(fields.Imports),
|
|
8476
|
+
depends: splitDeps(fields.Depends),
|
|
8477
|
+
suggests: splitDeps(fields.Suggests),
|
|
8478
|
+
linkingTo: splitDeps(fields.LinkingTo),
|
|
8479
|
+
};
|
|
8480
|
+
}
|
|
8481
|
+
function splitDeps(value) {
|
|
8482
|
+
if (!value) return [];
|
|
8483
|
+
return value.split(',')
|
|
8484
|
+
.map((s) => s.trim().replace(/\s*\([^)]*\)\s*$/, '').trim())
|
|
8485
|
+
.filter((s) => s && s !== 'R');
|
|
8486
|
+
}
|
|
8487
|
+
function readNamespace(cwd) {
|
|
8488
|
+
const p = path.join(cwd, 'NAMESPACE');
|
|
8489
|
+
if (!fs.existsSync(p)) return null;
|
|
8490
|
+
let raw;
|
|
8491
|
+
try { raw = fs.readFileSync(p, 'utf8'); } catch (_) { return null; }
|
|
8492
|
+
const text = raw.replace(/#.*$/gm, '');
|
|
8493
|
+
const exports = new Set();
|
|
8494
|
+
const exportPatterns = [];
|
|
8495
|
+
const s3methods = [];
|
|
8496
|
+
const importFrom = new Map();
|
|
8497
|
+
for (const m of text.matchAll(/\bexport\s*\(\s*([^)]+)\)/g)) {
|
|
8498
|
+
for (const name of splitArgs(m[1])) {
|
|
8499
|
+
const clean = stripQuotes(name);
|
|
8500
|
+
if (clean) exports.add(clean);
|
|
8501
|
+
}
|
|
8502
|
+
}
|
|
8503
|
+
for (const m of text.matchAll(/\bexportMethods\s*\(\s*([^)]+)\)/g)) {
|
|
8504
|
+
for (const name of splitArgs(m[1])) {
|
|
8505
|
+
const clean = stripQuotes(name);
|
|
8506
|
+
if (clean) exports.add(clean);
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
for (const m of text.matchAll(/\bexportPattern\s*\(\s*["']([^"']+)["']\s*\)/g)) {
|
|
8510
|
+
try { exportPatterns.push(new RegExp(m[1])); } catch (_) {}
|
|
8511
|
+
}
|
|
8512
|
+
for (const m of text.matchAll(/\bS3method\s*\(\s*([\w.]+)\s*,\s*([\w.]+)\s*\)/g)) {
|
|
8513
|
+
s3methods.push({ generic: m[1], class: m[2] });
|
|
8514
|
+
exports.add(m[1]);
|
|
8515
|
+
}
|
|
8516
|
+
for (const m of text.matchAll(/\bimportFrom\s*\(\s*([\w.]+)\s*,\s*([^)]+)\)/g)) {
|
|
8517
|
+
const pkg = m[1];
|
|
8518
|
+
if (!importFrom.has(pkg)) importFrom.set(pkg, new Set());
|
|
8519
|
+
for (const name of splitArgs(m[2])) {
|
|
8520
|
+
const clean = stripQuotes(name);
|
|
8521
|
+
if (clean) importFrom.get(pkg).add(clean);
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
return { exports, exportPatterns, s3methods, importFrom };
|
|
8525
|
+
}
|
|
8526
|
+
function splitArgs(raw) {
|
|
8527
|
+
return raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
8528
|
+
}
|
|
8529
|
+
function stripQuotes(s) {
|
|
8530
|
+
return s.replace(/^["']|["']$/g, '').trim();
|
|
8531
|
+
}
|
|
8532
|
+
function collectLocalDefs(rFiles) {
|
|
8533
|
+
const defs = new Map();
|
|
8534
|
+
const reAssign = /^(?:[ \t]*)([\w.]+)\s*(?:<<-|<-|=)\s*(?:(?:R6::)?R6Class|(?:S7::)?new_class|function)\b/gm;
|
|
8535
|
+
const reS4Generic = /^[ \t]*setGeneric\s*\(\s*["']([\w.]+)["']/gm;
|
|
8536
|
+
const reS4Class = /^[ \t]*setClass\s*\(\s*["']([\w.]+)["']/gm;
|
|
8537
|
+
for (const filePath of rFiles) {
|
|
8538
|
+
let content;
|
|
8539
|
+
try { content = fs.readFileSync(filePath, 'utf8'); } catch (_) { continue; }
|
|
8540
|
+
const stripped = content.replace(/#.*$/gm, '');
|
|
8541
|
+
let m;
|
|
8542
|
+
while ((m = reAssign.exec(stripped)) !== null) {
|
|
8543
|
+
if (m[1].startsWith('.')) continue;
|
|
8544
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
8545
|
+
}
|
|
8546
|
+
while ((m = reS4Generic.exec(stripped)) !== null) {
|
|
8547
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
8548
|
+
}
|
|
8549
|
+
while ((m = reS4Class.exec(stripped)) !== null) {
|
|
8550
|
+
if (!defs.has(m[1])) defs.set(m[1], filePath);
|
|
8551
|
+
}
|
|
8552
|
+
}
|
|
8553
|
+
return defs;
|
|
8554
|
+
}
|
|
8555
|
+
};
|
|
8556
|
+
|
|
8236
8557
|
// ── ./src/workspace/detector ──
|
|
8237
8558
|
__factories["./src/workspace/detector"] = function(module, exports) {
|
|
8238
8559
|
'use strict';
|
|
@@ -8334,7 +8655,7 @@ const path = require('path');
|
|
|
8334
8655
|
const os = require('os');
|
|
8335
8656
|
const { execSync } = require('child_process');
|
|
8336
8657
|
|
|
8337
|
-
const VERSION = '6.10.
|
|
8658
|
+
const VERSION = '6.10.11';
|
|
8338
8659
|
const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
|
|
8339
8660
|
|
|
8340
8661
|
function requireSourceOrBundled(key) {
|
|
@@ -8370,6 +8691,7 @@ const EXT_MAP = {
|
|
|
8370
8691
|
'.swift': 'swift',
|
|
8371
8692
|
'.dart': 'dart',
|
|
8372
8693
|
'.scala': 'scala', '.sc': 'scala',
|
|
8694
|
+
'.r': 'r', '.R': 'r',
|
|
8373
8695
|
'.vue': 'vue_sfc',
|
|
8374
8696
|
'.svelte': 'svelte',
|
|
8375
8697
|
'.html': 'html', '.htm': 'html',
|
|
@@ -8509,10 +8831,11 @@ function detectAndExtract(filePath, content, maxSigsPerFile) {
|
|
|
8509
8831
|
function extractFileDeps(filePath, content, config) {
|
|
8510
8832
|
if (config && config.depMap === false) return [];
|
|
8511
8833
|
try {
|
|
8512
|
-
const { extractPythonDeps, extractTSDeps } = requireSourceOrBundled('./src/extractors/deps');
|
|
8834
|
+
const { extractPythonDeps, extractTSDeps, extractRDeps } = requireSourceOrBundled('./src/extractors/deps');
|
|
8513
8835
|
const ext = path.extname(filePath).toLowerCase();
|
|
8514
8836
|
if (ext === '.py' || ext === '.pyw') return extractPythonDeps(content);
|
|
8515
8837
|
if (['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(ext)) return extractTSDeps(content);
|
|
8838
|
+
if (ext === '.r') return extractRDeps ? extractRDeps(content) : [];
|
|
8516
8839
|
} catch (_) {}
|
|
8517
8840
|
return [];
|
|
8518
8841
|
}
|
|
@@ -11425,6 +11748,7 @@ function main() {
|
|
|
11425
11748
|
'.java': 'java', '.kt': 'kotlin', '.go': 'go', '.rs': 'rust',
|
|
11426
11749
|
'.cs': 'csharp', '.cpp': 'cpp', '.rb': 'ruby', '.php': 'php',
|
|
11427
11750
|
'.swift': 'swift', '.dart': 'dart', '.scala': 'scala',
|
|
11751
|
+
'.r': 'r', '.R': 'r',
|
|
11428
11752
|
'.vue': 'vue', '.svelte': 'svelte', '.html': 'html',
|
|
11429
11753
|
'.css': 'css', '.yml': 'yaml', '.sh': 'shell',
|
|
11430
11754
|
};
|