Skip to content

Commit b5f35be

Browse files
committed
Apply FND's suggestions
* Improvements to FileFinder * Doc improvement * fileName => filename * determineCompactors * Inline processFiles * Code organization * Remove last `then` * Inline isDotfile
1 parent e3f330e commit b5f35be

File tree

6 files changed

+163
-230
lines changed

6 files changed

+163
-230
lines changed

lib.js

Lines changed: 0 additions & 100 deletions
This file was deleted.
Lines changed: 32 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
1+
let { FileFinder } = require("./util.js");
12
let { readFile, stat } = require("node:fs/promises");
23
let path = require("node:path");
3-
let { FileFinder } = require("./lib.js");
4-
/** @import {
5-
* Config,
6-
* AssetManager,
7-
* FaucetPlugin,
8-
* FaucetPluginOptions,
9-
* FaucetPluginFunc,
10-
* CompactorMap,
11-
* WriteFileOpts,
12-
* ProcessFile
13-
* } from "./types.ts"
14-
**/
154

165
module.exports = {
176
key: "static",
@@ -49,33 +38,18 @@ function makeCopier(copyConfig, assetManager, { compact } = {}) {
4938
filter: copyConfig.filter
5039
});
5140
let { fingerprint } = copyConfig;
52-
let compactors = determineCompactors(compact, copyConfig);
41+
let compactors = (compact && copyConfig.compact) || {};
5342

54-
return filepaths => {
55-
return Promise.all([
43+
return async filepaths => {
44+
let [filenames, targetDir] = await Promise.all([
5645
(filepaths ? fileFinder.match(filepaths) : fileFinder.all()),
5746
determineTargetDir(source, target)
58-
]).then(([fileNames, targetDir]) => {
59-
return processFiles(fileNames, {
60-
assetManager, source, target, targetDir, compactors, fingerprint
61-
});
62-
});
63-
};
64-
}
65-
66-
/**
67-
* Determine which compactors should be used
68-
*
69-
* @param {boolean | undefined} compact
70-
* @param {Config} copyConfig
71-
* @returns {CompactorMap}
72-
*/
73-
function determineCompactors(compact, copyConfig) {
74-
if(!compact) {
75-
return {};
76-
}
47+
]);
7748

78-
return copyConfig.compact || {};
49+
return Promise.all(filenames.map(filename => processFile(filename, {
50+
assetManager, source, target, targetDir, compactors, fingerprint
51+
})));
52+
};
7953
}
8054

