All files / kernel-platforms/src/capabilities/fs shared.ts

100% Statements 29/29
83.33% Branches 10/12
100% Functions 6/6
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130                                      5x           14x 10x   10x     5x 5x   5x                     5x           10x 7x   7x   3x 3x   4x                               5x       10x                         24x 24x   24x   24x 7x             24x 13x   13x 8x           11x 6x           10x     21x        
import type {
  PathLike,
  SyncPathCaveat,
  ReadFile,
  Access,
  ExistsSync,
  FsConfig,
  FsCapability,
} from './types.ts';
import { fsConfigStruct } from './types.ts';
import { makeCapabilitySpecification } from '../../specification.ts';
 
/**
 * Cross-platform FS operation wrapper with validation (async version)
 *
 * @param operation - The underlying operation to wrap
 * @param syncPathCaveat - The caveat to apply to path arguments
 * @returns The operation restricted by the provided caveat
 */
export const makeCaveatedFsOperation = <
  Operation extends (...args: never[]) => Promise<unknown>,
>(
  operation: Operation,
  syncPathCaveat: SyncPathCaveat,
): Operation => {
  return harden(async (...args: Parameters<Operation>) => {
    try {
      // Assuming first argument is always the path
      syncPathCaveat(args[0] as unknown as PathLike);
      // We don't need async caveats yet, but we could await one here.
    } catch (cause) {
      const message = cause instanceof Error ? cause.message : 'Caveat failed';
      throw new Error(`fs.${operation.name}: ${message}`, { cause });
    }
    return operation(...args);
  }) as Operation;
};
 
/**
 * Cross-platform synchronous FS operation wrapper with validation
 *
 * @param operation - The underlying synchronous operation to wrap
 * @param syncPathCaveat - The caveat to apply to path arguments
 * @returns The operation restricted by the provided caveat
 */
export const makeCaveatedSyncFsOperation = <
  Operation extends (...args: never[]) => unknown,
>(
  operation: Operation,
  syncPathCaveat: SyncPathCaveat,
): Operation => {
  return harden((...args: Parameters<Operation>) => {
    try {
      // Assuming first argument is always the path
      syncPathCaveat(args[0] as unknown as PathLike);
    } catch (cause) {
      const message = cause instanceof Error ? cause.message : 'Caveat failed';
      throw new Error(`fs.${operation.name}: ${message}`, { cause });
    }
    return operation(...args);
  }) as Operation;
};
 
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/**
 * Cross-platform FS capability specification factory
 *
 * @param config - The configuration for the capability specification
 * @param config.makeExistsSync - The factory returning an existsSync operation
 * @param config.promises - Object containing promise-based operation factories
 * @param config.promises.makeReadFile - The factory returning a read file operation
 * @param config.promises.makeAccess - The factory returning an access operation
 * @param config.makePathCaveat - Factory function to create path caveats
 * @returns The capability specification
 */
export const makeFsSpecification = ({
  makeExistsSync,
  promises,
  makePathCaveat,
}: {
  makeExistsSync: () => ExistsSync;
  promises: {
    makeReadFile: () => ReadFile;
    makeAccess: () => Access;
  };
  makePathCaveat: (rootDir: string) => SyncPathCaveat;
}) =>
  makeCapabilitySpecification(
    fsConfigStruct,
    (config: FsConfig): FsCapability => {
      // The construction of this capability left ad-hoc until additional
      // requirements dictate additional structure.
      const { rootDir, existsSync, promises: promisesConfig } = config;
      const caveat = makePathCaveat(rootDir);
 
      const toExport: FsCapability = {};
 
      if (existsSync) {
        toExport.existsSync = makeCaveatedSyncFsOperation(
          // eslint-disable-next-line n/no-sync
          makeExistsSync(),
          caveat,
        );
      }
 
      if (promisesConfig) {
        const promisesObj: FsCapability['promises'] = {};
 
        if (promisesConfig.readFile) {
          promisesObj.readFile = makeCaveatedFsOperation(
            promises.makeReadFile(),
            caveat,
          );
        }
 
        if (promisesConfig.access) {
          promisesObj.access = makeCaveatedFsOperation(
            promises.makeAccess(),
            caveat,
          );
        }
 
        toExport.promises = harden(promisesObj);
      }
 
      return harden(toExport);
    },
  );
/* eslint-enable @typescript-eslint/explicit-function-return-type */