Skip to content

Commit

Permalink
Enforce type checking on babel-{cli,node} (#14765)
Browse files Browse the repository at this point in the history
* ts

* Update packages/babel-node/src/babel-node.ts

Co-authored-by: Hu谩ng J霉nli脿ng <jlhwung@gmail.com>

* review

* review

* fix

* Update packages/babel-node/src/_babel-node.ts

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>

* review

* Apply suggestions from code review

Co-authored-by: Justin Ridgewell <justin@ridgewell.name>

* review

Co-authored-by: Hu谩ng J霉nli脿ng <jlhwung@gmail.com>
Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
  • Loading branch information
4 people committed Jul 20, 2022
1 parent 486d27a commit b807206
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 68 deletions.
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;
}
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
20 changes: 15 additions & 5 deletions packages/babel-cli/src/babel/file.ts
Expand Up @@ -8,17 +8,24 @@ import * as util from "./util";
import type { CmdOptions } from "./options";
import * as watcher from "./watcher";

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

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: SectionedSourceMap["sections"] = [];

let code = "";
let offset = 0;
Expand Down Expand Up @@ -70,7 +77,7 @@ export default async function ({
}
return count;
}
function emptyMap() {
function emptyMap(): DecodedSourceMap {
return {
version: 3,
names: [],
Expand All @@ -89,7 +96,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 +139,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

0 comments on commit b807206

Please sign in to comment.