Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Built and signed on GitHub Actions
Library to write out the contents of a JavaScript object structure to the file system in a granular directory structure.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117import { DirectoryReference } from "./directory_reference.ts"; import type { DirectoryCreator, ValueStorageHandler, ValueStorageHandlerOptions, } from "./interfaces.ts"; import { isObject, mergeOptions } from "./merge_utilities.ts"; import { encodePathElement } from "./path_encoder.ts"; export class DirectoryValueStorageHandler implements ValueStorageHandler { readonly #name: string; readonly #handlers: Readonly<ValueStorageHandler[]>; readonly #directoryCreator: DirectoryCreator; readonly #defaultOptions: Readonly<ValueStorageHandlerOptions> | undefined; constructor( name: string, handlers: Readonly<ValueStorageHandler[]>, directoryCreator: DirectoryCreator, defaultOptions?: Readonly<ValueStorageHandlerOptions>, ) { this.#name = name; this.#handlers = handlers; this.#directoryCreator = directoryCreator; this.#defaultOptions = defaultOptions; } get name(): string { return this.#name; } canStoreValue( _pathInSource: string, _destinationUrl: URL, value: unknown, ): boolean { return isObject(value); } async storeValue( pathInSource: string, destinationUrl: URL, value: unknown, options?: Readonly<ValueStorageHandlerOptions>, ): Promise<void> { options?.signal?.throwIfAborted(); if (!isObject(value)) { throw new TypeError( `Attempting to store non-object value at path "${pathInSource}" as a directory.`, ); } const directoryReference = new DirectoryReference(destinationUrl); const mergedOptions = mergeOptions(this.#defaultOptions, options); const propertyNameEncoder = mergedOptions?.propertyNameEncoder ?? encodePathElement; // First things first, let's make sure the destination directory is created... await this.#directoryCreator.createDirectory( directoryReference.canonicalUrl, { recursive: true }, ); for (const [nestedKey, nestedValue] of Object.entries(value)) { const nestedPathInSource = `${pathInSource}/${ encodePathElement(nestedKey) }`; const nestedDestinationUrl = directoryReference.getContentsUrl( encodeURIComponent(propertyNameEncoder(nestedKey)), ); let stored = false; for (const candidateHandler of this.#handlers) { if ( candidateHandler.canStoreValue( nestedPathInSource, nestedDestinationUrl, nestedValue, ) ) { await candidateHandler.storeValue( nestedPathInSource, nestedDestinationUrl, nestedValue, mergedOptions, ); stored = true; break; } } if (!stored) { if ( this.canStoreValue( nestedPathInSource, nestedDestinationUrl, nestedValue, ) ) { await this.storeValue( nestedPathInSource, nestedDestinationUrl, nestedValue, mergedOptions, ); } else { if (mergedOptions?.strict) { throw new Error( `Could not store value at path "${nestedPathInSource}" -- no storage handler matches it`, ); } } } } } }