@akanjs/devkit 0.0.143 → 0.0.145
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/cjs/src/aiEditor.js +152 -16
- package/cjs/src/builder.js +1 -2
- package/cjs/src/commandDecorators/command.js +0 -1
- package/cjs/src/executors.js +151 -60
- package/cjs/src/guideline.js +15 -0
- package/cjs/src/index.js +5 -1
- package/cjs/src/linter.js +238 -0
- package/cjs/src/prompter.js +78 -0
- package/cjs/src/typeChecker.js +203 -0
- package/cjs/src/uploadRelease.js +59 -33
- package/esm/src/aiEditor.js +158 -17
- package/esm/src/builder.js +1 -2
- package/esm/src/commandDecorators/command.js +0 -1
- package/esm/src/executors.js +152 -61
- package/esm/src/guideline.js +0 -0
- package/esm/src/index.js +2 -0
- package/esm/src/linter.js +205 -0
- package/esm/src/prompter.js +45 -0
- package/esm/src/typeChecker.js +170 -0
- package/esm/src/uploadRelease.js +59 -33
- package/package.json +3 -1
- package/src/aiEditor.d.ts +23 -4
- package/src/executors.d.ts +63 -23
- package/src/guideline.d.ts +19 -0
- package/src/index.d.ts +2 -0
- package/src/linter.d.ts +109 -0
- package/src/prompter.d.ts +13 -0
- package/src/typeChecker.d.ts +49 -0
- package/src/types.d.ts +4 -0
- package/src/uploadRelease.d.ts +1 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var linter_exports = {};
|
|
29
|
+
__export(linter_exports, {
|
|
30
|
+
Linter: () => Linter
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(linter_exports);
|
|
33
|
+
var import_common = require("@akanjs/common");
|
|
34
|
+
var import_chalk = __toESM(require("chalk"));
|
|
35
|
+
var import_eslint = require("eslint");
|
|
36
|
+
var fs = __toESM(require("fs"));
|
|
37
|
+
var path = __toESM(require("path"));
|
|
38
|
+
class Linter {
|
|
39
|
+
#logger = new import_common.Logger("Linter");
|
|
40
|
+
#eslint;
|
|
41
|
+
lintRoot;
|
|
42
|
+
constructor(cwdPath) {
|
|
43
|
+
this.lintRoot = this.#findEslintRootPath(cwdPath);
|
|
44
|
+
this.#eslint = new import_eslint.ESLint({ cwd: this.lintRoot, errorOnUnmatchedPattern: false });
|
|
45
|
+
}
|
|
46
|
+
#findEslintRootPath(dir) {
|
|
47
|
+
const configPath = path.join(dir, "eslint.config.ts");
|
|
48
|
+
if (fs.existsSync(configPath))
|
|
49
|
+
return dir;
|
|
50
|
+
const parentDir = path.dirname(dir);
|
|
51
|
+
return this.#findEslintRootPath(parentDir);
|
|
52
|
+
}
|
|
53
|
+
async lint(filePath, { fix = false, dryRun = false } = {}) {
|
|
54
|
+
if (fix)
|
|
55
|
+
return await this.fixFile(filePath, dryRun);
|
|
56
|
+
return await this.lintFile(filePath);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Lint a single file using ESLint
|
|
60
|
+
* @param filePath - Path to the file to lint
|
|
61
|
+
* @returns Array of ESLint results
|
|
62
|
+
*/
|
|
63
|
+
async lintFile(filePath) {
|
|
64
|
+
if (!fs.existsSync(filePath))
|
|
65
|
+
throw new Error(`File not found: ${filePath}`);
|
|
66
|
+
const isIgnored = await this.#eslint.isPathIgnored(filePath);
|
|
67
|
+
if (isIgnored) {
|
|
68
|
+
this.#logger.warn(`File ${filePath} is ignored by ESLint configuration`);
|
|
69
|
+
return { fixed: false, results: [], errors: [], warnings: [] };
|
|
70
|
+
}
|
|
71
|
+
const results = await this.#eslint.lintFiles([filePath]);
|
|
72
|
+
const errors = results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
|
|
73
|
+
const warnings = results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
|
|
74
|
+
return { fixed: false, results, errors, warnings };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Format lint results for console output
|
|
78
|
+
* @param results - Array of ESLint results
|
|
79
|
+
* @returns Formatted string
|
|
80
|
+
*/
|
|
81
|
+
formatLintResults(results) {
|
|
82
|
+
if (results.length === 0)
|
|
83
|
+
return "No files to lint";
|
|
84
|
+
const output = [];
|
|
85
|
+
let totalErrors = 0;
|
|
86
|
+
let totalWarnings = 0;
|
|
87
|
+
results.forEach((result) => {
|
|
88
|
+
totalErrors += result.errorCount;
|
|
89
|
+
totalWarnings += result.warningCount;
|
|
90
|
+
if (result.messages.length > 0) {
|
|
91
|
+
output.push(`
|
|
92
|
+
${import_chalk.default.cyan(result.filePath)}`);
|
|
93
|
+
let sourceLines = [];
|
|
94
|
+
if (fs.existsSync(result.filePath)) {
|
|
95
|
+
try {
|
|
96
|
+
const sourceContent = fs.readFileSync(result.filePath, "utf8");
|
|
97
|
+
sourceLines = sourceContent.split("\n");
|
|
98
|
+
} catch (error) {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
result.messages.forEach((message) => {
|
|
102
|
+
const type = message.severity === 2 ? "error" : "warning";
|
|
103
|
+
const typeColor = message.severity === 2 ? import_chalk.default.red : import_chalk.default.yellow;
|
|
104
|
+
const icon = message.severity === 2 ? "\u274C" : "\u26A0\uFE0F";
|
|
105
|
+
const ruleInfo = message.ruleId ? import_chalk.default.dim(` (${message.ruleId})`) : "";
|
|
106
|
+
output.push(`
|
|
107
|
+
${icon} ${typeColor(type)}: ${message.message}${ruleInfo}`);
|
|
108
|
+
output.push(` ${import_chalk.default.gray("at")} ${result.filePath}:${import_chalk.default.bold(`${message.line}:${message.column}`)}`);
|
|
109
|
+
if (sourceLines.length > 0 && message.line <= sourceLines.length) {
|
|
110
|
+
const sourceLine = sourceLines[message.line - 1];
|
|
111
|
+
const lineNumber = message.line.toString().padStart(5, " ");
|
|
112
|
+
output.push(`
|
|
113
|
+
${import_chalk.default.dim(lineNumber + " |")} ${sourceLine}`);
|
|
114
|
+
const underlinePrefix = " ".repeat(message.column - 1);
|
|
115
|
+
const underlineLength = message.endColumn ? message.endColumn - message.column : 1;
|
|
116
|
+
const underline = "^".repeat(Math.max(1, underlineLength));
|
|
117
|
+
output.push(`${import_chalk.default.dim(" ".repeat(lineNumber.length) + " |")} ${underlinePrefix}${typeColor(underline)}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
if (totalErrors === 0 && totalWarnings === 0)
|
|
123
|
+
return import_chalk.default.bold("\u2705 No ESLint errors or warnings found");
|
|
124
|
+
const errorText = totalErrors > 0 ? import_chalk.default.red(`${totalErrors} error(s)`) : "0 errors";
|
|
125
|
+
const warningText = totalWarnings > 0 ? import_chalk.default.yellow(`${totalWarnings} warning(s)`) : "0 warnings";
|
|
126
|
+
const summary = [`
|
|
127
|
+
${errorText}, ${warningText} found`];
|
|
128
|
+
return summary.concat(output).join("\n");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get detailed lint information
|
|
132
|
+
* @param filePath - Path to the file to lint
|
|
133
|
+
* @returns Object containing detailed lint information
|
|
134
|
+
*/
|
|
135
|
+
async getDetailedLintInfo(filePath) {
|
|
136
|
+
const { results } = await this.lintFile(filePath);
|
|
137
|
+
const details = results.flatMap(
|
|
138
|
+
(result) => result.messages.map((message) => ({
|
|
139
|
+
line: message.line,
|
|
140
|
+
column: message.column,
|
|
141
|
+
message: message.message,
|
|
142
|
+
ruleId: message.ruleId,
|
|
143
|
+
severity: message.severity === 2 ? "error" : "warning",
|
|
144
|
+
fix: message.fix,
|
|
145
|
+
suggestions: message.suggestions
|
|
146
|
+
}))
|
|
147
|
+
);
|
|
148
|
+
const stats = results.reduce(
|
|
149
|
+
(acc, result) => ({
|
|
150
|
+
errorCount: acc.errorCount + result.errorCount,
|
|
151
|
+
warningCount: acc.warningCount + result.warningCount,
|
|
152
|
+
fixableErrorCount: acc.fixableErrorCount + result.fixableErrorCount,
|
|
153
|
+
fixableWarningCount: acc.fixableWarningCount + result.fixableWarningCount
|
|
154
|
+
}),
|
|
155
|
+
{ errorCount: 0, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0 }
|
|
156
|
+
);
|
|
157
|
+
return { results, details, stats };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Check if a file has lint errors
|
|
161
|
+
* @param filePath - Path to the file to check
|
|
162
|
+
* @returns true if there are no errors, false otherwise
|
|
163
|
+
*/
|
|
164
|
+
async hasNoLintErrors(filePath) {
|
|
165
|
+
try {
|
|
166
|
+
const { results } = await this.lintFile(filePath);
|
|
167
|
+
return results.every((result) => result.errorCount === 0);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get only error messages (excluding warnings)
|
|
174
|
+
* @param filePath - Path to the file to lint
|
|
175
|
+
* @returns Array of error messages
|
|
176
|
+
*/
|
|
177
|
+
async getErrors(filePath) {
|
|
178
|
+
const { results } = await this.lintFile(filePath);
|
|
179
|
+
return results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get only warning messages
|
|
183
|
+
* @param filePath - Path to the file to lint
|
|
184
|
+
* @returns Array of warning messages
|
|
185
|
+
*/
|
|
186
|
+
async getWarnings(filePath) {
|
|
187
|
+
const { results } = await this.lintFile(filePath);
|
|
188
|
+
return results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Fix lint errors automatically
|
|
192
|
+
* @param filePath - Path to the file to fix
|
|
193
|
+
* @param dryRun - If true, returns the fixed content without writing to file
|
|
194
|
+
* @returns Fixed content and remaining issues
|
|
195
|
+
*/
|
|
196
|
+
async fixFile(filePath, dryRun = false) {
|
|
197
|
+
if (!fs.existsSync(filePath))
|
|
198
|
+
throw new Error(`File not found: ${filePath}`);
|
|
199
|
+
const eslint = new import_eslint.ESLint({ cwd: this.lintRoot, fix: true });
|
|
200
|
+
const results = await eslint.lintFiles([filePath]);
|
|
201
|
+
const errors = results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
|
|
202
|
+
const warnings = results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
|
|
203
|
+
if (!dryRun)
|
|
204
|
+
await import_eslint.ESLint.outputFixes(results);
|
|
205
|
+
const fixedResult = results[0];
|
|
206
|
+
return { fixed: fixedResult.output !== void 0, output: fixedResult.output, results, errors, warnings };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get ESLint configuration for a file
|
|
210
|
+
* @param filePath - Path to the file
|
|
211
|
+
* @returns ESLint configuration object
|
|
212
|
+
*/
|
|
213
|
+
async getConfigForFile(filePath) {
|
|
214
|
+
const eslint = new import_eslint.ESLint();
|
|
215
|
+
const config = await eslint.calculateConfigForFile(filePath);
|
|
216
|
+
return config;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get rules that are causing errors in a file
|
|
220
|
+
* @param filePath - Path to the file to check
|
|
221
|
+
* @returns Object mapping rule IDs to their error counts
|
|
222
|
+
*/
|
|
223
|
+
async getProblematicRules(filePath) {
|
|
224
|
+
const { results } = await this.lintFile(filePath);
|
|
225
|
+
const ruleCounts = {};
|
|
226
|
+
results.forEach((result) => {
|
|
227
|
+
result.messages.forEach((message) => {
|
|
228
|
+
if (message.ruleId)
|
|
229
|
+
ruleCounts[message.ruleId] = (ruleCounts[message.ruleId] || 0) + 1;
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
return ruleCounts;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
236
|
+
0 && (module.exports = {
|
|
237
|
+
Linter
|
|
238
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var prompter_exports = {};
|
|
29
|
+
__export(prompter_exports, {
|
|
30
|
+
Prompter: () => Prompter
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(prompter_exports);
|
|
33
|
+
var import_prompts = require("@inquirer/prompts");
|
|
34
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
35
|
+
class Prompter {
|
|
36
|
+
static async selectGuideline() {
|
|
37
|
+
const guideNames = (await import_promises.default.readdir(`${__dirname}/src/guidelines`)).filter((name) => !name.startsWith("_"));
|
|
38
|
+
return await (0, import_prompts.select)({ message: "Select a guideline", choices: guideNames.map((name) => ({ name, value: name })) });
|
|
39
|
+
}
|
|
40
|
+
static async getGuideJson(guideName) {
|
|
41
|
+
const filePath = `${__dirname}/src/guidelines/${guideName}/${guideName}.generate.json`;
|
|
42
|
+
const guideJson = await import_promises.default.readFile(filePath, "utf-8");
|
|
43
|
+
return JSON.parse(guideJson);
|
|
44
|
+
}
|
|
45
|
+
static async getInstruction(guideName) {
|
|
46
|
+
const filePath = `${__dirname}/src/guidelines/${guideName}/${guideName}.instruction.md`;
|
|
47
|
+
const content = await import_promises.default.readFile(filePath, "utf-8");
|
|
48
|
+
return content;
|
|
49
|
+
}
|
|
50
|
+
async makeTsFileUpdatePrompt({ context, request }) {
|
|
51
|
+
return `You are a senior developer writing TypeScript-based programs using Akan.js, an in-house framework. Here's an overview of the Akan.js framework:
|
|
52
|
+
${await this.getDocumentation("framework")}
|
|
53
|
+
Please understand the following background information, write code that meets the requirements, verify that it satisfies the validation conditions, and return the result.
|
|
54
|
+
|
|
55
|
+
# Background Information
|
|
56
|
+
\`\`\`markdown
|
|
57
|
+
${context}
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
# Requirements
|
|
61
|
+
\`\`\`markdown
|
|
62
|
+
${request}
|
|
63
|
+
\`\`\`
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
async getDocumentation(guideName) {
|
|
67
|
+
const filePath = `${__dirname}/src/guidelines/${guideName}/${guideName}.instruction.md`;
|
|
68
|
+
const document = await import_promises.default.readFile(filePath, "utf-8");
|
|
69
|
+
return `\`\`\`markdown
|
|
70
|
+
${document}
|
|
71
|
+
\`\`\`
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
76
|
+
0 && (module.exports = {
|
|
77
|
+
Prompter
|
|
78
|
+
});
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var typeChecker_exports = {};
|
|
29
|
+
__export(typeChecker_exports, {
|
|
30
|
+
TypeChecker: () => TypeChecker
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(typeChecker_exports);
|
|
33
|
+
var import_chalk = __toESM(require("chalk"));
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var ts = __toESM(require("typescript"));
|
|
37
|
+
class TypeChecker {
|
|
38
|
+
configPath;
|
|
39
|
+
configFile;
|
|
40
|
+
config;
|
|
41
|
+
constructor(executor) {
|
|
42
|
+
const configPath = this.#findConfigFile(executor.cwdPath);
|
|
43
|
+
if (!configPath)
|
|
44
|
+
throw new Error("No tsconfig.json found in the project");
|
|
45
|
+
this.configPath = configPath;
|
|
46
|
+
this.configFile = ts.readConfigFile(this.configPath, (fileName) => ts.sys.readFile(fileName));
|
|
47
|
+
const parsedConfig = ts.parseJsonConfigFileContent(
|
|
48
|
+
this.configFile.config,
|
|
49
|
+
ts.sys,
|
|
50
|
+
path.dirname(this.configPath),
|
|
51
|
+
void 0,
|
|
52
|
+
this.configPath
|
|
53
|
+
);
|
|
54
|
+
if (parsedConfig.errors.length > 0) {
|
|
55
|
+
const errorMessages = parsedConfig.errors.map((error) => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n");
|
|
56
|
+
throw new Error(`Error parsing tsconfig.json:
|
|
57
|
+
${errorMessages}`);
|
|
58
|
+
}
|
|
59
|
+
this.config = parsedConfig;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Find tsconfig.json by walking up the directory tree
|
|
63
|
+
*/
|
|
64
|
+
#findConfigFile(searchPath) {
|
|
65
|
+
return ts.findConfigFile(searchPath, (fileName) => ts.sys.fileExists(fileName), "tsconfig.json");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Type-check a single TypeScript file
|
|
69
|
+
* @param filePath - Path to the TypeScript file to check
|
|
70
|
+
* @returns Array of diagnostic messages
|
|
71
|
+
*/
|
|
72
|
+
check(filePath) {
|
|
73
|
+
const program = ts.createProgram([filePath], this.config.options);
|
|
74
|
+
const diagnostics = [
|
|
75
|
+
...program.getSemanticDiagnostics(),
|
|
76
|
+
...program.getSyntacticDiagnostics(),
|
|
77
|
+
...program.getDeclarationDiagnostics()
|
|
78
|
+
];
|
|
79
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
|
|
80
|
+
const warnings = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Warning);
|
|
81
|
+
return { diagnostics, errors, warnings };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Format diagnostics for console output
|
|
85
|
+
* @param diagnostics - Array of TypeScript diagnostics
|
|
86
|
+
* @returns Formatted string
|
|
87
|
+
*/
|
|
88
|
+
formatDiagnostics(diagnostics) {
|
|
89
|
+
if (diagnostics.length === 0)
|
|
90
|
+
return import_chalk.default.bold("\u2705 No type errors found");
|
|
91
|
+
const output = [];
|
|
92
|
+
let errorCount = 0;
|
|
93
|
+
let warningCount = 0;
|
|
94
|
+
let suggestionCount = 0;
|
|
95
|
+
const diagnosticsByFile = /* @__PURE__ */ new Map();
|
|
96
|
+
diagnostics.forEach((diagnostic) => {
|
|
97
|
+
if (diagnostic.category === ts.DiagnosticCategory.Error)
|
|
98
|
+
errorCount++;
|
|
99
|
+
else if (diagnostic.category === ts.DiagnosticCategory.Warning)
|
|
100
|
+
warningCount++;
|
|
101
|
+
else if (diagnostic.category === ts.DiagnosticCategory.Suggestion)
|
|
102
|
+
suggestionCount++;
|
|
103
|
+
if (diagnostic.file) {
|
|
104
|
+
const fileName = diagnostic.file.fileName;
|
|
105
|
+
if (!diagnosticsByFile.has(fileName))
|
|
106
|
+
diagnosticsByFile.set(fileName, []);
|
|
107
|
+
const fileDiagnostics = diagnosticsByFile.get(fileName);
|
|
108
|
+
if (fileDiagnostics)
|
|
109
|
+
fileDiagnostics.push(diagnostic);
|
|
110
|
+
} else {
|
|
111
|
+
if (!diagnosticsByFile.has(""))
|
|
112
|
+
diagnosticsByFile.set("", []);
|
|
113
|
+
const fileDiagnostics = diagnosticsByFile.get("");
|
|
114
|
+
if (fileDiagnostics)
|
|
115
|
+
fileDiagnostics.push(diagnostic);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
diagnosticsByFile.forEach((fileDiagnostics, fileName) => {
|
|
119
|
+
if (fileName)
|
|
120
|
+
output.push(`
|
|
121
|
+
${import_chalk.default.cyan(fileName)}`);
|
|
122
|
+
fileDiagnostics.forEach((diagnostic) => {
|
|
123
|
+
const categoryText = diagnostic.category === ts.DiagnosticCategory.Error ? "error" : diagnostic.category === ts.DiagnosticCategory.Warning ? "warning" : "suggestion";
|
|
124
|
+
const categoryColor = diagnostic.category === ts.DiagnosticCategory.Error ? import_chalk.default.red : diagnostic.category === ts.DiagnosticCategory.Warning ? import_chalk.default.yellow : import_chalk.default.blue;
|
|
125
|
+
const icon = diagnostic.category === ts.DiagnosticCategory.Error ? "\u274C" : diagnostic.category === ts.DiagnosticCategory.Warning ? "\u26A0\uFE0F" : "\u{1F4A1}";
|
|
126
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
127
|
+
const tsCode = import_chalk.default.dim(`(TS${diagnostic.code})`);
|
|
128
|
+
if (diagnostic.file && diagnostic.start !== void 0) {
|
|
129
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
130
|
+
output.push(`
|
|
131
|
+
${icon} ${categoryColor(categoryText)}: ${message} ${tsCode}`);
|
|
132
|
+
output.push(` ${import_chalk.default.gray("at")} ${fileName}:${import_chalk.default.bold(`${line + 1}:${character + 1}`)}`);
|
|
133
|
+
const sourceLines = diagnostic.file.text.split("\n");
|
|
134
|
+
if (line < sourceLines.length) {
|
|
135
|
+
const sourceLine = sourceLines[line];
|
|
136
|
+
const lineNumber = (line + 1).toString().padStart(5, " ");
|
|
137
|
+
output.push(`
|
|
138
|
+
${import_chalk.default.dim(lineNumber + " |")} ${sourceLine}`);
|
|
139
|
+
const underlinePrefix = " ".repeat(character);
|
|
140
|
+
const length = diagnostic.length ?? 1;
|
|
141
|
+
const underline = "~".repeat(Math.max(1, length));
|
|
142
|
+
output.push(
|
|
143
|
+
`${import_chalk.default.dim(" ".repeat(lineNumber.length) + " |")} ${underlinePrefix}${categoryColor(underline)}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
} else
|
|
147
|
+
output.push(`
|
|
148
|
+
${icon} ${categoryColor(categoryText)}: ${message} ${tsCode}`);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
const summary = [];
|
|
152
|
+
if (errorCount > 0)
|
|
153
|
+
summary.push(import_chalk.default.red(`${errorCount} error(s)`));
|
|
154
|
+
if (warningCount > 0)
|
|
155
|
+
summary.push(import_chalk.default.yellow(`${warningCount} warning(s)`));
|
|
156
|
+
if (suggestionCount > 0)
|
|
157
|
+
summary.push(import_chalk.default.blue(`${suggestionCount} suggestion(s)`));
|
|
158
|
+
return `
|
|
159
|
+
${summary.join(", ")} found` + output.join("\n");
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get detailed diagnostic information with code snippet
|
|
163
|
+
* @param filePath - Path to the TypeScript file to check
|
|
164
|
+
* @returns Object containing diagnostics and detailed information
|
|
165
|
+
*/
|
|
166
|
+
getDetailedDiagnostics(filePath) {
|
|
167
|
+
const { diagnostics } = this.check(filePath);
|
|
168
|
+
const sourceFile = ts.createSourceFile(filePath, fs.readFileSync(filePath, "utf8"), ts.ScriptTarget.Latest, true);
|
|
169
|
+
const details = diagnostics.map((diagnostic) => {
|
|
170
|
+
if (diagnostic.file && diagnostic.start !== void 0) {
|
|
171
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
172
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
173
|
+
const lines = sourceFile.text.split("\n");
|
|
174
|
+
const codeSnippet = line < lines.length ? lines[line] : void 0;
|
|
175
|
+
return { line: line + 1, column: character + 1, message, code: diagnostic.code, codeSnippet };
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
line: 0,
|
|
179
|
+
column: 0,
|
|
180
|
+
message: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
|
|
181
|
+
code: diagnostic.code
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
return { diagnostics, details };
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Check if a file has type errors
|
|
188
|
+
* @param filePath - Path to the TypeScript file to check
|
|
189
|
+
* @returns true if there are no type errors, false otherwise
|
|
190
|
+
*/
|
|
191
|
+
hasNoTypeErrors(filePath) {
|
|
192
|
+
try {
|
|
193
|
+
const { diagnostics } = this.check(filePath);
|
|
194
|
+
return diagnostics.length === 0;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
201
|
+
0 && (module.exports = {
|
|
202
|
+
TypeChecker
|
|
203
|
+
});
|
package/cjs/src/uploadRelease.js
CHANGED
|
@@ -30,52 +30,78 @@ __export(uploadRelease_exports, {
|
|
|
30
30
|
uploadRelease: () => uploadRelease
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(uploadRelease_exports);
|
|
33
|
+
var import_common = require("@akanjs/common");
|
|
33
34
|
var import_axios = __toESM(require("axios"));
|
|
34
35
|
var import_form_data = __toESM(require("form-data"));
|
|
35
36
|
var import_fs = __toESM(require("fs"));
|
|
36
|
-
|
|
37
|
+
var import_spinner = require("./spinner");
|
|
38
|
+
const spinning = (message) => {
|
|
39
|
+
const spinner = new import_spinner.Spinner(message, { prefix: message, enableSpin: true }).start();
|
|
40
|
+
return spinner;
|
|
41
|
+
};
|
|
42
|
+
const uploadRelease = async (appName, {
|
|
37
43
|
workspaceRoot,
|
|
38
44
|
environment,
|
|
39
45
|
buildNum,
|
|
40
46
|
platformVersion,
|
|
41
47
|
local
|
|
42
48
|
}) => {
|
|
49
|
+
const logger = new import_common.Logger("uploadRelease");
|
|
43
50
|
const basePath = local ? "http://localhost:8080/backend" : "https://akasys.akamir.com/backend";
|
|
44
|
-
const buildPath = `${workspaceRoot}/releases/builds/${
|
|
45
|
-
const appBuildPath = `${workspaceRoot}/releases/builds/${
|
|
46
|
-
const sourcePath = `${workspaceRoot}/releases/sources/${
|
|
47
|
-
const
|
|
48
|
-
const build = import_fs.default.readFileSync(buildPath);
|
|
49
|
-
const source = import_fs.default.readFileSync(sourcePath);
|
|
50
|
-
const appBuild = import_fs.default.readFileSync(appBuildPath);
|
|
51
|
-
const buildStat = import_fs.default.statSync(buildPath);
|
|
52
|
-
const sourceStat = import_fs.default.statSync(sourcePath);
|
|
53
|
-
const appBuildStat = import_fs.default.statSync(appBuildPath);
|
|
54
|
-
formData.append("files", build, `${projectName}-release.tar.gz`);
|
|
55
|
-
formData.append("files", source, `${projectName}-source.tar.gz`);
|
|
56
|
-
formData.append("files", appBuild, `${projectName}-appBuild.zip`);
|
|
57
|
-
formData.append(
|
|
58
|
-
"metas",
|
|
59
|
-
JSON.stringify([
|
|
60
|
-
{ lastModifiedAt: buildStat.mtime, size: buildStat.size },
|
|
61
|
-
{ lastModifiedAt: sourceStat.mtime, size: sourceStat.size },
|
|
62
|
-
{ lastModifiedAt: appBuildStat.mtime, size: appBuildStat.size }
|
|
63
|
-
])
|
|
64
|
-
);
|
|
65
|
-
formData.append("type", "release");
|
|
51
|
+
const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
|
|
52
|
+
const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
|
|
53
|
+
const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
|
|
54
|
+
const readingFilesSpinner = spinning("Reading files...");
|
|
66
55
|
try {
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
56
|
+
const build = import_fs.default.readFileSync(buildPath);
|
|
57
|
+
const source = import_fs.default.readFileSync(sourcePath);
|
|
58
|
+
const appBuild = import_fs.default.readFileSync(appBuildPath);
|
|
59
|
+
const buildStat = import_fs.default.statSync(buildPath);
|
|
60
|
+
const sourceStat = import_fs.default.statSync(sourcePath);
|
|
61
|
+
const appBuildStat = import_fs.default.statSync(appBuildPath);
|
|
62
|
+
readingFilesSpinner.succeed("Reading files... done");
|
|
63
|
+
const preparingFormSpinner = spinning("Preparing form data...");
|
|
64
|
+
const formData = new import_form_data.default();
|
|
65
|
+
formData.append("files", build, `${appName}-release.tar.gz`);
|
|
66
|
+
formData.append("files", source, `${appName}-source.tar.gz`);
|
|
67
|
+
formData.append("files", appBuild, `${appName}-appBuild.zip`);
|
|
68
|
+
formData.append(
|
|
69
|
+
"metas",
|
|
70
|
+
JSON.stringify([
|
|
71
|
+
{ lastModifiedAt: buildStat.mtime, size: buildStat.size },
|
|
72
|
+
{ lastModifiedAt: sourceStat.mtime, size: sourceStat.size },
|
|
73
|
+
{ lastModifiedAt: appBuildStat.mtime, size: appBuildStat.size }
|
|
74
|
+
])
|
|
73
75
|
);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
formData.append("type", "release");
|
|
77
|
+
preparingFormSpinner.succeed("Preparing form data... done");
|
|
78
|
+
try {
|
|
79
|
+
const uploadingFilesSpinner = spinning("Uploading files to server...");
|
|
80
|
+
const [buildFile, sourceFile, appBuildFile] = (await import_axios.default.post(`${basePath}/file/addFilesRestApi`, formData)).data;
|
|
81
|
+
uploadingFilesSpinner.succeed("Uploading files to server... done");
|
|
82
|
+
const fetchingAppSpinner = spinning(`Fetching dev app information for ${appName}...`);
|
|
83
|
+
const major = platformVersion ? parseInt(platformVersion.split(".")[0]) : 1;
|
|
84
|
+
const minor = platformVersion ? parseInt(platformVersion.split(".")[1]) : 0;
|
|
85
|
+
const patch = platformVersion ? parseInt(platformVersion.split(".")[2]) : 0;
|
|
86
|
+
const devApp = (await import_axios.default.get(`${basePath}/devApp/devAppInName/${appName}`)).data;
|
|
87
|
+
fetchingAppSpinner.succeed(`Fetching dev app information for ${appName}... done`);
|
|
88
|
+
const pushingReleaseSpinner = spinning(`Pushing release to ${environment} environment...`);
|
|
89
|
+
const release = (await import_axios.default.post(
|
|
90
|
+
`${basePath}/release/pushRelease/${devApp.id}/${environment}/${major}/${minor}/${sourceFile.id}/${buildFile.id}/${appBuildFile.id}`
|
|
91
|
+
)).data;
|
|
92
|
+
pushingReleaseSpinner.succeed(`Pushing release to ${environment} environment... done`);
|
|
93
|
+
new import_spinner.Spinner(`Successfully pushed release to ${appName}-${environment} server. `, {
|
|
94
|
+
prefix: `Successfully pushed release to ${appName}-${environment} server. `,
|
|
95
|
+
enableSpin: false
|
|
96
|
+
}).succeed(`Successfully pushed release to ${appName}-${environment} server. `);
|
|
97
|
+
return release;
|
|
98
|
+
} catch (e) {
|
|
99
|
+
const errorMessage = e instanceof Error ? e.message : "Unknown error";
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
78
102
|
} catch (e) {
|
|
103
|
+
const errorMessage = e instanceof Error ? e.message : "Unknown error";
|
|
104
|
+
readingFilesSpinner.fail(`Reading files failed: ${errorMessage}`);
|
|
79
105
|
return null;
|
|
80
106
|
}
|
|
81
107
|
};
|