tools/core/validators/entrypoint.validator.ts
tools/core/validators/entrypoint.validator.ts is a file in Coordination Surface. 94 lines of code and 33 definitions.
import type { Mutation, RequestedOperation } from "../types/entrypoint.types.ts";
import { codeMask, matchesAt, spacesFrom, wordFrom } from "../analyzers/source.analyzer.ts";
const FLAG_LEAD = "--";
const READ = "readFileSync";
const WRITE = "writeFileSync";
const COMPARISONS = ["!==", "===", "!=", "=="];
interface Event {
readonly kind: "read" | "write";
readonly target: string;
readonly index: number;
readonly line: number;
}
export const unsuppliedOperands = function unsuppliedOperands(requested: readonly RequestedOperation[]): string[] {
return requested.filter((entry) => entry.requested && !entry.supplied).map((entry) => entry.refusal);
};
export const writesNothing = function writesNothing(
argv: readonly string[],
flag: string,
selfRehearsing: readonly string[],
): boolean {
return argv.includes(flag) && !selfRehearsing.some((form) => argv.includes(form));
};
const flagOf = function flagOf(token: string): string {
const equals = token.indexOf("=");
return equals === -1 ? token : token.slice(0, equals);
};
export const unknownArguments = function unknownArguments(argv: readonly string[], known: readonly string[]): string[] {
const flags = argv
.filter((token) => token.startsWith(FLAG_LEAD) && token.length > FLAG_LEAD.length)
.map(flagOf)
.filter((flag) => !known.includes(flag));
return [...new Set(flags)];
};
export const unshareableOperations = function unshareableOperations(
requested: readonly string[],
exclusive: readonly string[],
): string[] {
const held = requested.filter((flag) => exclusive.includes(flag));
return held.length > 0 && requested.length > 1 ? held : [];
};
const argumentAt = function argumentAt(source: string, after: number): string | null {
const open = spacesFrom(source, after);
if (source.charAt(open) !== "(") {
return null;
}
const argument = wordFrom(source, spacesFrom(source, open + 1));
return argument.length === 0 ? null : argument;
};
const eventAt = function eventAt(source: string, index: number, line: number): Event | null {
const read = matchesAt(source, index, READ);
if (!read && !matchesAt(source, index, WRITE)) {
return null;
}
const target = argumentAt(source, index + (read ? READ : WRITE).length);
return target === null ? null : { index, kind: read ? "read" : "write", line, target };
};
const events = function events(source: string): Event[] {
const mask = codeMask(source);
const out: Event[] = [];
let line = 1;
for (let index = 0; index < source.length; index += 1) {
const event = mask[index] === true ? eventAt(source, index, line) : null;
if (event !== null) {
out.push(event);
}
line += source.charAt(index) === "\n" ? 1 : 0;
}
return out;
};
const comparedBetween = function comparedBetween(source: string, from: number, to: number): boolean {
return COMPARISONS.some((operator) => {
const at = source.indexOf(operator, from);
return at !== -1 && at + operator.length <= to;
});
};
const witnessedWrite = function witnessedWrite(source: string, priors: readonly Event[], write: Event): boolean {
const last = priors.at(-1);
return priors.length >= 2 && last !== undefined && comparedBetween(source, last.index, write.index);
};
export const unwitnessedWrites = function unwitnessedWrites(source: string): Mutation[] {
const ordered = events(source);
return ordered
.filter((event) => event.kind === "write")
.flatMap((write) => {
const priors = ordered.filter(
(candidate) =>
candidate.kind === "read" && candidate.target === write.target && candidate.index < write.index,
);
const witnessed = witnessedWrite(source, priors, write);
return priors.length === 0 || witnessed
? []
: [{ line: write.line, reads: priors.length, target: write.target, witnessed }];
});
};