@travetto/base
Advanced tools
Comparing version 3.4.0-rc.3 to 3.4.0-rc.4
{ | ||
"name": "@travetto/base", | ||
"version": "3.4.0-rc.3", | ||
"version": "3.4.0-rc.4", | ||
"description": "Environment config and common utilities for travetto applications.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -70,3 +70,3 @@ <!-- This file was generated by @travetto/doc and should not be modified directly --> | ||
* `dynamic` - This is derived from `process.env.TRV_DYNAMIC`. This field reflects certain feature sets used throughout the framework. | ||
* `resourcePaths` - This is a list derived from `process.env.TRV_RESOURCES`. This points to a list of folders that the [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L46) will search against, by default. | ||
* `resourcePaths` - This is a list derived from `process.env.TRV_RESOURCES`. This points to a list of folders that the [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21) will search against, by default. | ||
* `test` - This is true if `envName` is `test` | ||
@@ -103,33 +103,8 @@ * `nodeVersion` - This is derived from `process.version`, and is used primarily for logging purposes | ||
**Code: ResourceProvider contract** | ||
```typescript | ||
export interface ResourceProvider { | ||
/** | ||
* Describe the resource | ||
* @param pth The path to resolve | ||
*/ | ||
describe(pth: string): Promise<ResourceDescription>; | ||
The [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21) allows for accessing information about the resources, and subsequently reading the file as text/binary or to access the resource as a `Readable` stream. If a file is not found, it will throw an [AppError](https://github.com/travetto/travetto/tree/main/module/base/src/error.ts#L13) with a category of 'notfound'. This [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21) will utilize the [GlobalEnv](https://github.com/travetto/travetto/tree/main/module/base/src/global-env.ts#L17)'s `resourcePaths` information on where to attempt to find a requested resource. | ||
/** | ||
* Read a resource, mimicking fs.read | ||
* @param pth The path to read | ||
*/ | ||
read(pth: string, binary?: false): Promise<string>; | ||
read(pth: string, binary: true): Promise<Buffer>; | ||
read(pth: string, binary?: boolean): Promise<string | Buffer>; | ||
/** | ||
* Read a resource as a stream, mimicking fs.readStream | ||
* @param pth The path to read | ||
*/ | ||
readStream(pth: string, binary?: boolean): Promise<Readable>; | ||
} | ||
``` | ||
The [ResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21) allows for accessing information about the resources, and subsequently reading the file as text/binary or to access the resource as a `Readable` stream. If a file is not found, it will throw an [AppError](https://github.com/travetto/travetto/tree/main/module/base/src/error.ts#L13) with a category of 'notfound'. This contract is fairly simple to fill out, and the predominant implementation is [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L46). This [ResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21) will utilize the [GlobalEnv](https://github.com/travetto/travetto/tree/main/module/base/src/global-env.ts#L17)'s `resourcePaths` information on where to attempt to find a requested resource. | ||
### Scanning for Resources | ||
Beyond directly asking for a resource, there a times where it is helpful to know what resources are available at runtime. This is primarily used during development, and is a discouraged pattern for production as assumptions about the file-system may be incorrect (or change without warning). | ||
To that end, [FileQueryProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource-query.ts#L10) exists, and is a valid [ResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21). It also provides the `query` method, to allow for scanning/finding resources that match certain patterns. Additionally, this class also allows for watching all the resource folders. This again is helpful during development/compilation, but should not be used in production. | ||
To that end, [FileQueryProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource-query.ts#L10) exists, and is a valid [FileResourceProvider](https://github.com/travetto/travetto/tree/main/module/base/src/resource.ts#L21). It also provides the `query` method, to allow for scanning/finding resources that match certain patterns. Additionally, this class also allows for watching all the resource folders. This again is helpful during development/compilation, but should not be used in production. | ||
@@ -136,0 +111,0 @@ ## Standard Error Support |
@@ -21,3 +21,3 @@ import rl from 'readline/promises'; | ||
type ChangeEvent = { action: 'create' | 'update' | 'delete'; file: string; folder: string; output: string; module: string; time: number; }; | ||
type ChangeEvent = { action: 'create' | 'update' | 'delete', file: string, folder: string, output: string, module: string, time: number }; | ||
type ProgressEvent = { idx: number, total: number, message: string, operation: string, complete?: boolean }; | ||
@@ -32,2 +32,3 @@ type StateEvent = { state: ServerInfo['state'] }; | ||
{ type: 'state', payload: StateEvent } | | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
{ type: 'custom', payload: any }; | ||
@@ -57,3 +58,3 @@ | ||
replaceSignal(signal: AbortSignal) { | ||
replaceSignal(signal: AbortSignal): void { | ||
this.#kill = new AbortController(); | ||
@@ -63,3 +64,3 @@ signal.addEventListener('abort', () => this.#kill.abort()); | ||
close() { | ||
close(): void { | ||
this.#kill.abort(); | ||
@@ -66,0 +67,0 @@ } |
@@ -20,6 +20,6 @@ import fs from 'fs/promises'; | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
const search = [...this.paths.map(x => [x, x, 0] as [string, string, number])]; | ||
const search = [...this.searchPaths.map(x => [x, x] as [string, string])]; | ||
const seen = new Set(); | ||
while (search.length) { | ||
const [folder, root, depth] = search.shift()!; | ||
const [folder, root] = search.shift()!; | ||
for (const sub of await fs.readdir(folder).catch(() => [])) { | ||
@@ -32,3 +32,3 @@ if (sub === '.' || sub === '..' || (!includeHidden && sub.startsWith('.'))) { | ||
if (stats.isDirectory()) { | ||
search.push([resolved, root, depth + 1]); | ||
search.push([resolved, root]); | ||
} else { | ||
@@ -35,0 +35,0 @@ const rel = resolved.replace(`${root}/`, ''); |
@@ -19,32 +19,7 @@ import { Readable } from 'stream'; | ||
/** | ||
* Primary contract for resource handling | ||
* File-based resource provider | ||
*/ | ||
export interface ResourceProvider { | ||
/** | ||
* Describe the resource | ||
* @param pth The path to resolve | ||
*/ | ||
describe(pth: string): Promise<ResourceDescription>; | ||
export class FileResourceProvider { | ||
/** | ||
* Read a resource, mimicking fs.read | ||
* @param pth The path to read | ||
*/ | ||
read(pth: string, binary?: false): Promise<string>; | ||
read(pth: string, binary: true): Promise<Buffer>; | ||
read(pth: string, binary?: boolean): Promise<string | Buffer>; | ||
/** | ||
* Read a resource as a stream, mimicking fs.readStream | ||
* @param pth The path to read | ||
*/ | ||
readStream(pth: string, binary?: boolean): Promise<Readable>; | ||
} | ||
/** | ||
* Simple file-based resource provider | ||
*/ | ||
export class FileResourceProvider implements ResourceProvider { | ||
static resolvePaths(cfgOrPaths: FileResourceConfig | string[]): string[] { | ||
static resolveSearchConfig(cfgOrPaths: FileResourceConfig | string[]): string[] { | ||
const main = RootIndex.manifest.mainModule; | ||
@@ -79,34 +54,61 @@ const cfg = Array.isArray(cfgOrPaths) ? { paths: cfgOrPaths } : cfgOrPaths; | ||
constructor(cfg: FileResourceConfig | string[]) { | ||
this.#paths = FileResourceProvider.resolvePaths(cfg); | ||
this.#paths = FileResourceProvider.resolveSearchConfig(cfg); | ||
} | ||
async #getPath(file: string): Promise<string> { | ||
async #getPaths(relativePath: string, minSize = Number.MAX_SAFE_INTEGER): Promise<string[]> { | ||
const out: string[] = []; | ||
for (const sub of this.#paths) { | ||
const resolved = path.join(sub, file); | ||
const resolved = path.join(sub, relativePath); | ||
if (await fs.stat(resolved).catch(() => false)) { | ||
return resolved; | ||
out.push(resolved); | ||
if (out.length >= minSize) { | ||
break; | ||
} | ||
} | ||
} | ||
throw new AppError(`Unable to find: ${file}, searched=${this.#paths.join(',')}`, 'notfound'); | ||
if (!out.length) { | ||
throw new AppError(`Unable to find: ${relativePath}, searched=${this.#paths.join(',')}`, 'notfound'); | ||
} | ||
return out; | ||
} | ||
get paths(): string[] { | ||
get searchPaths(): string[] { | ||
return this.#paths.slice(0); | ||
} | ||
async describe(file: string): Promise<ResourceDescription> { | ||
file = await this.#getPath(file); | ||
const stat = await fs.stat(file); | ||
return { size: stat.size, path: file }; | ||
/** | ||
* Return the absolute path for the given relative path | ||
* @param relativePath The path to resolve | ||
*/ | ||
async resolve(relativePath: string): Promise<string> { | ||
return this.#getPaths(relativePath, 1).then(v => v[0]); | ||
} | ||
async read(file: string, binary?: false): Promise<string>; | ||
async read(file: string, binary: true): Promise<Buffer>; | ||
async read(file: string, binary = false): Promise<string | Buffer> { | ||
file = await this.#getPath(file); | ||
/** | ||
* Return all of the matching absolute paths for the given | ||
* relative path, if one or more found | ||
* @param relativePath The path to resolve | ||
*/ | ||
async resolveAll(relativePath: string): Promise<string[]> { | ||
return this.#getPaths(relativePath); | ||
} | ||
/** | ||
* Read a resource, mimicking fs.read | ||
* @param relativePath The path to read | ||
*/ | ||
async read(relativePath: string, binary?: false): Promise<string>; | ||
async read(relativePath: string, binary: true): Promise<Buffer>; | ||
async read(relativePath: string, binary = false): Promise<string | Buffer> { | ||
const file = await this.resolve(relativePath); | ||
return fs.readFile(file, binary ? undefined : 'utf8'); | ||
} | ||
async readStream(file: string, binary = true): Promise<Readable> { | ||
file = await this.#getPath(file); | ||
/** | ||
* Read a resource as a stream, mimicking fs.readStream | ||
* @param relativePath The path to read | ||
*/ | ||
async readStream(relativePath: string, binary = true): Promise<Readable> { | ||
const file = await this.resolve(relativePath); | ||
const handle = await fs.open(file); | ||
@@ -113,0 +115,0 @@ return handle.createReadStream({ encoding: binary ? undefined : 'utf8' }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2195
100264
359