@ts-for-gir/cli 4.0.0-beta.9 → 4.0.0-rc.10
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/README.md +335 -86
- package/bin/ts-for-gir +28832 -0
- package/bin/ts-for-gir-dev +43 -0
- package/bin/ts-for-gir-gjs +348955 -0
- package/dist-templates/types-locally/.ts-for-girrc.js +6 -0
- package/dist-templates/types-locally/README.md +15 -0
- package/dist-templates/types-locally/esbuild.ts +10 -0
- package/dist-templates/types-locally/main.ts +21 -0
- package/dist-templates/types-locally/package.json +18 -0
- package/dist-templates/types-locally/tsconfig.json +17 -0
- package/dist-templates/types-npm/README.md +14 -0
- package/dist-templates/types-npm/esbuild.ts +10 -0
- package/dist-templates/types-npm/main.ts +19 -0
- package/dist-templates/types-npm/package.json +23 -0
- package/dist-templates/types-npm/tsconfig.json +15 -0
- package/dist-templates/types-workspace/.ts-for-girrc.js +12 -0
- package/dist-templates/types-workspace/README.md +26 -0
- package/dist-templates/types-workspace/package.json +22 -0
- package/dist-templates/types-workspace/packages/app/esbuild.ts +10 -0
- package/dist-templates/types-workspace/packages/app/main.ts +19 -0
- package/dist-templates/types-workspace/packages/app/package.json +23 -0
- package/dist-templates/types-workspace/packages/app/tsconfig.json +15 -0
- package/dist-templates/types-workspace/tsconfig.json +11 -0
- package/package.json +60 -37
- package/src/commands/analyze.ts +344 -0
- package/src/commands/command-builder.ts +30 -0
- package/src/commands/copy.ts +71 -76
- package/src/commands/create.ts +223 -0
- package/src/commands/doc.ts +44 -47
- package/src/commands/generate.ts +35 -79
- package/src/commands/index.ts +8 -4
- package/src/commands/json.ts +43 -0
- package/src/commands/list.ts +71 -90
- package/src/commands/run-generation-command.ts +75 -0
- package/src/commands/self-update.ts +142 -0
- package/src/config/config-loader.ts +238 -0
- package/src/config/config-writer.ts +52 -0
- package/src/config/defaults.ts +68 -0
- package/src/config/index.ts +16 -0
- package/src/config/options.ts +365 -0
- package/src/config.ts +3 -456
- package/src/formatters/typescript-formatter.ts +17 -0
- package/src/generation-handler.ts +122 -67
- package/src/index.ts +4 -4
- package/src/module-loader/dependency-resolver.ts +100 -0
- package/src/module-loader/file-finder.ts +65 -0
- package/src/module-loader/index.ts +8 -0
- package/src/module-loader/module-grouper.ts +77 -0
- package/src/module-loader/prompt-handler.ts +111 -0
- package/src/module-loader.ts +321 -578
- package/src/start.ts +36 -15
- package/src/types/command-args.ts +154 -0
- package/src/types/command-definition.ts +17 -0
- package/src/types/commands.ts +30 -0
- package/src/types/index.ts +15 -0
- package/src/types/report-types.ts +34 -0
- package/lib/commands/copy.d.ts +0 -12
- package/lib/commands/copy.js +0 -80
- package/lib/commands/copy.js.map +0 -1
- package/lib/commands/doc.d.ts +0 -12
- package/lib/commands/doc.js +0 -40
- package/lib/commands/doc.js.map +0 -1
- package/lib/commands/generate.d.ts +0 -12
- package/lib/commands/generate.js +0 -71
- package/lib/commands/generate.js.map +0 -1
- package/lib/commands/index.d.ts +0 -4
- package/lib/commands/index.js +0 -5
- package/lib/commands/index.js.map +0 -1
- package/lib/commands/list.d.ts +0 -12
- package/lib/commands/list.js +0 -81
- package/lib/commands/list.js.map +0 -1
- package/lib/config.d.ts +0 -108
- package/lib/config.js +0 -410
- package/lib/config.js.map +0 -1
- package/lib/generation-handler.d.ts +0 -10
- package/lib/generation-handler.js +0 -48
- package/lib/generation-handler.js.map +0 -1
- package/lib/index.d.ts +0 -4
- package/lib/index.js +0 -5
- package/lib/index.js.map +0 -1
- package/lib/module-loader.d.ts +0 -148
- package/lib/module-loader.js +0 -468
- package/lib/module-loader.js.map +0 -1
- package/lib/start.d.ts +0 -2
- package/lib/start.js +0 -16
- package/lib/start.js.map +0 -1
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything you need for the `ts-for-gir analyze` command is located here
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { APP_NAME, Logger } from "@ts-for-gir/lib";
|
|
7
|
+
import type { ProblemEntry } from "@ts-for-gir/reporter";
|
|
8
|
+
import { analyzeOptions } from "../config.ts";
|
|
9
|
+
import type { AnalyzeCommandArgs, ReportData } from "../types/index.ts";
|
|
10
|
+
import { createBuilder } from "./command-builder.ts";
|
|
11
|
+
|
|
12
|
+
const command = "analyze [options]";
|
|
13
|
+
|
|
14
|
+
const description = "Analyze report files generated by ts-for-gir reporter";
|
|
15
|
+
|
|
16
|
+
const examples: ReadonlyArray<[string, string?]> = [
|
|
17
|
+
[`${APP_NAME} analyze -f ./ts-for-gir-report.json`, "Show summary statistics of the report"],
|
|
18
|
+
[`${APP_NAME} analyze -f ./ts-for-gir-report.json --summary`, "Show only summary statistics"],
|
|
19
|
+
[`${APP_NAME} analyze -f ./ts-for-gir-report.json --severity error critical`, "Show only errors and critical issues"],
|
|
20
|
+
[
|
|
21
|
+
`${APP_NAME} analyze -f ./ts-for-gir-report.json --category type_resolution --detailed`,
|
|
22
|
+
"Show detailed type resolution problems",
|
|
23
|
+
],
|
|
24
|
+
[`${APP_NAME} analyze -f ./ts-for-gir-report.json --namespace GLib --top 5`, "Show top 5 problems in GLib namespace"],
|
|
25
|
+
[
|
|
26
|
+
`${APP_NAME} analyze -f ./ts-for-gir-report.json --type time_t --export ./time_t_issues.json`,
|
|
27
|
+
"Export all time_t related issues",
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
`${APP_NAME} analyze -f ./ts-for-gir-report.json --search "Unable to resolve" --format csv`,
|
|
31
|
+
"Search for resolution failures and export as CSV",
|
|
32
|
+
],
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const builder = createBuilder<AnalyzeCommandArgs>(analyzeOptions, examples);
|
|
36
|
+
|
|
37
|
+
const parseReportDate = (dateValue: string | Date): Date => {
|
|
38
|
+
return typeof dateValue === "string" ? new Date(dateValue) : dateValue;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const loadReportFile = (filePath: string): ReportData => {
|
|
42
|
+
if (!existsSync(filePath)) {
|
|
43
|
+
throw new Error(`Report file not found: ${filePath}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const content = readFileSync(filePath, "utf-8");
|
|
48
|
+
const report = JSON.parse(content) as ReportData;
|
|
49
|
+
|
|
50
|
+
// Convert string dates to Date objects
|
|
51
|
+
report.metadata.generatedAt = parseReportDate(report.metadata.generatedAt);
|
|
52
|
+
report.statistics.startTime = parseReportDate(report.statistics.startTime);
|
|
53
|
+
|
|
54
|
+
if (report.statistics.endTime) {
|
|
55
|
+
report.statistics.endTime = parseReportDate(report.statistics.endTime);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Convert problem timestamps
|
|
59
|
+
report.problems = report.problems.map((problem) => ({
|
|
60
|
+
...problem,
|
|
61
|
+
timestamp: parseReportDate(problem.timestamp),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
return report;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
67
|
+
throw new Error(`Failed to parse report file: ${errorMessage}`);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const filterProblems = (problems: ProblemEntry[], args: AnalyzeCommandArgs): ProblemEntry[] => {
|
|
72
|
+
let filtered = [...problems];
|
|
73
|
+
|
|
74
|
+
// Filter by severity
|
|
75
|
+
if (args.severity?.length) {
|
|
76
|
+
filtered = filtered.filter((p) => args.severity?.includes(p.severity));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Filter by category
|
|
80
|
+
if (args.category?.length) {
|
|
81
|
+
filtered = filtered.filter((p) => args.category?.includes(p.category));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Filter by namespace
|
|
85
|
+
if (args.namespace?.length) {
|
|
86
|
+
filtered = filtered.filter((p) =>
|
|
87
|
+
args.namespace?.some((ns) => p.location?.includes(ns) || p.module?.includes(ns) || p.metadata?.namespace === ns),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Filter by type name
|
|
92
|
+
if (args.type?.length) {
|
|
93
|
+
filtered = filtered.filter((p) => Boolean(p.typeName && args.type?.includes(p.typeName)));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Search filter
|
|
97
|
+
if (args.search) {
|
|
98
|
+
const searchLower = args.search.toLowerCase();
|
|
99
|
+
filtered = filtered.filter(
|
|
100
|
+
(p) =>
|
|
101
|
+
p.message.toLowerCase().includes(searchLower) ||
|
|
102
|
+
p.details?.toLowerCase().includes(searchLower) ||
|
|
103
|
+
p.typeName?.toLowerCase().includes(searchLower),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Time range filters
|
|
108
|
+
if (args.since) {
|
|
109
|
+
const sinceDate = new Date(args.since);
|
|
110
|
+
filtered = filtered.filter((p) => p.timestamp >= sinceDate);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (args.until) {
|
|
114
|
+
const untilDate = new Date(args.until);
|
|
115
|
+
filtered = filtered.filter((p) => p.timestamp <= untilDate);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return filtered;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const displaySummary = (report: ReportData, args: AnalyzeCommandArgs): void => {
|
|
122
|
+
const { statistics } = report;
|
|
123
|
+
|
|
124
|
+
console.log("📊 Report Summary\n");
|
|
125
|
+
|
|
126
|
+
// Basic info
|
|
127
|
+
console.log(`Generated: ${report.metadata.generatedAt}`);
|
|
128
|
+
console.log(`Version: ${report.metadata.version}`);
|
|
129
|
+
console.log(`Total Problems: ${statistics.totalProblems}`);
|
|
130
|
+
|
|
131
|
+
if (statistics.durationMs) {
|
|
132
|
+
console.log(`Generation Duration: ${(statistics.durationMs / 1000).toFixed(2)}s`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Problems by severity
|
|
136
|
+
console.log("\n🔴 Problems by Severity:");
|
|
137
|
+
Object.entries(statistics.bySeverity)
|
|
138
|
+
.filter(([, count]) => count > 0)
|
|
139
|
+
.sort(([, a], [, b]) => b - a)
|
|
140
|
+
.forEach(([severity, count]) => {
|
|
141
|
+
console.log(` ${severity}: ${count}`);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Problems by category
|
|
145
|
+
console.log("\n📂 Problems by Category:");
|
|
146
|
+
Object.entries(statistics.byCategory)
|
|
147
|
+
.filter(([, count]) => count > 0)
|
|
148
|
+
.sort(([, a], [, b]) => b - a)
|
|
149
|
+
.forEach(([category, count]) => {
|
|
150
|
+
console.log(` ${category}: ${count}`);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Top problematic namespaces
|
|
154
|
+
if (statistics.typeStatistics.problematicNamespaces.length > 0) {
|
|
155
|
+
console.log("\n🏢 Most Problematic Namespaces:");
|
|
156
|
+
const topCount = args.top ?? 10;
|
|
157
|
+
statistics.typeStatistics.problematicNamespaces.slice(0, topCount).forEach((ns) => {
|
|
158
|
+
console.log(` ${ns.namespace}: ${ns.problems} problems`);
|
|
159
|
+
if (args.detailed) {
|
|
160
|
+
const typesList = ns.types.slice(0, 5).join(", ");
|
|
161
|
+
const moreTypes = ns.types.length > 5 ? "..." : "";
|
|
162
|
+
console.log(` Types: ${typesList}${moreTypes}`);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Common unresolved types
|
|
168
|
+
if (statistics.typeStatistics.commonUnresolvedTypes.length > 0) {
|
|
169
|
+
console.log("\n🔍 Most Common Unresolved Types:");
|
|
170
|
+
const topCount = args.top ?? 10;
|
|
171
|
+
statistics.typeStatistics.commonUnresolvedTypes.slice(0, topCount).forEach((type) => {
|
|
172
|
+
console.log(` ${type.type}: ${type.count} occurrences`);
|
|
173
|
+
if (args.detailed) {
|
|
174
|
+
const namespacesList = type.namespaces.slice(0, 3).join(", ");
|
|
175
|
+
const moreNamespaces = type.namespaces.length > 3 ? "..." : "";
|
|
176
|
+
console.log(` Namespaces: ${namespacesList}${moreNamespaces}`);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const displayProblems = (problems: ProblemEntry[], args: AnalyzeCommandArgs): void => {
|
|
183
|
+
if (problems.length === 0) {
|
|
184
|
+
console.log("No problems match the specified filters.");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(`\n🔍 Found ${problems.length} matching problems:\n`);
|
|
189
|
+
|
|
190
|
+
problems.forEach((problem, index) => {
|
|
191
|
+
const message = `${index + 1}. [${problem.severity.toUpperCase()}] ${problem.message}`;
|
|
192
|
+
|
|
193
|
+
console.log(message);
|
|
194
|
+
|
|
195
|
+
if (args.detailed) {
|
|
196
|
+
console.log(` ID: ${problem.id}`);
|
|
197
|
+
console.log(` Category: ${problem.category}`);
|
|
198
|
+
console.log(` Module: ${problem.module}`);
|
|
199
|
+
if (problem.typeName) {
|
|
200
|
+
console.log(` Type: ${problem.typeName}`);
|
|
201
|
+
}
|
|
202
|
+
if (problem.location) {
|
|
203
|
+
console.log(` Location: ${problem.location}`);
|
|
204
|
+
}
|
|
205
|
+
if (problem.details) {
|
|
206
|
+
console.log(` Details: ${problem.details}`);
|
|
207
|
+
}
|
|
208
|
+
console.log(` Timestamp: ${problem.timestamp}`);
|
|
209
|
+
if (problem.metadata && Object.keys(problem.metadata).length > 0) {
|
|
210
|
+
console.log(` Metadata: ${JSON.stringify(problem.metadata)}`);
|
|
211
|
+
}
|
|
212
|
+
} else if (problem.typeName) {
|
|
213
|
+
const location = problem.location ?? "unknown";
|
|
214
|
+
console.log(` Type: ${problem.typeName} | Location: ${location}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (index < problems.length - 1) {
|
|
218
|
+
console.log("");
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const formatAsTable = (problems: ProblemEntry[]): string => {
|
|
224
|
+
if (problems.length === 0) {
|
|
225
|
+
return "No problems found.";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const headers = ["Severity", "Category", "Module", "Type", "Message"];
|
|
229
|
+
const rows = problems.map((p) => [
|
|
230
|
+
p.severity,
|
|
231
|
+
p.category,
|
|
232
|
+
p.module ?? "",
|
|
233
|
+
p.typeName ?? "",
|
|
234
|
+
p.message.length > 50 ? `${p.message.substring(0, 47)}...` : p.message,
|
|
235
|
+
]);
|
|
236
|
+
|
|
237
|
+
const columnWidths = headers.map((header, i) => Math.max(header.length, ...rows.map((row) => row[i].length)));
|
|
238
|
+
|
|
239
|
+
const separator = columnWidths.map((w) => "-".repeat(w)).join(" | ");
|
|
240
|
+
const headerRow = headers.map((h, i) => h.padEnd(columnWidths[i])).join(" | ");
|
|
241
|
+
const dataRows = rows.map((row) => row.map((cell, i) => cell.padEnd(columnWidths[i])).join(" | "));
|
|
242
|
+
|
|
243
|
+
return [headerRow, separator, ...dataRows].join("\n");
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const formatAsCsv = (problems: ProblemEntry[]): string => {
|
|
247
|
+
const headers = ["id", "severity", "category", "module", "typeName", "location", "message", "details", "timestamp"];
|
|
248
|
+
const rows = problems.map((p) => [
|
|
249
|
+
p.id,
|
|
250
|
+
p.severity,
|
|
251
|
+
p.category,
|
|
252
|
+
p.module ?? "",
|
|
253
|
+
p.typeName ?? "",
|
|
254
|
+
p.location ?? "",
|
|
255
|
+
`"${p.message.replace(/"/g, '""')}"`,
|
|
256
|
+
`"${(p.details ?? "").replace(/"/g, '""')}"`,
|
|
257
|
+
p.timestamp.toISOString(),
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
return [headers.join(","), ...rows.map((row) => row.join(","))].join("\n");
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const exportResults = (problems: ProblemEntry[], filePath: string, format: string, logger: Logger): void => {
|
|
264
|
+
let content: string;
|
|
265
|
+
|
|
266
|
+
switch (format) {
|
|
267
|
+
case "json": {
|
|
268
|
+
content = JSON.stringify(problems, null, 2);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
case "csv": {
|
|
272
|
+
content = formatAsCsv(problems);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case "table": {
|
|
276
|
+
content = formatAsTable(problems);
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
default: {
|
|
280
|
+
throw new Error(`Unsupported export format: ${format}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
writeFileSync(filePath, content, "utf-8");
|
|
285
|
+
logger.success(`Results exported to: ${filePath}`);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const handler = async (args: AnalyzeCommandArgs): Promise<void> => {
|
|
289
|
+
const logger = new Logger(args.verbose ?? false, "AnalyzeCommand");
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
// Load and parse report file
|
|
293
|
+
const report = loadReportFile(args.reportFile);
|
|
294
|
+
|
|
295
|
+
if (args.verbose) {
|
|
296
|
+
logger.info(`Loaded report with ${report.problems.length} problems`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Show summary if requested or if no specific filters are applied
|
|
300
|
+
const hasFilters = Boolean(args.severity || args.category || args.namespace || args.type || args.search);
|
|
301
|
+
|
|
302
|
+
if (args.summary || !hasFilters) {
|
|
303
|
+
displaySummary(report, args);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// If summary-only mode, stop here
|
|
307
|
+
if (args.summary) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Filter problems based on criteria
|
|
312
|
+
const filteredProblems = filterProblems(report.problems, args);
|
|
313
|
+
|
|
314
|
+
// Display filtered results
|
|
315
|
+
if (hasFilters || args.detailed) {
|
|
316
|
+
displayProblems(filteredProblems, args);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Export results if requested
|
|
320
|
+
if (args.export) {
|
|
321
|
+
const format = args.format ?? "json";
|
|
322
|
+
exportResults(filteredProblems, args.export, format, logger);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Show filter summary if filters were applied
|
|
326
|
+
if (hasFilters && !args.summary) {
|
|
327
|
+
console.log(
|
|
328
|
+
`\n📋 Filter Summary: Showing ${filteredProblems.length} of ${report.problems.length} total problems`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
} catch (error) {
|
|
332
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
333
|
+
logger.error(`Analysis failed: ${errorMessage}`);
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
export const analyze = {
|
|
339
|
+
command,
|
|
340
|
+
description,
|
|
341
|
+
builder,
|
|
342
|
+
handler,
|
|
343
|
+
examples,
|
|
344
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to build yargs commands with common structure
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ConfigFlags } from "@ts-for-gir/lib";
|
|
6
|
+
import type { Argv, BuilderCallback, Options } from "yargs";
|
|
7
|
+
|
|
8
|
+
export interface CommandDefinition {
|
|
9
|
+
command: string;
|
|
10
|
+
description: string;
|
|
11
|
+
builder: BuilderCallback<unknown, ConfigFlags>;
|
|
12
|
+
handler: (args: ConfigFlags) => Promise<void>;
|
|
13
|
+
examples: ReadonlyArray<[string, string?]>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a builder function for yargs commands
|
|
18
|
+
*/
|
|
19
|
+
export function createBuilder<TArgs>(
|
|
20
|
+
options: Record<string, Options>,
|
|
21
|
+
examples: ReadonlyArray<[string, string?]>,
|
|
22
|
+
): BuilderCallback<TArgs, ConfigFlags> {
|
|
23
|
+
return (yargs: Argv<TArgs>) => {
|
|
24
|
+
const optionNames = Object.keys(options);
|
|
25
|
+
for (const optionName of optionNames) {
|
|
26
|
+
yargs = yargs.option(optionName, options[optionName]);
|
|
27
|
+
}
|
|
28
|
+
return yargs.example(examples) as Argv<ConfigFlags>;
|
|
29
|
+
};
|
|
30
|
+
}
|
package/src/commands/copy.ts
CHANGED
|
@@ -2,93 +2,88 @@
|
|
|
2
2
|
* Everything you need for the `ts-for-gir copy` command is located here
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
5
|
+
import { copyFile, mkdir } from "node:fs/promises";
|
|
6
|
+
import { basename, join } from "node:path";
|
|
7
|
+
import type { ConfigFlags, GirModuleResolvedBy, UserConfig } from "@ts-for-gir/lib";
|
|
8
|
+
import { APP_NAME, ERROR_NO_MODULES_FOUND, Logger, NSRegistry } from "@ts-for-gir/lib";
|
|
9
|
+
import { copyOptions, getOptionsGeneration, load } from "../config.ts";
|
|
10
|
+
import { ModuleLoader } from "../module-loader.ts";
|
|
11
|
+
import type { CopyCommandArgs } from "../types/index.ts";
|
|
12
|
+
import { createBuilder } from "./command-builder.ts";
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
const command = "copy [modules..]";
|
|
13
15
|
|
|
14
|
-
const
|
|
16
|
+
const description = "Scan for *.gir files and copy them to a new directory";
|
|
15
17
|
|
|
16
|
-
const
|
|
18
|
+
const logger = new Logger(true, "CopyCommand");
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
const examples: ReadonlyArray<[string, string?]> = [
|
|
21
|
+
[`${APP_NAME} copy -o ./gir`, "Copy found *.gir files to ./gir"],
|
|
22
|
+
[
|
|
23
|
+
`${APP_NAME} copy -g /usr/share/gir-1.0 --ignore=Gtk-3.0 xrandr-1.3 -o ./gir`,
|
|
24
|
+
"Copy all found *.gir files in /usr/share/gir-1.0 excluding Gtk-3.0 and xrandr-1.3 to ./gir",
|
|
25
|
+
],
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const builder = createBuilder<CopyCommandArgs>(copyOptions, examples);
|
|
26
29
|
|
|
27
30
|
const copyGirFile = async (config: UserConfig, depModule: GirModuleResolvedBy) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
31
|
+
if (!depModule.path) {
|
|
32
|
+
logger.danger(`- ${depModule.packageName} not found`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!config.outdir) {
|
|
36
|
+
logger.error("outdir not found");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const filename = basename(depModule.path);
|
|
40
|
+
const dest = join(config.outdir, filename);
|
|
41
|
+
if (depModule.path === dest) {
|
|
42
|
+
logger.yellow(`Skip ${depModule.path}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
logger.success(`Copy ${depModule.path}`);
|
|
46
|
+
await copyFile(depModule.path, dest);
|
|
47
|
+
};
|
|
45
48
|
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
49
|
const handler = async (args: ConfigFlags) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
const config = await load(args);
|
|
51
|
+
const generateConfig = getOptionsGeneration(config);
|
|
52
|
+
const registry = new NSRegistry();
|
|
53
|
+
const moduleLoader = new ModuleLoader(generateConfig, registry);
|
|
54
|
+
const { grouped, failed } = await moduleLoader.getModules(config.modules, config.ignore);
|
|
55
|
+
const moduleGroups = Object.values(grouped);
|
|
56
|
+
if (Object.keys(grouped).length === 0) {
|
|
57
|
+
return logger.error(ERROR_NO_MODULES_FOUND(config.girDirectories));
|
|
58
|
+
}
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if (!config.outdir) {
|
|
61
|
+
logger.error("outdir not found");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
await mkdir(config.outdir, { recursive: true }).catch((err) => {
|
|
66
|
+
logger.error(`Failed to copy gir files to ${config.outdir}: ${err}`);
|
|
67
|
+
});
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
for (const module of moduleGroups) {
|
|
70
|
+
for (const mod of module.modules) {
|
|
71
|
+
await copyGirFile(config, mod);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const examples: ReadonlyArray<[string, string?]> = [
|
|
81
|
-
[`${Config.appName} copy -o ./gir`, `Copy found *.gir files to ./gir`],
|
|
82
|
-
[
|
|
83
|
-
`${Config.appName} copy -g /usr/share/gir-1.0 --ignore=Gtk-3.0 xrandr-1.3 -o ./gir`,
|
|
84
|
-
'Copy all found *.gir files in /usr/share/gir-1.0 excluding Gtk-3.0 and xrandr-1.3 to ./gir',
|
|
85
|
-
],
|
|
86
|
-
]
|
|
75
|
+
if (failed.length > 0) {
|
|
76
|
+
logger.danger("\nDependencies not found:");
|
|
77
|
+
for (const fail of failed) {
|
|
78
|
+
logger.white(`- ${fail}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
87
82
|
|
|
88
83
|
export const copy = {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
84
|
+
command,
|
|
85
|
+
description,
|
|
86
|
+
builder,
|
|
87
|
+
handler,
|
|
88
|
+
examples,
|
|
89
|
+
};
|