Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce type checking on babel-{cli,node} #14765

Merged
merged 9 commits into from Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/fs-readdir-recursive.d.ts
@@ -0,0 +1,7 @@
declare module "fs-readdir-recursive" {
function read(
root: string,
filter?: (filename: string, index: number, dir: string) => boolean
): string[];
export = read;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a follow-up, could you open a PR to update https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/fs-readdir-recursive/index.d.ts so that then we can use @types/fs-readdir-recursive?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DefinitelyTyped/DefinitelyTyped#61344
Finish. I think we might be able to remove this package at some point.

4 changes: 4 additions & 0 deletions lib/kexec.d.ts
@@ -0,0 +1,4 @@
declare module "kexec" {
function execvp(cmd: string, args?: string[]): string;
export = execvp;
}
4 changes: 2 additions & 2 deletions packages/babel-cli/src/babel/dir.ts
Expand Up @@ -129,7 +129,7 @@ export default async function ({
}

let compiledFiles = 0;
let startTime = null;
let startTime: [number, number] | null = null;

const logSuccess = util.debounce(function () {
if (startTime === null) {
Expand Down Expand Up @@ -178,7 +178,7 @@ export default async function ({
// when we are sure that all the files have been compiled.
let processing = 0;
const { filenames } = cliOptions;
let getBase;
let getBase: (filename: string) => string | null;
if (filenames.length === 1) {
// fast path: If there is only one filenames, we know it must be the base
const base = filenames[0];
Expand Down
21 changes: 16 additions & 5 deletions packages/babel-cli/src/babel/file.ts
Expand Up @@ -8,17 +8,25 @@ import * as util from "./util";
import type { CmdOptions } from "./options";
import * as watcher from "./watcher";

import type {
SectionedSourceMap,
SourceMapInput,
TraceMap,
} from "@jridgewell/trace-mapping";

type Section = SectionedSourceMap["sections"][0];

type CompilationOutput = {
code: string;
map: any;
map: SourceMapInput;
};

export default async function ({
cliOptions,
babelOptions,
}: CmdOptions): Promise<void> {
function buildResult(fileResults: Array<any>): CompilationOutput {
const mapSections = [];
const mapSections: Section[] = [];
liuxingbaoyu marked this conversation as resolved.
Show resolved Hide resolved

let code = "";
let offset = 0;
Expand Down Expand Up @@ -70,7 +78,7 @@ export default async function ({
}
return count;
}
function emptyMap() {
function emptyMap(): Section["map"] {
liuxingbaoyu marked this conversation as resolved.
Show resolved Hide resolved
return {
version: 3,
names: [],
Expand All @@ -89,7 +97,10 @@ export default async function ({
if (babelOptions.sourceMaps && babelOptions.sourceMaps !== "inline") {
const mapLoc = cliOptions.outFile + ".map";
result.code = util.addSourceMappingUrl(result.code, mapLoc);
fs.writeFileSync(mapLoc, JSON.stringify(encodedMap(result.map)));
fs.writeFileSync(
mapLoc,
JSON.stringify(encodedMap(result.map as TraceMap)),
);
}

fs.writeFileSync(cliOptions.outFile, result.code);
Expand Down Expand Up @@ -129,7 +140,7 @@ export default async function ({
}

async function walk(filenames: Array<string>): Promise<void> {
const _filenames = [];
const _filenames: string[] = [];

filenames.forEach(function (filename) {
if (!fs.existsSync(filename)) return;
Expand Down
34 changes: 28 additions & 6 deletions packages/babel-cli/src/babel/options.ts
Expand Up @@ -4,6 +4,8 @@ import commander from "commander";
import { version, DEFAULT_EXTENSIONS } from "@babel/core";
import glob from "glob";

import type { InputOptions } from "@babel/core";

// Standard Babel input configs.
commander.option(
"-f, --filename [filename]",
Expand Down Expand Up @@ -179,17 +181,35 @@ commander.usage("[options] <files ...>");
commander.action(() => {});

export type CmdOptions = {
babelOptions: any;
cliOptions: any;
babelOptions: InputOptions;
cliOptions: {
filename: string;
filenames: string[];
extensions: string[];
keepFileExtension: boolean;
outFileExtension: string;
watch: boolean;
skipInitialBuild: boolean;
outFile: string;
outDir: string;
relative: boolean;
copyFiles: boolean;
copyIgnored: boolean;
includeDotfiles: boolean;
verbose: boolean;
quiet: boolean;
deleteDirOnStart: boolean;
sourceMapTarget: string;
};
};

export default function parseArgv(args: Array<string>): CmdOptions | null {
//
commander.parse(args);

const errors = [];
const errors: string[] = [];

let filenames = commander.args.reduce(function (globbed, input) {
let filenames = commander.args.reduce(function (globbed: string[], input) {
let files = glob.sync(input);
if (!files.length) files = [input];
globbed.push(...files);
Expand Down Expand Up @@ -264,7 +284,7 @@ export default function parseArgv(args: Array<string>): CmdOptions | null {

const opts = commander.opts();

const babelOptions = {
const babelOptions: InputOptions = {
presets: opts.presets,
plugins: opts.plugins,
rootMode: opts.rootMode,
Expand Down Expand Up @@ -303,7 +323,9 @@ export default function parseArgv(args: Array<string>): CmdOptions | null {
// new options for @babel/core, we'll potentially get option validation errors from
// @babel/core. To avoid that, we delete undefined options, so @babel/core will only
// give the error if users actually pass an unsupported CLI option.
for (const key of Object.keys(babelOptions)) {
for (const key of Object.keys(babelOptions) as Array<
keyof typeof babelOptions
>) {
if (babelOptions[key] === undefined) {
delete babelOptions[key];
}
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-cli/src/babel/util.ts
Expand Up @@ -20,7 +20,7 @@ export function readdir(
includeDotfiles: boolean,
filter?: ReaddirFilter,
): Array<string> {
return readdirRecursive(dirname, (filename, _index, currentDirectory) => {
return readdirRecursive(dirname, (filename, index, currentDirectory) => {
const stat = fs.statSync(path.join(currentDirectory, filename));

if (stat.isDirectory()) return true;
Expand Down Expand Up @@ -134,7 +134,7 @@ export function withExtension(filename: string, ext: string = ".js") {
}

export function debounce(fn: () => void, time: number) {
let timer;
let timer: NodeJS.Timeout;
function debounced() {
clearTimeout(timer);
timer = setTimeout(fn, time);
Expand Down
32 changes: 19 additions & 13 deletions packages/babel-cli/src/babel/watcher.ts
@@ -1,11 +1,12 @@
import { createRequire } from "module";
import path from "path";
import type { WatchOptions, FSWatcher } from "chokidar";

const fileToDeps = new Map<string, Set<string>>();
const depToFiles = new Map<string, Set<string>>();

let isWatchMode = false;
let watcher;
let watcher: FSWatcher;
const watchQueue = new Set<string>();
let hasStarted = false;

Expand All @@ -14,15 +15,16 @@ export function enable({ enableGlobbing }: { enableGlobbing: boolean }) {

const { FSWatcher } = requireChokidar();

watcher = new FSWatcher({
const options: WatchOptions = {
disableGlobbing: !enableGlobbing,
persistent: true,
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 50,
pollInterval: 10,
},
});
};
watcher = new FSWatcher(options);

watcher.on("unlink", unwatchFile);
}
Expand Down Expand Up @@ -94,33 +96,37 @@ export function updateExternalDependencies(
Array.from(dependencies, dep => path.resolve(dep)),
);

if (fileToDeps.has(absFilename)) {
for (const dep of fileToDeps.get(absFilename)) {
const deps = fileToDeps.get(absFilename);
if (deps) {
for (const dep of deps) {
if (!absDependencies.has(dep)) {
removeFileDependency(absFilename, dep);
}
}
}
for (const dep of absDependencies) {
if (!depToFiles.has(dep)) {
depToFiles.set(dep, new Set());
let deps = depToFiles.get(dep);
if (!deps) {
depToFiles.set(dep, (deps = new Set()));

if (!hasStarted) {
watchQueue.add(dep);
} else {
watcher.add(dep);
}
}
depToFiles.get(dep).add(absFilename);

deps.add(absFilename);
}

fileToDeps.set(absFilename, absDependencies);
}

function removeFileDependency(filename: string, dep: string) {
depToFiles.get(dep).delete(filename);
const deps = depToFiles.get(dep) as Set<string>;
deps.delete(filename);

if (depToFiles.get(dep).size === 0) {
if (deps.size === 0) {
depToFiles.delete(dep);

if (!hasStarted) {
Expand All @@ -132,16 +138,16 @@ function removeFileDependency(filename: string, dep: string) {
}

function unwatchFile(filename: string) {
if (!fileToDeps.has(filename)) return;
const deps = fileToDeps.get(filename);
if (!deps) return;

for (const dep of fileToDeps.get(filename)) {
for (const dep of deps) {
removeFileDependency(filename, dep);
}
fileToDeps.delete(filename);
}

function requireChokidar(): any {
// @ts-expect-error - TS is not configured to support import.meta.
const require = createRequire(import.meta.url);

try {
Expand Down
1 change: 1 addition & 0 deletions packages/babel-node/package.json
Expand Up @@ -37,6 +37,7 @@
"@babel/core": "workspace:^",
"@babel/helper-fixtures": "workspace:^",
"@babel/runtime": "workspace:^",
"@types/v8flags": "^3.1.1",
"fs-readdir-recursive": "^1.0.0",
"make-dir": "condition:BABEL_8_BREAKING ? : ^2.1.0",
"rimraf": "^3.0.0"
Expand Down