Skip to content

Commit 482b3b7

Browse files
Started making solid typings
1 parent b74893d commit 482b3b7

File tree

10 files changed

+123
-32
lines changed

10 files changed

+123
-32
lines changed

src/@types/Backlinks.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { TFile } from "obsidian"
2+
3+
export default interface Backlink {
4+
recomputeBacklink(file: TFile | null): void
5+
}

src/@types/Canvas.d.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export interface Canvas {
2525

2626
getData(): CanvasData
2727
setData(data: CanvasData): void
28-
2928
/** Basically setData (if clearCanvas == true), but without modifying the history */
30-
importData(data: CanvasData, clearCanvas?: boolean): void
29+
importData(data: CanvasData, clearCanvas?: boolean, /* custom */ silent?: boolean): void
30+
clear(): void
3131

3232
nodes: Map<string, CanvasNode>
3333
edges: Map<string, CanvasEdge>
@@ -39,7 +39,7 @@ export interface Canvas {
3939

4040
wrapperEl: HTMLElement
4141
canvasEl: HTMLElement
42-
menu: PopupMenu
42+
menu: CanvasPopupMenu
4343
cardMenuEl: HTMLElement
4444
canvasControlsEl: HTMLElement
4545
quickSettingsButton: HTMLElement
@@ -48,6 +48,8 @@ export interface Canvas {
4848
canvasRect: DOMRect
4949
getViewportBBox(): BBox
5050
setViewport(tx: number, ty: number, tZoom: number): void
51+
52+
viewportChanged: boolean
5153
markViewportChanged(): void
5254

5355
x: number
@@ -82,6 +84,8 @@ export interface Canvas {
8284
createTextNode(options: { [key: string]: any }): CanvasNode
8385
createGroupNode(options: { [key: string]: any }): CanvasNode
8486
createFileNode(options: { [key: string]: any }): CanvasNode
87+
createFileNodes(filepaths: string[], position: Position): CanvasNode[]
88+
createLinkNode(options: { [key: string]: any }): CanvasNode
8589

8690
addNode(node: CanvasNode): void
8791
removeNode(node: CanvasNode): void
@@ -97,6 +101,8 @@ export interface Canvas {
97101

98102
posFromEvt(event: MouseEvent): Position
99103
onDoubleClick(event: MouseEvent): void
104+
handleCopy(e: ClipboardEvent): void
105+
100106
handlePaste(): void
101107
requestSave(): void
102108

@@ -355,11 +361,13 @@ export interface CanvasEdge extends CanvasElement {
355361
}
356362

357363
export interface NodeInteractionLayer {
364+
canvas: Canvas
358365
interactionEl: HTMLElement
359366
setTarget(node: CanvasNode): void
360367
}
361368

362-
export interface PopupMenu {
369+
export interface CanvasPopupMenu {
370+
canvas: Canvas
363371
menuEl: HTMLElement
364372
render(): void
365373
}

src/@types/Obsidian.d.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ declare module "obsidian" {
99
/** @public */
1010
scope: Scope
1111
/** @public */
12-
vault: Vault
12+
vault: ExtendedVault
1313
/** @public */
1414
fileManager: FileManager
1515
/**
@@ -20,22 +20,35 @@ declare module "obsidian" {
2020

2121
internalPlugins: any
2222

23-
// Custom
2423
/** @public */
2524
metadataCache: ExtendedMetadataCache
2625
/** @public */
2726
workspace: Workspace & ExtendedWorkspace
2827
}
2928

29+
export interface ExtendedVault extends Vault {
30+
getMarkdownFiles: () => TFile[]
31+
32+
// Custom
33+
recurseChildrenAC: (origin: TAbstractFile, traverse: (file: TAbstractFile) => void) => void
34+
}
35+
3036
export interface ExtendedMetadataCache extends MetadataCache {
37+
vault: ExtendedVault
38+
3139
fileCache: FileCache
3240
metadataCache: MetadataCacheMap
3341
resolvedLinks: ResolvedLinks
3442

43+
computeMetadataAsync: (buffer: ArrayBuffer) => Promise<ExtendedCachedMetadata>
44+
3545
computeFileMetadataAsync: (file: TFile) => void
3646
saveFileCache: (filepath: string, cache: FileCacheEntry) => void
3747
linkResolver: () => void
38-
resolveLinks: (filepath: string) => void
48+
resolveLinks: (filepath: string, /* custom */ cachedContent: any) => void
49+
50+
// Custom
51+
registerInternalLinkAC: (canvasName: string, from: string, to: string) => void
3952
}
4053

4154
export interface ExtendedWorkspace {

src/@types/OutgoingLink.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { TFile } from "obsidian"
2+
3+
export default interface OutgoingLink {
4+
file: TFile
5+
6+
recomputeLinks(): void
7+
recomputeUnlinked(): void
8+
}

src/patchers/backlinks-patcher.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { TAbstractFile, TFile, TFolder } from "obsidian"
1+
import { ExtendedVault, TAbstractFile, TFile, TFolder } from "obsidian"
22
import PatchHelper from "src/utils/patch-helper"
33
import Patcher from "./patcher"
4+
import Backlink from "src/@types/Backlinks"
45

56
export default class BacklinksPatcher extends Patcher {
67
private isRecomputingBacklinks: boolean = false
@@ -9,7 +10,7 @@ export default class BacklinksPatcher extends Patcher {
910
if (!this.plugin.settings.getSetting('canvasMetadataCompatibilityEnabled')) return
1011

1112
const that = this
12-
const backlinkPatch = PatchHelper.tryPatchWorkspacePrototype(this.plugin, () => (
13+
const backlinkPatch = PatchHelper.tryPatchWorkspacePrototype<Backlink>(this.plugin, () => (
1314
(this.plugin.app.workspace.getLeavesOfType('backlink').first()?.view as any)?.backlink
1415
), {
1516
recomputeBacklink: PatchHelper.OverrideExisting(next => function (file: TFile, ...args: any[]) {
@@ -20,7 +21,7 @@ export default class BacklinksPatcher extends Patcher {
2021
})
2122
})
2223

23-
const vaultPatch = PatchHelper.patchPrototype<any>(this.plugin, this.plugin.app.vault, {
24+
const vaultPatch = PatchHelper.patchPrototype<ExtendedVault>(this.plugin, this.plugin.app.vault, {
2425
recurseChildrenAC: _next => function (origin: TAbstractFile, traverse: (file: TAbstractFile) => void) {
2526
for (var stack = [origin]; stack.length > 0;) {
2627
var current = stack.pop()
@@ -32,8 +33,8 @@ export default class BacklinksPatcher extends Patcher {
3233
}
3334
}
3435
},
35-
getMarkdownFiles: PatchHelper.OverrideExisting(next => function (file: TFile, ...args: any[]) {
36-
if (!that.isRecomputingBacklinks) return next.call(this, file, ...args)
36+
getMarkdownFiles: PatchHelper.OverrideExisting(next => function (...args: any[]) {
37+
if (!that.isRecomputingBacklinks) return next.call(this, ...args)
3738

3839
// If we are recomputing backlinks, we need to include markdown as well as canvas files
3940
var files: TFile[] = []
@@ -45,7 +46,7 @@ export default class BacklinksPatcher extends Patcher {
4546
}
4647
})
4748

48-
return files
49+
return "files"
4950
})
5051
})
5152

src/patchers/canvas-patcher.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { EditorView, ViewUpdate } from "@codemirror/view"
22
import JSONSS from "json-stable-stringify"
33
import { around } from "monkey-around"
44
import { editorInfoField, requireApiVersion, WorkspaceLeaf } from "obsidian"
5-
import { BBox, CanvasData, CanvasEdge, CanvasEdgeData, CanvasElement, CanvasNode, CanvasNodeData, CanvasView } from "src/@types/Canvas"
5+
import { BBox, Canvas, CanvasData, CanvasEdge, CanvasEdgeData, CanvasElement, CanvasNode, CanvasNodeData, CanvasPopupMenu, CanvasView, NodeInteractionLayer } from "src/@types/Canvas"
66
import PatchHelper from "src/utils/patch-helper"
77
import JSONC from "tiny-jsonc"
88
import { CanvasEvent } from "../events"
@@ -39,7 +39,7 @@ export default class CanvasPatcher extends Patcher {
3939
})
4040

4141
// Patch canvas view
42-
PatchHelper.patchPrototype<any>(this.plugin, canvasView, {
42+
PatchHelper.patchPrototype<CanvasView>(this.plugin, canvasView, {
4343
getViewData: PatchHelper.OverrideExisting(next => function (...args: any) {
4444
const canvasData = this.canvas.getData()
4545

@@ -79,7 +79,7 @@ export default class CanvasPatcher extends Patcher {
7979
})
8080

8181
// Patch canvas
82-
PatchHelper.patchPrototype<any>(this.plugin, canvasView.canvas, {
82+
PatchHelper.patchPrototype<Canvas>(this.plugin, canvasView.canvas, {
8383
markViewportChanged: PatchHelper.OverrideExisting(next => function (...args: any) {
8484
that.triggerWorkspaceEvent(CanvasEvent.ViewportChanged.Before, this)
8585
const result = next.call(this, ...args)
@@ -245,7 +245,7 @@ export default class CanvasPatcher extends Patcher {
245245
})
246246

247247
// Patch canvas popup menu
248-
PatchHelper.patchPrototype<any>(this.plugin, canvasView.canvas.menu, {
248+
PatchHelper.patchPrototype<CanvasPopupMenu>(this.plugin, canvasView.canvas.menu, {
249249
render: PatchHelper.OverrideExisting(next => function (...args: any) {
250250
const result = next.call(this, ...args)
251251
that.triggerWorkspaceEvent(CanvasEvent.PopupMenuCreated, this.canvas)
@@ -255,7 +255,7 @@ export default class CanvasPatcher extends Patcher {
255255
})
256256

257257
// Patch interaction layer
258-
PatchHelper.patchPrototype<any>(this.plugin, canvasView.canvas.nodeInteractionLayer, {
258+
PatchHelper.patchPrototype<NodeInteractionLayer>(this.plugin, canvasView.canvas.nodeInteractionLayer, {
259259
setTarget: PatchHelper.OverrideExisting(next => function (node: CanvasNode) {
260260
const result = next.call(this, node)
261261
that.triggerWorkspaceEvent(CanvasEvent.NodeInteraction, this.canvas, node)
@@ -287,7 +287,7 @@ export default class CanvasPatcher extends Patcher {
287287
private patchNode(node: CanvasNode) {
288288
const that = this
289289

290-
PatchHelper.patch<any>(this.plugin, node, {
290+
PatchHelper.patch<CanvasNode>(this.plugin, node, {
291291
setData: PatchHelper.OverrideExisting(next => function (data: CanvasNodeData, addHistory?: boolean) {
292292
const result = next.call(this, data)
293293

@@ -332,7 +332,7 @@ export default class CanvasPatcher extends Patcher {
332332
private patchEdge(edge: CanvasEdge) {
333333
const that = this
334334

335-
PatchHelper.patch<any>(this.plugin, edge, {
335+
PatchHelper.patch<CanvasEdge>(this.plugin, edge, {
336336
setData: PatchHelper.OverrideExisting(next => function (data: CanvasEdgeData, addHistory?: boolean) {
337337
const result = next.call(this, data)
338338

src/patchers/metadata-cache-patcher.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TFile } from "obsidian"
1+
import { ExtendedMetadataCache, TFile } from "obsidian"
22
import { CanvasData, CanvasNodeData } from "src/@types/Canvas"
33
import { ExtendedCachedMetadata, MetadataCacheMap } from "src/@types/Obsidian"
44
import HashHelper from "src/utils/hash-helper"
@@ -11,7 +11,7 @@ export default class MetadataCachePatcher extends Patcher {
1111
if (!this.plugin.settings.getSetting('canvasMetadataCompatibilityEnabled')) return
1212

1313
const that = this
14-
await PatchHelper.patchPrototype<any>(this.plugin, this.plugin.app.metadataCache, {
14+
PatchHelper.patchPrototype<ExtendedMetadataCache>(this.plugin, this.plugin.app.metadataCache, {
1515
getCache: PatchHelper.OverrideExisting(next => function (filepath: string, ...args: any[]) {
1616
// Bypass the "md" extension check by handling the "canvas" extension here
1717
if (PathHelper.extension(filepath) === 'canvas') {

src/patchers/outgoing-links-patcher.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import PatchHelper from "src/utils/patch-helper"
22
import Patcher from "./patcher"
3+
import OutgoingLink from "src/@types/OutgoingLink"
34

45
export default class OutgoingLinksPatcher extends Patcher {
56
protected async patch() {
67
if (!this.plugin.settings.getSetting('canvasMetadataCompatibilityEnabled')) return
78

89
const that = this
9-
const outgoingLinkPatch = PatchHelper.tryPatchWorkspacePrototype(this.plugin, () => (
10+
const outgoingLinkPatch = PatchHelper.tryPatchWorkspacePrototype<OutgoingLink>(this.plugin, () => (
1011
(this.plugin.app.workspace.getLeavesOfType('outgoing-link').first()?.view as any)?.outgoingLink
1112
), {
1213
recomputeLinks: PatchHelper.OverrideExisting(next => function (...args: any[]) {

src/utils/_type-test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Canvas } from "src/@types/Canvas"
2+
import PatchHelper from "./patch-helper"
3+
4+
PatchHelper.patchPrototype<Canvas>(null as any, null as any, {
5+
// @ts-expect-error
6+
onResize: PatchHelper.OverrideExisting((next) => function (width: number, height: number) {
7+
console.log("Resizing canvas")
8+
9+
// @ts-expect-error
10+
next.call(this, width, height)
11+
}),
12+
onDoubleClick: (next) => function (event: MouseEvent) {
13+
console.log("Double click")
14+
next.call(this, event)
15+
},
16+
createFileNode: (next) => function (file: File) {
17+
// @ts-expect-error
18+
return next?.(file, null, "dfsaf")
19+
},
20+
// @ts-expect-error
21+
getData: (next) => function (...args: any[]) {
22+
console.log("Getting data")
23+
return 0
24+
},
25+
createTextNode: (next) => function (text: Record<string, any>) {
26+
console.log("Creating text node")
27+
return next.call(this, text)
28+
},
29+
createGroupNode: PatchHelper.OverrideExisting((next) => function (options: Record<string, any>) {
30+
console.log("Creating group node")
31+
return next.call(this, options)
32+
})
33+
})
34+
35+
PatchHelper.patchPrototype<Canvas>(null as any, null as any, {
36+
createTextNode: PatchHelper.OverrideExisting((next) => function (text: Record<string, any>) {
37+
console.log("Creating text node")
38+
return 0 as any
39+
})
40+
})

src/utils/patch-helper.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
import { around } from "monkey-around"
22
import { Plugin } from "obsidian"
33

4+
// All keys in T that are functions
5+
type FunctionKeys<T> = {
6+
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never
7+
}[keyof T]
8+
9+
// The type of the function at key K in T
10+
type KeyFunction<T, K extends FunctionKeys<T>> =
11+
T[K] extends (...args: any[]) => any ? T[K] : never
12+
13+
// The type of a patch function for key K in T
14+
type KeyFunctionReplacement<T, K extends FunctionKeys<T>> =
15+
(this: T, ...args: Parameters<KeyFunction<T, K>>) => ReturnType<KeyFunction<T, K>>
16+
17+
// The wrapper of a patch function for key K in T
18+
type PatchFunctionWrapper<T, K extends FunctionKeys<T>> =
19+
(next: KeyFunction<T, K>) => KeyFunctionReplacement<T, K>
20+
21+
// The object of patch functions for T
422
type FunctionPatchObject<T> = {
5-
[Key in keyof T | any]: ((next: T[Key | any]) => (this: T, ...args: any) => any) & { __overrideExisting?: boolean }
23+
[K in FunctionKeys<T>]?: PatchFunctionWrapper<T, K> & { __overrideExisting?: boolean }
624
}
725

826
export default class PatchHelper {
9-
static OverrideExisting<
10-
T,
11-
K extends keyof T
12-
>(fn: (next: T[K]) => (this: T, ...args: any[]) => any) {
13-
return Object.assign(fn, { __overrideExisting: true })
14-
}
27+
static OverrideExisting<T, K extends FunctionKeys<T>>(
28+
fn: PatchFunctionWrapper<T, K> & { __overrideExisting?: boolean }
29+
) { return Object.assign(fn, { __overrideExisting: true }) }
1530

1631
static patchPrototype<T>(
1732
plugin: Plugin,
@@ -31,9 +46,9 @@ export default class PatchHelper {
3146
const target = prototype ? object.constructor.prototype : object
3247

3348
// Validate override requirements
34-
for (const key of Object.keys(patches) as Array<keyof T>) {
49+
for (const key of Object.keys(patches) as Array<FunctionKeys<T>>) {
3550
const patch = patches[key]
36-
if (patch.__overrideExisting) {
51+
if (patch?.__overrideExisting) {
3752
if (typeof target[key] !== 'function')
3853
throw new Error(`Method ${String(key)} does not exist on target`)
3954
}

0 commit comments

Comments
 (0)