8155
/**
@@ -86,63 +60,54 @@ function determineCompactors(compact, copyConfig) {
8660
* @param {string} target
8761
* @returns {Promise<string>}
8862
*/
89-
function determineTargetDir(source, target) {
90-
return stat(source).
91-
then(results => results.isDirectory() ? target : path.dirname(target));
63+
async function determineTargetDir(source, target) {
64+
let results = await stat(source);
65+
return results.isDirectory() ? target : path.dirname(target);
9266
}
9367

9468
/**
95-
* @param {string[]} fileNames
96-
* @param {ProcessFile} config
97-
* @returns {Promise<unknown>}
98-
*/
99-
function processFiles(fileNames, config) {
100-
return Promise.all(fileNames.map(fileName => processFile(fileName, config)));
101-
}
102-
103-
/**
104-
* @param {string} fileName
69+
* @param {string} filename
10570
* @param {ProcessFile} opts
10671
* @returns {Promise<unknown>}
10772
*/
108-
async function processFile(fileName,
73+
async function processFile(filename,
10974
{ source, target, targetDir, fingerprint, assetManager, compactors }) {
110-
let sourcePath = path.join(source, fileName);
111-
let targetPath = path.join(target, fileName);
75+
let sourcePath = path.join(source, filename);
76+
let targetPath = path.join(target, filename);
11277

11378
try {
11479
var content = await readFile(sourcePath); // eslint-disable-line no-var
11580
} catch(err) {
116-
// @ts-ignore
81+
// @ts-expect-error TS2345
11782
if(err.code !== "ENOENT") {
11883
throw err;
11984
}
12085
console.error(`WARNING: \`${sourcePath}\` no longer exists`);
12186
return;
12287
}
12388

124-
let type = determineFileType(sourcePath);
125-
if(type && compactors[type]) {
126-
let compactor = compactors[type];
89+
let fileExtension = path.extname(sourcePath).substr(1).toLowerCase();
90+
if(fileExtension && compactors[fileExtension]) {
91+
let compactor = compactors[fileExtension];
12792
content = await compactor(content);
12893
}
12994

130-
/**
131-
* @type WriteFileOpts
132-
*/
95+
/** @type WriteFileOpts */
13396
let options = { targetDir };
13497
if(fingerprint !== undefined) {
13598
options.fingerprint = fingerprint;
13699
}
137100
return assetManager.writeFile(targetPath, content, options);
138101
}
139102

140-
/**
141-
* The filetype is the lower case file extension
142-
*
143-
* @param {string} sourcePath
144-
* @returns {string}
145-
*/
146-
function determineFileType(sourcePath) {
147-
return path.extname(sourcePath).substr(1).toLowerCase();
148-
}
103+
/** @import {
104+
* Config,
105+
* AssetManager,
106+
* FaucetPlugin,
107+
* FaucetPluginOptions,
108+
* FaucetPluginFunc,
109+
* CompactorMap,
110+
* WriteFileOpts,
111+
* ProcessFile
112+
* } from "./types.ts"
113+
**/

lib/types.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// faucet-pipeline-core types
2+
export interface FaucetPlugin<T> {
3+
(config: T[], assetManager: AssetManager, options: FaucetPluginOptions): FaucetPluginFunc
4+
}
5+
6+
export interface FaucetPluginFunc {
7+
(filepaths: string[]): Promise<unknown>
8+
}
9+
10+
export interface FaucetPluginOptions {
11+
browsers?: string[],
12+
sourcemaps?: boolean,
13+
compact?: boolean
14+
}
15+
16+
export interface AssetManager {
17+
resolvePath: (path: string, opts?: ResolvePathOpts) => string
18+
writeFile: (targetPath: string, content: Buffer, options: WriteFileOpts) => Promise<unknown>
19+
}
20+
21+
export interface ResolvePathOpts {
22+
enforceRelative?: boolean
23+
}
24+
25+
export interface WriteFileOpts {
26+
targetDir: string,
27+
fingerprint?: boolean
28+
}
29+
30+
// faucet-pipeline-static types
31+
export interface Config {
32+
source: string,
33+
target: string,
34+
targetDir: string,
35+
fingerprint?: boolean,
36+
compact?: CompactorMap,
37+
assetManager: AssetManager,
38+
filter?: (filename: string) => boolean
39+
}
40+
41+
export interface CompactorMap {
42+
[fileExtension: string]: Compactor
43+
}
44+
45+
export interface Compactor {
46+
(contact: Buffer): Promise<Buffer>
47+
}
48+
49+
export interface ProcessFile {
50+
source: string,
51+
target: string,
52+
targetDir: string,
53+
fingerprint?: boolean,
54+
compactors: CompactorMap,
55+
assetManager: AssetManager,
56+
filter?: (filename: string) => boolean
57+
}
58+
59+
export interface FileFinderOptions {
60+
skipDotfiles: boolean,
61+
filter?: (filename: string) => boolean
62+
}

lib/util.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
let { readdir, stat } = require("node:fs/promises");
2+
let path = require("node:path");
3+
4+
exports.FileFinder = class FileFinder {
5+
/**
6+
* @param {string} root
7+
* @param {FileFinderOptions} options
8+
*/
9+
constructor(root, { skipDotfiles, filter }) {
10+
this._root = root;
11+
12+
/**
13+
* @param {string} filename
14+
* @return {boolean}
15+
*/
16+
this._filter = filename => {
17+
if(skipDotfiles && path.basename(filename).startsWith(".")) {
18+
return false;
19+
}
20+
return filter ? filter(filename) : true;
21+
};
22+
}
23+
24+
/**
25+
* a list of relative file paths within the respective directory
26+
*
27+
* @returns {Promise<string[]>}
28+
*/
29+
async all() {
30+
let filenames = await tree(this._root);
31+
return filenames.filter(this._filter);
32+
}
33+
34+
/**
35+
* all file paths that match the filter function
36+
*
37+
* @param {string[]} filepaths
38+
* @returns {Promise<string[]>}
39+
*/
40+
async match(filepaths) {
41+
return filepaths.map(filepath => path.relative(this._root, filepath)).
42+
filter(filename => !filename.startsWith("..")).
43+
filter(this._filter);
44+
}
45+
};
46+
47+
/**
48+
* flat list of all files of a directory tree
49+
*
50+
* @param {string} filepath
51+
* @param {string} referenceDir
52+
* @returns {Promise<string[]>}
53+
*/
54+
async function tree(filepath, referenceDir = filepath) {
55+
let stats = await stat(filepath);
56+
57+
if(!stats.isDirectory()) {
58+
return [path.relative(referenceDir, filepath)];
59+
}
60+
61+
let entries = await Promise.all((await readdir(filepath)).map(entry => {
62+
return tree(path.join(filepath, entry), referenceDir);
63+
}));
64+
return entries.flat();
65+
}
66+
67+
/** @import { FileFinderOptions } from "./types.ts" */

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"name": "faucet-pipeline-static",
33
"version": "2.1.0",
44
"description": "static files for faucet-pipeline",
5-
"main": "index.js",
5+
"main": "lib/index.js",
66
"scripts": {
77
"test": "npm run lint && npm run typecheck && npm run test:cli",
88
"test:cli": "./test/run",
9-
"lint": "eslint --cache index.js test && echo ✓",
9+
"lint": "eslint --cache lib test && echo ✓",
1010
"typecheck": "tsc"
1111
},
1212
"repository": {

0 commit comments

Comments
 (0)