@akanjs/devkit 1.0.20 → 2.1.0-rc.1

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 (195) hide show
  1. package/README.ko.md +65 -0
  2. package/README.md +62 -6
  3. package/aiEditor.ts +304 -0
  4. package/akanApp/akanApp.host.ts +393 -0
  5. package/akanApp/index.ts +1 -0
  6. package/akanConfig/akanConfig.test.ts +236 -0
  7. package/akanConfig/akanConfig.ts +384 -0
  8. package/akanConfig/index.ts +2 -0
  9. package/akanConfig/types.ts +23 -0
  10. package/applicationBuildReporter.ts +69 -0
  11. package/applicationBuildRunner.ts +302 -0
  12. package/applicationReleasePackager.ts +206 -0
  13. package/artifact/implicitRootLayout.ts +155 -0
  14. package/artifact/index.ts +1 -0
  15. package/artifact/routeSeedIndex.test.ts +98 -0
  16. package/artifact/routeSeedIndex.ts +130 -0
  17. package/auth.ts +41 -0
  18. package/builder.ts +164 -0
  19. package/capacitor.base.config.ts +88 -0
  20. package/capacitorApp.ts +440 -0
  21. package/commandDecorators/argMeta.ts +102 -0
  22. package/commandDecorators/command.ts +351 -0
  23. package/commandDecorators/commandBuilder.ts +224 -0
  24. package/commandDecorators/commandDecorators.test.ts +212 -0
  25. package/commandDecorators/commandMeta.ts +7 -0
  26. package/commandDecorators/dependencyBuilder.ts +100 -0
  27. package/{esm/src/commandDecorators/helpFormatter.js → commandDecorators/helpFormatter.ts} +100 -47
  28. package/{esm/src/commandDecorators/index.js → commandDecorators/index.ts} +4 -2
  29. package/commandDecorators/targetMeta.ts +31 -0
  30. package/commandDecorators/types.ts +10 -0
  31. package/constants.ts +25 -0
  32. package/createTunnel.ts +36 -0
  33. package/dependencyScanner.ts +357 -0
  34. package/devkitUtils.test.ts +259 -0
  35. package/executors.test.ts +315 -0
  36. package/executors.ts +1390 -0
  37. package/{esm/src/extractDeps.js → extractDeps.ts} +26 -20
  38. package/{esm/src/fileEditor.js → fileEditor.ts} +51 -32
  39. package/fileSys.ts +39 -0
  40. package/frontendBuild/allRoutesBuilder.ts +103 -0
  41. package/frontendBuild/buildRouteClient.test.ts +190 -0
  42. package/frontendBuild/clientBuildTypes.ts +114 -0
  43. package/frontendBuild/clientEntriesBundler.ts +303 -0
  44. package/frontendBuild/clientEntryDiscovery.ts +199 -0
  45. package/frontendBuild/csrArtifactBuilder.ts +237 -0
  46. package/frontendBuild/cssCompiler.ts +286 -0
  47. package/frontendBuild/cssImportResolver.ts +116 -0
  48. package/frontendBuild/fontOptimizer.ts +427 -0
  49. package/frontendBuild/frontendBuild.test.ts +204 -0
  50. package/frontendBuild/hmrChangeClassifier.ts +28 -0
  51. package/frontendBuild/hmrWatcher.ts +102 -0
  52. package/frontendBuild/index.ts +18 -0
  53. package/frontendBuild/pagesBundleBuilder.ts +137 -0
  54. package/frontendBuild/pagesEntrySourceGenerator.ts +37 -0
  55. package/frontendBuild/precompressArtifacts.ts +59 -0
  56. package/frontendBuild/routeClientBuilder.ts +290 -0
  57. package/frontendBuild/routesManifestArtifactSerializer.ts +62 -0
  58. package/frontendBuild/ssrBaseArtifactBuilder.ts +139 -0
  59. package/frontendBuild/vendorSpecifiers.ts +16 -0
  60. package/frontendBuild/watchRootResolver.ts +28 -0
  61. package/getCredentials.ts +19 -0
  62. package/getDirname.ts +3 -0
  63. package/getModelFileData.ts +59 -0
  64. package/getRelatedCnsts.ts +313 -0
  65. package/guideline.ts +19 -0
  66. package/incrementalBuilder/incrementalBuilder.host.test.ts +51 -0
  67. package/incrementalBuilder/incrementalBuilder.host.ts +152 -0
  68. package/incrementalBuilder/incrementalBuilder.proc.ts +331 -0
  69. package/incrementalBuilder/index.ts +1 -0
  70. package/{esm/src/index.js → index.ts} +28 -15
  71. package/lint/no-deep-internal-import.grit +25 -0
  72. package/lint/no-import-client-functions.grit +32 -0
  73. package/lint/no-import-external-library.grit +21 -0
  74. package/lint/no-js-private-class-method.grit +42 -0
  75. package/lint/no-use-client-in-server.grit +7 -0
  76. package/lint/non-scalar-props-restricted.grit +13 -0
  77. package/linter.ts +271 -0
  78. package/mobile/index.ts +1 -0
  79. package/mobile/mobileTarget.test.ts +53 -0
  80. package/mobile/mobileTarget.ts +88 -0
  81. package/package.json +48 -31
  82. package/prompter.ts +72 -0
  83. package/scanInfo.ts +606 -0
  84. package/selectModel.ts +11 -0
  85. package/{esm/src/spinner.js → spinner.ts} +22 -28
  86. package/{esm/src/capacitorApp.js → src/capacitorApp.ts} +82 -81
  87. package/sshTunnel.ts +152 -0
  88. package/{esm/src/streamAi.js → streamAi.ts} +18 -12
  89. package/transforms/barrelAnalyzer.ts +278 -0
  90. package/transforms/barrelImportsPlugin.ts +504 -0
  91. package/transforms/externalizeFrameworkPlugin.ts +185 -0
  92. package/transforms/index.ts +5 -0
  93. package/transforms/rscUseClientTransform.ts +59 -0
  94. package/transforms/transforms.test.ts +208 -0
  95. package/transforms/useClientBundlePlugin.ts +47 -0
  96. package/tsconfig.json +37 -0
  97. package/typeChecker.ts +264 -0
  98. package/types.ts +44 -0
  99. package/ui/MultiScrollList.tsx +242 -0
  100. package/ui/ScrollList.tsx +107 -0
  101. package/ui/index.ts +2 -0
  102. package/{esm/src/uploadRelease.js → uploadRelease.ts} +50 -34
  103. package/{esm/src/useStdoutDimensions.js → useStdoutDimensions.ts} +5 -5
  104. package/cjs/index.js +0 -21
  105. package/cjs/src/aiEditor.js +0 -311
  106. package/cjs/src/auth.js +0 -72
  107. package/cjs/src/builder.js +0 -114
  108. package/cjs/src/capacitorApp.js +0 -313
  109. package/cjs/src/commandDecorators/argMeta.js +0 -88
  110. package/cjs/src/commandDecorators/command.js +0 -324
  111. package/cjs/src/commandDecorators/commandMeta.js +0 -30
  112. package/cjs/src/commandDecorators/helpFormatter.js +0 -211
  113. package/cjs/src/commandDecorators/index.js +0 -31
  114. package/cjs/src/commandDecorators/targetMeta.js +0 -57
  115. package/cjs/src/commandDecorators/types.js +0 -15
  116. package/cjs/src/constants.js +0 -46
  117. package/cjs/src/createTunnel.js +0 -49
  118. package/cjs/src/dependencyScanner.js +0 -220
  119. package/cjs/src/executors.js +0 -964
  120. package/cjs/src/extractDeps.js +0 -103
  121. package/cjs/src/fileEditor.js +0 -120
  122. package/cjs/src/getCredentials.js +0 -44
  123. package/cjs/src/getDirname.js +0 -38
  124. package/cjs/src/getModelFileData.js +0 -66
  125. package/cjs/src/getRelatedCnsts.js +0 -260
  126. package/cjs/src/guideline.js +0 -15
  127. package/cjs/src/index.js +0 -65
  128. package/cjs/src/linter.js +0 -238
  129. package/cjs/src/prompter.js +0 -85
  130. package/cjs/src/scanInfo.js +0 -491
  131. package/cjs/src/selectModel.js +0 -46
  132. package/cjs/src/spinner.js +0 -93
  133. package/cjs/src/streamAi.js +0 -62
  134. package/cjs/src/typeChecker.js +0 -207
  135. package/cjs/src/types.js +0 -15
  136. package/cjs/src/uploadRelease.js +0 -112
  137. package/cjs/src/useStdoutDimensions.js +0 -43
  138. package/esm/index.js +0 -1
  139. package/esm/src/aiEditor.js +0 -282
  140. package/esm/src/auth.js +0 -42
  141. package/esm/src/builder.js +0 -81
  142. package/esm/src/commandDecorators/argMeta.js +0 -54
  143. package/esm/src/commandDecorators/command.js +0 -290
  144. package/esm/src/commandDecorators/commandMeta.js +0 -7
  145. package/esm/src/commandDecorators/targetMeta.js +0 -33
  146. package/esm/src/commandDecorators/types.js +0 -0
  147. package/esm/src/constants.js +0 -17
  148. package/esm/src/createTunnel.js +0 -26
  149. package/esm/src/dependencyScanner.js +0 -187
  150. package/esm/src/executors.js +0 -928
  151. package/esm/src/getCredentials.js +0 -11
  152. package/esm/src/getDirname.js +0 -5
  153. package/esm/src/getModelFileData.js +0 -33
  154. package/esm/src/getRelatedCnsts.js +0 -221
  155. package/esm/src/guideline.js +0 -0
  156. package/esm/src/linter.js +0 -205
  157. package/esm/src/prompter.js +0 -51
  158. package/esm/src/scanInfo.js +0 -455
  159. package/esm/src/selectModel.js +0 -13
  160. package/esm/src/typeChecker.js +0 -174
  161. package/esm/src/types.js +0 -0
  162. package/index.d.ts +0 -1
  163. package/src/aiEditor.d.ts +0 -50
  164. package/src/auth.d.ts +0 -9
  165. package/src/builder.d.ts +0 -18
  166. package/src/capacitorApp.d.ts +0 -39
  167. package/src/commandDecorators/argMeta.d.ts +0 -67
  168. package/src/commandDecorators/command.d.ts +0 -2
  169. package/src/commandDecorators/commandMeta.d.ts +0 -2
  170. package/src/commandDecorators/helpFormatter.d.ts +0 -3
  171. package/src/commandDecorators/index.d.ts +0 -6
  172. package/src/commandDecorators/targetMeta.d.ts +0 -19
  173. package/src/commandDecorators/types.d.ts +0 -1
  174. package/src/constants.d.ts +0 -26
  175. package/src/createTunnel.d.ts +0 -8
  176. package/src/dependencyScanner.d.ts +0 -23
  177. package/src/executors.d.ts +0 -296
  178. package/src/extractDeps.d.ts +0 -7
  179. package/src/fileEditor.d.ts +0 -16
  180. package/src/getCredentials.d.ts +0 -12
  181. package/src/getDirname.d.ts +0 -1
  182. package/src/getModelFileData.d.ts +0 -16
  183. package/src/getRelatedCnsts.d.ts +0 -53
  184. package/src/guideline.d.ts +0 -19
  185. package/src/index.d.ts +0 -23
  186. package/src/linter.d.ts +0 -109
  187. package/src/prompter.d.ts +0 -14
  188. package/src/scanInfo.d.ts +0 -82
  189. package/src/selectModel.d.ts +0 -1
  190. package/src/spinner.d.ts +0 -20
  191. package/src/streamAi.d.ts +0 -6
  192. package/src/typeChecker.d.ts +0 -52
  193. package/src/types.d.ts +0 -31
  194. package/src/uploadRelease.d.ts +0 -10
  195. package/src/useStdoutDimensions.d.ts +0 -1
