@codecanvas-ide/engine 0.0.0-stage → 0.1.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.
@@ -0,0 +1,19 @@
1
+ import type { Block, Point } from './types.js';
2
+ /** Blocks laid out together: a block, or blocks side by side (row) or one above the other (column). */
3
+ export type Arrangement = {
4
+ block: string;
5
+ } | {
6
+ row: Arrangement[];
7
+ } | {
8
+ column: Arrangement[];
9
+ };
10
+ interface Size {
11
+ w: number;
12
+ h: number;
13
+ }
14
+ /**
15
+ * Positions for sibling blocks that were never laid out, following the rules in layoutRules.ts.
16
+ * Positions are relative to the group's origin; sizes come from the caller.
17
+ */
18
+ export declare function arrangeSiblings(blocks: Block[], sizeOf: (id: string) => Size, text: string, gap: number, isFile: boolean): Map<string, Point>;
19
+ export {};
@@ -0,0 +1,257 @@
1
+ import { type CanvasProject } from './project.js';
2
+ import { type ConflictChoice } from './conflicts.js';
3
+ import type { Block, CodeDiagnostic, FileLayout, FileModel, HostDiagnostic } from './types.js';
4
+ export interface EditorOptions {
5
+ parent: HTMLElement;
6
+ text: string;
7
+ /** Where `text` is in the file, for an editor that shows just this part of the whole document. */
8
+ start: number;
9
+ end: number;
10
+ /** Selection to apply on open, relative to `text`. */
11
+ selection?: [number, number];
12
+ /** While changes are shown: the block's code in the base version ('' for an added block). Show a diff against it. */
13
+ diffBase?: string;
14
+ /** For editors on their own copy of `text`. Editors that edit the file itself don't call it. */
15
+ onChange(text: string): void;
16
+ /** User pressed Escape / Mod-Enter inside the editor. */
17
+ onClose(): void;
18
+ }
19
+ export interface EditorHandle {
20
+ focus(): void;
21
+ destroy(): void;
22
+ /**
23
+ * The editor edits the file's document directly (e.g. Monaco on the real file, for IntelliSense).
24
+ * The canvas then gets its changes through `setText` and keeps the editor open, following the block.
25
+ */
26
+ editsFile?: boolean;
27
+ }
28
+ /** The host provides the code editor used inside blocks (CodeMirror in the playground, Monaco in the IDE). */
29
+ export type EditorFactory = (o: EditorOptions) => EditorHandle;
30
+ export interface CodeCanvasOptions {
31
+ createEditor: EditorFactory;
32
+ /** The canvas changed the file's text. */
33
+ /**
34
+ * The canvas changed the file's text. When the same action changed other files too (a rename),
35
+ * `otherFiles` lists them, already updated in the project: the host should treat it all as one undo step.
36
+ */
37
+ onTextChange(text: string, otherFiles?: OtherFileChange[]): void;
38
+ /**
39
+ * Block positions or collapsed state changed. Save with `serializeLayout`. `automatic` changes
40
+ * (first layout, blocks added in the text, renames) don't come from the user arranging the canvas:
41
+ * a host may keep those out of the repo until there's a `user` change.
42
+ */
43
+ onLayoutChange(layout: FileLayout, reason: LayoutChangeReason): void;
44
+ onUndo?(): void;
45
+ onRedo?(): void;
46
+ onCameraChange?(scale: number): void;
47
+ theme?: 'dark' | 'light';
48
+ /**
49
+ * The project the file belongs to, for references across files and type errors. Keep it updated
50
+ * with the other files' text. Without one, the canvas only sees the open file.
51
+ */
52
+ project?: CanvasProject;
53
+ /** The selected block changed (null: nothing selected). */
54
+ onSelect?(block: Block | null): void;
55
+ /** The user picked a block in another file, e.g. in the references list. */
56
+ onOpenBlock?(path: string, blockId: string): void;
57
+ }
58
+ export type LayoutChangeReason = 'user' | 'automatic';
59
+ /** Another file changed by the same canvas action, e.g. usages renamed there. */
60
+ export interface OtherFileChange {
61
+ path: string;
62
+ before: string;
63
+ after: string;
64
+ /** The file's model before the change, to carry renamed blocks' saved positions (`carryRenames`). */
65
+ previousModel: FileModel | undefined;
66
+ }
67
+ /**
68
+ * The visual editor for one file. Text is the source of truth: every action on the canvas
69
+ * becomes a text edit, and every text change re-renders the canvas.
70
+ */
71
+ export declare class CodeCanvas {
72
+ private opts;
73
+ readonly root: HTMLElement;
74
+ private world;
75
+ private frameEl;
76
+ private blocksEl;
77
+ private svg;
78
+ private bar;
79
+ private refsEl;
80
+ private banner;
81
+ private toastEl;
82
+ private path;
83
+ private text;
84
+ /** Latest parse. */
85
+ private model;
86
+ /** What's on screen: the latest parse without syntax errors. */
87
+ private view;
88
+ private layout;
89
+ private geom;
90
+ private hints;
91
+ private cam;
92
+ private camQueued;
93
+ private movingTimer;
94
+ private anim;
95
+ private lod;
96
+ /** The camera still shows the whole file as `fit` left it: resizing the view fits it again. */
97
+ private fittedToView;
98
+ private els;
99
+ private edges;
100
+ private selected;
101
+ private hovered;
102
+ private refsOpen;
103
+ private project;
104
+ /** Errors on screen: type errors from the last resolve, or syntax errors mapped onto the last good view. */
105
+ private diagnostics;
106
+ private incomingUsages;
107
+ /** The version changes are shown against (`setDiffBase`), and its geometry, computed once. */
108
+ private diffBase;
109
+ private diffCache;
110
+ /** Merge conflicts in the text. The canvas then shows its current side, marking the blocks they touch. */
111
+ private conflicts;
112
+ private incomingBlockEls;
113
+ private removedBlockEls;
114
+ /** Errors from the host (`setDiagnostics`), shown instead of the project's type errors. */
115
+ private hostDiagnostics;
116
+ private renaming;
117
+ /** The layout before the last Arrange, until the next layout change: Undo arrange puts it back. */
118
+ private layoutBeforeArrange;
119
+ /** Where the camera was before the block editor moved it out of the way, and where it moved it to. */
120
+ private cameraBeforeEditor;
121
+ private editing;
122
+ private clip;
123
+ private pointers;
124
+ private gesture;
125
+ private lastTap;
126
+ private lastPointer;
127
+ private toastTimer;
128
+ private ro;
129
+ private barObserver;
130
+ private cleanup;
131
+ constructor(container: HTMLElement, opts: CodeCanvasOptions);
132
+ /** Show a file. Fits it to the view. */
133
+ openFile(path: string, text: string, layout?: FileLayout | null): void;
134
+ /** The text changed outside the canvas (e.g. the text editor). */
135
+ setText(text: string): void;
136
+ /**
137
+ * Show the changes since a base version of the file (e.g. the last commit): unchanged blocks are
138
+ * desaturated, added and changed ones get a chip, removed ones show in red where they were.
139
+ * `layout` is the base version's saved layout, for placing removed blocks. Null hides the changes.
140
+ */
141
+ setDiffBase(base: {
142
+ text: string;
143
+ layout?: FileLayout | null;
144
+ } | null): void;
145
+ get isShowingChanges(): boolean;
146
+ private conflictsOf;
147
+ /** Resolve the conflicts that touch a block: their sections become the chosen side. */
148
+ keepConflictSide(id: string, choice: ConflictChoice): void;
149
+ /** While changes are shown: the block's code in the base version, '' if it's new. */
150
+ private baseCodeOf;
151
+ /** The changes of what's on screen, while a diff base is set. */
152
+ private currentDiff;
153
+ /**
154
+ * Errors reported by the host, e.g. VS Code's Problems. While set, the canvas shows these instead of
155
+ * resolving type errors itself. Pass null to go back to the project's own.
156
+ */
157
+ setDiagnostics(diagnostics: HostDiagnostic[] | null): void;
158
+ setLayout(layout: FileLayout): void;
159
+ getLayout(): FileLayout;
160
+ getModel(): FileModel | null;
161
+ /** Re-resolve usages and errors, e.g. after other files of the project changed. */
162
+ refreshProject(): void;
163
+ getDiagnostics(): CodeDiagnostic[];
164
+ setTheme(theme: 'dark' | 'light'): void;
165
+ get scale(): number;
166
+ /** Lay the whole file out again by the layout rules (layoutRules.ts), forgetting saved positions. */
167
+ arrange(): void;
168
+ undoArrange(): void;
169
+ /** Fit the whole file in the view. */
170
+ fit(animate?: boolean): void;
171
+ zoomBy(factor: number): void;
172
+ /** Center a block and select it. */
173
+ reveal(id: string): void;
174
+ select(id: string | null): void;
175
+ destroy(): void;
176
+ private usageTimer;
177
+ private parseNow;
178
+ /** Usage links and type errors go through the project's language service: only once typing pauses. */
179
+ private scheduleUsages;
180
+ private hostDiagnosticsOnBlocks;
181
+ /** The text changed while an editor on the file is open: keep tracking the part of the file it shows. */
182
+ private followEditedRange;
183
+ /** While the syntax is broken the last good view stays on screen: put its errors on the closest block it still has. */
184
+ private syntaxDiagnosticsOnView;
185
+ private get stale();
186
+ /** Apply a text edit made on the canvas. */
187
+ private commit;
188
+ private relayout;
189
+ private emitLayout;
190
+ private render;
191
+ /** Blocks only the incoming side of a conflict has, drawn dashed where they would go. */
192
+ private renderIncomingBlocks;
193
+ /** A changed block's preview: its changed lines with a line of context, as many as fit. */
194
+ private changedLinesPreview;
195
+ /** Removed blocks stay visible, in red, where they were in the base version. They can't be selected. */
196
+ private renderRemovedBlocks;
197
+ /** Diagnostics grouped by the block that shows them: the innermost visible block containing each error. */
198
+ private diagnosticsByShownBlock;
199
+ private updateErrorMarkers;
200
+ private blockHTML;
201
+ /** Faint miniature of a collapsed block's nested blocks. */
202
+ private miniMap;
203
+ private renderEdges;
204
+ private updateHighlight;
205
+ private queueCamera;
206
+ private applyCamera;
207
+ private setCamera;
208
+ private moveCamera;
209
+ private zoomAt;
210
+ private toWorld;
211
+ private local;
212
+ /** What's under a world point: a block (header or leaf), or empty space inside a container/the file. */
213
+ private hitTest;
214
+ private bindEvents;
215
+ private isOverlay;
216
+ private onDown;
217
+ private onMove;
218
+ private relayoutQueued;
219
+ private relayoutSoon;
220
+ private onUp;
221
+ private endDrag;
222
+ private onTap;
223
+ private onWheel;
224
+ private onKey;
225
+ private onClipboard;
226
+ private guard;
227
+ /** Edits that add, remove or rename blocks work on the text's structure, which conflicts break. */
228
+ private guardStructureEdit;
229
+ private toggleCollapse;
230
+ private createFunctionAt;
231
+ private createFunctionAtCenter;
232
+ /** Convert a world point into coordinates relative to a container's content origin. */
233
+ private relativeTo;
234
+ private applyInsert;
235
+ private deleteBlock;
236
+ private duplicate;
237
+ private copy;
238
+ private paste;
239
+ /** Show a name field in the block's header. Enter renames the block and its usages in every file. */
240
+ startRename(id: string): void;
241
+ private cancelRename;
242
+ private commitRename;
243
+ openEditor(id: string, selection?: [number, number]): void;
244
+ private openRangeEditor;
245
+ private onEditorChange;
246
+ closeEditor({ restoreCamera }?: {
247
+ restoreCamera?: boolean;
248
+ }): void;
249
+ private renderBar;
250
+ private toggleRefs;
251
+ private showErrorsOf;
252
+ private diagnosticsInside;
253
+ private refsFor;
254
+ private renderRefs;
255
+ private openEditorAtDiagnostic;
256
+ private toast;
257
+ }
@@ -0,0 +1,37 @@
1
+ import type { TextEdit } from './edits.js';
2
+ /** Where one side of a conflict is in the file: its code, without the marker lines. */
3
+ export interface ConflictSide {
4
+ start: number;
5
+ end: number;
6
+ }
7
+ /**
8
+ * A merge conflict as git writes it into the file:
9
+ * `<<<<<<< current` … (`||||||| base` …) `=======` … `>>>>>>> incoming`.
10
+ */
11
+ export interface ConflictHunk {
12
+ /** The whole section, marker lines included (up to and including the last marker's line break). */
13
+ start: number;
14
+ end: number;
15
+ current: ConflictSide;
16
+ incoming: ConflictSide;
17
+ /** Only with `merge.conflictStyle = diff3` (or zdiff3). */
18
+ base?: ConflictSide;
19
+ /** What git wrote after the markers, e.g. `HEAD` and the branch name. */
20
+ currentLabel: string;
21
+ incomingLabel: string;
22
+ }
23
+ export type ConflictChoice = 'current' | 'incoming' | 'both';
24
+ /** One side of a conflicted file: each conflict replaced by that side's code. */
25
+ export interface ConflictSideText {
26
+ text: string;
27
+ /** Where each conflict's code is in `text`, in the order of the hunks. */
28
+ hunkRanges: ConflictSide[];
29
+ /** The file offset of an offset in `text`. */
30
+ toFileOffset(offset: number): number;
31
+ }
32
+ /** The merge conflicts in a file. Unfinished marker sections are left alone. */
33
+ export declare function findConflicts(text: string): ConflictHunk[];
34
+ /** The file with every conflict replaced by one side's code. */
35
+ export declare function conflictSideText(text: string, hunks: ConflictHunk[], side: 'current' | 'incoming'): ConflictSideText;
36
+ /** The edit that resolves one conflict: its whole section becomes the chosen code. */
37
+ export declare function resolveConflict(text: string, hunk: ConflictHunk, choice: ConflictChoice): TextEdit;
@@ -0,0 +1,28 @@
1
+ import type { Block, FileModel } from './types.js';
2
+ /**
3
+ * How a block compares with the base version of its file (e.g. the last commit).
4
+ * - `containsChanges`: its own code is the same, but nested blocks changed.
5
+ */
6
+ export type BlockChange = 'added' | 'changed' | 'containsChanges' | 'unchanged';
7
+ export interface DiffLine {
8
+ kind: 'same' | 'added' | 'removed';
9
+ text: string;
10
+ }
11
+ export interface FileDiff {
12
+ base: FileModel;
13
+ /** The change of every block of the current version. */
14
+ changes: Map<string, BlockChange>;
15
+ /** Blocks of the base that are gone (only the outermost one of a removed subtree). */
16
+ removed: Block[];
17
+ }
18
+ /** Compare two versions of a file block by block. Blocks are matched by id, so a renamed block is removed + added. */
19
+ export declare function diffModels(base: FileModel, current: FileModel): FileDiff;
20
+ /** Line diff of a block's own code (nested blocks left out) between the base and now. */
21
+ export declare function diffOwnCode(base: FileModel, baseBlock: Block | undefined, current: FileModel, block: Block): DiffLine[];
22
+ /** Shortest edit script between two lists of lines (longest common subsequence). */
23
+ export declare function diffLines(before: string[], after: string[]): DiffLine[];
24
+ /** The changed lines, with one line of context around each change if there's room, to fit in `max` lines. */
25
+ export declare function diffPreview(lines: DiffLine[], max: number): {
26
+ lines: DiffLine[];
27
+ more: number;
28
+ };
@@ -0,0 +1,38 @@
1
+ import type { Block, FileModel } from './types.js';
2
+ /** A single text replacement. */
3
+ export interface TextEdit {
4
+ start: number;
5
+ end: number;
6
+ text: string;
7
+ }
8
+ export declare function applyEdit(text: string, e: TextEdit): string;
9
+ /** Apply edits that don't overlap, given as offsets into the original text. */
10
+ export declare function applyEdits(text: string, edits: TextEdit[]): string;
11
+ /** Result of a structural edit: the text change plus the id the new block will have. */
12
+ export interface InsertResult {
13
+ edit: TextEdit;
14
+ id: string;
15
+ /** Selection to put in the editor, relative to the new block's start. */
16
+ select: [number, number];
17
+ }
18
+ export declare function replaceBlock(model: FileModel, id: string, code: string): TextEdit;
19
+ /** Remove a block and the blank space it leaves behind. */
20
+ export declare function deleteBlock(model: FileModel, id: string): TextEdit;
21
+ /** Pick a name that isn't taken in the block's scope. */
22
+ export declare function uniqueName(model: FileModel, parentId: string | null, base: string): string;
23
+ /** Where nested code can go: the block itself if it can hold code, else its nearest container. */
24
+ export declare function containerFor(model: FileModel, id: string | null): Block | null;
25
+ export declare function newFunction(model: FileModel, parentId: string | null, base?: string): InsertResult;
26
+ /** What the clipboard holds after copying a block. */
27
+ export interface BlockClip {
28
+ code: string;
29
+ name: string;
30
+ kind: Block['kind'];
31
+ /** Copied from inside a class (method/property syntax). */
32
+ fromClass: boolean;
33
+ }
34
+ export declare function copyBlock(model: FileModel, id: string): BlockClip;
35
+ /** Paste a copied block into `parentId` (or the file), converting method ↔ function syntax as needed. */
36
+ export declare function pasteBlock(model: FileModel, parentId: string | null, clip: BlockClip): InsertResult;
37
+ /** Turn plain clipboard text (e.g. copied from another app) into a block clip. */
38
+ export declare function clipFromText(code: string): BlockClip;
@@ -0,0 +1 @@
1
+ export declare function setHTML(element: Element, html: string): void;
@@ -0,0 +1,20 @@
1
+ export * from './types.js';
2
+ export { parseFile, detectIndentUnit, blockAt } from './parse.js';
3
+ export { Project } from './project.js';
4
+ export type { CanvasProject, ConfigFile, FileResolution, ProjectOptions, RenameResult } from './project.js';
5
+ export { RemoteProject } from './remoteProject.js';
6
+ export type { ProjectServerCall } from './remoteProject.js';
7
+ export { ProjectServer, callProjectServer } from './projectServer.js';
8
+ export type { ProjectServerMethod } from './projectServer.js';
9
+ export { connectProjectWorker, serveProject } from './projectWorker.js';
10
+ export type { MessagePortLike } from './projectWorker.js';
11
+ export * from './edits.js';
12
+ export { diffLines, diffModels, diffOwnCode, diffPreview } from './diff.js';
13
+ export { conflictSideText, findConflicts, resolveConflict } from './conflicts.js';
14
+ export type { ConflictChoice, ConflictHunk, ConflictSide, ConflictSideText } from './conflicts.js';
15
+ export type { BlockChange, DiffLine, FileDiff } from './diff.js';
16
+ export { computeGeometry, carryRenames, serializeLayout, emptyLayout, freeSpotNear, M } from './layout.js';
17
+ export type { Geo, FileGeometry } from './layout.js';
18
+ export { CodeCanvas } from './canvas.js';
19
+ export type { CodeCanvasOptions, EditorFactory, EditorHandle, EditorOptions, LayoutChangeReason, OtherFileChange } from './canvas.js';
20
+ export { injectStyles } from './styles.js';
@@ -0,0 +1,75 @@
1
+ import type { Block, FileLayout, FileModel, Point } from './types.js';
2
+ /** Visual metrics. Monospace everywhere so sizes can be computed without measuring the DOM. */
3
+ export declare const M: {
4
+ headerH: number;
5
+ headerCharW: number;
6
+ previewLineH: number;
7
+ previewCharW: number;
8
+ previewPad: number;
9
+ pad: number;
10
+ gap: number;
11
+ minW: number;
12
+ maxW: number;
13
+ miniH: number;
14
+ fileHeader: number;
15
+ filePad: number;
16
+ };
17
+ export interface Geo {
18
+ id: string;
19
+ block: Block;
20
+ /** Position relative to the parent's content origin. */
21
+ x: number;
22
+ y: number;
23
+ w: number;
24
+ h: number;
25
+ /** Absolute world position. */
26
+ ax: number;
27
+ ay: number;
28
+ /** Y offset (inside the block) where nested blocks start. */
29
+ contentTop: number;
30
+ collapsed: boolean;
31
+ /** Hidden because an ancestor is collapsed. */
32
+ hidden: boolean;
33
+ }
34
+ export interface FileGeometry {
35
+ geo: Map<string, Geo>;
36
+ /** Order to draw blocks: parents before children. */
37
+ order: Geo[];
38
+ frame: {
39
+ x: number;
40
+ y: number;
41
+ w: number;
42
+ h: number;
43
+ };
44
+ /** Positions that were assigned during this pass (new blocks). Save them so they stay put. */
45
+ assigned: Record<string, Point>;
46
+ }
47
+ export declare function emptyLayout(): FileLayout;
48
+ /**
49
+ * Compute every block's size and position. Saved positions are always respected.
50
+ * Blocks without a saved position get one: a tidy flow layout for a never-laid-out file,
51
+ * otherwise a free spot near their neighbors (or the hint, e.g. where the user clicked).
52
+ */
53
+ export declare function computeGeometry(model: FileModel, layout: FileLayout, hints?: Record<string, Point>, opts?: {
54
+ resolveOverlaps?: boolean;
55
+ }): FileGeometry;
56
+ interface Rect {
57
+ x: number;
58
+ y: number;
59
+ w: number;
60
+ h: number;
61
+ }
62
+ /** The closest free spot to `at` (e.g. where a block was dropped or created). */
63
+ export declare function freeSpotNear(at: Point, g: {
64
+ w: number;
65
+ h: number;
66
+ id?: string;
67
+ }, placed: Rect[], clampPositive: boolean): Point;
68
+ /**
69
+ * When a block is renamed its id changes. If exactly one block disappeared and one appeared
70
+ * under the same parent, carry the old position (and its children's) over to the new id.
71
+ */
72
+ export declare function carryRenames(prev: FileModel | null, next: FileModel, layout: FileLayout): boolean;
73
+ /** Layout ready to be written to `.codecanvas/`: only live blocks, sorted keys, whole numbers. */
74
+ export declare function serializeLayout(layout: FileLayout, model: FileModel | null): string;
75
+ export {};
@@ -0,0 +1,48 @@
1
+ import type { Block } from './types.js';
2
+ /**
3
+ * How the canvas arranges a group of sibling blocks (a file, or a class's members) the first time,
4
+ * to make the file easy to read. The arranger (arrange.ts) applies these rules; they only decide.
5
+ *
6
+ * Three kinds of rules:
7
+ * - zones: where a block goes (the left column, or a band from top to bottom)
8
+ * - stacks: blocks that always go together, one above the other
9
+ * - relatedness: which blocks end up next to each other
10
+ * Plus one shape the arranger always applies, the newspaper: a function on the left, the functions it
11
+ * calls in a column to its right, in the order it calls them.
12
+ */
13
+ export type Zone = 'left' | 'data' | 'types' | 'main' | 'bottom';
14
+ /** The bands from top to bottom. The left column holds `left` blocks next to all of them. */
15
+ export declare const BAND_ORDER: Zone[];
16
+ export interface ZoneRule {
17
+ zone: Zone;
18
+ description: string;
19
+ matches(block: Block): boolean;
20
+ }
21
+ /** First match wins. */
22
+ export declare const ZONE_RULES: ZoneRule[];
23
+ export interface StackRule {
24
+ description: string;
25
+ /** Pairs to stack: the first block on top, the second right below it. */
26
+ pairs(blocks: Block[]): [Block, Block][];
27
+ }
28
+ export declare const STACK_RULES: StackRule[];
29
+ /** What a block knows about its siblings, read from its own code. */
30
+ export interface SiblingFacts {
31
+ /** Sibling functions it calls, in the order of their first call. */
32
+ calls: string[];
33
+ /** Every sibling it names (calls included). */
34
+ uses: Set<string>;
35
+ }
36
+ export interface RelatednessRule {
37
+ description: string;
38
+ /** How strongly two blocks belong together (0: not at all). */
39
+ score(a: Block, b: Block, factsOf: (block: Block) => SiblingFacts): number;
40
+ }
41
+ export declare const RELATEDNESS_RULES: RelatednessRule[];
42
+ /**
43
+ * How many levels of callees the newspaper shows to the right of a function. Deeper calls start a
44
+ * shape of their own, so a long chain of calls doesn't become one very wide staircase.
45
+ */
46
+ export declare const NEWSPAPER_DEPTH = 3;
47
+ /** The newspaper shape applies to these: a caller and the functions it calls. */
48
+ export declare const isFunctionLike: (block: Block) => boolean;
@@ -0,0 +1,72 @@
1
+ import ts from 'typescript';
2
+ import type { Block, CodeDiagnostic, FileModel, Usage } from './types.js';
3
+ /**
4
+ * Parse a TypeScript file into a tree of blocks plus the usage links between them.
5
+ * Pure function: same text in, same model out.
6
+ */
7
+ export declare function parseFile(path: string, text: string): FileModel;
8
+ /**
9
+ * Fast part of parsing: blocks only (usages left empty). Pass the previous model of the same
10
+ * file to parse incrementally, re-reading only the changed region.
11
+ */
12
+ export declare function parseStructure(path: string, text: string, prev?: FileModel | null): FileModel;
13
+ /** Innermost block whose text range contains `offset`. */
14
+ export declare function blockAt(model: FileModel, offset: number): Block | null;
15
+ export declare function toCodeDiagnostic(model: FileModel, sf: ts.SourceFile, d: ts.Diagnostic, source: CodeDiagnostic['source']): CodeDiagnostic;
16
+ /** The builder that produced `model`: used by the project to resolve usages across files. */
17
+ export declare function builderOf(model: FileModel): Builder | undefined;
18
+ /** Slower part: resolve every name to its declaration and link the blocks. */
19
+ export declare function computeUsages(model: FileModel): Usage[];
20
+ export declare function detectIndentUnit(text: string): string;
21
+ declare class Builder {
22
+ private sf;
23
+ private text;
24
+ roots: Block[];
25
+ byId: Map<string, Block>;
26
+ /**
27
+ * Declaration node → block id, keyed by node position (see `nodeKey`) so a syntax tree parsed
28
+ * elsewhere from the same text (the project's language service) maps to the same blocks.
29
+ */
30
+ private declToBlock;
31
+ /** Range node → block, to find which block contains a usage. Keyed like `declToBlock`. */
32
+ private rangeToBlock;
33
+ /** Every name a usage could resolve to. Other identifiers skip the (slow) checker. */
34
+ readonly names: Set<string>;
35
+ constructor(sf: ts.SourceFile, text: string);
36
+ collectStatements(stmts: readonly ts.Statement[], parent: Block | null, depth: number, declarationsOnly?: boolean): void;
37
+ private addImport;
38
+ private addFunctionLike;
39
+ private addClass;
40
+ private collectMembers;
41
+ private addVariableStatement;
42
+ private addVariable;
43
+ private add;
44
+ /** Include doc comments directly above the node (no blank line in between). */
45
+ private startWithComments;
46
+ private lineStartOf;
47
+ private indentAt;
48
+ blockIdForDeclaration(declaration: ts.Node): string | undefined;
49
+ /**
50
+ * Link every name used inside a block to the block that declares it. `sf` is a tree of the same
51
+ * text (this builder's own, or the language service's when resolving across files).
52
+ */
53
+ collectUsages(sf: ts.SourceFile, checker: ts.TypeChecker, otherFiles?: OtherFileResolver): Usage[];
54
+ private recordUsage;
55
+ }
56
+ /** Finds blocks declared in other files of the project. */
57
+ export interface OtherFileResolver {
58
+ /** Names declared anywhere in the project. Identifiers with other names skip the checker. */
59
+ projectNames: Set<string>;
60
+ blockInOtherFile(declaration: ts.Node): {
61
+ path: string;
62
+ id: string;
63
+ } | null;
64
+ }
65
+ /** Faint code preview: the block's own code with nested blocks cut out, dedented and trimmed. */
66
+ /** The text of `range` with the given nested blocks cut out: a block's own code. */
67
+ export declare function codeWithoutChildren(text: string, range: [number, number], children: Block[]): string;
68
+ export declare function makePreview(text: string, range: [number, number], children: Block[], max: number): {
69
+ lines: string[];
70
+ more: number;
71
+ };
72
+ export {};