ucn 5.2.2 → 5.3.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.
- package/.claude/skills/ucn/SKILL.md +59 -3
- package/.claude/skills/ucn/references/commands.md +3 -1
- package/README.md +158 -533
- package/cli/index.js +71 -10
- package/core/analysis.js +178 -14
- package/core/cache.js +22 -13
- package/core/callers.js +51 -52
- package/core/check.js +2 -2
- package/core/execute.js +24 -6
- package/core/graph.js +167 -35
- package/core/index-ir.js +12 -9
- package/core/output/analysis-ext.js +4 -0
- package/core/output/analysis.js +30 -2
- package/core/output/endpoints.js +1 -1
- package/core/output/graph.js +60 -11
- package/core/output/lines.js +272 -0
- package/core/output/public.js +15 -0
- package/core/output/reporting.js +9 -2
- package/core/output/tracing.js +10 -2
- package/core/output-budget.js +7 -4
- package/core/project.js +15 -2
- package/core/registry.js +7 -6
- package/core/reporting.js +159 -14
- package/languages/javascript.js +213 -6
- package/languages/python.js +167 -39
- package/mcp/server.js +3 -1
- package/package.json +2 -2
- package/assets/demo.svg +0 -31
package/languages/python.js
CHANGED
|
@@ -1317,34 +1317,59 @@ function pythonTargetBindsName(left, name) {
|
|
|
1317
1317
|
return false;
|
|
1318
1318
|
}
|
|
1319
1319
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1320
|
+
// One walk per scope body collects every name it binds at this scope level
|
|
1321
|
+
// (declarations, assignment targets, for/with targets; nested def/class bodies
|
|
1322
|
+
// are separate scopes, lambdas too). Memoized per tree by native node id: the
|
|
1323
|
+
// caller loop asks the same body about many names, and a per-name walk made
|
|
1324
|
+
// the Python build cost functions x tracked names x body size (measured 10s of
|
|
1325
|
+
// a 60s sequential build on a 20MB Python repo).
|
|
1326
|
+
const scopeBoundNamesByTree = new WeakMap();
|
|
1327
|
+
function pythonScopeBoundNames(scopeNode) {
|
|
1328
|
+
let byId = scopeBoundNamesByTree.get(scopeNode.tree);
|
|
1329
|
+
if (!byId) { byId = new Map(); scopeBoundNamesByTree.set(scopeNode.tree, byId); }
|
|
1330
|
+
const cached = byId.get(scopeNode.id);
|
|
1331
|
+
if (cached) return cached;
|
|
1332
|
+
const names = new Set();
|
|
1333
|
+
const addTarget = (left) => {
|
|
1334
|
+
if (!left) return;
|
|
1335
|
+
if (left.type === 'identifier') names.add(left.text);
|
|
1336
|
+
else if (left.type === 'pattern_list' || left.type === 'tuple_pattern') {
|
|
1337
|
+
for (const item of left.namedChildren) {
|
|
1338
|
+
if (item.type === 'identifier') names.add(item.text);
|
|
1339
|
+
}
|
|
1330
1340
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
child.type === '
|
|
1335
|
-
|
|
1336
|
-
child.
|
|
1337
|
-
name)
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1341
|
+
};
|
|
1342
|
+
const walk = (node) => {
|
|
1343
|
+
for (const child of node.namedChildren) {
|
|
1344
|
+
if (child.type === 'function_definition' ||
|
|
1345
|
+
child.type === 'async_function_definition' ||
|
|
1346
|
+
child.type === 'class_definition') {
|
|
1347
|
+
const declared = child.childForFieldName('name')?.text;
|
|
1348
|
+
if (declared) names.add(declared);
|
|
1349
|
+
continue;
|
|
1350
|
+
}
|
|
1351
|
+
if (child.type === 'lambda') continue;
|
|
1352
|
+
if (child.type === 'assignment' ||
|
|
1353
|
+
child.type === 'augmented_assignment' ||
|
|
1354
|
+
child.type === 'named_expression') {
|
|
1355
|
+
addTarget(child.childForFieldName('left') || child.childForFieldName('name'));
|
|
1356
|
+
} else if (child.type === 'for_statement') {
|
|
1357
|
+
addTarget(child.childForFieldName('left'));
|
|
1358
|
+
} else if (child.type === 'with_statement') {
|
|
1359
|
+
const text = child.namedChild(0)?.text || '';
|
|
1360
|
+
const match = text.match(/\bas\s+([A-Za-z_][A-Za-z0-9_]*)/);
|
|
1361
|
+
if (match) names.add(match[1]);
|
|
1362
|
+
}
|
|
1363
|
+
walk(child);
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
walk(scopeNode);
|
|
1367
|
+
byId.set(scopeNode.id, names);
|
|
1368
|
+
return names;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
function pythonScopeBindsName(scopeNode, name) {
|
|
1372
|
+
return pythonScopeBoundNames(scopeNode).has(name);
|
|
1348
1373
|
}
|
|
1349
1374
|
|
|
1350
1375
|
const PY_COMPREHENSIONS = new Set([
|
|
@@ -2936,20 +2961,123 @@ function findImportsInCode(code, parser) {
|
|
|
2936
2961
|
// module initialization. Preserve that AST fact so dependency-cycle
|
|
2937
2962
|
// reporting can distinguish an eager import loop from a deliberate lazy
|
|
2938
2963
|
// edge without deleting either edge from the graph.
|
|
2939
|
-
|
|
2964
|
+
// fix #338: `if TYPE_CHECKING:` (bare, `t.TYPE_CHECKING`,
|
|
2965
|
+
// `typing.TYPE_CHECKING`) consequence blocks never execute at runtime —
|
|
2966
|
+
// the import exists for the type checker only. Only the consequence
|
|
2967
|
+
// branch is guarded: `else:` and `if not TYPE_CHECKING:` bodies DO run.
|
|
2968
|
+
let typingBindings = null;
|
|
2969
|
+
let typingWildcard = false;
|
|
2970
|
+
const isNestedScope = node => {
|
|
2971
|
+
for (let p = node.parent; p; p = p.parent) {
|
|
2972
|
+
if (p.type === 'function_definition' || p.type === 'class_definition' || p.type === 'lambda') return true;
|
|
2973
|
+
}
|
|
2974
|
+
return false;
|
|
2975
|
+
};
|
|
2976
|
+
// Which local names prove a runtime-false guard, and where. A guard at
|
|
2977
|
+
// module level reads the module binding: only module-level rebindings
|
|
2978
|
+
// (assignments, loops, def/class names, walrus, `as` targets) and a
|
|
2979
|
+
// second import of the same name can disturb it — a function parameter
|
|
2980
|
+
// or a nested import lives in its own scope. A guard INSIDE a function
|
|
2981
|
+
// can additionally be shadowed by that function's locals, so nested
|
|
2982
|
+
// rebindings poison nested guards (conservative: any nested scope, not
|
|
2983
|
+
// just the enclosing one). Same-spelled user flags/attributes can be
|
|
2984
|
+
// true; only a unique `typing` binding proves the guard false.
|
|
2985
|
+
const typingBindingKind = (name, guardNested) => {
|
|
2986
|
+
if (!typingBindings) {
|
|
2987
|
+
typingBindings = new Map();
|
|
2988
|
+
const entry = local => {
|
|
2989
|
+
let e = typingBindings.get(local);
|
|
2990
|
+
if (!e) { e = { kind: null, imports: 0, moduleShadow: false, nestedShadow: false }; typingBindings.set(local, e); }
|
|
2991
|
+
return e;
|
|
2992
|
+
};
|
|
2993
|
+
const shadow = (pattern, nested) => {
|
|
2994
|
+
if (!pattern) return;
|
|
2995
|
+
traverseTree(pattern, child => {
|
|
2996
|
+
if (child.type === 'identifier') {
|
|
2997
|
+
const e = entry(child.text);
|
|
2998
|
+
if (nested) e.nestedShadow = true; else e.moduleShadow = true;
|
|
2999
|
+
}
|
|
3000
|
+
return true;
|
|
3001
|
+
});
|
|
3002
|
+
};
|
|
3003
|
+
traverseTree(tree.rootNode, n => {
|
|
3004
|
+
const nested = isNestedScope(n);
|
|
3005
|
+
if (n.type === 'import_statement' || n.type === 'import_from_statement') {
|
|
3006
|
+
if (n.namedChildren.some(item => item.type === 'wildcard_import')) typingWildcard = true;
|
|
3007
|
+
const moduleNode = n.childForFieldName('module_name');
|
|
3008
|
+
for (const item of n.namedChildren) {
|
|
3009
|
+
if (moduleNode && sameNode(moduleNode, item)) continue;
|
|
3010
|
+
const imported = item.type === 'aliased_import' ? item.childForFieldName('name')?.text : item.text;
|
|
3011
|
+
const local = item.type === 'aliased_import' ? item.childForFieldName('alias')?.text : imported?.split('.')[0];
|
|
3012
|
+
if (!local) continue;
|
|
3013
|
+
const e = entry(local);
|
|
3014
|
+
if (nested) { e.nestedShadow = true; continue; }
|
|
3015
|
+
const kind = n.type === 'import_statement'
|
|
3016
|
+
? (imported === 'typing' ? 'module' : null)
|
|
3017
|
+
: (moduleNode?.text === 'typing' && imported === 'TYPE_CHECKING' ? 'flag' : null);
|
|
3018
|
+
e.imports++;
|
|
3019
|
+
e.kind = e.imports === 1 ? kind : null;
|
|
3020
|
+
}
|
|
3021
|
+
} else if (n.type === 'assignment' || n.type === 'augmented_assignment' || n.type === 'for_statement' || n.type === 'for_in_clause') {
|
|
3022
|
+
shadow(n.childForFieldName('left'), nested);
|
|
3023
|
+
} else if (n.type === 'parameters' || n.type === 'lambda_parameters') {
|
|
3024
|
+
// Parameter NAMES rebind; annotations (`x: t.Any`) and
|
|
3025
|
+
// default values are expressions that READ the outer
|
|
3026
|
+
// binding. Walking the whole subtree treated every
|
|
3027
|
+
// `t.`-annotated parameter as a rebinding of `t` and
|
|
3028
|
+
// reverted click's TYPE_CHECKING guards to eager.
|
|
3029
|
+
for (const param of n.namedChildren) {
|
|
3030
|
+
if (param.type === 'default_parameter' || param.type === 'typed_default_parameter') {
|
|
3031
|
+
shadow(param.childForFieldName('name'), true);
|
|
3032
|
+
} else if (param.type === 'typed_parameter') {
|
|
3033
|
+
shadow(param.namedChild(0), true);
|
|
3034
|
+
} else if (param.type !== 'keyword_separator' && param.type !== 'positional_separator') {
|
|
3035
|
+
shadow(param, true);
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
} else if (n.type === 'named_expression') shadow(n.childForFieldName('name'), nested);
|
|
3039
|
+
else if (n.type === 'function_definition' || n.type === 'class_definition') shadow(n.childForFieldName('name'), nested);
|
|
3040
|
+
else if (n.type === 'as_pattern') shadow(n.childForFieldName('alias'), nested);
|
|
3041
|
+
return true;
|
|
3042
|
+
});
|
|
3043
|
+
}
|
|
3044
|
+
if (typingWildcard) return null;
|
|
3045
|
+
const e = typingBindings.get(name);
|
|
3046
|
+
if (!e || e.imports !== 1 || e.moduleShadow) return null;
|
|
3047
|
+
if (guardNested && e.nestedShadow) return null;
|
|
3048
|
+
return e.kind;
|
|
3049
|
+
};
|
|
3050
|
+
const isTypeCheckingGuard = (condition, guardNested = true) => {
|
|
3051
|
+
if (!condition) return false;
|
|
3052
|
+
if (condition.type === 'parenthesized_expression') return isTypeCheckingGuard(condition.namedChild(0), guardNested);
|
|
3053
|
+
if (condition.type === 'identifier') return typingBindingKind(condition.text, guardNested) === 'flag';
|
|
3054
|
+
if (condition.type === 'attribute') {
|
|
3055
|
+
const object = condition.childForFieldName('object');
|
|
3056
|
+
return condition.childForFieldName('attribute')?.text === 'TYPE_CHECKING' &&
|
|
3057
|
+
object?.type === 'identifier' && typingBindingKind(object.text, guardNested) === 'module';
|
|
3058
|
+
}
|
|
3059
|
+
return false;
|
|
3060
|
+
};
|
|
3061
|
+
const importDeferral = (node) => {
|
|
2940
3062
|
for (let parent = node.parent; parent; parent = parent.parent) {
|
|
2941
3063
|
if (parent.type === 'function_definition' || parent.type === 'lambda') {
|
|
2942
|
-
return
|
|
3064
|
+
return 'function-local';
|
|
3065
|
+
}
|
|
3066
|
+
if (parent.type === 'block' && parent.parent &&
|
|
3067
|
+
(parent.parent.type === 'if_statement' || parent.parent.type === 'elif_clause') &&
|
|
3068
|
+
sameNode(parent.parent.childForFieldName('consequence'), parent) &&
|
|
3069
|
+
isTypeCheckingGuard(parent.parent.childForFieldName('condition'), isNestedScope(parent.parent))) {
|
|
3070
|
+
return 'type-checking';
|
|
2943
3071
|
}
|
|
2944
3072
|
}
|
|
2945
|
-
return
|
|
3073
|
+
return null;
|
|
2946
3074
|
};
|
|
2947
3075
|
|
|
2948
3076
|
traverseTreeCached(tree.rootNode, (node) => {
|
|
2949
3077
|
// import statement: import os, import sys as system
|
|
2950
3078
|
if (node.type === 'import_statement') {
|
|
2951
3079
|
const line = node.startPosition.row + 1;
|
|
2952
|
-
const
|
|
3080
|
+
const deferral = importDeferral(node);
|
|
2953
3081
|
|
|
2954
3082
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
2955
3083
|
const child = node.namedChild(i);
|
|
@@ -2966,14 +3094,14 @@ function findImportsInCode(code, parser) {
|
|
|
2966
3094
|
names: [parts[0]],
|
|
2967
3095
|
type: 'import',
|
|
2968
3096
|
line,
|
|
2969
|
-
...(
|
|
3097
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
2970
3098
|
});
|
|
2971
3099
|
imports.push({
|
|
2972
3100
|
module: child.text,
|
|
2973
3101
|
names: [],
|
|
2974
3102
|
type: 'import-submodule',
|
|
2975
3103
|
line,
|
|
2976
|
-
...(
|
|
3104
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
2977
3105
|
});
|
|
2978
3106
|
} else {
|
|
2979
3107
|
imports.push({
|
|
@@ -2981,7 +3109,7 @@ function findImportsInCode(code, parser) {
|
|
|
2981
3109
|
names: [child.text],
|
|
2982
3110
|
type: 'import',
|
|
2983
3111
|
line,
|
|
2984
|
-
...(
|
|
3112
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
2985
3113
|
});
|
|
2986
3114
|
}
|
|
2987
3115
|
} else if (child.type === 'aliased_import') {
|
|
@@ -2994,7 +3122,7 @@ function findImportsInCode(code, parser) {
|
|
|
2994
3122
|
names: [aliasNode ? aliasNode.text : nameNode.text.split('.').pop()],
|
|
2995
3123
|
type: 'import',
|
|
2996
3124
|
line,
|
|
2997
|
-
...(
|
|
3125
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
2998
3126
|
});
|
|
2999
3127
|
if (aliasNode && aliasNode.text !== nameNode.text) {
|
|
3000
3128
|
if (!importAliases) importAliases = [];
|
|
@@ -3009,7 +3137,7 @@ function findImportsInCode(code, parser) {
|
|
|
3009
3137
|
// from ... import statement
|
|
3010
3138
|
if (node.type === 'import_from_statement') {
|
|
3011
3139
|
const line = node.startPosition.row + 1;
|
|
3012
|
-
const
|
|
3140
|
+
const deferral = importDeferral(node);
|
|
3013
3141
|
let modulePath = '';
|
|
3014
3142
|
const names = [];
|
|
3015
3143
|
|
|
@@ -3043,7 +3171,7 @@ function findImportsInCode(code, parser) {
|
|
|
3043
3171
|
names,
|
|
3044
3172
|
type: isRelative ? 'relative' : 'from',
|
|
3045
3173
|
line,
|
|
3046
|
-
...(
|
|
3174
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
3047
3175
|
});
|
|
3048
3176
|
}
|
|
3049
3177
|
return true;
|
|
@@ -3058,7 +3186,7 @@ function findImportsInCode(code, parser) {
|
|
|
3058
3186
|
const firstArg = argsNode.namedChild(0);
|
|
3059
3187
|
if ((funcName === 'importlib.import_module' || funcName === '__import__') && firstArg) {
|
|
3060
3188
|
const line = node.startPosition.row + 1;
|
|
3061
|
-
const
|
|
3189
|
+
const deferral = importDeferral(node);
|
|
3062
3190
|
const isLiteral = firstArg.type === 'string';
|
|
3063
3191
|
imports.push({
|
|
3064
3192
|
module: isLiteral ? firstArg.text.replace(/^['"]|['"]$/g, '') : firstArg.text,
|
|
@@ -3066,7 +3194,7 @@ function findImportsInCode(code, parser) {
|
|
|
3066
3194
|
type: 'dynamic',
|
|
3067
3195
|
line,
|
|
3068
3196
|
dynamic: !isLiteral,
|
|
3069
|
-
...(
|
|
3197
|
+
...(deferral && { deferred: true, deferredReason: deferral })
|
|
3070
3198
|
});
|
|
3071
3199
|
}
|
|
3072
3200
|
}
|
package/mcp/server.js
CHANGED
|
@@ -271,7 +271,7 @@ const INPUT_SHAPE = {
|
|
|
271
271
|
include_exported: booleanParam('Include exported symbols in deadcode results'),
|
|
272
272
|
include_decorated: booleanParam('Include decorated/annotated symbols in deadcode results'),
|
|
273
273
|
calls_only: booleanParam('tests: retain direct calls and test-case matches only.'),
|
|
274
|
-
max_lines: integerParam('source: maximum lines
|
|
274
|
+
max_lines: integerParam('source: maximum lines per declaration; raw mode discloses any truncation.', { exclusiveMinimum: 0, maximum: 1000000 }),
|
|
275
275
|
direction: stringParam('trace: callees/callers. deps: imports/importers/both.', { enum: ['callees', 'callers', 'imports', 'importers', 'both'] }),
|
|
276
276
|
to: stringParam('trace with direction=callers: continue toward entry points.', { enum: ['entrypoints'] }),
|
|
277
277
|
cycles: booleanParam('deps: report circular imports instead of a file graph.'),
|
|
@@ -280,6 +280,8 @@ const INPUT_SHAPE = {
|
|
|
280
280
|
functions: booleanParam('repo stats: include per-function line counts sorted by size.'),
|
|
281
281
|
hot: booleanParam('repo stats: include the top N most-called functions.'),
|
|
282
282
|
diverse: booleanParam('show example: return representatives from distinct argument shapes.'),
|
|
283
|
+
lines: booleanParam('find/usages/search/show/impact: path:line:text listings without default row caps; explicit top/limit still apply. show accepts callers/callees sections, default callers. Tier tags follow a tab; accounting and notes follow as "# " lines. MCP transport budgets still apply and preserve accounting.'),
|
|
284
|
+
raw: booleanParam('source: code text without a header or line-number gutter, including full large classes. Notes follow as "# " lines; MCP transport budgets still apply.'),
|
|
283
285
|
git: booleanParam('show summary: attach last-modified, author, and recent-change metadata.'),
|
|
284
286
|
add_param: stringParam('Parameter name to add (plan command)'),
|
|
285
287
|
remove_param: stringParam('Parameter name to remove (plan command)'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ucn",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.1",
|
|
4
4
|
"mcpName": "io.github.mleoca/ucn",
|
|
5
5
|
"description": "Auditable AST code intelligence for AI agents: 18 task-oriented commands through one MCP tool, CLI, or agent skill. Supports JS/TS, Python, Go, Rust, Java, C, C++, C#, and HTML.",
|
|
6
6
|
"main": "index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"version": "node scripts/sync-server-version.js && git add server.json",
|
|
13
|
-
"test": "node --test test/parser-unit.test.js test/integration.test.js test/cache.test.js test/formatter.test.js test/interactive.test.js test/feature.test.js test/regression-js.test.js test/regression-py.test.js test/regression-go.test.js test/regression-java.test.js test/regression-rust.test.js test/regression-c-family.test.js test/regression-cross.test.js test/regression-mcp.test.js test/mcp-protocol.test.js test/mcp-sdk-compat.test.js test/dependency-security.test.js test/regression-parser.test.js test/regression-commands.test.js test/regression-fixes.test.js test/regression-bugfixes.test.js test/release-surface-regressions.test.js test/prerelease-audit.test.js test/release-readiness-audit.test.js test/cross-language.test.js test/accuracy.test.js test/command-coverage.test.js test/perf-optimizations.test.js test/performance-gate-policy.test.js test/oracle-gate-policy.test.js test/outcome-policy.test.js test/consistency-eval.test.js test/agent-public-surface-benchmark.test.js test/command-contracts.test.js test/language-adapter.test.js test/systematic-test.js test/mcp-edge-cases.js test/conservation.test.js test/parity-test.js test/trust-matrix.test.js",
|
|
13
|
+
"test": "node --test test/shell-output.test.js test/parser-unit.test.js test/integration.test.js test/cache.test.js test/formatter.test.js test/interactive.test.js test/feature.test.js test/regression-js.test.js test/regression-py.test.js test/regression-go.test.js test/regression-java.test.js test/regression-rust.test.js test/regression-c-family.test.js test/regression-cross.test.js test/regression-mcp.test.js test/mcp-protocol.test.js test/mcp-sdk-compat.test.js test/dependency-security.test.js test/regression-parser.test.js test/regression-commands.test.js test/regression-fixes.test.js test/regression-bugfixes.test.js test/release-surface-regressions.test.js test/prerelease-audit.test.js test/release-readiness-audit.test.js test/cross-language.test.js test/accuracy.test.js test/command-coverage.test.js test/perf-optimizations.test.js test/performance-gate-policy.test.js test/oracle-gate-policy.test.js test/outcome-policy.test.js test/consistency-eval.test.js test/agent-public-surface-benchmark.test.js test/command-contracts.test.js test/language-adapter.test.js test/systematic-test.js test/mcp-edge-cases.js test/conservation.test.js test/parity-test.js test/trust-matrix.test.js",
|
|
14
14
|
"benchmark:agent": "node test/agent-public-surface-benchmark.js",
|
|
15
15
|
"benchmark:agent:gate": "node test/agent-public-surface-benchmark.js --gate",
|
|
16
16
|
"benchmark:agent:legacy": "node test/agent-understanding-benchmark.js",
|
package/assets/demo.svg
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 453" font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace" font-size="12">
|
|
2
|
-
<!-- Terminal window -->
|
|
3
|
-
<rect x="0.5" y="0.5" width="999" height="452" rx="10" fill="#0d1117" stroke="#30363d"/>
|
|
4
|
-
<!-- Title bar -->
|
|
5
|
-
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h979 a10 10 0 0 1 10 10 v23 h-999 z" fill="#161b22"/>
|
|
6
|
-
<line x1="0.5" y1="34" x2="999.5" y2="34" stroke="#30363d"/>
|
|
7
|
-
<circle cx="20" cy="17" r="6" fill="#ff5f57"/>
|
|
8
|
-
<circle cx="40" cy="17" r="6" fill="#febc2e"/>
|
|
9
|
-
<circle cx="60" cy="17" r="6" fill="#28c840"/>
|
|
10
|
-
<text x="500" y="21" text-anchor="middle" fill="#8b949e" font-size="11.5">ucn - ripgrep @ 82313cf9 (pinned oracle commit) - output abridged</text>
|
|
11
|
-
<!-- Session -->
|
|
12
|
-
<g fill="#c9d1d9">
|
|
13
|
-
<text x="24" y="62"><tspan fill="#8b949e">$ </tspan><tspan fill="#7ee787">ucn show Searcher.search_reader --sections=summary,callers --compact</tspan></text>
|
|
14
|
-
<text x="24" y="100">SUMMARY</text>
|
|
15
|
-
<text x="24" y="119">───────</text>
|
|
16
|
-
<text x="24" y="138">pub search_reader<M, R, S>(&mut self, matcher: M, read_from: R, write_to: S): Result<(), S::Error></text>
|
|
17
|
-
<text x="39" y="157">crates/searcher/src/searcher/mod.rs:727-765 (39 lines)</text>
|
|
18
|
-
<text x="39" y="176">handle: crates/searcher/src/searcher/mod.rs:727:search_reader</text>
|
|
19
|
-
<text x="39" y="195">"Execute a search over any implementation of `std::io::Read` and write"</text>
|
|
20
|
-
<text x="24" y="233">CALLERS — CONFIRMED (123):</text>
|
|
21
|
-
<text x="39" y="252">evidence: 2 exact-binding, 121 receiver-hint</text>
|
|
22
|
-
<text x="39" y="271">[1] crates/core/search.rs:426 [search_reader]: searcher.search_reader(&matcher, &mut rdr, &mut sink)?;</text>
|
|
23
|
-
<text x="39" y="290">[4] crates/printer/src/json.rs:940 [binary_detection]: .search_reader(&matcher, BINARY, printer.sink(&matcher))</text>
|
|
24
|
-
<text x="39" y="309">[11] crates/printer/src/standard.rs:1788 [reports_match]: .search_reader(&matcher, SHERLOCK.as_bytes(), &mut sink)</text>
|
|
25
|
-
<text x="69" y="328" fill="#8b949e">… 120 more callers</text>
|
|
26
|
-
<text x="24" y="366">ACCOUNT: "search_reader" occurs on 136 lines in 8 files: 123 confirmed, 1 unverified,</text>
|
|
27
|
-
<text x="39" y="385">6 non-call, 6 other-target, 0 unaccounted</text>
|
|
28
|
-
<text x="24" y="404">CONTRACT: literal-name text partition complete; semantic completeness is not claimed.</text>
|
|
29
|
-
<text x="24" y="433"><tspan fill="#8b949e">$ </tspan><tspan fill="#c9d1d9">▍</tspan></text>
|
|
30
|
-
</g>
|
|
31
|
-
</svg>
|