UNPKG

@velcro/resolver

Version:

Resolve references to absolute urls using the node module resolution algorithm using an generic host interface

356 lines 13.7 kB
/// <reference types="node" /> import { CancellationToken, Decoder, MapSet, PackageJson, Uri, PackageMainField, Thenable } from "@velcro/common"; declare const version = "__VERSION__"; type MaybeThenable<T> = T | Thenable<T>; interface ResolverStrategy { /** * Produce a url given the components of a bare module specifier. * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param name The name of a bare module * @param spec The optional `@version` of a bare module specifier * @param path The optional path at the end of the bare module specifier */ getUrlForBareModule?(ctx: ResolverContext, name: string, spec: string, path: string): MaybeThenable<ResolverStrategy.BareModuleResult>; /** * Determine the canonical uri for a given uri. * * For example, you might consider symlink targets their canonicalized path or you might * consider the canonicalized path of https://unpkg.com/react to be * https://unpkg.com/react@16.13.1/index.js. * * Dealing only in canonical uris means that anything produced from those can be cached. * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param uri The uri to canonicalize */ getCanonicalUrl(ctx: ResolverContext, uri: Uri): MaybeThenable<ResolverStrategy.CanonicalizeResult>; /** * Get the logical resolve root for a given uri. * * For example, a filesystem-based strategy might consider the root to be `file:///`. Or, * if it was scoped to /home/filearts, the root might be `file:///home/filearts/`. * * Any uri that is not a 'child' of the resolve root should be considered out of scope for a given * strategy. * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param uri The uri for which the logical resolve root uri should be found */ getResolveRoot(ctx: ResolverContext, uri: Uri): MaybeThenable<ResolverStrategy.ResolveRootResult>; /** * Get the settings for a given uri * * This indirection allows resolver strategies to have per-strategy or even per-uri settings. * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param uri The uri for which to load settings */ getSettings(ctx: ResolverContext, uri: Uri): MaybeThenable<ResolverStrategy.SettingsResult>; /** * Produce a list of resolved entries that are direct children of the given uri. * * This is the moral equivalent to something like non-recursive `fs.readdir()`. It is only * designed to show files and folders (for now). * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param uri The uri at which to list entries */ listEntries(ctx: ResolverContext, uri: Uri): MaybeThenable<ResolverStrategy.ListEntriesResult>; /** * Read the content at the uri as an `ArrayBuffer` * * ArrayBuffers are the lowest-common-denominator across the web and node and can easily be * decoded with standard web apis like `StringDecoder`. In Node.js, `Buffer` objects are also * `ArrayBuffer`s, allowing the tooling to be built on that primitive. * * This is helpful for the understanding that not all uris are expected to produce meaningful * text representations. * * @param ctx A `ResolverContext` that should be used for making calls to other strategy methods * @param uri The uri at which to read the content */ readFileContent(ctx: ResolverContext, uri: Uri): MaybeThenable<ResolverStrategy.ReadFileContentResult>; } interface ResolverStrategyWithRoot extends ResolverStrategy { /** * The root uri of the strategy. * * A common parent to all uris that this strategy can handle. * * This may sometimes be the same value as would be returned by `getResolveRoot` but will * sometimes be a parent of that. Take, for example Unpkg; there, we may want to express * that a strategy should 'own' all uris under https://unpkg.com/ even though the resolve * root for https://unpkg.com/react@16.13.1/index.js will actually be * https://unpkg.com/react@16.13.1/. * * Notably, the `CompoundResolverStrategy` requires all child strategies implement the * `ResolverStrategyWithRoot` interface because it dispatches operations on different * uris according to each strategy's `rootUri`. */ rootUri: Uri; } declare namespace ResolverStrategy { enum EntryKind { File = "file", Directory = "directory" } interface Entry<TKind extends EntryKind = EntryKind> { uri: Uri; type: TKind; } type BareModuleResult = { found: boolean; uri: Uri | null; }; interface CanonicalizeResult { uri: Uri; } interface ResolveRootResult { uri: Uri; } interface SettingsResult { settings: Resolver.Settings; } interface ListEntriesResult { entries: Entry[]; } interface ReadFileContentResult { content: ArrayBuffer; } } declare abstract class AbstractResolverStrategy implements ResolverStrategy { getCanonicalUrl(_ctx: ResolverContext, uri: Uri): ReturnType<ResolverStrategy["getCanonicalUrl"]>; getSettings(ctx: ResolverContext, _uri: Uri): ReturnType<ResolverStrategy["getSettings"]>; /** * Create a new ResolverStrategy having one or more methods overridden. * * You might use this if you want to override specific behaviour of another strategy without * wanting to re-implement the whole strategy. * * If you need to invoke an overridden method, the overridden strategy will be available * on `this.parent`. * * @param overrides A map of ResolverStrategy methods that you would like to override */ withOverrides(overrides: { [TMethodName in keyof ResolverStrategy]?: ResolverStrategy[TMethodName]; }): ResolverStrategy; abstract getResolveRoot(ctx: ResolverContext, uri: Uri): ReturnType<ResolverStrategy["getResolveRoot"]>; abstract listEntries(ctx: ResolverContext, uri: Uri): ReturnType<ResolverStrategy["listEntries"]>; abstract readFileContent(ctx: ResolverContext, uri: Uri): ReturnType<ResolverStrategy["readFileContent"]>; } declare abstract class AbstractResolverStrategyWithRoot extends AbstractResolverStrategy implements ResolverStrategyWithRoot { readonly rootUri: Uri; constructor(rootUri: Uri); } declare class Resolver { private disposed; readonly rootCtx: ResolverContext; private readonly settings; private readonly strategy; private readonly tokenSource; constructor(strategy: ResolverStrategy, settings: Resolver.Settings); decode(buf: BufferSource | string): string; dispose(): void; getCanonicalUrl(uri: string | Uri): Promise<ResolverStrategy.CanonicalizeResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.CanonicalizeResult & { visited: ResolverContext.Visit[]; }); getResolveRoot(uri: string | Uri): Promise<ResolverStrategy.ResolveRootResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.ResolveRootResult & { visited: ResolverContext.Visit[]; }); getSettings(uri: string | Uri): Promise<ResolverStrategy.SettingsResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.SettingsResult & { visited: ResolverContext.Visit[]; }); getUrlForBareModule(name: string, spec: string, path: string): Promise<ResolverStrategy.BareModuleResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.BareModuleResult & { visited: ResolverContext.Visit[]; }); invalidate(uri: string | Uri): boolean; listEntries(uri: Uri): Promise<ResolverStrategy.ListEntriesResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.ListEntriesResult & { visited: ResolverContext.Visit[]; }); readFileContent(uri: Uri): Promise<ResolverStrategy.ReadFileContentResult & { visited: ResolverContext.Visit[]; }> | (ResolverStrategy.ReadFileContentResult & { visited: ResolverContext.Visit[]; }); readParentPackageJson(uri: Uri): Promise<({ found: true; packageJson: import("@velcro/common").PackageJson; uri: Uri; visitedDirs: Uri[]; } & { visited: ResolverContext.Visit[]; }) | ({ found: false; packageJson: null; uri: null; } & { visited: ResolverContext.Visit[]; })> | ({ found: true; packageJson: import("@velcro/common").PackageJson; uri: Uri; visitedDirs: Uri[]; } & { visited: ResolverContext.Visit[]; }) | ({ found: false; packageJson: null; uri: null; } & { visited: ResolverContext.Visit[]; }); resolve(spec: Uri): ReturnType<ResolverContext["resolve"]>; resolve(spec: string, fromUri: Uri): ReturnType<ResolverContext["resolve"]>; } declare namespace Resolver { interface Settings { debug?: boolean; extensions: string[]; packageMain: PackageMainField[]; } } type InvalidationRecord = { cacheKey: string; operationCache: Map<string, unknown>; }; type ResolveResult = { found: false; uri: null; parentPackageJson?: { packageJson: PackageJson; uri: Uri; }; } | { found: true; uri: null; parentPackageJson?: { packageJson: PackageJson; uri: Uri; }; rootUri: Uri; } | { found: true; uri: Uri; parentPackageJson?: { packageJson: PackageJson; uri: Uri; }; rootUri: Uri; }; type ReadParentPackageJsonResult = { found: true; packageJson: PackageJson; uri: Uri; visitedDirs: Uri[]; } | { found: false; packageJson: null; uri: null; }; type StrategyResult<T> = Promise<T & { visited: ResolverContext.Visit[]; }> | (T & { visited: ResolverContext.Visit[]; }); declare class Visits { readonly uri: { toString(): string; }; private readonly parent?; private readonly visits; constructor(uri: { toString(): string; }, parent?: Visits); child(uri: { toString(): string; }): Visits; push(visit: ResolverContext.Visit): void; toArray(): ResolverContext.Visit[]; } declare class ResolverContext { static create(resolver: Resolver, strategy: ResolverStrategy, settings: Resolver.Settings, token: CancellationToken, options?: { debug?: boolean; }): ResolverContext; private readonly cache; private readonly cacheInvalidations; private readonly debugMode; readonly decoder: ResolverContext.Options["decoder"]; private readonly mapResultWithVisits; readonly path: ReadonlyArray<string>; private readonly resolver; readonly settings: Readonly<ResolverContext.Options["settings"]>; private readonly strategy; private readonly tokenSource; private readonly visits; protected constructor(options: ResolverContext.Options); get token(): CancellationToken; get visited(): ResolverContext.Visit[]; dispose(): void; forOperation(operationName: string, uri: { toString(): string; }, options?: { resetPath?: boolean; resetVisits?: boolean; }): ResolverContext; getCanonicalUrl(uri: Uri): StrategyResult<ResolverStrategy.CanonicalizeResult>; getResolveRoot(uri: Uri): StrategyResult<ResolverStrategy.ResolveRootResult>; getSettings(uri: Uri): StrategyResult<ResolverStrategy.SettingsResult>; getUrlForBareModule(name: string, spec: string, path: string): StrategyResult<ResolverStrategy.BareModuleResult>; invalidate(uri: Uri): boolean; listEntries(uri: Uri): StrategyResult<ResolverStrategy.ListEntriesResult>; readFileContent(uri: Uri): StrategyResult<ResolverStrategy.ReadFileContentResult>; readParentPackageJson(uri: Uri): StrategyResult<ReadParentPackageJsonResult>; recordVisit(uri: Uri, type?: ResolverContext.VisitKind): void; resolve(spec: string, fromUri: Uri): StrategyResult<ResolveResult>; resolveUri(uri: Uri): StrategyResult<ResolveResult>; runInChildContext<T>(operationName: string, uri: { toString(): string; }, contextFn: (ctx: ResolverContext) => T): T; runInIsolatedContext<T>(operationName: string, uri: { toString(): string; }, contextFn: (ctx: ResolverContext) => T): T; private runInContext; private createStoreResultFn; private runWithCache; private _wrapError; debug(...args: Parameters<Console["warn"]>): void; } declare namespace ResolverContext { interface Options { cache: Map<string, Map<string, unknown>>; cacheInvalidations: MapSet<string, InvalidationRecord>; debug: boolean; decoder: Decoder; path: string[]; resolver: Resolver; settings: Resolver.Settings; strategy: ResolverStrategy; token: CancellationToken; visits: Visits; } enum VisitKind { Directory = "Directory", File = "File" } type Visit = { type: VisitKind.Directory; uri: Uri; } | { type: VisitKind.File; uri: Uri; }; } export { version, ResolverContext, Resolver, ResolverStrategy, ResolverStrategyWithRoot, AbstractResolverStrategy, AbstractResolverStrategyWithRoot }; //# sourceMappingURL=index.d.ts.map