UNPKG

@markandrus/effect-derive

Version:

Derive Covariant (Functor), Foldable, and Traversable instances, as well as base functors, for algebraic data types (ADTs)

70 lines (69 loc) 3.29 kB
import { OutFile } from './OutFile'; import { parseTypeWithHole } from './parseTypeWithHole'; import { resolveRelativePath } from './resolveRelativePath'; const parseCovariantFlags = createInstanceFlagsParser('--covariant', 'Covariant', true, 'map'); const parseFoldableFlags = createInstanceFlagsParser('--foldable', 'Foldable', true, 'reduce'); const parseTraversableFlags = createInstanceFlagsParser('--traversable', 'Traversable', true, 'traverse'); const parseTypeLambdaFlags = createInstanceFlagsParser('--type-lambda', 'TypeLambda', false, ''); export function parseRegistryFlags(cwd, inFilePath, outFilePath, flags) { const outFile = new OutFile(); const [covariant, outFile1] = parseCovariantFlags(cwd, inFilePath, outFilePath, flags.covariant); const [foldable, outFile2] = parseFoldableFlags(cwd, inFilePath, outFilePath, flags.foldable); const [traversable, outFile3] = parseTraversableFlags(cwd, inFilePath, outFilePath, flags.traversable); const [typeLambda, outFile4] = parseTypeLambdaFlags(cwd, inFilePath, outFilePath, flags.typeLambda); const registries = { covariant, foldable, traversable, typeLambda }; return [registries, outFile.merge(outFile1).merge(outFile2).merge(outFile3).merge(outFile4)]; } function createInstanceFlagsParser(flagName, instance, expectHole, fn) { return (cwd, inFilePath, outFilePath, flags) => { const registry = new Map(); const outFile = new OutFile(); for (const flag of flags) { const parts = flag.split('#'); if (parts.length < 2) { throw new Error(`Failed to parse ${flagName} flag: expected at least an import path and a type name`); } else if (parts.length > 3) { throw new Error(`Failed to parse ${flagName} flag: expected at most an import path, an import name, and a type name`); } let importPath = parts[0]; let importName = null; let tyName; if (parts.length === 2) { tyName = parts[1]; } else { importName = parts[1]; tyName = parts[2]; } const [name, holeIndex] = parseTypeWithHole(tyName, expectHole); if (registry.has(name)) { throw new Error(`${flagName} flag for type name ${tyName} was already provided`); } registry.set(name, [holeIndex, `${name}${instance}.${fn}`]); if (!importPath.startsWith('.')) { if (importName == null) { outFile.addPackageDefaultImport(importPath, name + instance); } else { outFile.addPackageImport(importPath, importName, name + instance); } } else { importPath = resolveRelativePath(cwd, inFilePath, outFilePath, importPath); if (importName == null) { outFile.addLocalDefaultImport(importPath, name + instance); } else { outFile.addLocalImport(importPath, importName, name + instance); } } } return [registry, outFile]; }; }