Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
One-time setup that gathers your project's design context and saves it to CLAUDE.md for future sessions.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/detector/profile/profiler.mjs
1function profileNow() {2return typeof performance !== 'undefined' && performance.now3? performance.now()4: Date.now();5}67function createDetectorProfile() {8return { events: [] };9}1011function recordProfileEvent(profile, event) {12if (!profile) return;13const normalized = {14engine: event.engine || 'unknown',15phase: event.phase || 'unknown',16ruleId: event.ruleId || 'unknown',17target: event.target || '',18ms: Number.isFinite(event.ms) ? event.ms : 0,19findings: Number.isFinite(event.findings) ? event.findings : 0,20};21if (event.detail) normalized.detail = event.detail;22if (Array.isArray(event.findingIds) && event.findingIds.length) {23normalized.findingIds = event.findingIds;24}25if (typeof profile === 'function') {26profile(normalized);27} else if (typeof profile.record === 'function') {28profile.record(normalized);29} else if (Array.isArray(profile.events)) {30profile.events.push(normalized);31} else if (Array.isArray(profile)) {32profile.push(normalized);33}34}3536function extractFindingIds(findings) {37if (!Array.isArray(findings) || findings.length === 0) return [];38return [...new Set(findings.map(f => f?.id || f?.type || f?.antipattern).filter(Boolean))];39}4041function profileFindings(profile, meta, callback) {42if (!profile) return callback();43const started = profileNow();44const findings = callback();45recordProfileEvent(profile, {46...meta,47ms: profileNow() - started,48findings: Array.isArray(findings) ? findings.length : 0,49findingIds: extractFindingIds(findings),50});51return findings;52}5354function profileStep(profile, meta, callback) {55if (!profile) return callback();56const started = profileNow();57try {58return callback();59} finally {60recordProfileEvent(profile, {61...meta,62ms: profileNow() - started,63findings: 0,64});65}66}6768async function profileFindingsAsync(profile, meta, callback) {69if (!profile) return callback();70const started = profileNow();71const findings = await callback();72recordProfileEvent(profile, {73...meta,74ms: profileNow() - started,75findings: Array.isArray(findings) ? findings.length : 0,76findingIds: extractFindingIds(findings),77});78return findings;79}8081async function profileStepAsync(profile, meta, callback) {82if (!profile) return callback();83const started = profileNow();84try {85return await callback();86} finally {87recordProfileEvent(profile, {88...meta,89ms: profileNow() - started,90findings: 0,91});92}93}9495function percentile(sortedValues, pct) {96if (!sortedValues.length) return 0;97const idx = Math.min(98sortedValues.length - 1,99Math.max(0, Math.ceil((pct / 100) * sortedValues.length) - 1),100);101return sortedValues[idx];102}103104function summarizeDetectorProfile(profile) {105const events = Array.isArray(profile)106? profile107: (Array.isArray(profile?.events) ? profile.events : []);108const groups = new Map();109for (const event of events) {110const key = [111event.engine || 'unknown',112event.phase || 'unknown',113event.ruleId || 'unknown',114event.target || '',115].join('\u0000');116let group = groups.get(key);117if (!group) {118group = {119engine: event.engine || 'unknown',120phase: event.phase || 'unknown',121ruleId: event.ruleId || 'unknown',122target: event.target || '',123calls: 0,124totalMs: 0,125findings: 0,126samples: [],127};128groups.set(key, group);129}130const ms = Number.isFinite(event.ms) ? event.ms : 0;131group.calls += 1;132group.totalMs += ms;133group.findings += Number.isFinite(event.findings) ? event.findings : 0;134group.samples.push(ms);135}136return [...groups.values()]137.map(group => {138const samples = group.samples.sort((a, b) => a - b);139return {140engine: group.engine,141phase: group.phase,142ruleId: group.ruleId,143target: group.target,144calls: group.calls,145totalMs: Number(group.totalMs.toFixed(3)),146avgMs: Number((group.totalMs / group.calls).toFixed(3)),147p50: Number(percentile(samples, 50).toFixed(3)),148p95: Number(percentile(samples, 95).toFixed(3)),149findings: group.findings,150};151})152.sort((a, b) => b.totalMs - a.totalMs);153}154155export {156profileNow,157createDetectorProfile,158recordProfileEvent,159extractFindingIds,160profileFindings,161profileStep,162profileFindingsAsync,163profileStepAsync,164percentile,165summarizeDetectorProfile,166};167