@@ -1,11 +0,0 @@
1
- import fs from "fs";
2
- import yaml from "js-yaml";
3
- const getCredentials = (app, environment) => {
4
- const secret = yaml.load(
5
- fs.readFileSync(`${app.workspace.workspaceRoot}/infra/app/values/${app.name}-secret.yaml`, "utf-8")
6
- );
7
- return secret[environment];
8
- };
9
- export {
10
- getCredentials
11
- };
@@ -1,5 +0,0 @@
1
- import path from "path";
2
- const getDirname = (url) => path.dirname(new URL(url).pathname);
3
- export {
4
- getDirname
5
- };
@@ -1,33 +0,0 @@
1
- import fs from "fs";
2
- const getModelFileData = (modulePath, modelName) => {
3
- const moduleType = modulePath.startsWith("apps") ? "app" : "lib";
4
- const moduleName = modulePath.split("/")[1];
5
- const constantFilePath = `${modulePath}/lib/${modelName}/${modelName}.constant.ts`;
6
- const unitFilePath = `${modulePath}/lib/${modelName}/${modelName}.Unit.tsx`;
7
- const viewFilePath = `${modulePath}/lib/${modelName}/${modelName}.View.tsx`;
8
- const constantFileStr = fs.readFileSync(constantFilePath, "utf8");
9
- const unitFileStr = fs.readFileSync(unitFilePath, "utf8");
10
- const viewFileStr = fs.readFileSync(viewFilePath, "utf8");
11
- const constantFileLines = constantFileStr.split("\n");
12
- const importLibNames = constantFileLines.filter((line) => line.startsWith("import { cnst as ")).map((line) => line.split("cnst as ")[1].split(" ")[0]);
13
- const importLocalPaths = constantFileLines.filter((line) => line.startsWith("import { ") && line.includes('from "../')).map((line) => line.split("from ")[1].split('"')[1]);
14
- const importModelNames = importLocalPaths.map((path) => path.split("/")[1]).filter((name) => !name.startsWith("_"));
15
- const hasImportScalar = !!importLocalPaths.map((path) => path.split("/")[1]).filter((name) => name.startsWith("_")).length;
16
- return {
17
- moduleType,
18
- moduleName,
19
- modelName,
20
- constantFilePath,
21
- unitFilePath,
22
- viewFilePath,
23
- importModelNames,
24
- hasImportScalar,
25
- importLibNames,
26
- constantFileStr,
27
- unitFileStr,
28
- viewFileStr
29
- };
30
- };
31
- export {
32
- getModelFileData
33
- };
@@ -1,221 +0,0 @@
1
- import * as fs from "fs";
2
- import ora from "ora";
3
- import * as ts from "typescript";
4
- const parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
5
- const configFile = ts.readConfigFile(tsConfigPath, (path) => {
6
- return ts.sys.readFile(path);
7
- });
8
- return ts.parseJsonConfigFileContent(
9
- configFile.config,
10
- ts.sys,
11
- fs.realpathSync(tsConfigPath).replace(/[^/\\]+$/, "")
12
- );
13
- };
14
- const collectImportedFiles = (constantFilePath, parsedConfig) => {
15
- const allFilesToAnalyze = /* @__PURE__ */ new Set([constantFilePath]);
16
- const analyzedFiles = /* @__PURE__ */ new Set();
17
- const spinner = ora("Collecting related files...");
18
- spinner.start();
19
- function collectImported(filePath) {
20
- if (analyzedFiles.has(filePath))
21
- return;
22
- analyzedFiles.add(filePath);
23
- const tempProgram = ts.createProgram([filePath], parsedConfig.options);
24
- const source = tempProgram.getSourceFile(filePath);
25
- if (!source)
26
- return;
27
- function collectImports(node) {
28
- if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
29
- const importPath = node.moduleSpecifier.text;
30
- if (importPath.startsWith(".")) {
31
- const resolved = ts.resolveModuleName(importPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
32
- if (resolved && !allFilesToAnalyze.has(resolved)) {
33
- allFilesToAnalyze.add(resolved);
34
- collectImported(resolved);
35
- }
36
- }
37
- }
38
- ts.forEachChild(node, collectImports);
39
- }
40
- collectImports(source);
41
- }
42
- collectImported(constantFilePath);
43
- spinner.succeed(`Found ${allFilesToAnalyze.size} related files.`);
44
- return {
45
- allFilesToAnalyze,
46
- analyzedFiles
47
- };
48
- };
49
- const collectExportedFiles = (constantFilePath, parsedConfig) => {
50
- const allFilesToAnalyze = /* @__PURE__ */ new Set([constantFilePath]);
51
- const analyzedFiles = /* @__PURE__ */ new Set();
52
- const spinner = ora("Collecting files from exports...");
53
- spinner.start();
54
- function collectExported(filePath) {
55
- if (analyzedFiles.has(filePath))
56
- return;
57
- analyzedFiles.add(filePath);
58
- const tempProgram = ts.createProgram([filePath], parsedConfig.options);
59
- const source = tempProgram.getSourceFile(filePath);
60
- if (!source)
61
- return;
62
- function collectExports(node) {
63
- if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier) && !node.exportClause) {
64
- const exportPath = node.moduleSpecifier.text;
65
- if (exportPath.startsWith(".")) {
66
- const resolved = ts.resolveModuleName(exportPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
67
- if (resolved && !allFilesToAnalyze.has(resolved)) {
68
- allFilesToAnalyze.add(resolved);
69
- collectExported(resolved);
70
- }
71
- }
72
- } else if (ts.isExportDeclaration(node) && node.exportClause && ts.isNamedExports(node.exportClause) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
73
- const exportPath = node.moduleSpecifier.text;
74
- if (exportPath.startsWith(".")) {
75
- const resolved = ts.resolveModuleName(exportPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
76
- if (resolved && !allFilesToAnalyze.has(resolved)) {
77
- allFilesToAnalyze.add(resolved);
78
- collectExported(resolved);
79
- }
80
- }
81
- } else if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
82
- const importPath = node.moduleSpecifier.text;
83
- if (importPath.startsWith(".")) {
84
- const resolved = ts.resolveModuleName(importPath, filePath, parsedConfig.options, ts.sys).resolvedModule?.resolvedFileName;
85
- if (resolved && !allFilesToAnalyze.has(resolved)) {
86
- allFilesToAnalyze.add(resolved);
87
- collectExported(resolved);
88
- }
89
- }
90
- }
91
- if ((ts.isVariableStatement(node) || ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
92
- }
93
- ts.forEachChild(node, collectExports);
94
- }
95
- collectExports(source);
96
- }
97
- collectExported(constantFilePath);
98
- spinner.succeed(`Found ${allFilesToAnalyze.size} related files from exports.`);
99
- return {
100
- allFilesToAnalyze,
101
- analyzedFiles
102
- };
103
- };
104
- const createTsProgram = (filePaths, options) => {
105
- const spinner = ora("Creating TypeScript program for all files...");
106
- spinner.start();
107
- const program = ts.createProgram(Array.from(filePaths), options);
108
- const checker = program.getTypeChecker();
109
- spinner.succeed("TypeScript program created.");
110
- return {
111
- program,
112
- checker
113
- };
114
- };
115
- const createSymbolCache = (checker) => {
116
- const symbolCache = /* @__PURE__ */ new Map();
117
- return (node) => {
118
- const cacheKey = `${node.getSourceFile().fileName}:${node.pos}:${node.end}`;
119
- if (!symbolCache.has(cacheKey)) {
120
- symbolCache.set(cacheKey, checker.getSymbolAtLocation(node));
121
- }
122
- return symbolCache.get(cacheKey);
123
- };
124
- };
125
- const analyzeProperties = (filesToAnalyze, program, checker) => {
126
- const propertyMap = /* @__PURE__ */ new Map();
127
- const analyzedFiles = /* @__PURE__ */ new Set();
128
- const sourceLineCache = /* @__PURE__ */ new Map();
129
- const getCachedSymbol = createSymbolCache(checker);
130
- const spinner = ora("Analyzing property relationships...");
131
- spinner.start();
132
- function analyzeFileProperties(filePath) {
133
- if (analyzedFiles.has(filePath))
134
- return;
135
- analyzedFiles.add(filePath);
136
- const source = program.getSourceFile(filePath);
137
- if (!source)
138
- return;
139
- if (!sourceLineCache.has(filePath)) {
140
- sourceLineCache.set(filePath, source.getFullText().split("\n"));
141
- }
142
- const sourceLines = sourceLineCache.get(filePath);
143
- function visit(node) {
144
- if (!source)
145
- return;
146
- if (ts.isPropertyAccessExpression(node)) {
147
- const left = node.expression;
148
- const right = node.name;
149
- const { line } = ts.getLineAndCharacterOfPosition(source, node.getStart());
150
- if (ts.isIdentifier(left) && sourceLines && sourceLines.length > line && (sourceLines[line].includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
151
- const symbol = getCachedSymbol(right);
152
- if (symbol?.declarations && symbol.declarations.length > 0) {
153
- const key = symbol.declarations[0].getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
154
- const property = propertyMap.get(key);
155
- const isScalar = symbol.declarations[0].getSourceFile().fileName.includes("_");
156
- const symbolFilePath = symbol.declarations[0].getSourceFile().fileName.replace(`${ts.sys.getCurrentDirectory()}/`, "");
157
- if (property) {
158
- propertyMap.set(`${left.text}.${right.text}`, {
159
- filePath: symbolFilePath,
160
- isLibModule: true,
161
- isImport: false,
162
- libName: left.text,
163
- source: fs.readFileSync(symbolFilePath, "utf-8"),
164
- isScalar
165
- });
166
- } else {
167
- propertyMap.set(key, {
168
- filePath: symbolFilePath,
169
- isLibModule: true,
170
- isImport: false,
171
- libName: left.text,
172
- isScalar,
173
- source: fs.readFileSync(symbolFilePath, "utf-8")
174
- });
175
- }
176
- }
177
- }
178
- } else if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
179
- const importPath = node.moduleSpecifier.text;
180
- if (importPath.startsWith(".")) {
181
- const resolved = ts.resolveModuleName(importPath, filePath, program.getCompilerOptions(), ts.sys).resolvedModule?.resolvedFileName;
182
- const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
183
- const property = propertyMap.get(moduleName);
184
- const isScalar = importPath.includes("_");
185
- if (moduleName && resolved && (!property || property.filePath !== resolved)) {
186
- propertyMap.set(moduleName, {
187
- filePath: resolved,
188
- isLibModule: false,
189
- isImport: true,
190
- isScalar,
191
- source: fs.readFileSync(resolved, "utf-8")
192
- });
193
- }
194
- }
195
- }
196
- ts.forEachChild(node, visit);
197
- }
198
- visit(source);
199
- }
200
- for (const filePath of filesToAnalyze) {
201
- analyzeFileProperties(filePath);
202
- }
203
- spinner.succeed(`Analysis complete. Found ${propertyMap.size} properties.`);
204
- return propertyMap;
205
- };
206
- const getRelatedCnsts = (constantFilePath) => {
207
- const parsedConfig = parseTsConfig();
208
- const { allFilesToAnalyze } = collectImportedFiles(constantFilePath, parsedConfig);
209
- const { program, checker } = createTsProgram(allFilesToAnalyze, parsedConfig.options);
210
- const propertyMap = analyzeProperties(allFilesToAnalyze, program, checker);
211
- return Array.from(propertyMap.entries()).map(([key, value]) => ({ key, ...value }));
212
- };
213
- export {
214
- analyzeProperties,
215
- collectExportedFiles,
216
- collectImportedFiles,
217
- createSymbolCache,
218
- createTsProgram,
219
- getRelatedCnsts,
220
- parseTsConfig
221
- };
File without changes
package/esm/src/linter.js DELETED
@@ -1,205 +0,0 @@
1
- import { Logger } from "@akanjs/common";
2
- import chalk from "chalk";
3
- import { ESLint } from "eslint";
4
- import * as fs from "fs";
5
- import * as path from "path";
6
- class Linter {
7
- #logger = new Logger("Linter");
8
- #eslint;
9
- lintRoot;
10
- constructor(cwdPath) {
11
- this.lintRoot = this.#findEslintRootPath(cwdPath);
12
- this.#eslint = new ESLint({ cwd: this.lintRoot, errorOnUnmatchedPattern: false });
13
- }
14
- #findEslintRootPath(dir) {
15
- const configPath = path.join(dir, "eslint.config.ts");
16
- if (fs.existsSync(configPath))
17
- return dir;
18
- const parentDir = path.dirname(dir);
19
- return this.#findEslintRootPath(parentDir);
20
- }
21
- async lint(filePath, { fix = false, dryRun = false } = {}) {
22
- if (fix)
23
- return await this.fixFile(filePath, dryRun);
24
- return await this.lintFile(filePath);
25
- }
26
- /**
27
- * Lint a single file using ESLint
28
- * @param filePath - Path to the file to lint
29
- * @returns Array of ESLint results
30
- */
31
- async lintFile(filePath) {
32
- if (!fs.existsSync(filePath))
33
- throw new Error(`File not found: ${filePath}`);
34
- const isIgnored = await this.#eslint.isPathIgnored(filePath);
35
- if (isIgnored) {
36
- this.#logger.warn(`File ${filePath} is ignored by ESLint configuration`);
37
- return { fixed: false, results: [], errors: [], warnings: [] };
38
- }
39
- const results = await this.#eslint.lintFiles([filePath]);
40
- const errors = results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
41
- const warnings = results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
42
- return { fixed: false, results, errors, warnings };
43
- }
44
- /**
45
- * Format lint results for console output
46
- * @param results - Array of ESLint results
47
- * @returns Formatted string
48
- */
49
- formatLintResults(results) {
50
- if (results.length === 0)
51
- return "No files to lint";
52
- const output = [];
53
- let totalErrors = 0;
54
- let totalWarnings = 0;
55
- results.forEach((result) => {
56
- totalErrors += result.errorCount;
57
- totalWarnings += result.warningCount;
58
- if (result.messages.length > 0) {
59
- output.push(`
60
- ${chalk.cyan(result.filePath)}`);
61
- let sourceLines = [];
62
- if (fs.existsSync(result.filePath)) {
63
- try {
64
- const sourceContent = fs.readFileSync(result.filePath, "utf8");
65
- sourceLines = sourceContent.split("\n");
66
- } catch (error) {
67
- }
68
- }
69
- result.messages.forEach((message) => {
70
- const type = message.severity === 2 ? "error" : "warning";
71
- const typeColor = message.severity === 2 ? chalk.red : chalk.yellow;
72
- const icon = message.severity === 2 ? "\u274C" : "\u26A0\uFE0F";
73
- const ruleInfo = message.ruleId ? chalk.dim(` (${message.ruleId})`) : "";
74
- output.push(`
75
- ${icon} ${typeColor(type)}: ${message.message}${ruleInfo}`);
76
- output.push(` ${chalk.gray("at")} ${result.filePath}:${chalk.bold(`${message.line}:${message.column}`)}`);
77
- if (sourceLines.length > 0 && message.line <= sourceLines.length) {
78
- const sourceLine = sourceLines[message.line - 1];
79
- const lineNumber = message.line.toString().padStart(5, " ");
80
- output.push(`
81
- ${chalk.dim(lineNumber + " |")} ${sourceLine}`);
82
- const underlinePrefix = " ".repeat(message.column - 1);
83
- const underlineLength = message.endColumn ? message.endColumn - message.column : 1;
84
- const underline = "^".repeat(Math.max(1, underlineLength));
85
- output.push(`${chalk.dim(" ".repeat(lineNumber.length) + " |")} ${underlinePrefix}${typeColor(underline)}`);
86
- }
87
- });
88
- }
89
- });
90
- if (totalErrors === 0 && totalWarnings === 0)
91
- return chalk.bold("\u2705 No ESLint errors or warnings found");
92
- const errorText = totalErrors > 0 ? chalk.red(`${totalErrors} error(s)`) : "0 errors";
93
- const warningText = totalWarnings > 0 ? chalk.yellow(`${totalWarnings} warning(s)`) : "0 warnings";
94
- const summary = [`
95
- ${errorText}, ${warningText} found`];
96
- return summary.concat(output).join("\n");
97
- }
98
- /**
99
- * Get detailed lint information
100
- * @param filePath - Path to the file to lint
101
- * @returns Object containing detailed lint information
102
- */
103
- async getDetailedLintInfo(filePath) {
104
- const { results } = await this.lintFile(filePath);
105
- const details = results.flatMap(
106
- (result) => result.messages.map((message) => ({
107
- line: message.line,
108
- column: message.column,
109
- message: message.message,
110
- ruleId: message.ruleId,
111
- severity: message.severity === 2 ? "error" : "warning",
112
- fix: message.fix,
113
- suggestions: message.suggestions
114
- }))
115
- );
116
- const stats = results.reduce(
117
- (acc, result) => ({
118
- errorCount: acc.errorCount + result.errorCount,
119
- warningCount: acc.warningCount + result.warningCount,
120
- fixableErrorCount: acc.fixableErrorCount + result.fixableErrorCount,
121
- fixableWarningCount: acc.fixableWarningCount + result.fixableWarningCount
122
- }),
123
- { errorCount: 0, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0 }
124
- );
125
- return { results, details, stats };
126
- }
127
- /**
128
- * Check if a file has lint errors
129
- * @param filePath - Path to the file to check
130
- * @returns true if there are no errors, false otherwise
131
- */
132
- async hasNoLintErrors(filePath) {
133
- try {
134
- const { results } = await this.lintFile(filePath);
135
- return results.every((result) => result.errorCount === 0);
136
- } catch (error) {
137
- return false;
138
- }
139
- }
140
- /**
141
- * Get only error messages (excluding warnings)
142
- * @param filePath - Path to the file to lint
143
- * @returns Array of error messages
144
- */
145
- async getErrors(filePath) {
146
- const { results } = await this.lintFile(filePath);
147
- return results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
148
- }
149
- /**
150
- * Get only warning messages
151
- * @param filePath - Path to the file to lint
152
- * @returns Array of warning messages
153
- */
154
- async getWarnings(filePath) {
155
- const { results } = await this.lintFile(filePath);
156
- return results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
157
- }
158
- /**
159
- * Fix lint errors automatically
160
- * @param filePath - Path to the file to fix
161
- * @param dryRun - If true, returns the fixed content without writing to file
162
- * @returns Fixed content and remaining issues
163
- */
164
- async fixFile(filePath, dryRun = false) {
165
- if (!fs.existsSync(filePath))
166
- throw new Error(`File not found: ${filePath}`);
167
- const eslint = new ESLint({ cwd: this.lintRoot, fix: true });
168
- const results = await eslint.lintFiles([filePath]);
169
- const errors = results.flatMap((result) => result.messages.filter((message) => message.severity === 2));
170
- const warnings = results.flatMap((result) => result.messages.filter((message) => message.severity === 1));
171
- if (!dryRun)
172
- await ESLint.outputFixes(results);
173
- const fixedResult = results[0];
174
- return { fixed: fixedResult.output !== void 0, output: fixedResult.output, results, errors, warnings };
175
- }
176
- /**
177
- * Get ESLint configuration for a file
178
- * @param filePath - Path to the file
179
- * @returns ESLint configuration object
180
- */
181
- async getConfigForFile(filePath) {
182
- const eslint = new ESLint();
183
- const config = await eslint.calculateConfigForFile(filePath);
184
- return config;
185
- }
186
- /**
187
- * Get rules that are causing errors in a file
188
- * @param filePath - Path to the file to check
189
- * @returns Object mapping rule IDs to their error counts
190
- */
191
- async getProblematicRules(filePath) {
192
- const { results } = await this.lintFile(filePath);
193
- const ruleCounts = {};
194
- results.forEach((result) => {
195
- result.messages.forEach((message) => {
196
- if (message.ruleId)
197
- ruleCounts[message.ruleId] = (ruleCounts[message.ruleId] || 0) + 1;
198
- });
199
- });
200
- return ruleCounts;
201
- }
202
- }
203
- export {
204
- Linter
205
- };
@@ -1,51 +0,0 @@
1
- import { input, select } from "@inquirer/prompts";
2
- import fsPromise from "fs/promises";
3
- import { getDirname } from "./getDirname";
4
- class Prompter {
5
- static async selectGuideline() {
6
- const guideNames = (await fsPromise.readdir(`${getDirname(import.meta.url)}/src/guidelines`)).filter(
7
- (name) => !name.startsWith("_")
8
- );
9
- return await select({ message: "Select a guideline", choices: guideNames.map((name) => ({ name, value: name })) });
10
- }
11
- static async getGuideJson(guideName) {
12
- const filePath = `${getDirname(import.meta.url)}/src/guidelines/${guideName}/${guideName}.generate.json`;
13
- const guideJson = await fsPromise.readFile(filePath, "utf-8");
14
- return JSON.parse(guideJson);
15
- }
16
- static async getInstruction(guideName) {
17
- const filePath = `${getDirname(import.meta.url)}/src/guidelines/${guideName}/${guideName}.instruction.md`;
18
- const content = await fsPromise.readFile(filePath, "utf-8");
19
- return content;
20
- }
21
- static async getUpdateRequest(guideName) {
22
- return await input({ message: `What do you want to update in ${guideName}?` });
23
- }
24
- async makeTsFileUpdatePrompt({ context, request }) {
25
- 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:
26
- ${await this.getDocumentation("framework")}
27
- Please understand the following background information, write code that meets the requirements, verify that it satisfies the validation conditions, and return the result.
28
-
29
- # Background Information
30
- \`\`\`markdown
31
- ${context}
32
- \`\`\`
33
-
34
- # Requirements
35
- \`\`\`markdown
36
- ${request}
37
- \`\`\`
38
- `;
39
- }
40
- async getDocumentation(guideName) {
41
- const filePath = `${getDirname(import.meta.url)}/src/guidelines/${guideName}/${guideName}.instruction.md`;
42
- const document = await fsPromise.readFile(filePath, "utf-8");
43
- return `\`\`\`markdown
44
- ${document}
45
- \`\`\`
46
- `;
47
- }
48
- }
49
- export {
50
- Prompter
51
- };