flint-plugin-api 0.6.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.
Files changed (3) hide show
  1. package/README.md +45 -0
  2. package/index.d.ts +122 -0
  3. package/package.json +28 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Writing Flint plugins
2
+
3
+ A plugin is a folder inside a vault's `.flint/plugins/` directory:
4
+
5
+ ```
6
+ .flint/plugins/my-plugin/
7
+ ├─ manifest.json
8
+ ├─ main.js
9
+ └─ styles.css (optional)
10
+ ```
11
+
12
+ `manifest.json`:
13
+
14
+ ```json
15
+ {
16
+ "id": "my-plugin",
17
+ "name": "My plugin",
18
+ "version": "1.0.0",
19
+ "author": "You",
20
+ "description": "What it does.",
21
+ "license": "AGPL-3.0-or-later"
22
+ }
23
+ ```
24
+
25
+ The `license` is an [SPDX expression](https://spdx.org/licenses/). Flint is AGPL-3.0-or-later, so plugins must use a compatible free license; Flint warns before enabling a plugin that doesn't.
26
+
27
+ `main.js` is an ES module whose default export receives the Flint API:
28
+
29
+ ```js
30
+ export default function activate(flint) {
31
+ flint.commands.register({
32
+ id: 'hello',
33
+ name: 'Say hello',
34
+ run: () => flint.ui.notice('Hello from my plugin'),
35
+ })
36
+ }
37
+ ```
38
+
39
+ Everything registered through the API (commands, editor extensions, sidebar tabs, listeners) is removed automatically when the plugin is turned off. `activate` may also return a cleanup function for anything else.
40
+
41
+ Use `flint.codemirror` instead of bundling your own copy of CodeMirror; two copies in the same editor break it.
42
+
43
+ For type hints, copy [`index.d.ts`](index.d.ts) next to your plugin and annotate `activate` with `/** @type {import('./index').ActivatePlugin} */`. See it for the full API and [`examples/word-count`](../examples/word-count) for a working plugin. To try it, copy the folder into your vault's `.flint/plugins/` and turn it on in Settings.
44
+
45
+ Plugins run inside Flint with the same access as the app itself. Only turn on plugins you trust.
package/index.d.ts ADDED
@@ -0,0 +1,122 @@
1
+ import type * as autocomplete from '@codemirror/autocomplete'
2
+ import type * as language from '@codemirror/language'
3
+ import type * as state from '@codemirror/state'
4
+ import type * as view from '@codemirror/view'
5
+
6
+ export type Disposer = () => void
7
+
8
+ export interface PluginCommand {
9
+ /** Unique within the plugin; Flint prefixes it with the plugin id. */
10
+ id: string
11
+ name: string
12
+ /** For example `Mod+Shift+K`. `Mod` is Ctrl, or ⌘ on macOS. */
13
+ hotkey?: string
14
+ /** Replaces `hotkey` on macOS, where `Ctrl` is the Control key. */
15
+ macHotkey?: string
16
+ run: () => unknown
17
+ isAvailable?: () => boolean
18
+ }
19
+
20
+ export interface SidebarTab {
21
+ /** Unique within the plugin. */
22
+ id: string
23
+ name: string
24
+ /** Renders into `element`; the returned function runs when the tab is removed. */
25
+ render: (element: HTMLElement) => Disposer | undefined
26
+ }
27
+
28
+ export interface NoteEntry {
29
+ path: string
30
+ kind: 'file' | 'folder' | 'attachment'
31
+ }
32
+
33
+ export interface MarkdownSection {
34
+ /** First source line of the block, 0-based. */
35
+ lineStart: number
36
+ /** Line after the block's last line. */
37
+ lineEnd: number
38
+ }
39
+
40
+ /**
41
+ * Where rendered Markdown came from. Buttons, inputs, links, `summary` and elements with a
42
+ * `data-interactive` attribute receive clicks in live preview instead of moving the cursor.
43
+ */
44
+ export interface MarkdownContext {
45
+ /** The note the content was rendered from. */
46
+ sourcePath: string
47
+ /** The source lines of the innermost block containing `element`. */
48
+ sectionOf(element: HTMLElement): MarkdownSection | null
49
+ /** Replaces source lines of the note (an empty `text` removes them); open editors update and it is saved. */
50
+ replaceLines(lineStart: number, lineEnd: number, text: string): Promise<void>
51
+ }
52
+
53
+ export type PostProcessor = (element: HTMLElement, context: MarkdownContext) => unknown
54
+
55
+ export type CodeBlockProcessor = (
56
+ source: string,
57
+ element: HTMLElement,
58
+ context: MarkdownContext,
59
+ ) => unknown
60
+
61
+ export interface FlintApi {
62
+ /** The id from the plugin's manifest. */
63
+ readonly pluginId: string
64
+
65
+ commands: {
66
+ register(command: PluginCommand): Disposer
67
+ }
68
+
69
+ editor: {
70
+ /** Adds a CodeMirror extension to every editor. */
71
+ registerExtension(extension: state.Extension): Disposer
72
+ /** The editor showing the active note, if any. */
73
+ activeView(): view.EditorView | null
74
+ /** Replaces the selection in the active editor, or inserts at the cursor. */
75
+ replaceSelection(text: string): void
76
+ }
77
+
78
+ vault: {
79
+ list(): Promise<NoteEntry[]>
80
+ read(path: string): Promise<string>
81
+ write(path: string, contents: string): Promise<void>
82
+ create(path: string): Promise<void>
83
+ /** Called with vault-relative paths whenever files change. */
84
+ onChange(listener: (paths: string[]) => void): Disposer
85
+ }
86
+
87
+ workspace: {
88
+ activeNote(): string | null
89
+ openNote(path: string): Promise<void>
90
+ onNoteOpen(listener: (path: string | null) => void): Disposer
91
+ }
92
+
93
+ ui: {
94
+ notice(message: string): void
95
+ registerSidebarTab(tab: SidebarTab): Disposer
96
+ }
97
+
98
+ markdown: {
99
+ /** Runs on every rendered block of Markdown: the reading view and embedded notes. */
100
+ registerPostProcessor(processor: PostProcessor): Disposer
101
+ /** Renders fenced code blocks of `language` into `element` instead of showing the code. */
102
+ registerCodeBlockProcessor(language: string, processor: CodeBlockProcessor): Disposer
103
+ }
104
+
105
+ storage: {
106
+ load<T = unknown>(): Promise<T | null>
107
+ save(data: unknown): Promise<void>
108
+ }
109
+
110
+ /** Flint's own CodeMirror modules. Use these instead of bundling CodeMirror. */
111
+ codemirror: {
112
+ state: typeof state
113
+ view: typeof view
114
+ language: typeof language
115
+ autocomplete: typeof autocomplete
116
+ }
117
+ }
118
+
119
+ /** The default export of a plugin's `main.js`. It may return a cleanup function. */
120
+ export type ActivatePlugin = (
121
+ flint: FlintApi,
122
+ ) => Disposer | undefined | Promise<Disposer | undefined>
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "flint-plugin-api",
3
+ "version": "0.6.0",
4
+ "description": "TypeScript types for writing Flint plugins",
5
+ "license": "AGPL-3.0-or-later",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/cucsijuan/flint.git",
9
+ "directory": "plugin-api"
10
+ },
11
+ "homepage": "https://github.com/cucsijuan/flint/tree/main/plugin-api#readme",
12
+ "keywords": [
13
+ "flint",
14
+ "plugin",
15
+ "markdown",
16
+ "notes"
17
+ ],
18
+ "types": "index.d.ts",
19
+ "files": [
20
+ "index.d.ts"
21
+ ],
22
+ "dependencies": {
23
+ "@codemirror/autocomplete": "^6.20.3",
24
+ "@codemirror/language": "^6.12.4",
25
+ "@codemirror/state": "^6.7.6",
26
+ "@codemirror/view": "^6.43.13"
27
+ }
28
+ }