Skip to content

Commit 638a354

Browse files
authored
Refactor standalone functions and create removeFile function (#6)
* Improve async * Move functions to utils * Add remove file and dir func
1 parent 3692a20 commit 638a354

File tree

2 files changed

+166
-139
lines changed

2 files changed

+166
-139
lines changed

scrubber/scrubUtils.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import { ScrubberAction, TagNameToAction } from "./scrubberTypes";
4+
5+
const TAG_START_CHAR = "{";
6+
const TAG_END_CHAR = "}";
7+
8+
const FILE_TYPE_COMMENT: { [key: string]: string } = {
9+
js: "//",
10+
json: "//",
11+
ts: "//",
12+
py: "#",
13+
};
14+
15+
export function scrubberActionsToDict(
16+
actions: ScrubberAction[],
17+
): TagNameToAction {
18+
const dict: TagNameToAction = {};
19+
actions.forEach((action) => {
20+
action.tags.forEach((tag: string) => {
21+
dict[tag] = action.type;
22+
});
23+
});
24+
return dict;
25+
}
26+
27+
export function scrubFile(
28+
filePath: string,
29+
tags: TagNameToAction,
30+
isDryRun: boolean,
31+
): Promise<void> {
32+
return new Promise((resolve, reject) => {
33+
fs.readFile(filePath, { encoding: "utf8" }, (err, text) => {
34+
if (err) {
35+
reject(err);
36+
}
37+
38+
const ext = filePath.split(".").pop();
39+
const commentType = ext && FILE_TYPE_COMMENT[ext];
40+
const scrubbedLines: string[] = [];
41+
let skip = false;
42+
43+
const lines: string[] = text.split("\n");
44+
45+
for (let i = 0; i < lines.length; ++i) {
46+
const line = lines[i];
47+
let tryProcessTag = true;
48+
49+
if (line.length === 0) {
50+
scrubbedLines.push(line);
51+
continue;
52+
}
53+
54+
// Split on whitespace
55+
const tokens = line.trim().split(/[ ]+/);
56+
57+
if (commentType) {
58+
if (tokens[0] !== commentType) {
59+
tryProcessTag = false;
60+
}
61+
tokens.shift();
62+
}
63+
64+
if (tryProcessTag) {
65+
if (tokens[0] in tags && tokens.length !== 2) {
66+
console.warn(
67+
`WARNING line ${
68+
i + 1
69+
}: possible malformed tag; tags must be on their own line preceded by '}' or followed by '{'`,
70+
);
71+
scrubbedLines.push(line);
72+
continue;
73+
}
74+
75+
if (tokens[0] in tags || tokens[1] in tags) {
76+
const tag = tokens[0] in tags ? tokens[0] : tokens[1];
77+
const brace = tag === tokens[0] ? tokens[1] : tokens[0];
78+
79+
if (brace === tokens[1] && brace !== TAG_START_CHAR) {
80+
reject(
81+
new Error(
82+
`Malformed tag ${filePath}:line ${
83+
i + 1
84+
}: expected '{' after tag name`,
85+
),
86+
);
87+
}
88+
89+
if (brace === tokens[0] && brace !== TAG_END_CHAR) {
90+
reject(
91+
new Error(
92+
`Malformed tag ${filePath}:line ${
93+
i + 1
94+
}: expected '}' before tag name`,
95+
),
96+
);
97+
}
98+
99+
// NOTE: nested tagging is not currently supported and will lead to unexpected behaviour.
100+
101+
if (tags[tag] === "remove") {
102+
skip = brace === TAG_START_CHAR;
103+
}
104+
105+
// We always scrub tags from the final file.
106+
continue;
107+
}
108+
}
109+
110+
if (skip) {
111+
if (isDryRun) {
112+
console.log(`Skipping line ${i + 1}`);
113+
}
114+
continue;
115+
}
116+
117+
scrubbedLines.push(line);
118+
}
119+
120+
if (isDryRun) return;
121+
122+
fs.writeFileSync(filePath, scrubbedLines.join("\n"));
123+
124+
resolve();
125+
});
126+
});
127+
}
128+
129+
export function scrubDir(
130+
dir: string,
131+
tags: TagNameToAction,
132+
isDryRun: boolean,
133+
): Promise<void[]> {
134+
const files = fs.readdirSync(dir);
135+
const promises = files.map<Promise<any>>((name: string) => {
136+
const filePath = path.join(dir, name);
137+
const stat = fs.statSync(filePath);
138+
if (stat.isFile()) {
139+
return scrubFile(filePath, tags, isDryRun);
140+
}
141+
if (stat.isDirectory()) {
142+
return scrubDir(filePath, tags, isDryRun);
143+
}
144+
return Promise.resolve();
145+
});
146+
return Promise.all(promises);
147+
}
148+
149+
export function removeFile(filePath: string): Promise<void> {
150+
const stat = fs.statSync(filePath);
151+
if (stat.isDirectory() || stat.isFile()) {
152+
return new Promise((resolve, reject) =>
153+
fs.rm(filePath, { recursive: true }, (err) => {
154+
if (err) {
155+
reject(err);
156+
}
157+
resolve();
158+
}),
159+
);
160+
}
161+
162+
return Promise.reject(new Error(`${filePath} is not a directory or file.`));
163+
}

scrubber/scrubber.ts

Lines changed: 3 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,10 @@
11
import fs from "fs";
2-
import path from "path";
32
import {
43
ScrubberAction,
54
TagNameToAction,
65
ScrubberConfig,
76
} from "./scrubberTypes";
8-
9-
const TAG_START_CHAR = "{";
10-
const TAG_END_CHAR = "}";
11-
12-
const FILE_TYPE_COMMENT: { [key: string]: string } = {
13-
js: "//",
14-
json: "//",
15-
ts: "//",
16-
py: "#",
17-
};
18-
19-
function scrubberActionsToDict(actions: ScrubberAction[]): TagNameToAction {
20-
const dict: TagNameToAction = {};
21-
actions.forEach((action) => {
22-
action.tags.forEach((tag: string) => {
23-
dict[tag] = action.type;
24-
});
25-
});
26-
return dict;
27-
}
7+
import { scrubberActionsToDict, scrubDir } from "./scrubUtils";
288

299
async function getConfigFile(filename: string): Promise<ScrubberConfig> {
3010
try {
@@ -36,122 +16,6 @@ async function getConfigFile(filename: string): Promise<ScrubberConfig> {
3616
}
3717
}
3818

39-
async function scrubFile(
40-
filePath: string,
41-
tags: TagNameToAction,
42-
isDryRun: boolean,
43-
): Promise<void> {
44-
return new Promise((resolve, reject) => {
45-
fs.readFile(filePath, { encoding: "utf8" }, async (err, text) => {
46-
if (err) {
47-
reject(err);
48-
}
49-
50-
const ext = filePath.split(".").pop();
51-
const commentType = ext && FILE_TYPE_COMMENT[ext];
52-
const scrubbedLines: string[] = [];
53-
let skip = false;
54-
55-
const lines: string[] = text.split("\n");
56-
57-
for (let i = 0; i < lines.length; ++i) {
58-
const line = lines[i];
59-
let tryProcessTag = true;
60-
61-
if (line.length === 0) {
62-
scrubbedLines.push(line);
63-
continue;
64-
}
65-
66-
// Split on whitespace
67-
const tokens = line.trim().split(/[ ]+/);
68-
69-
if (commentType) {
70-
if (tokens[0] !== commentType) {
71-
tryProcessTag = false;
72-
}
73-
tokens.shift();
74-
}
75-
76-
if (tryProcessTag) {
77-
if (tokens[0] in tags && tokens.length !== 2) {
78-
console.warn(
79-
`WARNING line ${
80-
i + 1
81-
}: possible malformed tag; tags must be on their own line preceded by '}' or followed by '{'`,
82-
);
83-
scrubbedLines.push(line);
84-
continue;
85-
}
86-
87-
if (tokens[0] in tags || tokens[1] in tags) {
88-
const tag = tokens[0] in tags ? tokens[0] : tokens[1];
89-
const brace = tag === tokens[0] ? tokens[1] : tokens[0];
90-
91-
if (brace === tokens[1] && brace !== TAG_START_CHAR) {
92-
throw new Error(
93-
`Malformed tag ${filePath}:line ${
94-
i + 1
95-
}: expected '{' after tag name`,
96-
);
97-
}
98-
99-
if (brace === tokens[0] && brace !== TAG_END_CHAR) {
100-
throw new Error(
101-
`Malformed tag ${filePath}:line ${
102-
i + 1
103-
}: expected '}' before tag name`,
104-
);
105-
}
106-
107-
// NOTE: nested tagging is not currently expected and will lead to unexpected behaviour.
108-
109-
if (tags[tag] === "remove") {
110-
skip = brace === TAG_START_CHAR;
111-
}
112-
113-
// We always scrub tags from the final file.
114-
continue;
115-
}
116-
}
117-
118-
if (skip) {
119-
if (isDryRun) {
120-
console.log(`Skipping line ${i + 1}`);
121-
}
122-
continue;
123-
}
124-
125-
scrubbedLines.push(line);
126-
}
127-
128-
if (isDryRun) return;
129-
130-
fs.writeFileSync(filePath, scrubbedLines.join("\n"));
131-
132-
resolve();
133-
});
134-
});
135-
}
136-
137-
async function scrubDir(dir: string, tags: TagNameToAction, isDryRun: boolean) {
138-
const files = await fs.readdirSync(dir);
139-
const promises = files.map(
140-
async (name: string): Promise<void> => {
141-
const filePath = path.join(dir, name);
142-
const stat = fs.statSync(filePath);
143-
if (stat.isFile()) {
144-
return scrubFile(filePath, tags, isDryRun);
145-
}
146-
if (stat.isDirectory()) {
147-
return scrubDir(filePath, tags, isDryRun);
148-
}
149-
return Promise.resolve();
150-
},
151-
);
152-
await Promise.all(promises);
153-
}
154-
15519
class Scrubber {
15620
tags: TagNameToAction = {};
15721

@@ -168,11 +32,11 @@ class Scrubber {
16832
async start(
16933
actions: ScrubberAction[],
17034
isDryRun: boolean = false,
171-
): Promise<void> {
35+
): Promise<void[][]> {
17236
const tags = { ...this.tags, ...scrubberActionsToDict(actions) };
17337

17438
// TODO: specify file extensions?
175-
await Promise.all(this.dirs.map((dir) => scrubDir(dir, tags, isDryRun)));
39+
return Promise.all(this.dirs.map((dir) => scrubDir(dir, tags, isDryRun)));
17640
}
17741
}
17842

0 commit comments

Comments
 (0)