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

Nested src dir shows up in out dir #108 #123

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/swc/__tests__/sources.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,30 @@ describe("globSources", () => {
});

it("exclude dotfiles sources when includeDotfiles=false", async () => {
const files = await globSources([".dotfile"], false);
const [files, _] = await globSources([".dotfile"], false);

expect([...files]).toEqual([]);
});

it("include dotfiles sources when includeDotfiles=true", async () => {
(fs as any).setMockStats({ ".dotfile": { isDirectory: () => false } });
const files = await globSources([".dotfile"], true);
const [files, _] = await globSources([".dotfile"], true);

expect([...files]).toEqual([".dotfile"]);
});

it("include multiple file sources", async () => {
(fs as any).setMockStats({ ".dotfile": { isDirectory: () => false } });
(fs as any).setMockStats({ file: { isDirectory: () => false } });
const files = await globSources([".dotfile", "file"], true);
const [files, _] = await globSources([".dotfile", "file"], true);

expect([...files]).toEqual([".dotfile", "file"]);
});

it("exclude files that errors on stats", async () => {
(fs as any).setMockStats({ ".dotfile": { isDirectory: () => false } });
(fs as any).setMockStats({ file: new Error("Failed stat") });
const files = await globSources([".dotfile", "file"], true);
const [files, _] = await globSources([".dotfile", "file"], true);

expect([...files]).toEqual([".dotfile"]);
});
Expand All @@ -44,7 +44,7 @@ describe("globSources", () => {
(fs as any).setMockStats({ file: { isDirectory: () => false } });

(glob as unknown as jest.Mock).mockResolvedValue(["fileDir1", "fileDir2"]);
const files = await globSources(["file", "directory"], true);
const [files, _] = await globSources(["file", "directory"], true);

expect([...files]).toEqual(["file", "fileDir1", "fileDir2"]);
});
Expand All @@ -54,7 +54,7 @@ describe("globSources", () => {
(fs as any).setMockStats({ file: { isDirectory: () => false } });

(glob as unknown as jest.Mock).mockRejectedValue(new Error("Failed"));
const files = await globSources(["file", "directory"], true);
const [files, _] = await globSources(["file", "directory"], true);

expect([...files]).toEqual(["file"]);
});
Expand Down
138 changes: 101 additions & 37 deletions src/swc/dir.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import slash from "slash";
import { existsSync, promises } from "fs";
import { dirname, relative, join } from "path";
import { dirname, relative, join, isAbsolute, resolve } from "path";
import { CompileStatus } from "./constants";
import { CliOptions } from "./options";
import { compile } from "./util";
Expand All @@ -11,6 +11,7 @@ import {
slitCompilableAndCopyable,
watchSources,
} from "./sources";
import { FileContext } from "./file";

import type { Options } from "@swc/core";

