Skip to content

Commit 0368de8

Browse files
committed
Use vscode workspace fs API
1 parent 922d97e commit 0368de8

File tree

14 files changed

+172
-81
lines changed

14 files changed

+172
-81
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [2.8.0] 03-07-2024
44

5+
- Updates to use the `vscode.workspace.fs` API
56
- [#13](https://github.com/estruyf/vscode-typescript-exportallmodules/issues/13) [#14](https://github.com/estruyf/vscode-typescript-exportallmodules/issues/14): Added support for named exports (thanks to [Mike Rheault](https://github.com/mrheault))
67

78
## [2.7.0] 11-09-2023

src/commands/ExportAll.ts

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,56 @@
11
import * as vscode from "vscode";
2-
import * as path from "path";
3-
import * as fs from "fs";
42
import {
5-
CONFIG_EXCLUDE,
6-
CONFIG_INCLUDE_FOLDERS,
7-
CONFIG_RELATIVE_EXCLUDE,
8-
CONFIG_SEMIS,
9-
CONFIG_QUOTE,
103
EXTENSION_NAME,
11-
CONFIG_MESSAGE,
124
EXTENSION_KEY,
135
CONFIG_FOLDERS,
14-
CONFIG_NAMED_EXPORTS,
6+
BarrelFiles,
157
} from "../constants";
168
import {
179
clearWildcard,
10+
fileExists,
1811
getAbsoluteFolderPath,
1912
getFileContents,
2013
getRelativeFolderPath,
2114
parseFileForNamedExports,
2215
parseWinPath,
16+
writeFile,
2317
} from "../helpers";
2418
import { Logger } from "../helpers/logger";
25-
26-
interface FileOrFolderToExport {
27-
name: string;
28-
type: "file" | "folder";
29-
}
19+
import { join, parse } from "path";
20+
import { getConfig } from "../helpers/getConfig";
21+
import { FileOrFolderToExport } from "../models";
3022

3123
export class ExportAll {
32-
public static barrelFiles = ["index.ts", "index.tsx"];
33-
3424
public static async start(crntUri: vscode.Uri, runSilent: boolean = true) {
3525
const uri = vscode.Uri.file(clearWildcard(parseWinPath(crntUri.fsPath)));
3626

3727
try {
38-
const config = vscode.workspace.getConfiguration(EXTENSION_KEY);
39-
const excludeFiles: string | undefined = config.get(CONFIG_EXCLUDE);
40-
const excludeRel: string | undefined = config.get(
41-
CONFIG_RELATIVE_EXCLUDE
42-
);
43-
const includeFolders: boolean | undefined = config.get(
44-
CONFIG_INCLUDE_FOLDERS
45-
);
46-
const namedExports: boolean | undefined = config.get(CONFIG_NAMED_EXPORTS);
47-
const semis: boolean | undefined = config.get(CONFIG_SEMIS);
48-
const quote: '"' | "'" = config.get(CONFIG_QUOTE) ?? "'";
49-
const message: string | string[] | undefined = config.get<
50-
string | string[]
51-
>(CONFIG_MESSAGE);
28+
const {
29+
excludeFiles,
30+
excludeRel,
31+
includeFolders,
32+
message,
33+
namedExports,
34+
quote,
35+
semis,
36+
} = getConfig();
5237

5338
const folderPath = uri.fsPath;
54-
const files = fs.readdirSync(folderPath);
39+
const files = await vscode.workspace.fs.readDirectory(
40+
vscode.Uri.parse(folderPath)
41+
);
5542
let filesToExport: FileOrFolderToExport[] = [];
5643

5744
if (files && files.length > 0) {
58-
for (const file of files) {
59-
const absPath = path.join(folderPath, file);
45+
for (const [file] of files) {
46+
const absPath = join(folderPath, file);
6047
let include = false;
6148
let relPath = file;
6249

6350
// Include all TS files except for the index
6451
if (
6552
(file.endsWith(".ts") || file.endsWith(".tsx")) &&
66-
this.barrelFiles.indexOf(file.toLowerCase()) === -1
53+
BarrelFiles.indexOf(file.toLowerCase()) === -1
6754
) {
6855
relPath = getRelativeFolderPath(absPath);
6956
include = true;
@@ -72,10 +59,13 @@ export class ExportAll {
7259
// Check if folders should be included
7360
if (includeFolders) {
7461
// Only allow folder which contain an index file
75-
if (fs.lstatSync(absPath).isDirectory()) {
76-
for (const indexFile of this.barrelFiles) {
77-
const indexPath = path.join(absPath, indexFile);
78-
if (fs.existsSync(indexPath)) {
62+
const stat = await vscode.workspace.fs.stat(
63+
vscode.Uri.file(absPath)
64+
);
65+
if (stat.type === vscode.FileType.Directory) {
66+
for (const indexFile of BarrelFiles) {
67+
const indexPath = join(absPath, indexFile);
68+
if (await fileExists(indexPath)) {
7969
relPath = getRelativeFolderPath(absPath);
8070
include = true;
8171
break;
@@ -114,9 +104,13 @@ export class ExportAll {
114104
// Add the file/folder to the array
115105
if (include) {
116106
try {
107+
const stat = await vscode.workspace.fs.stat(
108+
vscode.Uri.file(absPath)
109+
);
117110
filesToExport.push({
118111
name: file,
119-
type: fs.statSync(absPath).isDirectory() ? "folder" : "file",
112+
type:
113+
stat.type === vscode.FileType.Directory ? "folder" : "file",
120114
});
121115
} catch (ex) {
122116
// Ignore
@@ -127,33 +121,45 @@ export class ExportAll {
127121

128122
// Check if there are still files after the filter
129123
if (filesToExport && filesToExport.length > 0) {
130-
let output = filesToExport.map((item) => {
124+
const output: string[] = [];
125+
126+
for (const item of filesToExport) {
131127
const fileWithoutExtension =
132-
item.type === "folder" ? item.name : path.parse(item.name).name;
128+
item.type === "folder" ? item.name : parse(item.name).name;
133129
if (namedExports) {
134-
const filePath = path.join(uri.fsPath, item.name);
135-
const fileContents = getFileContents(filePath);
136-
const { namedExports, typeExports } = parseFileForNamedExports(fileContents);
130+
const filePath = join(uri.fsPath, item.name);
131+
const fileContents = await getFileContents(filePath);
132+
const { namedExports, typeExports } = parseFileForNamedExports(
133+
fileContents || ""
134+
);
137135

138-
const namedExportsStr = namedExports.filter(Boolean).join(', ');
139-
const typeExportsStr = typeExports.filter(Boolean).join(', ');
140-
let exportStr = '';
136+
const namedExportsStr = namedExports.filter(Boolean).join(", ");
137+
const typeExportsStr = typeExports.filter(Boolean).join(", ");
138+
let exportStr = "";
141139
if (namedExportsStr) {
142-
exportStr += `export { ${namedExportsStr} } from ${quote}./${fileWithoutExtension}${quote}${semis ? ";" : ""}\n`;
140+
exportStr += `export { ${namedExportsStr} } from ${quote}./${fileWithoutExtension}${quote}${
141+
semis ? ";" : ""
142+
}\n`;
143143
}
144144
if (typeExportsStr) {
145-
exportStr += `export type { ${typeExportsStr} } from ${quote}./${fileWithoutExtension}${quote}${semis ? ";" : ""}\n`;
145+
exportStr += `export type { ${typeExportsStr} } from ${quote}./${fileWithoutExtension}${quote}${
146+
semis ? ";" : ""
147+
}\n`;
146148
}
147-
return exportStr;
149+
output.push(exportStr);
148150
} else {
149-
return `export * from ${quote}./${fileWithoutExtension}${quote}${semis ? ";" : ""}\n`;
151+
output.push(
152+
`export * from ${quote}./${fileWithoutExtension}${quote}${
153+
semis ? ";" : ""
154+
}\n`
155+
);
150156
}
151-
});
157+
}
152158

153159
if (output && output.length > 0) {
154-
const filePath = path.join(uri.fsPath, "index.ts");
155-
if (!fs.existsSync(filePath)) {
156-
fs.writeFileSync(filePath, "");
160+
const filePath = join(uri.fsPath, "index.ts");
161+
if (!(await fileExists(filePath))) {
162+
await writeFile(filePath, "");
157163
}
158164

159165
const fileUri = vscode.Uri.file(filePath);
@@ -220,11 +226,10 @@ export class ExportAll {
220226
}
221227
}
222228
} catch (e) {
223-
console.error((e as Error).message);
224-
225229
Logger.error(
226230
`Sorry, something failed when exporting all modules in ${uri.fsPath}`
227231
);
232+
Logger.error((e as Error).message);
228233
vscode.window.showErrorMessage(
229234
`${EXTENSION_NAME}: Sorry, something failed when exporting all modules in the current folder.`
230235
);

src/constants/BarrelFiles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const BarrelFiles = ["index.ts", "index.tsx"];

src/constants/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export * from './Extension';
1+
export * from "./BarrelFiles";
2+
export * from "./Extension";

src/extension.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as vscode from "vscode";
2-
import { ExportAll } from "./commands/ExportAll";
3-
import { FolderListener, ExcludeCommand } from "./commands";
2+
import { FolderListener, ExcludeCommand, ExportAll } from "./commands";
43
import { ExportProvider, ExportFolder } from "./providers";
54
import {
65
EXTENSION_KEY,
@@ -10,14 +9,6 @@ import {
109
} from "./constants";
1110
import { Logger } from "./helpers/logger";
1211

13-
/**
14-
* TODO:
15-
* - add the excluded files & folders to the view
16-
* - add exclude file command
17-
* - add exclude folder command
18-
* - documentation
19-
* @param context
20-
*/
2112
export function activate(context: vscode.ExtensionContext) {
2213
const generate = vscode.commands.registerCommand(
2314
getCommandName(COMMAND_KEYS.Generate),

src/helpers/fileExists.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Uri, workspace } from "vscode";
2+
3+
export const fileExists = async (filePath: string): Promise<boolean> => {
4+
try {
5+
await workspace.fs.stat(Uri.file(filePath));
6+
return true;
7+
} catch (e) {
8+
return false;
9+
}
10+
};

src/helpers/getConfig.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { workspace } from "vscode";
2+
import {
3+
CONFIG_EXCLUDE,
4+
CONFIG_INCLUDE_FOLDERS,
5+
CONFIG_MESSAGE,
6+
CONFIG_NAMED_EXPORTS,
7+
CONFIG_QUOTE,
8+
CONFIG_RELATIVE_EXCLUDE,
9+
CONFIG_SEMIS,
10+
EXTENSION_KEY,
11+
} from "../constants";
12+
import { Config } from "../models";
13+
14+
export const getConfig = (): Config => {
15+
const config = workspace.getConfiguration(EXTENSION_KEY);
16+
const excludeFiles: string | undefined = config.get(CONFIG_EXCLUDE);
17+
const excludeRel: string | undefined = config.get(CONFIG_RELATIVE_EXCLUDE);
18+
const includeFolders: boolean | undefined = config.get(
19+
CONFIG_INCLUDE_FOLDERS
20+
);
21+
const namedExports: boolean | undefined = config.get(CONFIG_NAMED_EXPORTS);
22+
const semis: boolean | undefined = config.get(CONFIG_SEMIS);
23+
const quote: '"' | "'" = config.get(CONFIG_QUOTE) ?? "'";
24+
const message: string | string[] | undefined = config.get<string | string[]>(
25+
CONFIG_MESSAGE
26+
);
27+
28+
return {
29+
excludeFiles,
30+
excludeRel,
31+
includeFolders,
32+
namedExports,
33+
semis,
34+
quote,
35+
message,
36+
};
37+
};

src/helpers/getFileContents.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import * as fs from "fs";
2-
import * as path from "path";
3-
import { ExportAll } from "../commands";
1+
import { join } from "path";
2+
import { fileExists, readFile } from ".";
3+
import { FileType, Uri, workspace } from "vscode";
4+
import { BarrelFiles } from "../constants";
45

5-
export const getFileContents = (filePath: string): string => {
6-
if (fs.lstatSync(filePath).isDirectory()) {
7-
for (const indexFile of ExportAll.barrelFiles) {
8-
const indexPath = path.join(filePath, indexFile);
9-
if (fs.existsSync(indexPath)) {
10-
return fs.readFileSync(indexPath, "utf8");
6+
export const getFileContents = async (
7+
filePath: string
8+
): Promise<string | undefined> => {
9+
const stat = await workspace.fs.stat(Uri.file(filePath));
10+
if (stat.type === FileType.Directory) {
11+
for (const indexFile of BarrelFiles) {
12+
const indexPath = join(filePath, indexFile);
13+
if (await fileExists(indexPath)) {
14+
return await readFile(indexPath);
1115
}
1216
}
13-
return "";
14-
} else if (fs.lstatSync(filePath).isFile()) {
15-
return fs.readFileSync(filePath, "utf8");
17+
return undefined;
18+
} else if (stat.type === FileType.File) {
19+
return await readFile(filePath);
1620
}
17-
return "";
21+
return undefined;
1822
};

src/helpers/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
export * from "./clearWildcard";
2+
export * from "./fileExists";
23
export * from "./getFileContents";
34
export * from "./logger";
45
export * from "./parseFileForNamedExports";
56
export * from "./parseWinPath";
7+
export * from "./readFile";
68
export * from "./util";
9+
export * from "./writeFile";

src/helpers/readFile.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { TextDecoder } from "util";
2+
import { Uri, workspace } from "vscode";
3+
4+
export const readFile = async (
5+
filePath: string
6+
): Promise<string | undefined> => {
7+
const file = await workspace.fs.readFile(Uri.file(filePath));
8+
if (!file) {
9+
return undefined;
10+
}
11+
12+
return new TextDecoder().decode(file);
13+
};

0 commit comments

Comments
 (0)