Skip to content

Commit

Permalink
refactor: migrate codebase to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
fraxken committed Mar 16, 2024
1 parent 2490a5e commit 688e83f
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 158 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ export interface WalkOptions {
extensions?: Set<string>;
}

export type WalkResult = [dirent: fs.Dirent, absoluteFileLocation: string];
export type WalkEntry = [dirent: fs.Dirent, absoluteFileLocation: string];
```

### walk(directory: string, options?: WalkOptions): AsyncIterableIterator< WalkResult >
### walk(directory: string, options?: WalkOptions): AsyncIterableIterator< WalkEntry >

Asynchronous walk.

### walkSync(directory: string, options?: WalkOptions): IterableIterator< WalkResult >
### walkSync(directory: string, options?: WalkOptions): IterableIterator< WalkEntry >

Synchronous walk (using readdirSync under the hood instead of opendir).

Expand Down
1 change: 0 additions & 1 deletion index.d.ts

This file was deleted.

77 changes: 0 additions & 77 deletions index.js

This file was deleted.

30 changes: 18 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
"name": "@nodesecure/fs-walk",
"version": "1.0.0",
"description": "Modern FileSystem (fs) utilities to lazy walk directories Asynchronously (but also Synchronously)",
"exports": "./index.js",
"exports": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"lint": "eslint index.js",
"test-only": "node --test",
"build": "tsc",
"prepublishOnly": "npm run build",
"lint": "eslint src/**/*.ts test/**/*.ts",
"test-only": "glob -c \"tsx --test\" \"./test/**/*.spec.ts\"",
"test": "npm run lint && npm run test-only",
"coverage": "c8 -r html npm test"
},
Expand All @@ -24,21 +31,20 @@
],
"author": "GENTILHOMME Thomas <[email protected]>",
"files": [
"index.d.ts",
"index.js",
"type"
"dist"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/NodeSecure/fs-walk/issues"
},
"homepage": "https://github.com/NodeSecure/fs-walk#readme",
"devDependencies": {
"@nodesecure/eslint-config": "^1.7.0",
"c8": "^8.0.0"
},
"type": "module",
"engines": {
"node": ">=18.0.0"
"@nodesecure/eslint-config": "^1.9.0",
"@types/node": "^20.11.28",
"c8": "^8.0.1",
"eslint": "^8.57.0",
"glob": "^10.3.10",
"tsx": "^4.7.1",
"typescript": "^5.4.2"
}
}
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export const EXCLUDED_DIRECTORY = new Set([
"node_modules",
".vscode",
".git"
]);
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./walk.js";
export * from "./walkSync.js";
export * from "./types.js";
14 changes: 14 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Import Node.js Dependencies
import { Dirent } from "node:fs";

export interface WalkOptions {
/**
* Whitelist of extensions
*
* @example
* new Set([".js", ".cjs", ".mjs"]);
*/
extensions?: Set<string>;
}

export type WalkEntry = [dirent: Dirent, absoluteFileLocation: string];
45 changes: 45 additions & 0 deletions src/walk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Import Node.js Dependencies
import * as fs from "node:fs/promises";
import * as path from "node:path";

// Import Internal Dependencies
import { EXCLUDED_DIRECTORY } from "./constants.js";
import type { WalkOptions, WalkEntry } from "./types.js";

/**
* @example
* import { walk } from "@nodesecure/fs-walk";
*
* for await (const [dirent, location] of walk(__dirname) {
* if (dirent.isFile()) {
* console.log(location);
* }
* }
*/
export async function* walk(
directory: string,
options: WalkOptions = Object.create(null)
): AsyncIterableIterator<WalkEntry> {
const extensions = options?.extensions ?? null;
const dirents = await fs.opendir(directory);

for await (const dirent of dirents) {
if (EXCLUDED_DIRECTORY.has(dirent.name)) {
continue;
}

if (dirent.isFile()) {
if (extensions !== null && !extensions.has(path.extname(dirent.name))) {
continue;
}

yield [dirent, path.join(directory, dirent.name)];
}
else if (dirent.isDirectory()) {
const subDirectoryLocation = path.join(directory, dirent.name);

yield [dirent, subDirectoryLocation];
yield* walk(subDirectoryLocation, options);
}
}
}
45 changes: 45 additions & 0 deletions src/walkSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Import Node.js Dependencies
import * as fs from "node:fs";
import * as path from "node:path";

// Import Internal Dependencies
import { EXCLUDED_DIRECTORY } from "./constants.js";
import type { WalkOptions, WalkEntry } from "./types.js";

/**
* @example
* import { walkSync, FILE } from "@nodesecure/fs-walk";
*
* for (const [type, location] of walkSync(__dirname) {
* if (type === FILE) {
* console.log(location);
* }
* }
*/
export function* walkSync(
directory: string,
options: WalkOptions = Object.create(null)
): IterableIterator<WalkEntry> {
const extensions = options?.extensions ?? null;
const dirents = fs.readdirSync(directory, { withFileTypes: true });

for (const dirent of dirents) {
if (EXCLUDED_DIRECTORY.has(dirent.name)) {
continue;
}

if (dirent.isFile()) {
if (extensions !== null && !extensions.has(path.extname(dirent.name))) {
continue;
}

yield [dirent, path.join(directory, dirent.name)];
}
else if (dirent.isDirectory()) {
const subDirectoryLocation = path.join(directory, dirent.name);

yield [dirent, subDirectoryLocation];
yield* walkSync(subDirectoryLocation, options);
}
}
}
54 changes: 0 additions & 54 deletions test/walk.js

This file was deleted.

70 changes: 70 additions & 0 deletions test/walk.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Import Node.js Dependencies
import { describe, it } from "node:test";
import assert from "node:assert";
import path from "node:path";
import { fileURLToPath } from "node:url";

// Import Internal Dependencies
import { walk, walkSync } from "../src/index.js";

// CONSTANTS
const __dirname = path.dirname(fileURLToPath(import.meta.url));

const kRootLocation = path.join(__dirname, "..");
const kFixturesDir = path.join(__dirname, "fixtures");

const kExpectedJSFiles = [
"src/index.ts",
"src/constants.ts",
"src/types.ts",
"src/walk.ts",
"src/walkSync.ts",
"test/walk.spec.ts"
]
.map((fileLocation) => path.normalize(fileLocation))
.sort();

describe("walk", () => {
it("should return all TypeScript files of the package", async() => {
const files: string[] = [];
const options = { extensions: new Set([".ts"]) };

for await (const [dirent, absoluteFileLocation] of walk(
kRootLocation,
options
)) {
if (dirent.isFile()) {
files.push(path.relative(kRootLocation, absoluteFileLocation));
}
}

assert.deepEqual(files.sort(), kExpectedJSFiles);
});
});

describe("walkSync", () => {
it("should return all TypeScript files of the package", () => {
const options = { extensions: new Set([".ts"]) };

const files = [...walkSync(kRootLocation, options)]
.filter(([dirent]) => dirent.isFile())
.map(([, absoluteFileLocation]) => path.relative(kRootLocation, absoluteFileLocation));

assert.deepEqual(files, kExpectedJSFiles);
});

it("should return all files in the fixtures directory", () => {
const files = [...walkSync(kFixturesDir)]
.filter(([dirent]) => dirent.isFile())
.map(([, absoluteFileLocation]) => path.relative(kRootLocation, absoluteFileLocation));

const expectedFiles = [
"test/fixtures/foobar.txt",
"test/fixtures/test.md"
].map((fileLocation) => path.normalize(fileLocation));

assert.deepEqual(files, expectedFiles);
});
});


Loading

0 comments on commit 688e83f

Please sign in to comment.