@nocturnium/svelte-ide 1.0.5 → 1.0.6
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.
|
@@ -83,9 +83,11 @@
|
|
|
83
83
|
* Get the color based on score level
|
|
84
84
|
*/
|
|
85
85
|
function getColor(score: number): string {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return '
|
|
86
|
+
// Bands match the analyzer's levels: critical >= 85, high >= 70,
|
|
87
|
+
// medium otherwise (lines below the minScore threshold aren't shown).
|
|
88
|
+
if (score >= 85) return 'var(--ide-error)'; // Critical
|
|
89
|
+
if (score >= 70) return 'var(--ide-warning)'; // High
|
|
90
|
+
return 'var(--ide-info)'; // Medium
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
/**
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import CommandPalette from './CommandPalette.svelte';
|
|
27
27
|
import { getComplexityAnalyzer, type ComplexityMetrics } from './core/complexity-analyzer';
|
|
28
28
|
import { registerSemanticFoldCommands } from './core/commands';
|
|
29
|
-
import { getSemanticAnalyzer } from './core/semantic-analyzer';
|
|
29
|
+
import { getSemanticAnalyzer, type FoldPreset } from './core/semantic-analyzer';
|
|
30
30
|
import type { AIAwareness } from './core/ai-awareness';
|
|
31
31
|
import {
|
|
32
32
|
CURSOR_BLINK_MS,
|
|
@@ -501,6 +501,38 @@
|
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Collapse every semantic region whose category is listed in `preset.hide`,
|
|
506
|
+
* after first expanding everything so presets compose predictably. Shared by
|
|
507
|
+
* the command-palette preset commands and the exported imperative API.
|
|
508
|
+
*/
|
|
509
|
+
function applyFoldPresetInternal(preset: FoldPreset) {
|
|
510
|
+
if (!folding || !editorState) return;
|
|
511
|
+
foldManager.expandAll();
|
|
512
|
+
const analyzer = getSemanticAnalyzer();
|
|
513
|
+
const regions = analyzer.analyze(editorState.lines, language);
|
|
514
|
+
for (const category of preset.hide) {
|
|
515
|
+
for (const region of analyzer.getByCategory(regions, category)) {
|
|
516
|
+
foldManager.collapse(region.startLine);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Imperative API (accessible via `bind:this`): apply a semantic fold preset.
|
|
523
|
+
*/
|
|
524
|
+
export function applyFoldPreset(preset: FoldPreset) {
|
|
525
|
+
applyFoldPresetInternal(preset);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Imperative API (accessible via `bind:this`): expand all folded regions.
|
|
530
|
+
*/
|
|
531
|
+
export function unfoldAll() {
|
|
532
|
+
if (!folding || !editorState) return;
|
|
533
|
+
foldManager.expandAll();
|
|
534
|
+
}
|
|
535
|
+
|
|
504
536
|
function handleFoldIndicatorClick(lineNumber: number, e: MouseEvent) {
|
|
505
537
|
e.preventDefault();
|
|
506
538
|
e.stopPropagation();
|
|
@@ -787,17 +819,7 @@
|
|
|
787
819
|
foldManager?.expandAll();
|
|
788
820
|
},
|
|
789
821
|
onApplyPreset: (preset) => {
|
|
790
|
-
|
|
791
|
-
foldManager?.expandAll();
|
|
792
|
-
// Then collapse categories that should be hidden
|
|
793
|
-
const analyzer = getSemanticAnalyzer();
|
|
794
|
-
const regions = analyzer.analyze(editorState.lines, language);
|
|
795
|
-
for (const category of preset.hide) {
|
|
796
|
-
const categoryRegions = analyzer.getByCategory(regions, category);
|
|
797
|
-
for (const region of categoryRegions) {
|
|
798
|
-
foldManager?.collapse(region.startLine);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
822
|
+
applyFoldPresetInternal(preset);
|
|
801
823
|
},
|
|
802
824
|
getLanguage: () => language
|
|
803
825
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EditorPreferences } from '../../types';
|
|
2
2
|
import { type Cursor } from './core';
|
|
3
3
|
import { type ComplexityMetrics } from './core/complexity-analyzer';
|
|
4
|
+
import { type FoldPreset } from './core/semantic-analyzer';
|
|
4
5
|
import type { AIAwareness } from './core/ai-awareness';
|
|
5
6
|
interface Props {
|
|
6
7
|
content: string;
|
|
@@ -32,6 +33,9 @@ interface Props {
|
|
|
32
33
|
onComplexityChange?: (metrics: ComplexityMetrics | null) => void;
|
|
33
34
|
onSave?: () => void;
|
|
34
35
|
}
|
|
35
|
-
declare const CustomEditor: import("svelte").Component<Props, {
|
|
36
|
+
declare const CustomEditor: import("svelte").Component<Props, {
|
|
37
|
+
applyFoldPreset: (preset: FoldPreset) => void;
|
|
38
|
+
unfoldAll: () => void;
|
|
39
|
+
}, "content">;
|
|
36
40
|
type CustomEditor = ReturnType<typeof CustomEditor>;
|
|
37
41
|
export default CustomEditor;
|
|
@@ -19,7 +19,11 @@ const THRESHOLDS = {
|
|
|
19
19
|
* Weights for different complexity factors
|
|
20
20
|
*/
|
|
21
21
|
const WEIGHTS = {
|
|
22
|
-
|
|
22
|
+
// Nesting is the dominant cognitive-load factor, but 15/level over-rated
|
|
23
|
+
// shallow code: a function with two nested `if`s landed at ~71 ("High").
|
|
24
|
+
// 12/level keeps deeply-nested code critical while letting genuinely medium
|
|
25
|
+
// code read as medium.
|
|
26
|
+
nestingDepth: 12,
|
|
23
27
|
branchingFactor: 8,
|
|
24
28
|
lineCount: 0.3,
|
|
25
29
|
identifierCount: 0.2,
|
|
@@ -77,12 +81,15 @@ export class ComplexityAnalyzer {
|
|
|
77
81
|
* Get complexity for a specific line
|
|
78
82
|
*/
|
|
79
83
|
getLineComplexity(metrics, line) {
|
|
84
|
+
// A line can sit inside several nested regions; report the highest score
|
|
85
|
+
// so an inner low-complexity region never masks the hot function around it.
|
|
86
|
+
let best = 0;
|
|
80
87
|
for (const region of metrics.regions) {
|
|
81
|
-
if (line >= region.startLine && line <= region.endLine) {
|
|
82
|
-
|
|
88
|
+
if (line >= region.startLine && line <= region.endLine && region.score > best) {
|
|
89
|
+
best = region.score;
|
|
83
90
|
}
|
|
84
91
|
}
|
|
85
|
-
return
|
|
92
|
+
return best;
|
|
86
93
|
}
|
|
87
94
|
/**
|
|
88
95
|
* Check if a line is a hotspot
|
|
@@ -234,6 +241,20 @@ export class ComplexityAnalyzer {
|
|
|
234
241
|
*/
|
|
235
242
|
getDefinitionCandidate(text, funcMatch, allowMethodStyle) {
|
|
236
243
|
if (funcMatch) {
|
|
244
|
+
// The arrow-assignment branch (`name = (`) also matches a parenthesised
|
|
245
|
+
// expression like `const x = (a - b) / c`, which is NOT a function.
|
|
246
|
+
// Only treat it as one when the line actually starts an arrow: it
|
|
247
|
+
// contains `=>`, or it has an unclosed `(` that opens a multi-line arrow
|
|
248
|
+
// signature. Otherwise the stale candidate gets attached to the next
|
|
249
|
+
// `if (...) {` block and a phantom region is reported.
|
|
250
|
+
const isArrowAssignment = !!funcMatch[3] && !funcMatch[2] && !funcMatch[4] && !funcMatch[5];
|
|
251
|
+
if (isArrowAssignment) {
|
|
252
|
+
const opens = (text.match(/\(/g) || []).length;
|
|
253
|
+
const closes = (text.match(/\)/g) || []).length;
|
|
254
|
+
if (!text.includes('=>') && opens <= closes) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
237
258
|
return {
|
|
238
259
|
type: funcMatch[5] ? 'class' : 'function',
|
|
239
260
|
name: funcMatch[2] || funcMatch[3] || funcMatch[4] || funcMatch[5]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocturnium/svelte-ide",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Svelte 5 code editor and IDE building blocks — custom editor, syntax highlighting, code folding, multi-cursor, LSP client, and optional realtime collaboration.",
|
|
5
5
|
"author": "Nocturnium & Jordan Dziat <hello@nocturnium.ai> (https://nocturnium.ai)",
|
|
6
6
|
"license": "MIT",
|