@repokit/core 4.0.4 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +59 -3
- package/Cargo.toml +2 -1
- package/dist/CommandParser.mjs +4 -5
- package/dist/ConfigurationParser.mjs +3 -3
- package/dist/TSCompiler.mjs +33 -5
- package/dist/index.d.mts +2 -2
- package/dist/types.d.mts +2 -1
- package/externals/CommandParser.ts +5 -6
- package/externals/ConfigurationParser.ts +5 -4
- package/externals/TSCompiler.ts +51 -6
- package/externals/commands/parse_configuration.ts +1 -3
- package/externals/types.ts +5 -0
- package/installation/install.sh +1 -1
- package/internals/caches/crawl_cache.rs +5 -3
- package/internals/context/typescript_bridge.rs +29 -13
- package/internals/file_walker/file_walker.rs +13 -3
- package/internals/file_walker/walker.rs +72 -37
- package/internals/logger/logger.rs +14 -0
- package/internals/repokit/repokit_command.rs +0 -26
- package/internals/repokit/repokit_config.rs +4 -2
- package/package.json +1 -1
package/Cargo.lock
CHANGED
|
@@ -121,6 +121,12 @@ version = "0.6.9"
|
|
|
121
121
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
122
122
|
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
|
123
123
|
|
|
124
|
+
[[package]]
|
|
125
|
+
name = "bytes"
|
|
126
|
+
version = "1.11.1"
|
|
127
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
128
|
+
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
129
|
+
|
|
124
130
|
[[package]]
|
|
125
131
|
name = "cfg-if"
|
|
126
132
|
version = "1.0.4"
|
|
@@ -170,7 +176,7 @@ dependencies = [
|
|
|
170
176
|
"bitflags 1.3.2",
|
|
171
177
|
"crossterm_winapi",
|
|
172
178
|
"libc",
|
|
173
|
-
"mio",
|
|
179
|
+
"mio 0.7.14",
|
|
174
180
|
"parking_lot 0.11.2",
|
|
175
181
|
"signal-hook",
|
|
176
182
|
"signal-hook-mio",
|
|
@@ -685,6 +691,17 @@ dependencies = [
|
|
|
685
691
|
"winapi",
|
|
686
692
|
]
|
|
687
693
|
|
|
694
|
+
[[package]]
|
|
695
|
+
name = "mio"
|
|
696
|
+
version = "1.2.0"
|
|
697
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
698
|
+
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
|
699
|
+
dependencies = [
|
|
700
|
+
"libc",
|
|
701
|
+
"wasi",
|
|
702
|
+
"windows-sys",
|
|
703
|
+
]
|
|
704
|
+
|
|
688
705
|
[[package]]
|
|
689
706
|
name = "miow"
|
|
690
707
|
version = "0.3.7"
|
|
@@ -996,7 +1013,7 @@ checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
|
|
|
996
1013
|
|
|
997
1014
|
[[package]]
|
|
998
1015
|
name = "repokit"
|
|
999
|
-
version = "4.0.
|
|
1016
|
+
version = "4.0.5"
|
|
1000
1017
|
dependencies = [
|
|
1001
1018
|
"alphanumeric-sort",
|
|
1002
1019
|
"colored",
|
|
@@ -1010,6 +1027,7 @@ dependencies = [
|
|
|
1010
1027
|
"serde_json",
|
|
1011
1028
|
"shellexpand",
|
|
1012
1029
|
"terminal-spinners",
|
|
1030
|
+
"tokio",
|
|
1013
1031
|
]
|
|
1014
1032
|
|
|
1015
1033
|
[[package]]
|
|
@@ -1138,7 +1156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
1138
1156
|
checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
|
|
1139
1157
|
dependencies = [
|
|
1140
1158
|
"libc",
|
|
1141
|
-
"mio",
|
|
1159
|
+
"mio 0.7.14",
|
|
1142
1160
|
"signal-hook",
|
|
1143
1161
|
]
|
|
1144
1162
|
|
|
@@ -1164,6 +1182,16 @@ version = "1.15.1"
|
|
|
1164
1182
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1165
1183
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
1166
1184
|
|
|
1185
|
+
[[package]]
|
|
1186
|
+
name = "socket2"
|
|
1187
|
+
version = "0.6.3"
|
|
1188
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1189
|
+
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
|
1190
|
+
dependencies = [
|
|
1191
|
+
"libc",
|
|
1192
|
+
"windows-sys",
|
|
1193
|
+
]
|
|
1194
|
+
|
|
1167
1195
|
[[package]]
|
|
1168
1196
|
name = "stable_deref_trait"
|
|
1169
1197
|
version = "1.2.1"
|
|
@@ -1275,6 +1303,34 @@ dependencies = [
|
|
|
1275
1303
|
"zerovec",
|
|
1276
1304
|
]
|
|
1277
1305
|
|
|
1306
|
+
[[package]]
|
|
1307
|
+
name = "tokio"
|
|
1308
|
+
version = "1.52.1"
|
|
1309
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1310
|
+
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
|
|
1311
|
+
dependencies = [
|
|
1312
|
+
"bytes",
|
|
1313
|
+
"libc",
|
|
1314
|
+
"mio 1.2.0",
|
|
1315
|
+
"parking_lot 0.12.5",
|
|
1316
|
+
"pin-project-lite",
|
|
1317
|
+
"signal-hook-registry",
|
|
1318
|
+
"socket2",
|
|
1319
|
+
"tokio-macros",
|
|
1320
|
+
"windows-sys",
|
|
1321
|
+
]
|
|
1322
|
+
|
|
1323
|
+
[[package]]
|
|
1324
|
+
name = "tokio-macros"
|
|
1325
|
+
version = "2.7.0"
|
|
1326
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1327
|
+
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
|
1328
|
+
dependencies = [
|
|
1329
|
+
"proc-macro2",
|
|
1330
|
+
"quote",
|
|
1331
|
+
"syn",
|
|
1332
|
+
]
|
|
1333
|
+
|
|
1278
1334
|
[[package]]
|
|
1279
1335
|
name = "unicode-general-category"
|
|
1280
1336
|
version = "1.1.0"
|
package/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "repokit"
|
|
3
|
-
version = "4.0.
|
|
3
|
+
version = "4.0.5"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
|
|
6
6
|
[[bin]]
|
|
@@ -20,3 +20,4 @@ shellexpand = "3.1.2"
|
|
|
20
20
|
schemars = "1.2.1"
|
|
21
21
|
terminal-spinners = "0.3.2"
|
|
22
22
|
futures = "0.3.32"
|
|
23
|
+
tokio = { version = "1.52.1", features = ["full"] }
|
package/dist/CommandParser.mjs
CHANGED
|
@@ -6,12 +6,11 @@ import { stat } from "node:fs/promises";
|
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
7
|
//#region externals/CommandParser.ts
|
|
8
8
|
var CommandParser = class extends TSCompiler {
|
|
9
|
-
static async
|
|
9
|
+
static parse = this.wrapParsingOperation(async () => {
|
|
10
10
|
const { paths, root } = this.parsePaths();
|
|
11
|
-
if (!root || !existsSync(root) || !(await stat(root)).isDirectory()) return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
11
|
+
if (!root || !existsSync(root) || !(await stat(root)).isDirectory()) return [];
|
|
12
|
+
return paths.split(",").filter(Boolean).map((path) => this.parseCommand(root, path)).flat();
|
|
13
|
+
});
|
|
15
14
|
static parseCommand(root, path) {
|
|
16
15
|
const commands = [];
|
|
17
16
|
const declaredExports = super.compile(join(root, path));
|
|
@@ -5,12 +5,12 @@ import { join } from "node:path";
|
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
//#region externals/ConfigurationParser.ts
|
|
7
7
|
var ConfigurationParser = class extends TSCompiler {
|
|
8
|
-
static parse() {
|
|
8
|
+
static parse = this.wrapParsingOperation(() => {
|
|
9
9
|
const path = join(this.parseRoot(), "repokit.ts");
|
|
10
10
|
if (!existsSync(path)) return;
|
|
11
11
|
const config = super.compile(path);
|
|
12
|
-
for (const key in config) if (config[key] instanceof RepoKitConfig) return
|
|
13
|
-
}
|
|
12
|
+
for (const key in config) if (config[key] instanceof RepoKitConfig) return config[key].toScoped(path);
|
|
13
|
+
});
|
|
14
14
|
static parseRoot() {
|
|
15
15
|
return parseArgs({ options: { root: {
|
|
16
16
|
default: "",
|
package/dist/TSCompiler.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { __require } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
2
2
|
import { register } from "ts-node";
|
|
3
3
|
//#region externals/TSCompiler.ts
|
|
4
4
|
var TSCompiler = class {
|
|
5
|
+
static PARSE_INDICATOR = "=============== REPOKIT PARSE FLAG ===============";
|
|
5
6
|
static compilerOptions = {
|
|
6
7
|
swc: true,
|
|
7
8
|
typeCheck: false,
|
|
@@ -14,11 +15,38 @@ var TSCompiler = class {
|
|
|
14
15
|
moduleTypes: { "**": "cjs" }
|
|
15
16
|
};
|
|
16
17
|
static compile(path) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
try {
|
|
19
|
+
const compiler = register(this.compilerOptions);
|
|
20
|
+
compiler.enabled(true);
|
|
21
|
+
const result = __require(path);
|
|
22
|
+
compiler.enabled(false);
|
|
23
|
+
return result;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`Failure to parse module at path ${path}`, error);
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
static wrapParsingOperation(operation) {
|
|
30
|
+
return (...params) => {
|
|
31
|
+
const restore = this.plugExits();
|
|
32
|
+
const result = operation(...params);
|
|
33
|
+
if (result instanceof Promise) return result.then((v) => this.toStdout(v, restore));
|
|
34
|
+
return this.toStdout(result, restore);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
static toStdout(result, ...callbacks) {
|
|
38
|
+
if (typeof result !== "undefined") console.log(`${this.PARSE_INDICATOR}${JSON.stringify(result)}${this.PARSE_INDICATOR}`);
|
|
39
|
+
callbacks.forEach((c) => c());
|
|
40
|
+
}
|
|
41
|
+
static plugExits() {
|
|
42
|
+
const { exit, abort } = process;
|
|
43
|
+
process.abort = () => void 0;
|
|
44
|
+
process.exit = (_code) => void 0;
|
|
45
|
+
return () => {
|
|
46
|
+
process.exit = exit;
|
|
47
|
+
process.abort = abort;
|
|
48
|
+
process.exitCode = 0;
|
|
49
|
+
};
|
|
22
50
|
}
|
|
23
51
|
};
|
|
24
52
|
//#endregion
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RepoKitTheme } from "./RepoKitTheme.mjs";
|
|
2
2
|
import { RepoKitConfig } from "./RepoKitConfig.mjs";
|
|
3
|
-
import { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitThemeColors } from "./types.mjs";
|
|
3
|
+
import { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitThemeColors, UnwrappedBrigdeOperation } from "./types.mjs";
|
|
4
4
|
import { RepoKitCommand } from "./RepoKitCommand.mjs";
|
|
5
|
-
export { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitCommand, RepoKitConfig, RepoKitTheme, RepoKitThemeColors };
|
|
5
|
+
export { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitCommand, RepoKitConfig, RepoKitTheme, RepoKitThemeColors, UnwrappedBrigdeOperation };
|
package/dist/types.d.mts
CHANGED
|
@@ -34,5 +34,6 @@ interface IRepoKitTheme {
|
|
|
34
34
|
name: string;
|
|
35
35
|
colors: RepoKitThemeColors;
|
|
36
36
|
}
|
|
37
|
+
type UnwrappedBrigdeOperation<F extends (...args: unknown[]) => unknown, T = void> = ReturnType<F> extends Promise<unknown> ? Promise<T> : T;
|
|
37
38
|
//#endregion
|
|
38
|
-
export { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitThemeColors };
|
|
39
|
+
export { AsyncTask, ICommand, ILocatedCommand, IRepoKitCommand, IRepoKitConfig, IRepoKitTheme, RGBString, RepoKitThemeColors, UnwrappedBrigdeOperation };
|
|
@@ -6,24 +6,23 @@ import { existsSync } from "node:fs";
|
|
|
6
6
|
import type { ILocatedCommand } from "./types";
|
|
7
7
|
import { TSCompiler } from "./TSCompiler";
|
|
8
8
|
import { RepoKitCommand } from "./RepoKitCommand";
|
|
9
|
-
/* oxlint-disable typescript-eslint(no-misused-spread) */
|
|
10
9
|
|
|
11
10
|
export class CommandParser extends TSCompiler {
|
|
12
|
-
public static
|
|
11
|
+
public static readonly parse = this.wrapParsingOperation(async () => {
|
|
13
12
|
const { paths, root } = this.parsePaths();
|
|
14
13
|
if (!root || !existsSync(root) || !(await stat(root)).isDirectory()) {
|
|
15
|
-
return
|
|
14
|
+
return [];
|
|
16
15
|
}
|
|
17
16
|
const pathList = paths.split(",").filter(Boolean);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
17
|
+
return pathList.map(path => this.parseCommand(root, path)).flat();
|
|
18
|
+
});
|
|
21
19
|
|
|
22
20
|
private static parseCommand(root: string, path: string) {
|
|
23
21
|
const commands: ILocatedCommand[] = [];
|
|
24
22
|
const declaredExports = super.compile(join(root, path));
|
|
25
23
|
for (const key in declaredExports) {
|
|
26
24
|
if (declaredExports[key] instanceof RepoKitCommand) {
|
|
25
|
+
// oxlint-disable-next-line typescript-eslint(no-misused-spread)
|
|
27
26
|
commands.push({ ...declaredExports[key], location: path });
|
|
28
27
|
}
|
|
29
28
|
}
|
|
@@ -6,19 +6,20 @@ import { TSCompiler } from "./TSCompiler";
|
|
|
6
6
|
import { RepoKitConfig } from "./RepoKitConfig";
|
|
7
7
|
|
|
8
8
|
export class ConfigurationParser extends TSCompiler {
|
|
9
|
-
public static parse() {
|
|
9
|
+
public static readonly parse = this.wrapParsingOperation(() => {
|
|
10
10
|
const root = this.parseRoot();
|
|
11
11
|
const path = join(root, "repokit.ts");
|
|
12
12
|
if (!existsSync(path)) {
|
|
13
|
-
return;
|
|
13
|
+
return undefined;
|
|
14
14
|
}
|
|
15
15
|
const config = super.compile(path);
|
|
16
16
|
for (const key in config) {
|
|
17
17
|
if (config[key] instanceof RepoKitConfig) {
|
|
18
|
-
return
|
|
18
|
+
return config[key].toScoped(path);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
return undefined;
|
|
22
|
+
});
|
|
22
23
|
|
|
23
24
|
private static parseRoot() {
|
|
24
25
|
return parseArgs({
|
package/externals/TSCompiler.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { register } from "ts-node";
|
|
2
1
|
import type { RegisterOptions } from "ts-node";
|
|
2
|
+
import { register } from "ts-node";
|
|
3
|
+
|
|
4
|
+
import type { UnwrappedBrigdeOperation } from "./types";
|
|
3
5
|
|
|
4
6
|
export class TSCompiler {
|
|
7
|
+
private static PARSE_INDICATOR =
|
|
8
|
+
"=============== REPOKIT PARSE FLAG ===============";
|
|
5
9
|
private static readonly compilerOptions: RegisterOptions = {
|
|
6
10
|
swc: true,
|
|
7
11
|
typeCheck: false,
|
|
@@ -17,10 +21,51 @@ export class TSCompiler {
|
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
public static compile<T extends Record<string, unknown>>(path: string) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
try {
|
|
25
|
+
const compiler = register(this.compilerOptions);
|
|
26
|
+
compiler.enabled(true);
|
|
27
|
+
const result = require(path) as T;
|
|
28
|
+
compiler.enabled(false);
|
|
29
|
+
return result;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error(`Failure to parse module at path ${path}`, error);
|
|
32
|
+
return {} as T;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static wrapParsingOperation<F extends (...args: unknown[]) => unknown>(
|
|
37
|
+
operation: F,
|
|
38
|
+
) {
|
|
39
|
+
return (...params: Parameters<F>) => {
|
|
40
|
+
const restore = this.plugExits();
|
|
41
|
+
const result = operation(...params);
|
|
42
|
+
if (result instanceof Promise) {
|
|
43
|
+
return result.then(v =>
|
|
44
|
+
this.toStdout(v, restore),
|
|
45
|
+
) as UnwrappedBrigdeOperation<F>;
|
|
46
|
+
}
|
|
47
|
+
return this.toStdout(result, restore) as UnwrappedBrigdeOperation<F>;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private static toStdout<T>(result: T, ...callbacks: (() => void)[]) {
|
|
52
|
+
if (typeof result !== "undefined") {
|
|
53
|
+
console.log(
|
|
54
|
+
`${this.PARSE_INDICATOR}${JSON.stringify(result)}${this.PARSE_INDICATOR}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
callbacks.forEach(c => c());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private static plugExits() {
|
|
61
|
+
// oxlint-disable-next-line typescript-eslint(unbound-method)
|
|
62
|
+
const { exit, abort } = process;
|
|
63
|
+
process.abort = () => undefined as never;
|
|
64
|
+
process.exit = (_code?: string | number | null) => undefined as never;
|
|
65
|
+
return () => {
|
|
66
|
+
process.exit = exit;
|
|
67
|
+
process.abort = abort;
|
|
68
|
+
process.exitCode = 0;
|
|
69
|
+
};
|
|
25
70
|
}
|
|
26
71
|
}
|
package/externals/types.ts
CHANGED
package/installation/install.sh
CHANGED
|
@@ -13,12 +13,14 @@ use crate::{
|
|
|
13
13
|
#[derive(Clone)]
|
|
14
14
|
pub struct CrawlCache {
|
|
15
15
|
pub cache_directory: Option<PathBuf>,
|
|
16
|
+
pub changed_files: Option<Vec<String>>,
|
|
16
17
|
pub files_to_crawl: Option<Vec<String>>,
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
impl CrawlCache {
|
|
20
21
|
pub fn new(cache_directory: &Option<PathBuf>) -> Self {
|
|
21
22
|
CrawlCache {
|
|
23
|
+
changed_files: None,
|
|
22
24
|
files_to_crawl: None,
|
|
23
25
|
cache_directory: cache_directory.clone(),
|
|
24
26
|
}
|
|
@@ -34,7 +36,7 @@ impl CrawlCache {
|
|
|
34
36
|
if commit_hash != head_commit {
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
|
-
let
|
|
39
|
+
let lines = self.line_buffer_to_vec(lines);
|
|
38
40
|
if lines.is_empty() {
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
@@ -48,8 +50,8 @@ impl CrawlCache {
|
|
|
48
50
|
changed_files.remove(line);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
if !changed_files.is_empty() {
|
|
54
|
+
self.changed_files = Some(changed_files.into_iter().collect());
|
|
53
55
|
}
|
|
54
56
|
self.files_to_crawl = Some(lines);
|
|
55
57
|
}
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
use core::panic;
|
|
2
2
|
use std::{
|
|
3
3
|
path::{Path, PathBuf},
|
|
4
|
-
sync::MutexGuard,
|
|
4
|
+
sync::{LazyLock, MutexGuard},
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
use regex::Regex;
|
|
7
8
|
use serde_json::{Value, from_str};
|
|
8
9
|
|
|
9
10
|
use crate::{
|
|
10
11
|
context::{file_system::FileSystem, node_scope::NodeScope},
|
|
11
12
|
executor::executor::Executor,
|
|
13
|
+
logger::logger::Logger,
|
|
12
14
|
repokit::{
|
|
13
15
|
repokit_command::RepoKitCommand, repokit_config::RepoKitConfig,
|
|
14
16
|
repokit_runtime::RepoKitRuntime,
|
|
15
17
|
},
|
|
16
18
|
};
|
|
17
19
|
|
|
20
|
+
static BRIDGE_PARSING_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
|
21
|
+
Regex::new(r#"=============== REPOKIT PARSE FLAG ===============(.*)=============== REPOKIT PARSE FLAG ==============="#).unwrap()
|
|
22
|
+
});
|
|
23
|
+
|
|
18
24
|
pub struct TypeScriptBridge;
|
|
19
25
|
|
|
20
26
|
impl TypeScriptBridge {
|
|
@@ -27,14 +33,14 @@ impl TypeScriptBridge {
|
|
|
27
33
|
if stdout.is_empty() {
|
|
28
34
|
RepoKitConfig::create(files);
|
|
29
35
|
}
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
Ok(config)
|
|
33
|
-
|
|
34
|
-
RepoKitConfig::on_parsing_error(&files.git_root, node, Value::Null);
|
|
35
|
-
panic!();
|
|
36
|
+
if let Some(parsed_config) = TypeScriptBridge::unwrap_stdout(&stdout) {
|
|
37
|
+
let parse_result: Result<Value, serde_json::Error> = from_str(parsed_config);
|
|
38
|
+
if let Ok(config) = parse_result {
|
|
39
|
+
return RepoKitConfig::from_input(&files.git_root, node, config);
|
|
36
40
|
}
|
|
37
41
|
}
|
|
42
|
+
Logger::parse_error("configuration", &stdout);
|
|
43
|
+
panic!();
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
pub fn parse_commands(path_list: &MutexGuard<Vec<String>>) -> Vec<RepoKitCommand> {
|
|
@@ -50,14 +56,15 @@ impl TypeScriptBridge {
|
|
|
50
56
|
.as_str(),
|
|
51
57
|
)
|
|
52
58
|
});
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
RepoKitCommand::
|
|
58
|
-
panic!();
|
|
59
|
+
if let Some(parsed_commands) = TypeScriptBridge::unwrap_stdout(&stdout) {
|
|
60
|
+
let parse_result: Result<Vec<Value>, serde_json::Error> =
|
|
61
|
+
serde_json::from_str(parsed_commands);
|
|
62
|
+
if let Ok(commands) = parse_result {
|
|
63
|
+
return RepoKitCommand::from_input(commands);
|
|
59
64
|
}
|
|
60
65
|
}
|
|
66
|
+
Logger::parse_error("commands", &stdout);
|
|
67
|
+
panic!();
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
fn execute_with_node(root: &PathBuf, args: &str) -> String {
|
|
@@ -65,4 +72,13 @@ impl TypeScriptBridge {
|
|
|
65
72
|
cmd.current_dir(Path::new(root))
|
|
66
73
|
})
|
|
67
74
|
}
|
|
75
|
+
|
|
76
|
+
fn unwrap_stdout(stdout: &str) -> Option<&str> {
|
|
77
|
+
if let Some(capture) = BRIDGE_PARSING_REGEX.captures(stdout)
|
|
78
|
+
&& let Some(result) = capture.get(1)
|
|
79
|
+
{
|
|
80
|
+
return Some(result.as_str());
|
|
81
|
+
}
|
|
82
|
+
None
|
|
83
|
+
}
|
|
68
84
|
}
|
|
@@ -2,7 +2,10 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
|
|
2
2
|
|
|
3
3
|
use ignore::WalkBuilder;
|
|
4
4
|
|
|
5
|
-
use crate::{
|
|
5
|
+
use crate::{
|
|
6
|
+
file_walker::walker::{TSFileVisitor, TSFileVisitorBuilder},
|
|
7
|
+
repokit::repokit_runtime::RepoKitRuntime,
|
|
8
|
+
};
|
|
6
9
|
|
|
7
10
|
pub struct FileWalker {
|
|
8
11
|
pub command_paths: Arc<Mutex<Vec<String>>>,
|
|
@@ -47,13 +50,20 @@ impl FileWalker {
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
fn from_cache(&self) {
|
|
50
|
-
let mut paths_to_search = self.command_paths.lock().unwrap();
|
|
51
53
|
RepoKitRuntime::with_runtime(|runtime| {
|
|
54
|
+
let mut paths_to_search = self.command_paths.lock().unwrap();
|
|
52
55
|
if let Some(files_to_crawl) = &runtime.caches.crawl_cache.files_to_crawl {
|
|
53
56
|
for file in files_to_crawl {
|
|
54
57
|
paths_to_search.push(file.to_owned());
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
|
-
|
|
60
|
+
if let Some(changed_files) = &runtime.caches.crawl_cache.changed_files {
|
|
61
|
+
let mut paths_to_import =
|
|
62
|
+
TSFileVisitor::traverse_list(&runtime.git.root, changed_files.to_owned());
|
|
63
|
+
if !paths_to_import.is_empty() {
|
|
64
|
+
paths_to_search.append(&mut paths_to_import);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
58
68
|
}
|
|
59
69
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
use std::{
|
|
2
2
|
fs::File,
|
|
3
3
|
io::{BufRead, BufReader},
|
|
4
|
-
|
|
4
|
+
path::Path,
|
|
5
|
+
sync::{Arc, LazyLock, Mutex},
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
use ignore::{DirEntry, Error, ParallelVisitor, ParallelVisitorBuilder, WalkState};
|
|
8
9
|
use regex::Regex;
|
|
10
|
+
use tokio::task::JoinSet;
|
|
9
11
|
|
|
10
12
|
use crate::{internal_filesystem::file_builder::FileBuilder, logger::logger::Logger};
|
|
11
13
|
|
|
@@ -14,47 +16,80 @@ pub struct TSFileVisitor {
|
|
|
14
16
|
paths: Arc<Mutex<Vec<String>>>,
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
static REPOKIT_IMPORT_MATCHER: LazyLock<Regex> = LazyLock::new(|| {
|
|
20
|
+
Regex::new(r#"(require\(|from[\s*]?)['"]@repokit/core["'][\)]?[;]?$"#).unwrap()
|
|
21
|
+
});
|
|
22
|
+
|
|
17
23
|
impl ParallelVisitor for TSFileVisitor {
|
|
18
24
|
fn visit(&mut self, entry: Result<DirEntry, Error>) -> WalkState {
|
|
19
25
|
let root_replacer = format!("{}/", self.root);
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if repokit_import_matcher.is_match(line) {
|
|
43
|
-
let mut vector = self.paths.lock().unwrap();
|
|
44
|
-
vector.push(path_string.to_string().replace(&root_replacer, ""));
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
if !line.is_empty()
|
|
48
|
-
&& !line.starts_with("import ")
|
|
49
|
-
&& !line.contains("require(")
|
|
50
|
-
&& !(line.starts_with("//") || line.starts_with("/*"))
|
|
51
|
-
{
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
26
|
+
if let Ok(file_entry) = entry
|
|
27
|
+
&& file_entry.file_type().is_some_and(|ft| ft.is_file())
|
|
28
|
+
&& file_entry.file_name().to_string_lossy().ends_with(".ts")
|
|
29
|
+
&& let Some(matched_path) = TSFileVisitor::on_file(file_entry.path())
|
|
30
|
+
{
|
|
31
|
+
let mut vector = self.paths.lock().unwrap();
|
|
32
|
+
vector.push(matched_path.to_string_lossy().replace(&root_replacer, ""));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
WalkState::Continue
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl TSFileVisitor {
|
|
40
|
+
#[tokio::main]
|
|
41
|
+
pub async fn traverse_list(root: &str, path_list: Vec<String>) -> Vec<String> {
|
|
42
|
+
let mut handles = JoinSet::new();
|
|
43
|
+
let root_replacer = format!("{}/", root);
|
|
44
|
+
for path in path_list {
|
|
45
|
+
handles.spawn(async move {
|
|
46
|
+
if let Some(result) = TSFileVisitor::on_file(Path::new(&path)) {
|
|
47
|
+
return Some(result.to_owned());
|
|
54
48
|
}
|
|
49
|
+
None
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
handles
|
|
53
|
+
.join_all()
|
|
54
|
+
.await
|
|
55
|
+
.iter()
|
|
56
|
+
.filter_map(|result| {
|
|
57
|
+
result
|
|
58
|
+
.as_ref()
|
|
59
|
+
.map(|path| path.to_string_lossy().replace(&root_replacer, ""))
|
|
60
|
+
})
|
|
61
|
+
.collect()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
pub fn on_file(path: &Path) -> Option<&Path> {
|
|
65
|
+
let mut open_comment = false;
|
|
66
|
+
let file: File = FileBuilder::open(path, |_| Logger::open_file_error());
|
|
67
|
+
let reader: BufReader<File> = BufReader::new(file);
|
|
68
|
+
for line_result in reader.lines() {
|
|
69
|
+
let unwrapped = line_result.unwrap();
|
|
70
|
+
let line = unwrapped.trim();
|
|
71
|
+
if !open_comment && line.starts_with("/*") {
|
|
72
|
+
open_comment = true;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if open_comment {
|
|
76
|
+
if line.ends_with("*/") {
|
|
77
|
+
open_comment = false;
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if REPOKIT_IMPORT_MATCHER.is_match(line) {
|
|
82
|
+
return Some(path);
|
|
83
|
+
}
|
|
84
|
+
if !line.is_empty()
|
|
85
|
+
&& !line.starts_with("import ")
|
|
86
|
+
&& !line.contains("require(")
|
|
87
|
+
&& !(line.starts_with("//") || line.starts_with("/*"))
|
|
88
|
+
{
|
|
89
|
+
break;
|
|
55
90
|
}
|
|
56
91
|
}
|
|
57
|
-
|
|
92
|
+
None
|
|
58
93
|
}
|
|
59
94
|
}
|
|
60
95
|
|
|
@@ -72,8 +107,8 @@ impl<'a> TSFileVisitorBuilder<'a> {
|
|
|
72
107
|
impl<'s> ParallelVisitorBuilder<'s> for TSFileVisitorBuilder<'s> {
|
|
73
108
|
fn build(&mut self) -> Box<dyn ParallelVisitor + 's> {
|
|
74
109
|
Box::new(TSFileVisitor {
|
|
75
|
-
paths: self.paths.clone(),
|
|
76
110
|
root: self.root.to_string(),
|
|
111
|
+
paths: self.paths.clone(),
|
|
77
112
|
})
|
|
78
113
|
}
|
|
79
114
|
}
|
|
@@ -55,6 +55,20 @@ impl Logger {
|
|
|
55
55
|
})
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
pub fn parse_error(file_type: &str, stdout: &str) {
|
|
59
|
+
Logger::info(format!("There was an error parsing your {}", file_type).as_str());
|
|
60
|
+
Logger::info(
|
|
61
|
+
"This can occur when RepoKit attempts to parse a TypeScript file that can terminate the process upon evaluation",
|
|
62
|
+
);
|
|
63
|
+
Logger::info("Please file a bug to with any related error or stack trace found below");
|
|
64
|
+
Logger::log_issue_link();
|
|
65
|
+
println!();
|
|
66
|
+
if !stdout.is_empty() {
|
|
67
|
+
println!("{stdout}");
|
|
68
|
+
}
|
|
69
|
+
panic!();
|
|
70
|
+
}
|
|
71
|
+
|
|
58
72
|
pub fn space_around(message: &str) {
|
|
59
73
|
println!("\n{}{}\n", Logger::info_prefix(), message);
|
|
60
74
|
}
|
|
@@ -73,32 +73,6 @@ impl RepoKitCommand {
|
|
|
73
73
|
None
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
pub fn full_blown_crash() {
|
|
77
|
-
Logger::error("I hit a snag parsing your commands");
|
|
78
|
-
Logger::error(
|
|
79
|
-
format!(
|
|
80
|
-
"This kind of error is indicative of a bug within {}",
|
|
81
|
-
Logger::with_theme(|theme| theme.highlight("Repokit"))
|
|
82
|
-
)
|
|
83
|
-
.as_str(),
|
|
84
|
-
);
|
|
85
|
-
println!();
|
|
86
|
-
Logger::info("Let's blaim the AI's for this one");
|
|
87
|
-
let version = RepoKitRuntime::with_runtime(|runtime| {
|
|
88
|
-
runtime.caches.version_cache.installed_version.clone()
|
|
89
|
-
});
|
|
90
|
-
Logger::info(
|
|
91
|
-
format!(
|
|
92
|
-
"In the interim, please file a bug here and downgrade to the most recent version behind {}",
|
|
93
|
-
Logger::with_theme(|theme| theme.highlight(&version))
|
|
94
|
-
)
|
|
95
|
-
.as_str(),
|
|
96
|
-
);
|
|
97
|
-
Logger::log_issue_link();
|
|
98
|
-
Logger::info("We'll get a hotfix out asap!");
|
|
99
|
-
panic!();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
76
|
fn register_encountered_errors(failed_paths: Vec<String>) {
|
|
103
77
|
PostProcessor::get().register_task(move || {
|
|
104
78
|
println!();
|
|
@@ -74,12 +74,14 @@ impl RepoKitConfig {
|
|
|
74
74
|
if path.exists() {
|
|
75
75
|
Logger::info(
|
|
76
76
|
format!(
|
|
77
|
-
"I found a Repokit configuration
|
|
77
|
+
"I found a Repokit configuration but could not resolve the exported {} instance",
|
|
78
78
|
Logger::with_theme(|theme| theme.highlight("RepokitConfig"))
|
|
79
79
|
)
|
|
80
80
|
.as_str(),
|
|
81
81
|
);
|
|
82
|
-
|
|
82
|
+
Logger::exit_with_info(
|
|
83
|
+
"Please double check that your config file is free of any sideffects that can cause the parser to crash",
|
|
84
|
+
);
|
|
83
85
|
}
|
|
84
86
|
Logger::info("Welcome to Repokit! Let's get you setup");
|
|
85
87
|
Logger::info("Creating your configuration file:");
|