Creating a Recursive Schema for a File System Structure

Hi, I'm trying to use Schema to represent a recursive data structure but I'm having some trouble.

My goal is to have a representation of a file system, where each node is either a file or a directory. In the latter case, each directory has a reference to all its children (other FSNodes). Also, every node has a reference to its parent.

This can be represented easily with ts:
type DirNode = {
  _tag: 'dir';
  children: Record<string, FSNode>;
};

type FileNode = {
  _tag: 'file';
  content: ProgramRef | RawData; // these are just other schemas
};

export type FSNode = {
  name: string;
  parent: Option.Option<FSNode>;
} & (FileNode | DirNode);



but trying to make it into Schema is quite tricky:

// this one is straightforward
const FileNode = Schema.TaggedStruct('file', {
  content: Schema.Union(ProgramRef, RawData)
});

// following the example at https://effect.website/docs/schema/advanced-usage/#mutually-recursive-schemas
const DirNode = Schema.TaggedStruct('dir', {
  children: Schema.Record({
    key: Schema.NonEmptyString,
    value: Schema.suspend((): Schema.Schema<fnode> => fnode)
  })
});

const fields = {
  name: Schema.NonEmptyString
};
// this extends from fields, but how do i also add the union? (the & (FileNode | DirNode) part)
interface FSNode extends Schema.Struct.Type<typeof fields> {
  readonly parent: Option.Option<FSNode>;
}

// i've tried with extend
const FSNode = Schema.extend(
  Schema.Struct({
    ...fields,
    parent: Schema.OptionFromSelf(Schema.suspend((): Schema.Schema<fnode> => FSNode))
    }),
// ...how do i add this?
    Schema.Union(DirNode, FileNode)
);
Was this page helpful?