codemods/selectors/program.selector.ts

codemods/selectors/program.selector.ts is a file in GovLab Extension Host. 46 lines of code and 20 definitions.

import { dirname, relative, resolve, sep } from "node:path";
import { MEMBER_ROOTS } from "../../shared/registries/location.registry.ts";
import { existsSync } from "node:fs";
import ts from "typescript";

const REPO_ROOT = process.cwd().split(sep).join("/");
const NODE_MODULES = "/node_modules/";
const ARGV_START = 2;
const TSCONFIG_FLAG = "--tsconfig";
const TSCONFIG = "tsconfig.json";

const ALL_TSCONFIGS: readonly string[] = MEMBER_ROOTS.map((member) => `${member}/${TSCONFIG}`).filter((file) =>
    existsSync(resolve(process.cwd(), file)),
);

const requestedTsconfigs = function requestedTsconfigs(argv: readonly string[]): string[] {
    const flagIndex = argv.indexOf(TSCONFIG_FLAG);
    const value = flagIndex === -1 ? "" : (argv[flagIndex + 1] ?? "");
    return value.split(",").filter((entry) => entry.length > 0);
};

const REQUESTED = requestedTsconfigs(process.argv.slice(ARGV_START));

export const CODEMOD_TSCONFIGS: readonly string[] = REQUESTED.length > 0 ? REQUESTED : ALL_TSCONFIGS;

export const toPosix = function toPosix(value: string): string {
    return value.split(sep).join("/");
};

export const relPath = function relPath(fileName: string): string {
    return toPosix(relative(process.cwd(), fileName));
};

export const inRepo = function inRepo(fileName: string): boolean {
    return toPosix(fileName).startsWith(REPO_ROOT) && !toPosix(fileName).includes(NODE_MODULES);
};

export const programFor = function programFor(tsconfigPath: string): ts.Program {
    const absolute = resolve(process.cwd(), tsconfigPath);
    const configFile = ts.readConfigFile(absolute, (file) => ts.sys.readFile(file));
    const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(absolute));
    return ts.createProgram({
        host: ts.createCompilerHost(parsed.options),
        options: parsed.options,
        rootNames: parsed.fileNames,
    });
};

export const repoSourceFiles = function repoSourceFiles(program: ts.Program): ts.SourceFile[] {
    return program
        .getSourceFiles()
        .filter((sourceFile) => !sourceFile.isDeclarationFile && inRepo(sourceFile.fileName));
};

export const lineOf = function lineOf(sourceFile: ts.SourceFile, node: ts.Node): number {
    return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
};