Expand All @@ -26,39 +27,33 @@ declare module "fs" {

const { mkdir, rmdir, rm, copyFile, unlink } = promises;

const cwd = process.cwd();
const recursive = { recursive: true };

/**
* Removes the leading directory, including all parent relative paths
*/
function stripComponents(filename: string) {
const components = filename.split("/").slice(1);
if (!components.length) {
return filename;
}
while (components[0] === "..") {
components.shift();
}
return components.join("/");
}
function getDest(
filename: string,
sourceLength: number,
cwd: string,
outDir: string,
ext?: string
) {
const outDirAbsolutePath = slash(resolve(cwd, outDir));
let relativePath = slash(filename.slice(sourceLength));

function getDest(filename: string, outDir: string, ext?: string) {
const relativePath = slash(relative(cwd, filename));
let base = stripComponents(relativePath);
if (ext) {
base = base.replace(/\.\w*$/, ext);
relativePath = relativePath.replace(/\.\w*$/, ext);
}
return join(outDir, base);
return join(outDirAbsolutePath, relativePath);
}

async function handleCompile(
filename: string,
sourceLength: number,
cwd: string,
outDir: string,
sync: boolean,
swcOptions: Options
) {
const dest = getDest(filename, outDir, ".js");
const dest = getDest(filename, sourceLength, cwd, outDir, ".js");
const sourceFileName = slash(relative(dirname(dest), filename));

const options = { ...swcOptions, sourceFileName };
Expand All @@ -73,11 +68,15 @@ async function handleCompile(
}
}

async function handleCopy(filename: string, outDir: string) {
const dest = getDest(filename, outDir);
async function handleCopy(
filename: string,
sourceLength: number,
cwd: string,
outDir: string
) {
const dest = getDest(filename, sourceLength, cwd, outDir);
const dir = dirname(dest);

console.log(filename);
await mkdir(dir, recursive);
await copyFile(filename, dest);

Expand All @@ -95,12 +94,29 @@ async function beforeStartCompilation(cliOptions: CliOptions) {
}
}

async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
function absolutePath(filenames: string[], cwd: string): string[] {
return filenames.map((filename: string) => {
if (!isAbsolute(filename)) {
filename = resolve(cwd, filename);
}
return filename;
});
}

function resolveCwd(cwd: string): string {
return cwd ?? process.cwd();
}

async function initialCompilation(
cliOptions: CliOptions,
swcOptions: Options
): Promise<FileContext> {
const {
includeDotfiles,
filenames,
copyFiles,
extensions,
cwd,
outDir,
sync,
quiet,
Expand All @@ -110,7 +126,12 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
const results = new Map<string, CompileStatus>();

const start = process.hrtime();
const sourceFiles = await globSources(filenames, includeDotfiles);
const resolvedCwd = resolveCwd(cwd);
const filenamesAbsolutePath = absolutePath(filenames, resolvedCwd);
const [sourceFiles, fileContext] = await globSources(
filenamesAbsolutePath,
includeDotfiles
);
const [compilable, copyable] = slitCompilableAndCopyable(
sourceFiles,
extensions,
Expand All @@ -120,7 +141,14 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
if (sync) {
for (const filename of compilable) {
try {
const result = await handleCompile(filename, outDir, sync, swcOptions);
const result = await handleCompile(
filename,
fileContext[filename],
resolvedCwd,
outDir,
sync,
swcOptions
);
results.set(filename, result);
} catch (err) {
console.error(err.message);
Expand All @@ -129,7 +157,12 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
}
for (const filename of copyable) {
try {
const result = await handleCopy(filename, outDir);
const result = await handleCopy(
filename,
fileContext[filename],
resolvedCwd,
outDir
);
results.set(filename, result);
} catch (err) {
console.error(err.message);
Expand All @@ -140,13 +173,24 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
await Promise.all([
Promise.allSettled(
compilable.map(file =>
handleCompile(file, outDir, sync, swcOptions).catch(err => {
handleCompile(
file,
fileContext[file],
resolvedCwd,
outDir,
sync,
swcOptions
).catch(err => {
console.error(err.message);
throw err;
})
)
),
Promise.allSettled(copyable.map(file => handleCopy(file, outDir))),
Promise.allSettled(
copyable.map(file =>
handleCopy(file, fileContext[file], resolvedCwd, outDir)
)
),
]).then(([compiled, copied]) => {
compiled.forEach((result, index) => {
const filename = compilable[index];
Expand Down Expand Up @@ -212,10 +256,17 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
throw new Error("Failed to compile");
}
}

return fileContext;
}

async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
async function watchCompilation(
cliOptions: CliOptions,
swcOptions: Options,
fileContext: FileContext
) {
const {
cwd,
includeDotfiles,
filenames,
copyFiles,
Expand All @@ -225,7 +276,9 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
sync,
} = cliOptions;

const watcher = await watchSources(filenames, includeDotfiles);
const resolvedCwd = resolveCwd(cwd);
const filenamesAbsolutePath = absolutePath(filenames, resolvedCwd);
const watcher = await watchSources(filenamesAbsolutePath, includeDotfiles);
watcher.on("ready", () => {
if (!quiet) {
console.info("Watching for file changes.");
Expand All @@ -234,9 +287,13 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
watcher.on("unlink", async filename => {
try {
if (isCompilableExtension(filename, extensions)) {
await unlink(getDest(filename, outDir, ".js"));
await unlink(
getDest(filename, fileContext[filename], resolvedCwd, outDir, ".js")
);
} else if (copyFiles) {
await unlink(getDest(filename, outDir));
await unlink(
getDest(filename, fileContext[filename], resolvedCwd, outDir)
);
}
} catch (err) {
if (err.code !== "ENOENT") {
Expand All @@ -251,6 +308,8 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
const start = process.hrtime();
const result = await handleCompile(
filename,
fileContext[filename],
resolvedCwd,
outDir,
sync,
swcOptions
Expand All @@ -268,7 +327,12 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
} else if (copyFiles) {
try {
const start = process.hrtime();
const result = await handleCopy(filename, outDir);
const result = await handleCopy(
filename,
fileContext[filename],
resolvedCwd,
outDir
);
if (!quiet && result === CompileStatus.Copied) {
const end = process.hrtime(start);
console.log(
Expand All @@ -295,9 +359,9 @@ export default async function dir({
const { watch } = cliOptions;

await beforeStartCompilation(cliOptions);
await initialCompilation(cliOptions, swcOptions);
const fileContext = await initialCompilation(cliOptions, swcOptions);

if (watch) {
await watchCompilation(cliOptions, swcOptions);
await watchCompilation(cliOptions, swcOptions, fileContext);
}
}
14 changes: 12 additions & 2 deletions src/swc/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import { CliOptions } from "./options";
import { globSources, isCompilableExtension, watchSources } from "./sources";
import * as util from "./util";

// export interface File {
// filename: string;
// sourceLength: number;
// }

export interface FileContext {
[filename: string]: number;
}

export default async function ({
cliOptions,
swcOptions,
Expand Down Expand Up @@ -107,10 +116,11 @@ export default async function ({
) {
const results: typeof previousResults = new Map();

for (const filename of await globSources(
const [filenames, _] = await globSources(
cliOptions.filenames,
cliOptions.includeDotfiles
)) {
);
for (const filename of filenames) {
if (isCompilableExtension(filename, cliOptions.extensions)) {
results.set(filename, previousResults.get(filename)!);
}
Expand Down
2 changes: 1 addition & 1 deletion src/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dirCommand from "./dir";
import fileCommand from "./file";
import parseArgs, { initProgram } from "./options";

initProgram()
initProgram();
const opts = parseArgs(process.argv);
const fn = opts.cliOptions.outDir ? dirCommand : fileCommand;

Expand Down
4 changes: 4 additions & 0 deletions src/swc/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const initProgram = () => {
"filename to use when reading from stdin - this will be used in source-maps, errors etc"
);

program.option("--cwd [path]", "Specify the current working directory");

program.option("--config-file [path]", "Path to a .swcrc file to use");

program.option(
Expand Down Expand Up @@ -140,6 +142,7 @@ function collect(
}

export interface CliOptions {
readonly cwd: string;
readonly outDir: string;
readonly outFile: string;
/**
Expand Down Expand Up @@ -246,6 +249,7 @@ export default function parserArgs(args: string[]) {
}

const cliOptions: CliOptions = {
cwd: opts.cwd,
outDir: opts.outDir,
outFile: opts.outFile,
filename: opts.filename,
Expand Down
Loading