@ts-for-gir/cli 4.0.0-beta.25 → 4.0.0-beta.26

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.
Files changed (62) hide show
  1. package/README.md +84 -2
  2. package/bin/ts-for-gir.js +43 -0
  3. package/package.json +30 -36
  4. package/src/commands/analyze.ts +344 -0
  5. package/src/commands/command-builder.ts +30 -0
  6. package/src/commands/copy.ts +71 -76
  7. package/src/commands/doc.ts +58 -46
  8. package/src/commands/generate.ts +97 -77
  9. package/src/commands/index.ts +6 -4
  10. package/src/commands/json.ts +104 -0
  11. package/src/commands/list.ts +81 -90
  12. package/src/config/config-loader.ts +203 -0
  13. package/src/config/config-writer.ts +52 -0
  14. package/src/config/defaults.ts +61 -0
  15. package/src/config/index.ts +8 -0
  16. package/src/config/options.ts +292 -0
  17. package/src/config.ts +3 -456
  18. package/src/formatters/typescript-formatter.ts +24 -0
  19. package/src/generation-handler.ts +122 -67
  20. package/src/index.ts +4 -4
  21. package/src/module-loader/dependency-resolver.ts +100 -0
  22. package/src/module-loader/file-finder.ts +56 -0
  23. package/src/module-loader/index.ts +8 -0
  24. package/src/module-loader/module-grouper.ts +77 -0
  25. package/src/module-loader/prompt-handler.ts +111 -0
  26. package/src/module-loader.ts +280 -580
  27. package/src/start.ts +18 -14
  28. package/src/types/command-args.ts +110 -0
  29. package/src/types/command-definition.ts +15 -0
  30. package/src/types/commands.ts +35 -0
  31. package/src/types/index.ts +15 -0
  32. package/src/types/report-types.ts +34 -0
  33. package/lib/commands/copy.d.ts +0 -12
  34. package/lib/commands/copy.js +0 -78
  35. package/lib/commands/copy.js.map +0 -1
  36. package/lib/commands/doc.d.ts +0 -12
  37. package/lib/commands/doc.js +0 -38
  38. package/lib/commands/doc.js.map +0 -1
  39. package/lib/commands/generate.d.ts +0 -12
  40. package/lib/commands/generate.js +0 -70
  41. package/lib/commands/generate.js.map +0 -1
  42. package/lib/commands/index.d.ts +0 -4
  43. package/lib/commands/index.js +0 -5
  44. package/lib/commands/index.js.map +0 -1
  45. package/lib/commands/list.d.ts +0 -12
  46. package/lib/commands/list.js +0 -79
  47. package/lib/commands/list.js.map +0 -1
  48. package/lib/config.d.ts +0 -108
  49. package/lib/config.js +0 -409
  50. package/lib/config.js.map +0 -1
  51. package/lib/generation-handler.d.ts +0 -10
  52. package/lib/generation-handler.js +0 -48
  53. package/lib/generation-handler.js.map +0 -1
  54. package/lib/index.d.ts +0 -4
  55. package/lib/index.js +0 -5
  56. package/lib/index.js.map +0 -1
  57. package/lib/module-loader.d.ts +0 -154
  58. package/lib/module-loader.js +0 -465
  59. package/lib/module-loader.js.map +0 -1
  60. package/lib/start.d.ts +0 -2
  61. package/lib/start.js +0 -16
  62. package/lib/start.js.map +0 -1
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Handles dependency resolution and traversal for GIR modules
3
+ */
4
+
5
+ import type { Dependency, DependencyMap, GirModule, GirModuleResolvedBy, GirModulesGroupedMap } from "@ts-for-gir/lib";
6
+ import { isIterable } from "@ts-for-gir/lib";
7
+
8
+ export class DependencyResolver {
9
+ private modDependencyMap: DependencyMap = {};
10
+
11
+ /**
12
+ * Extends the modDependencyMap by the current Module,
13
+ * should be called for each girModule so that the modDependencyMap is complete
14
+ */
15
+ extendDependencyMapByGirModule(girModule: GirModule): void {
16
+ this.modDependencyMap[girModule.packageName] = girModule.dependencies || [];
17
+ }
18
+
19
+ /**
20
+ * Figure out transitive module dependencies
21
+ */
22
+ traverseDependencies(packageName: string, result: { [name: string]: Dependency } = {}): void {
23
+ const deps = this.modDependencyMap[packageName];
24
+ if (isIterable(deps)) {
25
+ for (const dep of deps) {
26
+ if (result[dep.packageName]) continue;
27
+ result[dep.packageName] = dep;
28
+ this.traverseDependencies(dep.packageName, result);
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Get transitive dependencies for a package
35
+ */
36
+ getTransitiveDependencies(packageName: string): Dependency[] {
37
+ const result: { [name: string]: Dependency } = {};
38
+ this.traverseDependencies(packageName, result);
39
+ return Object.values(result);
40
+ }
41
+
42
+ /**
43
+ * Find modules that depend on the module with the name 'packageName'
44
+ */
45
+ findModulesDependingOnPackage(
46
+ girModulesGroupedMap: GirModulesGroupedMap,
47
+ packageName: string,
48
+ ): GirModuleResolvedBy[] {
49
+ const girModules: GirModuleResolvedBy[] = [];
50
+
51
+ for (const girModulesGrouped of Object.values(girModulesGroupedMap)) {
52
+ for (const girModuleResolvedBy of girModulesGrouped.modules) {
53
+ if (girModuleResolvedBy.packageName === packageName) {
54
+ continue;
55
+ }
56
+ for (const dep of girModuleResolvedBy.module.dependencies) {
57
+ if (dep.packageName === packageName && !girModules.includes(girModuleResolvedBy)) {
58
+ girModules.push(girModuleResolvedBy);
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ return girModules;
65
+ }
66
+
67
+ /**
68
+ * Find modules that depend on the modules with the names in `packageNames`
69
+ */
70
+ findModulesDependingOnPackages(
71
+ girModulesGroupedMap: GirModulesGroupedMap,
72
+ packageNames: string[],
73
+ ): GirModuleResolvedBy[] {
74
+ let girModules: GirModuleResolvedBy[] = [];
75
+
76
+ for (const packageName of packageNames) {
77
+ girModules = [...girModules, ...this.findModulesDependingOnPackage(girModulesGroupedMap, packageName)];
78
+ }
79
+
80
+ return girModules;
81
+ }
82
+
83
+ /**
84
+ * Returns a girModule found by `packageName` property
85
+ */
86
+ findGirModuleByFullNames(
87
+ girModules: (GirModuleResolvedBy | GirModule)[],
88
+ packageNames: string[],
89
+ ): Array<GirModuleResolvedBy | GirModule> {
90
+ return girModules.filter((girModule) => packageNames.includes(girModule.packageName));
91
+ }
92
+
93
+ /**
94
+ * Checks if a girModules with the `packageNames` exists
95
+ */
96
+ existsGirModules(girModules: (GirModuleResolvedBy | GirModule)[], packageName: string): boolean {
97
+ const foundModule = this.findGirModuleByFullNames(girModules, [packageName]);
98
+ return foundModule.length > 0;
99
+ }
100
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Handles finding GIR files in the filesystem
3
+ */
4
+
5
+ import { basename, join } from "node:path";
6
+ import type { Dependency, DependencyManager } from "@ts-for-gir/lib";
7
+ import { splitModuleName } from "@ts-for-gir/lib";
8
+ import { glob } from "glob";
9
+
10
+ export class FileFinder {
11
+ constructor(
12
+ private readonly girDirectories: string[],
13
+ private readonly dependencyManager: DependencyManager,
14
+ ) {}
15
+
16
+ /**
17
+ * Find modules with the possibility to use wild cards for module names. E.g. `Gtk*` or `'*'`
18
+ * @param globPackageNames Module names with potential wildcards
19
+ * @param ignore Modules to ignore
20
+ */
21
+ async findGirFiles(globPackageNames: string[], ignore: string[] = []): Promise<Set<string>> {
22
+ const foundFiles = new Set<string>();
23
+
24
+ for (let i = 0; i < globPackageNames.length; i++) {
25
+ if (!globPackageNames[i]) {
26
+ continue;
27
+ }
28
+
29
+ const filename = `${globPackageNames[i]}.gir`;
30
+ const pattern = this.girDirectories.map((girDirectory) => join(girDirectory, filename));
31
+ const ignoreGirs = ignore.map((girDirectory) => `${girDirectory}.gir`);
32
+ const files = await glob(pattern, { ignore: ignoreGirs });
33
+
34
+ files.forEach((file) => foundFiles.add(file));
35
+ }
36
+
37
+ return foundFiles;
38
+ }
39
+
40
+ /**
41
+ * Convert GIR file paths to Dependency objects
42
+ * @param girFiles Set of GIR file paths
43
+ */
44
+ async girFilePathToDependencies(girFiles: Set<string>): Promise<Dependency[]> {
45
+ const dependencies: Dependency[] = [];
46
+
47
+ for (const girFile of girFiles) {
48
+ const packageName = basename(girFile, ".gir");
49
+ const { namespace, version } = splitModuleName(packageName);
50
+ const dep = await this.dependencyManager.get(namespace, version);
51
+ dependencies.push(dep);
52
+ }
53
+
54
+ return dependencies;
55
+ }
56
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Module loader components exports
3
+ */
4
+
5
+ export { DependencyResolver } from "./dependency-resolver.ts";
6
+ export { FileFinder } from "./file-finder.ts";
7
+ export { ModuleGrouper } from "./module-grouper.ts";
8
+ export { PromptHandler } from "./prompt-handler.ts";
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Handles grouping of GIR modules and conflict resolution
3
+ */
4
+
5
+ import type { GirModuleResolvedBy, GirModulesGrouped, GirModulesGroupedMap } from "@ts-for-gir/lib";
6
+ import { splitModuleName } from "@ts-for-gir/lib";
7
+
8
+ export class ModuleGrouper {
9
+ /**
10
+ * Groups Gir modules by name id
11
+ * E.g. Gtk-3.0 and Gtk-4.0 will be grouped
12
+ */
13
+ groupGirFiles(resolveGirModules: Set<GirModuleResolvedBy> | GirModuleResolvedBy[]): GirModulesGroupedMap {
14
+ const girModulesGrouped: GirModulesGroupedMap = {};
15
+
16
+ for (const resolveGirModule of resolveGirModules) {
17
+ const { namespace } = splitModuleName(resolveGirModule.packageName);
18
+ const id = namespace.toLowerCase();
19
+
20
+ if (!girModulesGrouped[id]) {
21
+ girModulesGrouped[id] = {
22
+ namespace: namespace,
23
+ modules: [resolveGirModule],
24
+ hasConflict: false,
25
+ };
26
+ } else {
27
+ girModulesGrouped[id].modules.push(resolveGirModule);
28
+ girModulesGrouped[id].hasConflict = true;
29
+ }
30
+ }
31
+
32
+ return girModulesGrouped;
33
+ }
34
+
35
+ /**
36
+ * Sorts out the module the user has not selected via cli prompt
37
+ * @param girModulesGrouped Grouped modules
38
+ * @param selected Users selected module packageName
39
+ */
40
+ sortVersionsByAnswer(
41
+ girModulesGrouped: GirModulesGrouped,
42
+ selected: string[],
43
+ ): { keep: Set<GirModuleResolvedBy>; ignore: string[] } {
44
+ const keep = new Set<GirModuleResolvedBy>();
45
+ let ignore: string[] = [];
46
+
47
+ if (!girModulesGrouped.hasConflict) {
48
+ keep.add(girModulesGrouped.modules[0]);
49
+ } else {
50
+ const keepModules = this.findGirModuleByFullNames(girModulesGrouped.modules, selected);
51
+ const girModulePackageNames = girModulesGrouped.modules.map((resolveGirModule) => resolveGirModule.packageName);
52
+
53
+ if (!keepModules || keepModules.length <= 0) {
54
+ throw new Error("Module not found!");
55
+ }
56
+
57
+ for (const keepModule of keepModules) {
58
+ keep.add(keepModule);
59
+ }
60
+
61
+ const toIgnore = girModulePackageNames.filter((packageName) => !selected.includes(packageName));
62
+ ignore = ignore.concat(toIgnore);
63
+ }
64
+
65
+ return {
66
+ keep,
67
+ ignore,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Find modules by package names
73
+ */
74
+ private findGirModuleByFullNames(girModules: GirModuleResolvedBy[], packageNames: string[]): GirModuleResolvedBy[] {
75
+ return girModules.filter((girModule) => packageNames.includes(girModule.packageName));
76
+ }
77
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Handles CLI prompts for module version conflicts and ignored modules
3
+ */
4
+
5
+ import { select } from "@inquirer/prompts";
6
+ import type { AnswerVersion, GirModuleResolvedBy, GirModulesGrouped } from "@ts-for-gir/lib";
7
+ import { Logger } from "@ts-for-gir/lib";
8
+ import { bold } from "colorette";
9
+ import { addToConfig, configFilePath } from "../config.ts";
10
+
11
+ export class PromptHandler {
12
+ private readonly log: Logger;
13
+
14
+ constructor(verbose: boolean) {
15
+ this.log = new Logger(verbose, "PromptHandler");
16
+ }
17
+
18
+ /**
19
+ * Ask if user wants to ignore dependencies
20
+ */
21
+ async askIgnoreDepsPrompt(deps: GirModuleResolvedBy[] | Set<GirModuleResolvedBy>): Promise<"Yes" | "No" | "Go back"> {
22
+ const size = (deps as GirModuleResolvedBy[]).length || (deps as Set<GirModuleResolvedBy>).size || 0;
23
+
24
+ if (size > 0) {
25
+ // Show dependencies that would be ignored
26
+ this.log.log(bold("\nThe following modules have the ignored modules as dependencies:"));
27
+ for (const dep of deps) {
28
+ this.log.log(`- ${dep.packageName}`);
29
+ }
30
+ this.log.log(bold("\n"));
31
+
32
+ // Ask if user wants to ignore these dependencies
33
+ return select<"Yes" | "No" | "Go back">({
34
+ message: "Do you want to ignore them too?",
35
+ choices: [
36
+ { value: "Yes", name: "Yes" },
37
+ { value: "No", name: "No" },
38
+ { value: "Go back", name: "Go back" },
39
+ ],
40
+ });
41
+ }
42
+
43
+ // No dependencies found
44
+ this.log.log(bold("\nNo dependencies found on the ignored modules"));
45
+ return select<"Yes" | "Go back">({
46
+ message: "Do you want to continue?",
47
+ choices: [
48
+ { value: "Yes", name: "Yes" },
49
+ { value: "Go back", name: "Go back" },
50
+ ],
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Ask for module version selection
56
+ */
57
+ async askForVersionsPrompt(girModulesGrouped: GirModulesGrouped): Promise<AnswerVersion> {
58
+ const choices = ["All", ...girModulesGrouped.modules.map((module) => module.packageName)];
59
+
60
+ const selected = await select<string>({
61
+ message: `Multiple versions of '${girModulesGrouped.namespace}' found, which one do you want to use?`,
62
+ choices: choices.map((choice) => ({
63
+ value: choice,
64
+ name: choice,
65
+ })),
66
+ });
67
+
68
+ if (selected === "All") {
69
+ return {
70
+ selected: choices.filter((choice) => choice !== "All"),
71
+ unselected: [],
72
+ };
73
+ }
74
+
75
+ return {
76
+ selected: [selected],
77
+ unselected: choices.filter((choice) => choice !== selected && choice !== "All"),
78
+ };
79
+ }
80
+
81
+ /**
82
+ * Ask if user wants to add ignored modules to config
83
+ */
84
+ async askAddToIgnoreToConfigPrompt(ignoredModules: string[] | Set<string>): Promise<void> {
85
+ const shouldAdd = await select<"Yes" | "No">({
86
+ message: `Do you want to add the ignored modules to your config so that you don't need to select them again next time?\n Config path: '${configFilePath}'`,
87
+ choices: [
88
+ { value: "No", name: "No" },
89
+ { value: "Yes", name: "Yes" },
90
+ ],
91
+ });
92
+
93
+ if (shouldAdd === "Yes") {
94
+ await addToConfig({
95
+ ignore: Array.from(ignoredModules),
96
+ });
97
+ this.log.log(`Add ignored modules to '${configFilePath}'`);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Show ignored modules
103
+ */
104
+ showIgnoredModules(ignore: string[]): void {
105
+ if (ignore && ignore.length > 0) {
106
+ const ignoreLogList = `- ${ignore.join("\n- ")}`;
107
+ this.log.log(bold("\n The following modules will be ignored:"));
108
+ this.log.log(`\n${ignoreLogList}\n`);
109
+ }
110
+ }
111
+ }