UNPKG

@blacksmithgu/datacore

Version:

Reactive data engine for Obsidian.md.

1,056 lines (1,005 loc) 113 kB
import { App } from 'obsidian'; import { Component } from 'obsidian'; import { ComponentChildren } from 'preact'; import { CSSProperties } from 'preact/compat'; import { DateTime } from 'luxon'; import { Duration } from 'luxon'; import { EventRef } from 'obsidian'; import { Events } from 'obsidian'; import { FileManager } from 'obsidian'; import * as hooks from 'preact/hooks'; import { HTMLAttributes } from 'preact/compat'; import { JSX as JSX_2 } from 'preact/compat'; import { JSX as JSX_3 } from 'preact/jsx-runtime'; import { JSX as JSX_4 } from 'preact'; import * as luxon_2 from 'luxon'; import { MarkdownPostProcessorContext } from 'obsidian'; import { MarkdownRenderChild } from 'obsidian'; import { MetadataCache } from 'obsidian'; import { Plugin as Plugin_2 } from 'obsidian'; import * as preact_2 from 'preact'; import { PropsWithChildren } from 'preact/compat'; import { Queue } from '@datastructures-js/queue'; import { default as React_2 } from 'preact/compat'; import { ReactNode } from 'preact/compat'; import { TFile } from 'obsidian'; import { Vault } from 'obsidian'; import { VNode } from 'preact'; /** Arithmetic operators which yield numbers and other values. */ export declare type ArithmeticOp = "+" | "-" | "*" | "/" | "%" | "&" | "|"; /** @public A function which compares two types. */ export declare type ArrayComparator<T> = (a: T, b: T) => number; /** @public A function which maps an array element to some value. */ export declare type ArrayFunc<T, O> = (elem: T, index: number, arr: T[]) => O; /** Shared metadata for all canvas cards. */ export declare abstract class BaseCanvasCard implements Indexable, Linkable { abstract $types: string[]; abstract $typename: string; abstract readonly $type: string; $revision?: number | undefined; $id: string; $position: CardPos; $dimensions: CardDimensions; $parent?: Indexable; $file: string; $color?: string; constructor(init: Partial<BaseCanvasCard>); get $link(): Link; /** @internal */ json(): JsonBaseCanvasCard; } /** All valid binary operators. */ export declare type BinaryOp = CompareOp | ArithmeticOp | LogicalOp; /** A binary operator expression which combines two subnodes somehow. */ export declare interface BinaryOpExpression { type: "binaryop"; left: Expression; right: Expression; op: BinaryOp; } /** Provides implementations for binary operators on two types using a registry. */ declare class BinaryOpHandler { private map; private handleDefaultNulls; static create(): BinaryOpHandler; constructor(); register<T extends LiteralTypeOrAll, U extends LiteralTypeOrAll>(left: T, op: BinaryOp, right: U, func: BinaryOpImpl<LiteralReprAll<T>, LiteralReprAll<U>>): BinaryOpHandler; registerResult<T extends LiteralTypeOrAll, U extends LiteralTypeOrAll>(left: T, op: BinaryOp, right: U, func: BinaryOpResultImpl<LiteralReprAll<T>, LiteralReprAll<U>>): BinaryOpHandler; registerComm<T extends LiteralTypeOrAll, U extends LiteralTypeOrAll>(left: T, op: BinaryOp, right: U, func: BinaryOpImpl<LiteralReprAll<T>, LiteralReprAll<U>>): BinaryOpHandler; /** If enabled, all null (op) null operations produce null. */ withDefaultNullHandling(): BinaryOpHandler; /** Implement a comparison function. */ compare<T extends LiteralTypeOrAll>(type: T, compare: CompareImpl<LiteralReprAll<T>>): BinaryOpHandler; /** Attempt to evaluate the given binary operator on the two literal fields. */ evaluate(op: BinaryOp, left: Literal, right: Literal, ctx: Evaluator): Result<Literal, string>; /** Create a string representation of the given triplet for unique lookup in the map. */ static repr(op: BinaryOp, left: LiteralTypeOrAll, right: LiteralTypeOrAll): string; } /** An implementation for a binary operator. */ declare type BinaryOpImpl<A extends Literal, B extends Literal> = (first: A, second: B, ctx: Evaluator) => Literal; /** Binary operator which can fail and produce an error. */ declare type BinaryOpResultImpl<A extends Literal, B extends Literal> = (first: A, second: B, ctx: Evaluator) => Result<Literal, string>; /** * Wrapper for a regular HTML button with some default classes. * @group Components */ export declare function Button(props: { className?: string; intent?: Intent; children: ComponentChildren; } & React_2.ComponentProps<"button">): React_2.JSX.Element; /** A piece of data that has been cached for a specific version and time. */ declare interface Cached<T> { /** The version of the plugin that the data was written to cache with. */ version: string; /** The UNIX epoch time in milliseconds that the data was written to cache. */ time: number; /** The data that was cached. */ data: T; } /** * @group Components * @param props {@inheritDoc CalloutProps} */ export declare function Callout({ collapsible, open: openProp, initialOpen, onOpenChange, title, icon, children, type, }: PropsWithChildren<CalloutProps>): JSX_4.Element; /** General properties for configuring a callout. * @group Props */ export declare interface CalloutProps { /** Title of the callout. */ title: string | VNode; /** Arbitrary icon to show at the left side of the title in the callout. */ icon?: VNode; /** The type of the callout. */ type?: string; /** Whether the callout is collapsible (defaults to true). */ collapsible?: boolean; /** Controlled prop for setting whether the callout is open. */ open: boolean; /** Whether the callout is initially open if uncontrolled. */ initialOpen?: boolean; /** Called whenever the open state of the callout changes due to user action. */ onOpenChange?: (value: boolean) => void; } /** A canvas file, consisting of a set of canvas cards. */ export declare class Canvas implements Linkable, File_2, Linkbearing, Taggable, Indexable, Fieldbearing { static TYPES: string[]; $types: string[]; $typename: string; /** Time that the file was created on the file system. */ $ctime: DateTime; /** The that the file was last modified on the file system. */ $mtime: DateTime; /** File extension - for canvas files, generally always 'canvas'. */ $extension: string; /** The full path of the canvas file. */ get $file(): string; get $id(): string; /** A link object pointing to the canvas file. */ get $link(): Link; $path: string; $cards: BaseCanvasCard[]; $size: number; $tags: string[]; $links: Link[]; $infields: Record<string, InlineField>; private constructor(); get fields(): Field[]; field(key: string): Field | undefined; json(): JsonCanvas; static from(raw: JsonCanvas, normalizer?: LinkNormalizer): Canvas; private static FIELD_DEF; } /** All supported canvas card types. */ export declare type CanvasCard = CanvasTextCard | CanvasFileCard | CanvasWebCard; /** Canvas card that is just a file embedding. */ export declare class CanvasFileCard extends BaseCanvasCard implements Indexable { static TYPES: string[]; $types: string[]; $typename: string; private constructor(); readonly $type: string; $linkedFile: string; /** @internal */ json(): JsonCanvasFileCard; /** @internal */ static from(raw: JsonCanvasFileCard): CanvasFileCard; } /** Canvas card with markdown text in it. */ export declare class CanvasTextCard extends BaseCanvasCard implements Linkbearing, Taggable, Indexable, Fieldbearing { static TYPES: string[]; $types: string[]; $typename: string; $type: string; $id: string; $file: string; $links: Link[]; $tags: string[]; $title: string; $parent?: Indexable; $revision?: number; $infields: Record<string, InlineField>; $frontmatter?: Record<string, FrontmatterEntry>; $dimensions: CardDimensions; $sections: MarkdownSection[]; private constructor(); get fields(): Field[]; field(key: string): Field | undefined; /** @internal */ json(): JsonCanvasTextCard; /** @internal */ static from(raw: JsonCanvasTextCard, file: string, normalizer?: LinkNormalizer): CanvasTextCard; static FIELD_DEF: FieldExtractor<CanvasTextCard>; } export declare class CanvasWebCard extends BaseCanvasCard implements Indexable { static TYPES: string[]; $types: string[]; readonly $type: string; $typename: string; $url: string; private constructor(); /** @internal */ json(): JsonCanvasWebCard; /** @internal */ static from(raw: JsonCanvasWebCard, file: string): CanvasWebCard; } /** * A card with a title and content * * @group Components */ export declare function Card<T>(props: CardProps<T>): JSX_4.Element; /** 2D dimensions of a canvas card in logical units. */ export declare interface CardDimensions { width: number; height: number; } /** Absolute x, y position of a card on the canvas in logical units. */ export declare interface CardPos { x: number; y: number; } /** * Props for the card component * * @group Props */ export declare interface CardProps<T> { /** the actual value held in this card. */ value: T; /** The title of the card. */ title: Literal | ((val: T) => Literal | VNode); /** The raw content of the card. */ content: Literal | ((val: T) => Literal | VNode); /** optional footer (because why not?) */ footer?: Literal | ((val: T) => Literal | VNode); /** If true, the title will be rendered centered. */ centerTitle?: boolean; } /** * A checkbox that can be checked and unchecked. * @group Components */ export declare function Checkbox(props: { className?: string; disabled?: boolean; checked?: boolean; defaultChecked?: boolean; onCheckChange?: (checked: boolean) => void; children?: ComponentChildren; } & React_2.ComponentProps<"input">): React_2.JSX.Element; declare namespace Coerce { /** Coerces common types to string or otherwise undefined. */ function string(value: Literal): string | undefined; /** Coerces booleans and string-booleans. */ function boolean(value: Literal): boolean | undefined; /** Coerces numbers and strings to numbers. */ function number(value: Literal): number | undefined; /** Coerces dates and strings into dates. */ function date(value: Literal): DateTime | undefined; /** Coerces durations and strings into durations. */ function duration(value: Literal): Duration | undefined; /** Coerces links and strings into links. */ function link(value: Literal): Link | undefined; /** Coerces anything into an array, by converting non-arrays into unit length arrays. */ function array(value: Literal): Literal[] | undefined; } /** * Appends additional classes to a basic fixed class. * @group Utilities * */ export declare function combineClasses(fixed: string, ...rest: (string | undefined)[]): string; /** An implementation of a comparator (returning a number) which then automatically defines all of the comparison operators. */ declare type CompareImpl<T extends Literal> = (first: T, second: T, ctx: Evaluator) => number; /** Comparison operators which yield true/false. */ export declare type CompareOp = ">" | ">=" | "<=" | "<" | "=" | "!="; /** * @public Proxied interface which allows manipulating array-based data. All functions on a data array produce a NEW array * (i.e., the arrays are immutable). */ export declare interface DataArray<T> { /** The total number of elements in the array. */ length: number; /** Applies the given function to the entire data array. Allows using function chaining while applying an arbitrary intermediate function. */ chain<U>(op: (arr: DataArray<T>) => DataArray<U>): DataArray<U>; /** Filter the data array down to just elements which match the given predicate. */ where(predicate: ArrayFunc<T, boolean>): DataArray<T>; /** Alias for 'where' for people who want array semantics. */ filter(predicate: ArrayFunc<T, boolean>): DataArray<T>; /** Map elements in the data array by applying a function to each. */ map<U>(f: ArrayFunc<T, U>): DataArray<U>; /** Map elements in the data array by applying a function to each, then flatten the results to produce a new array. */ flatMap<U>(f: ArrayFunc<T, U[]>): DataArray<U>; /** Mutably change each value in the array, returning the same array which you can further chain off of. */ mutate(f: ArrayFunc<T, void>): DataArray<T>; /** Limit the total number of entries in the array to the given value. */ limit(count: number): DataArray<T>; /** * Take a slice of the array. If `start` is undefined, it is assumed to be 0; if `end` is undefined, it is assumbed * to be the end of the array. */ slice(start?: number, end?: number): DataArray<T>; /** Concatenate the values in this data array with those of another iterable / data array / array. */ concat(other: Iterable<T>): DataArray<T>; /** Return the first index of the given (optionally starting the search) */ indexOf(element: T, fromIndex?: number): number; /** Return the first element that satisfies the given predicate. */ find(pred: ArrayFunc<T, boolean>): T | undefined; /** Find the index of the first element that satisfies the given predicate. Returns -1 if nothing was found. */ findIndex(pred: ArrayFunc<T, boolean>, fromIndex?: number): number; /** Returns true if the array contains the given element, and false otherwise. */ includes(element: T): boolean; /** * Return a string obtained by converting each element in the array to a string, and joining it with the * given separator (which defaults to ', '). */ join(sep?: string): string; /** * Return a sorted array sorted by the given key; an optional comparator can be provided, which will * be used to compare the keys in leiu of the default dataview comparator. */ sort<U>(key: ArrayFunc<T, U>, direction?: "asc" | "desc", comparator?: ArrayComparator<U>): DataArray<T>; /** * Mutably modify the current array with an in place sort; this is less flexible than a regular sort in exchange * for being a little more performant. Only use this is performance is a serious consideration. */ sortInPlace<U>(key: (v: T) => U, direction?: "asc" | "desc", comparator?: ArrayComparator<U>): DataArray<T>; /** * Return an array where elements are grouped by the given key; the resulting array will have objects of the form * \`{ key: \<key value\>, rows: DataArray }`. */ groupBy<U>(key: ArrayFunc<T, U>, comparator?: ArrayComparator<U>): DataArray<{ key: U; rows: T[]; }>; /** * If the array is not grouped, groups it as `groupBy` does; otherwise, groups the elements inside each current * group. This allows for top-down recursive grouping which may be easier than bottom-up grouping. */ groupIn<U>(key: ArrayFunc<LowestKey<T>, U>, comparator?: ArrayComparator<U>): DataArray<Ingrouped<U, T>>; /** * Return distinct entries. If a key is provided, then rows with distinct keys are returned. */ distinct<U>(key?: ArrayFunc<T, U>, comparator?: ArrayComparator<U>): DataArray<T>; /** Return true if the predicate is true for all values. */ every(f: ArrayFunc<T, boolean>): boolean; /** Return true if the predicate is true for at least one value. */ some(f: ArrayFunc<T, boolean>): boolean; /** Return true if the predicate is FALSE for all values. */ none(f: ArrayFunc<T, boolean>): boolean; /** Return the first element in the data array. Returns undefined if the array is empty. */ first(): T | undefined; /** Return the last element in the data array. Returns undefined if the array is empty. */ last(): T | undefined; /** Map every element in this data array to the given key, and then flatten it.*/ to(key: string): DataArray<any>; /** Map every element in this data array to the given key; unlike to(), does not flatten the result. */ into(key: string): DataArray<any>; /** * Recursively expand the given key, flattening a tree structure based on the key into a flat array. Useful for handling * heirarchical data like tasks with 'subtasks'. */ expand(key: string): DataArray<any>; /** Run a lambda on each element in the array. */ forEach(f: ArrayFunc<T, void>): void; /** Convert this to a plain javascript array. */ array(): T[]; /** Allow iterating directly over the array. */ [Symbol.iterator](): Iterator<T>; /** Map indexes to values. */ [index: number]: any; /** Automatic flattening of fields. Equivalent to implicitly calling `array.to("field")` */ [field: string]: any; } /** @public Provides utility functions for generating data arrays. */ export declare namespace DataArray { /** Create a new Dataview data array. */ export function wrap<T>(raw: T[] | DataArray<T>): DataArray<T>; /** Create a new DataArray from an iterable object. */ export function from<T>(raw: Iterable<T>): DataArray<T>; /** Return true if the given object is a data array. */ export function isDataArray(obj: any): obj is DataArray<any>; } /** Central API object; handles initialization, events, debouncing, and access to datacore functionality. */ export declare class Datacore extends Component { app: App; version: string; settings: Settings; /** Access to the obsidian vault. */ vault: Vault; /** Provides access to per-(markdown)-file metadata. */ metadataCache: MetadataCache; /** Datacore events, mainly used to update downstream views. This object is shadowed by the Datacore object itself. */ events: Events; /** @internal In-memory index over all stored metadata. */ datastore: Datastore; /** @internal Asynchronous multi-threaded file importer with throttling. */ importer: FileImporter; /** @internal Queue of asynchronous read requests; ensures we limit the maximum number of concurrent file loads. */ reads: EmbedQueue; /** @internal Local-storage backed cache of metadata objects. */ persister: LocalStorageCache; /** @internal Only set when datacore is in the midst of initialization; tracks current progress. */ initializer?: DatacoreInitializer; /** If true, datacore is fully hydrated and all files have been indexed. */ initialized: boolean; constructor(app: App, version: string, settings: Settings); /** Obtain the current index revision, for determining if anything has changed. */ get revision(): number; /** Initialize datacore by scanning persisted caches and all available files, and queueing parses as needed. */ initialize(): void; /** Starts the background initializer. */ index(): void; private rename; /** * Read a file from the Obsidian cache efficiently, limiting the number of concurrent request and debouncing * multiple requests for the same file. */ read(file: TFile): Promise<string>; /** Queue a file for reloading; this is done asynchronously in the background and may take a few seconds. */ reload(file: TFile): Promise<Indexable>; /** Store a canvas document. */ storeCanvas(data: Canvas): void; /** Store a markdown document. */ storeMarkdown(data: MarkdownPage): void; /** Called whenever the index updates to a new revision. This is the broadest possible datacore event. */ on(evt: "update", callback: (revision: number) => any, context?: any): EventRef; /** Called whenever datacore records a file rename and has finished reindexing the rename. */ on(evt: "rename", callback: (newPath: string, oldPath: string) => any, context?: any): EventRef; /** Called when datacore has initialized and is querable. */ on(evt: "initialized", callback: () => any, context?: any): EventRef; /** Unsubscribe from an event using the event and original callback. */ off(evt: string, callback: (...data: any) => any): void; /** Unsubscribe from an event using the event reference. */ offref(ref: EventRef): void; /** Trigger an update event. */ private trigger; } /** * Exterally visible API for datacore. * @public */ export declare class DatacoreApi { core: Datacore; constructor(core: Datacore); /** Get access to luxon functions. */ get luxon(): typeof luxon_2; /** Get access to preact functions. */ get preact(): typeof preact_2; /** Central Obsidian app object. */ get app(): App; /** Construct a local API for the file at the given path. */ local(path: string): DatacoreLocalApi; /** Load a markdown file by full path or link. */ page(path: string | Link): MarkdownPage | undefined; /** Execute a textual or typed index query, returning all results. */ query(query: string | IndexQuery): Indexable[]; /** Execute a textual or typed index query, returning all results. */ tryQuery(query: string | IndexQuery): Result<Indexable[], string>; /** Execute a textual or typed index query, returning results plus performance metadata. */ fullquery(query: string | IndexQuery): SearchResult<Indexable>; /** Execute a textual or typed index query, returning results plus performance metadata. */ tryFullQuery(query: string | IndexQuery): Result<SearchResult<Indexable>, string>; /** Utilities for coercing types into one specific type for easier programming. */ coerce: typeof Coerce; /** Resolve a local or absolute path or link to an absolute path. */ resolvePath(path: string | Link, sourcePath?: string): string; /** Try to parse the given query, returning a monadic success/failure result. */ tryParseQuery(query: string | IndexQuery): Result<IndexQuery, string>; /** Try to parse the given query, throwing an error if it is invalid. */ parseQuery(query: string | IndexQuery): IndexQuery; /** Create a file link pointing to the given path. */ fileLink(path: string): Link; /** Create a link to a header with the given name. */ headerLink(path: string, header: string): Link; /** Create a link to a block with the given path and block ID. */ blockLink(path: string, block: string): Link; /** Try to parse the given link, throwing an error if it is invalid. */ parseLink(linktext: string): Link; /** Try to parse a link, returning a monadic success/failure result. */ tryParseLink(linktext: string): Result<Link, string>; /** Create a data array from a regular array. */ array<T>(input: T[] | DataArray<T>): DataArray<T>; /** Evaluate an expression and return it's evaluated value, throwing an exception on failure. */ evaluate(expression: string | Expression, variables?: Record<string, Literal> | any, sourcePath?: string): Literal; /** Evaluate an expression and return it's evaluated value. */ tryEvaluate(expression: string | Expression, variables?: Record<string, Literal> | any, sourcePath?: string): Result<Literal, string>; /** * Run the given DatacoreJS script, rendering it into the given container. This function * will return quickly; actual rendering is done asynchronously in the background. * * Returns a markdown render child representing the rendered object. */ executeJs(source: string, container: HTMLElement, component: Component | MarkdownPostProcessorContext, sourcePath: string): MarkdownRenderChild; /** * Similar to `executeJs`, but for JSX scripts. If you are unsure if your input will be JS * or JSX, use this one, as it also supports regular javascript (albeit at at a mild performance * hit to rendering). */ executeJsx(source: string, container: HTMLElement, component: Component | MarkdownPostProcessorContext, sourcePath: string): MarkdownRenderChild; /** * Similar to `executeJs`, but for TypeScript scripts. Use the TSX variant for TSX supprot. */ executeTs(source: string, container: HTMLElement, component: Component | MarkdownPostProcessorContext, sourcePath: string): MarkdownRenderChild; /** * Similar to `executeTs`, but for TSX scripts. If you are unsure if your input will be TS * or TSX, use this one, as it also supports regular javascript (albeit at at a mild performance * hit to rendering). * * This generally will also work if you are unsure if your input is javascript or typescript, * though beware there are a few niche cases where javascript and typescript diverge in syntax. */ executeTsx(source: string, container: HTMLElement, component: Component | MarkdownPostProcessorContext, sourcePath: string): MarkdownRenderChild; /** Shared logic for rendering any JS/TS script. */ private _renderJavascript; } /** Lifecycle-respecting file queue which will import files, reading them from the file cache if needed. */ declare class DatacoreInitializer extends Component { core: Datacore; /** Number of concurrent operations the initializer will perform. */ static BATCH_SIZE: number; /** Whether the initializer should continue to run. */ active: boolean; /** Queue of files to still import. */ queue: TFile[]; /** The files actively being imported. */ current: TFile[]; /** Deferred promise which resolves when importing is done. */ done: Deferred<InitializationStats>; /** The total number of target files to import. */ targetTotal: number; /** The time that init started in milliseconds. */ start: number; /** Total number of files to import. */ files: number; /** Total number of imported files so far. */ initialized: number; /** Total number of imported files. */ imported: number; /** Total number of skipped files. */ skipped: number; /** Total number of cached files. */ cached: number; constructor(core: Datacore); onload(): Promise<void>; /** Promise which resolves when the initialization completes. */ finished(): Promise<InitializationStats>; /** Cancel initialization. */ onunload(): void; /** Poll for another task to execute from the queue. */ private runNext; /** Process the result of an initialization and queue more runs. */ private handleResult; /** Initialize a specific file. */ private init; } /** * Local API provided to specific codeblocks when they are executing. * @public */ export declare class DatacoreLocalApi { api: DatacoreApi; path: string; /** * The cache of all currently loaded scripts in this context. * @private * @internal */ private scriptCache; constructor(api: DatacoreApi, path: string); /** The current file path for the local API. */ currentPath(): string; /** The full markdown file metadata for the current file. */ currentFile(): MarkdownPage; /** Get acess to luxon functions. */ get luxon(): typeof luxon_2; /** Get access to preact functions. */ get preact(): typeof preact_2; /** Central Obsidian app object. */ get app(): App; /** The internal plugin central datastructure. */ get core(): Datacore; /** * Asynchronously load a javascript block from the given path or link; you can either load from JS/TS/JSX/TSX files * directly, or from codeblocks by loading from the section the codeblock is inside of. There are a few stipulations * to loading: * - You cannot load cyclical dependencies. * - This is similar to vanilla js `require()`, not `import ... `. Your scripts you are requiring need to explicitly * return the things they are exporting, like the example below. The `export` keyword does not work. * * ```js * function MyElement() { * ... * } * * return { MyElement }; * ``` */ require(path: string | Link): Promise<any>; /** Utilities for coercing types into one specific type for easier programming. */ coerce: typeof Coerce; /** Resolve a local or absolute path or link to an absolute path. */ resolvePath(path: string | Link, sourcePath?: string): string; /** Try to parse the given query, returning a monadic success/failure result. */ tryParseQuery(query: string | IndexQuery): Result<IndexQuery, string>; /** Try to parse the given query, throwing an error if it is invalid. */ parseQuery(query: string | IndexQuery): IndexQuery; /** Create a file link pointing to the given path. */ fileLink(path: string): Link; /** Create a link to a header with the given name. */ headerLink(path: string, header: string): Link; /** Create a link to a block with the given path and block ID. */ blockLink(path: string, block: string): Link; /** Try to parse the given link, throwing an error if it is invalid. */ parseLink(linktext: string): Link; /** Try to parse a link, returning a monadic success/failure result. */ tryParseLink(linktext: string): Result<Link, string>; /** Create a data array from a regular array. */ array<T>(input: T[] | DataArray<T>): DataArray<T>; /** Evaluate an expression and return it's evaluated value. */ evaluate(expression: string | Expression, variables?: Record<string, Literal> | any, sourcePath?: string): Literal; /** Evaluate an expression and return it's evaluated value, throwing an exception on failure. */ tryEvaluate(expression: string | Expression, variables?: Record<string, Literal> | any, sourcePath?: string): Result<Literal, string>; /** Execute a textual or typed index query, returning all results. */ query(query: string | IndexQuery): Indexable[]; /** Execute a textual or typed index query, returning all results. */ tryQuery(query: string | IndexQuery): Result<Indexable[], string>; /** Execute a textual or typed index query, returning results plus performance metadata. */ fullquery(query: string | IndexQuery): SearchResult<Indexable>; /** Execute a textual or typed index query, returning results plus performance metadata. */ tryFullQuery(query: string | IndexQuery): Result<SearchResult<Indexable>, string>; /** See the preact or react 'useState' hook. */ useState: typeof hooks.useState; /** See the preact or react 'useCallback' hook. */ useCallback: typeof hooks.useCallback; /** Se the preact or react 'useReducer' hook. */ useReducer: typeof hooks.useReducer; /** See the preact or react 'useMemo' hook. */ useMemo: typeof hooks.useMemo; /** See the preact or react 'useEffect' hook. */ useEffect: typeof hooks.useEffect; /** See the preact or react 'createContext' function. */ createContext: typeof preact_2.createContext; /** See the preact or react 'useContext' function. */ useContext: typeof hooks.useContext; /** See the preact or react 'useRef' function. */ useRef: typeof hooks.useRef; /** * Calls a function to obtain a value; returns the same exact _instance_ of that value as long * as calls to the function return an equivalent value. Interning is a useful performance concept * for reducing the total number of unique objects in memory and for making better use of * React's reference-equality-based caching. */ useInterning: typeof useInterning; /** Memoize the input automatically and process it using a DataArray; returns a vanilla array back. */ useArray<T, U>(input: T[] | DataArray<T>, process: (data: DataArray<T>) => DataArray<U>, deps?: any[]): U[]; /** Use the file metadata for the current file. Automatically updates the view when the current file metadata changes. */ useCurrentFile(settings?: { debounce?: number; }): MarkdownPage; /** Use the current path. Automatically updates the view if the path changes (though that would be weird). */ useCurrentPath(settings?: { debounce?: number; }): string; /** Use the file metadata for a specific file. Automatically updates the view when the file changes. */ useFile(path: string, settings?: { debounce?: number; }): Indexable | undefined; /** Automatically refresh the view whenever the index updates; returns the latest index revision ID. */ useIndexUpdates(settings?: { debounce?: number; }): number; /** * Run a query, automatically re-running it whenever the vault changes. Returns more information about the query * execution, such as index revision and total search duration. */ useFullQuery(query: string | IndexQuery, settings?: { debounce?: number; }): SearchResult<Indexable>; /** Run a query, automatically re-running it whenever the vault changes. */ useQuery(query: string | IndexQuery, settings?: { debounce?: number; }): Indexable[]; /** Vertical flexbox container; good for putting items together in a column. */ Stack: typeof Stack; /** Horizontal flexbox container; good for putting items together in a row. */ Group: typeof Group; /** Renders a literal value in a pretty way that respects settings. */ Literal: any; /** Renders markdown using the Obsidian markdown renderer, optionally attaching additional styles. */ Markdown: any; /** Renders an obsidian-style link directly and more efficiently than rendering markdown. */ Link: ({ link, sourcePath: maybeSourcePath }: { link: string | Link; sourcePath?: string | undefined; }) => preact_2.JSX.Element; /** Create a vanilla Obsidian embed for the given link. */ LinkEmbed: any; /** Create an explicit 'span' embed which extracts a span of lines from a markdown file. */ SpanEmbed: any; /** Renders an obsidian lucide icon. */ Icon: typeof Icon; /** * Generate an embed of the given markdown element. Useful to pass to the 'renderer' prop of various views * to efficiently render embeds of various elements. * * For example, `dc.embed(<file>)` will produce a file embedding, and `dc.embed(<section>)` will produce a section embedding. */ embed: any; /** @deprecated - Use just `Table` instead. */ VanillaTable: typeof TableView; /** A simple and configurable table view that supports rendering paged and grouped data. */ Table: typeof TableView; /** A simple and configurable list view that supports rendering paged and grouped data. */ List: typeof ListView; /** A single card which can be composed into a grid view. */ Card: typeof Card; Button: typeof Button; Textbox: typeof Textbox; Callout: typeof Callout; Checkbox: typeof Checkbox; Slider: typeof Slider; Switch: typeof Switch; VanillaSelect: typeof VanillaSelect; } /** Reactive data engine for your Obsidian.md vault. */ export declare class DatacorePlugin extends Plugin_2 { /** Plugin-wide default settings. */ settings: Settings; /** Central internal state. */ core: Datacore; /** Externally visible API for querying. */ api: DatacoreApi; onload(): Promise<void>; onunload(): void; /** Register codeblock highlighting and return a closure which unregisters. */ registerCodeblockHighlighting(): () => void; /** Update the given settings to new values. */ updateSettings(settings: Partial<Settings>): Promise<void>; } /** Shorthand for a mapping from keys to values. */ export declare type DataObject = Record<string, any>; /** * Central, index storage for datacore values. * @internal */ export declare class Datastore { vault: Vault; metadataCache: MetadataCache; settings: Settings; /** The current store revision. */ revision: number; /** * Master collection of all object IDs. This is technically redundant with objects.keys() but this is a fast set * compared to an iterator. */ private ids; /** The master collection of ALL indexed objects, mapping ID -> the object. */ private objects; /** Map parent object to it's direct child objects. */ private children; /** Global map of object type -> list of all objects of that type. */ private types; /** Tracks exact tag occurence in objects. */ private etags; /** Tracks tag occurence in objects. */ private tags; /** Maps link strings to the object IDs that link to those links. */ private links; /** Tracks the existence of fields (indexed by normalized key name). */ private fields; /** * Quick searches for objects in folders. This index only tracks top-level objects - it is expanded recursively to * find child objects. */ private folder; constructor(vault: Vault, metadataCache: MetadataCache, settings: Settings); /** Return the total number of objects in the store. */ get size(): number; /** Update the revision of the datastore due to an external update. */ touch(): void; /** Load an object by ID. */ load(id: string): Indexable | undefined; /** Load a list of objects by ID. */ load(ids: string[]): Indexable[]; /** Sets up sane field defaults for several indexable fields. */ private _initializeFields; /** * Store the given object, making it immediately queryable. Storing an object * takes ownership over it, and index-specific variables (prefixed via '$') may be * added to the object. */ store<T extends Indexable>(object: T | T[], substorer?: Substorer<T>): void; /** Recursively store objects using a potential subindexer. */ private _recursiveStore; /** Delete an object by ID from the index, recursively deleting any child objects as well. */ delete(id: string): boolean; /** Internal method that does not bump the revision. */ private _deleteRecursive; /** Add the given indexable to the appropriate indices. */ private _index; /** Remove the given indexable from all indices. */ private _unindex; /** Completely clear the datastore of all values. */ clear(): void; /** Find the corresponding object for a given link. */ resolveLink(rawLink: string | Link, sourcePath?: string): Indexable | undefined; /** * Search the datastore for all documents matching the given query, returning them * as a list of indexed objects along with performance metadata. */ search(query: IndexQuery, settings?: SearchSettings): Result<SearchResult<Indexable>, string>; /** Create an expression evaluator backed by this datastore. */ evaluator(sourcePath?: string, globals?: Record<string, Literal>): Evaluator; /** Internal search which yields a filter of results. */ private _search; private _resolveSource; /** Resolve leaf nodes in a search AST, yielding raw sets of results. */ private _resolvePrimitive; /** Filter documents by field values, using the fast lookup if it returns a result and otherwise filtering over every document using the slow predicate. */ private _filterFields; /** * Does Breadth-first Search to find all linked files within distance <distance>. This includes all source nodes, * so remove them afterwards if you do not want them. */ private _traverseLinked; /** Iterate all linked objects for the given object. */ private _iterateAdjacentLinked; /** Iterator which produces all parents of the given object. */ private _iterateParents; /** Iterative which produces all children (recursively) of the given object. */ private _iterateChildren; } /** A promise that can be resolved directly. */ declare type Deferred<T> = Promise<T> & { resolve: (value: T) => void; reject: (error: any) => void; }; /** Queues up loads of files to reduce the maximum number of concurrent loads. */ declare class EmbedQueue extends Component { vault: Vault; concurrency: () => number; /** Set of pending loads. */ private queue; /** Set of promises waiting on each path. */ private promises; /** Active set of loads. */ private active; /** If true, prevent any further loads. */ private shutdown; constructor(vault: Vault, concurrency: () => number); /** Read a file asynchronously, controlling concurrency to prevent too many files being loaded simultaneously. */ read(file: TFile): Promise<string>; /** Schedule more loads from the queue into the active set if there is available space. */ private schedule; /** Communicate the result of a loaded file and then schedule more files to be loaded. */ private finish; /** Cancell all outstanding loads on unload. */ onunload(): void; } /** * Evaluation context that expressions can be evaluated in. Includes global state, as well as available functions and a handler * for binary operators. */ declare class Evaluator { linkHandler: LinkHandler; settings: Settings; globals: Record<string, Literal>; binaryOps: BinaryOpHandler; functions: Record<string, FunctionImpl>; /** * Create a new context with the given namespace of globals, as well as optionally with custom binary operator, function, * and link handlers. */ constructor(linkHandler: LinkHandler, settings: Settings, globals?: Record<string, Literal>, binaryOps?: BinaryOpHandler, functions?: Record<string, FunctionImpl>); /** Set a global value in this context. */ set(name: string, value: Literal): Evaluator; /** Get the value of a global variable by name. Returns null if not present. */ get(name: string): Literal; /** Try to evaluate an arbitrary expression in this context, raising an exception on failure. */ tryEvaluate(expr: Expression, variables?: Variables): Literal; /** Evaluate an arbitrary expression in this context. */ evaluate(expr: Expression, variables?: Variables): Result<Literal, string>; /** General logic for making a function call. */ private evaluateFunctionCall; } export declare type Expression = LiteralExpression | VariableExpression | ListExpression | ObjectExpression | BinaryOpExpression | FunctionExpression | MethodExpression | LambdaExpression | NegatedExpression; export declare namespace Expressions { /** The implicit field referencing the current field. */ const ROW: string; export function variable(name: string): VariableExpression; export function literal(value: Literal): LiteralExpression; export function binaryOp(left: Expression, op: BinaryOp, right: Expression): Expression; export function index(obj: Expression, index: Expression): Expression; /** Converts a string in dot-notation-format into a variable which indexes. */ export function indexVariable(name: string): Expression; export function lambda(args: string[], value: Expression): LambdaExpression; export function method(target: Expression, func: string, args: Expression[]): MethodExpression; export function func(func: Expression, args: Expression[]): FunctionExpression; export function list(values: Expression[]): ListExpression; export function object(values: Record<string, Expression>): ObjectExpression; export function negate(child: Expression): NegatedExpression; export function isCompareOp(op: BinaryOp): op is CompareOp; /** Returns a set of all unbound variables (i.e., variables not provided by `row`, lambdas, or similar.) */ export function unboundVariables(expr: Expression, bound?: Set<string>): Set<string>; /** Render an expression as a string. */ export function toString(expr: Expression): string; const NULL: LiteralExpression; } /** Quick utilities for generating fields and doing searches over them. * @hidden */ export declare namespace Extractors { /** Generate a list of fields for the given object, returning them as a list. */ export function intrinsics<T extends Record<string, any>>(except?: Set<string>): FieldExtractor<T>; /** Field extractor which extracts frontmatter fields. */ export function frontmatter<T extends Indexable>(front: (object: T) => Record<string, FrontmatterEntry> | undefined): FieldExtractor<T>; /** Field extractor which shows all inline fields. */ export function inlineFields<T extends Indexable>(inlineMap: (object: T) => Record<string, InlineField> | undefined): FieldExtractor<T>; /** Merge multiple field extractors into one; if multiple extractors produce identical keys, keys from the earlier extractor will be preferred. */ export function merge<T extends Fieldbearing>(...extractors: FieldExtractor<T>[]): FieldExtractor<T>; } /** Functional return type for error handling. * @hidden */ export declare class Failure<T, E> { error: E; successful: false; constructor(error: E); map<U>(_f: (a: T) => U): Result<U, E>; flatMap<U>(_f: (a: T) => Result<U, E>): Result<U, E>; mapErr<U>(f: (e: E) => U): Result<T, U>; bimap<T2, E2>(_succ: (a: T) => T2, fail: (b: E) => E2): Result<T2, E2>; orElse(value: T): T; cast<U>(): Result<U, E>; orElseThrow(message?: (e: E) => string): T; } /** * General definition for a field. Provides the field key, value, as well as information on it's source and how it can be edited. * @group Common Types * */ export declare interface Field { /** The canonical key name for the field (i.e., as it actually shows up in the data structure). */ key: string; /** The value of the field. */ value: Literal; /** The raw value of the field before parsing, if relevant. */ raw?: string; /** If present, describes where the field came from in precise detail, allowing the field to be edited. */ provenance?: Provenance; } export declare interface Fieldbearing { /** Return a list of all fields. This may be computed eagerly, so cache this value for repeated operations. */ fields: Field[]; /** Fetch a field with the given name if it is present on this object. */ field(key: string): Field | undefined; } /** Metadata for objects which are annotated with fields. */ export declare const FIELDBEARING_TYPE = "fields"; export declare namespace Fieldbearings { export function isFieldbearing(object: any): object is Fieldbearing; /** Get a key from a generic map or fieldbearing object. */ export function get(object: Fieldbearing | Record<string, Literal>, key: string): Literal | undefined; } /** * Generic function which extract fields. If no argument is provided, it should return all fields; otherwise, * it should return the field matching the given key. * * Keys are case-insensitive to match Obsidian standard behavior. */ export declare type FieldExtractor<T> = (object: T, key?: string) => Field[]; /** * {@inheritDoc FILE_TYPE} */ declare interface File_2 extends Linkable { /** The path this file exists at. */ $path: string; /** Obsidian-provided date this page was created. */ $ctime: DateTime; /** Obsidian-provided date this page was modified. */ $mtime: DateTime; /** Obsidian-provided size of this page in bytes. */ $size: number; /** The extension of the file. */ $extension: string; } export { File_2 as File } /** General metadata for any file. */ export declare const FILE_TYPE = "file"; /** Multi-threaded file parser which debounces rapid file requests automatically. */ declare class FileImporter extends Component { vault: Vault; fileManager: FileManager; metadataCache: MetadataCache; workers: Map<number, PoolWorker>; /** The next worker ID to hand out. */ nextWorkerId: number; /** If true, the importer is now inactive and will not process further files. */ shutdown: boolean; /** List of files which have been queued for a reload. */ queue: Queue<[TFile, Deferred<any>]>; /** Outstanding loads indexed by path. */ outstanding: Map<string, Promise<any>>; /** Throttle settings. */ throttle: () => ImportThrottle; constructor(vault: Vault, fileManager: Fi