tsfmt 0.0.0 → 0.2.0
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 +1 -1
- package/dist/build-plugins/transformGenericsPlugin.js +86 -0
- package/dist/cli.js +173 -0
- package/dist/core/ast/ASTAnalyzer.js +136 -0
- package/dist/core/ast/ASTTransformer.js +85 -0
- package/dist/core/ast/DependencyResolver.js +144 -0
- package/dist/core/config/ConfigDefaults.js +178 -0
- package/dist/core/config/ConfigLoader.js +251 -0
- package/dist/core/config/ConfigMerger.js +45 -0
- package/dist/core/config/ConfigTypes.js +70 -0
- package/dist/core/config/ConfigValidator.js +74 -0
- package/dist/core/di/Container.js +175 -0
- package/dist/core/di/ServiceRegistration.js +38 -0
- package/dist/core/formatters/BaseFormattingRule.js +37 -0
- package/dist/core/formatters/rules/ast/ClassMemberSortingRule.js +171 -0
- package/dist/core/formatters/rules/ast/FileDeclarationSortingRule.js +162 -0
- package/dist/core/formatters/rules/imports/ImportOrganizationRule.js +196 -0
- package/dist/core/formatters/rules/index-generation/IndexGenerationRule.js +208 -0
- package/dist/core/formatters/rules/spacing/BlankLineBeforeReturnsRule.js +32 -0
- package/dist/core/formatters/rules/spacing/BlankLineBetweenDeclarationsRule.js +93 -0
- package/dist/core/formatters/rules/spacing/BlankLineBetweenStatementTypesRule.js +57 -0
- package/dist/core/formatters/rules/spacing/BlockSpacingRule.js +17 -0
- package/dist/core/formatters/rules/spacing/BracketSpacingRule.js +108 -0
- package/dist/core/formatters/rules/style/DocBlockCommentRule.js +19 -0
- package/dist/core/formatters/rules/style/IndentationRule.js +45 -0
- package/dist/core/formatters/rules/style/QuoteStyleRule.js +63 -0
- package/dist/core/formatters/rules/style/SemicolonRule.js +68 -0
- package/dist/core/formatters/rules/style/StructuralIndentationRule.js +250 -0
- package/dist/core/pipeline/FormatterPipeline.js +252 -0
- package/dist/formatters/package.js +29 -0
- package/dist/index.js +66 -0
- package/dist/shared/types.js +28 -0
- package/dist/sortPackage.js +34 -0
- package/dist/sortTSConfig.js +34 -0
- package/package.json +11 -8
- package/bin/ci_build.sh +0 -50
- package/bin/cli.js +0 -20
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const ts = require("typescript");
|
|
4
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
5
|
+
function _interopNamespaceDefault(e) {
|
|
6
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
7
|
+
if (e) {
|
|
8
|
+
for (const k in e) {
|
|
9
|
+
if (k !== "default") {
|
|
10
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
11
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: () => e[k]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return Object.freeze(n);
|
|
20
|
+
}
|
|
21
|
+
const ts__namespace = /* @__PURE__ */ _interopNamespaceDefault(ts);
|
|
22
|
+
class ImportOrganizationRule extends BaseFormattingRule.BaseFormattingRule {
|
|
23
|
+
constructor() {
|
|
24
|
+
super(...arguments);
|
|
25
|
+
this.name = "ImportOrganizationRule";
|
|
26
|
+
}
|
|
27
|
+
createSourceFile(source) {
|
|
28
|
+
return ts__namespace.createSourceFile("temp.ts", source, ts__namespace.ScriptTarget.Latest, true, ts__namespace.ScriptKind.TS);
|
|
29
|
+
}
|
|
30
|
+
determineImportGroup(moduleSpecifier) {
|
|
31
|
+
if (moduleSpecifier.startsWith(".") || moduleSpecifier.startsWith("/")) {
|
|
32
|
+
return "relative";
|
|
33
|
+
}
|
|
34
|
+
if (moduleSpecifier.startsWith("@/") || moduleSpecifier.startsWith("~/")) {
|
|
35
|
+
return "internal";
|
|
36
|
+
}
|
|
37
|
+
return "external";
|
|
38
|
+
}
|
|
39
|
+
extractImports(sourceFile) {
|
|
40
|
+
const imports = [];
|
|
41
|
+
for (const statement of sourceFile.statements) {
|
|
42
|
+
if (ts__namespace.isImportDeclaration(statement)) {
|
|
43
|
+
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
44
|
+
const isSideEffect = !statement.importClause;
|
|
45
|
+
const isTypeOnly = statement.importClause?.isTypeOnly || false;
|
|
46
|
+
const group = this.determineImportGroup(moduleSpecifier);
|
|
47
|
+
imports.push({
|
|
48
|
+
statement,
|
|
49
|
+
moduleSpecifier,
|
|
50
|
+
importClause: statement.importClause,
|
|
51
|
+
isTypeOnly,
|
|
52
|
+
isSideEffect,
|
|
53
|
+
group
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return imports;
|
|
58
|
+
}
|
|
59
|
+
getImportedIdentifiers(importInfo) {
|
|
60
|
+
const identifiers = [];
|
|
61
|
+
if (!importInfo.importClause) {
|
|
62
|
+
return identifiers;
|
|
63
|
+
}
|
|
64
|
+
if (importInfo.importClause.name) {
|
|
65
|
+
identifiers.push(importInfo.importClause.name.text);
|
|
66
|
+
}
|
|
67
|
+
if (importInfo.importClause.namedBindings) {
|
|
68
|
+
if (ts__namespace.isNamedImports(importInfo.importClause.namedBindings)) {
|
|
69
|
+
for (const element of importInfo.importClause.namedBindings.elements) {
|
|
70
|
+
identifiers.push(element.name.text);
|
|
71
|
+
}
|
|
72
|
+
} else if (ts__namespace.isNamespaceImport(importInfo.importClause.namedBindings)) {
|
|
73
|
+
identifiers.push(importInfo.importClause.namedBindings.name.text);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return identifiers;
|
|
77
|
+
}
|
|
78
|
+
isIdentifierUsed(identifier, sourceFile) {
|
|
79
|
+
let found = false;
|
|
80
|
+
const visit = (node) => {
|
|
81
|
+
if (found)
|
|
82
|
+
return;
|
|
83
|
+
if (ts__namespace.isIdentifier(node) && node.text === identifier) {
|
|
84
|
+
const parent = node.parent;
|
|
85
|
+
if (!ts__namespace.isImportSpecifier(parent) && !ts__namespace.isImportClause(parent)) {
|
|
86
|
+
found = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
ts__namespace.forEachChild(node, visit);
|
|
90
|
+
};
|
|
91
|
+
visit(sourceFile);
|
|
92
|
+
return found;
|
|
93
|
+
}
|
|
94
|
+
isImportUsed(importInfo, sourceFile) {
|
|
95
|
+
if (importInfo.isSideEffect) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (!importInfo.importClause) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const identifiers = this.getImportedIdentifiers(importInfo);
|
|
102
|
+
return identifiers.some((id) => this.isIdentifierUsed(id, sourceFile));
|
|
103
|
+
}
|
|
104
|
+
filterUnusedImports(imports, sourceFile) {
|
|
105
|
+
const config = this.getImportsConfig();
|
|
106
|
+
if (!config?.removeUnused) {
|
|
107
|
+
return imports;
|
|
108
|
+
}
|
|
109
|
+
if (!config.removeSideEffects) {
|
|
110
|
+
return imports.filter((imp) => imp.isSideEffect || this.isImportUsed(imp, sourceFile));
|
|
111
|
+
}
|
|
112
|
+
return imports.filter((imp) => this.isImportUsed(imp, sourceFile));
|
|
113
|
+
}
|
|
114
|
+
sortImports(imports) {
|
|
115
|
+
const config = this.getImportsConfig();
|
|
116
|
+
if (!config?.sortImports) {
|
|
117
|
+
return imports;
|
|
118
|
+
}
|
|
119
|
+
return [...imports].sort((a, b) => {
|
|
120
|
+
return a.moduleSpecifier.localeCompare(b.moduleSpecifier);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
groupImports(imports) {
|
|
124
|
+
const config = this.getImportsConfig();
|
|
125
|
+
if (!config?.groupImports) {
|
|
126
|
+
return imports;
|
|
127
|
+
}
|
|
128
|
+
const groupOrder = config.groupOrder || ["external", "internal", "relative"];
|
|
129
|
+
const grouped = [];
|
|
130
|
+
for (const group of groupOrder) {
|
|
131
|
+
const groupImports = imports.filter((imp) => imp.group === group);
|
|
132
|
+
grouped.push(...groupImports);
|
|
133
|
+
}
|
|
134
|
+
return grouped;
|
|
135
|
+
}
|
|
136
|
+
reconstructSource(sourceFile, imports) {
|
|
137
|
+
const config = this.getImportsConfig();
|
|
138
|
+
const fullText = sourceFile.getFullText();
|
|
139
|
+
const leadingCommentsMatch = fullText.match(/^((?:\/\*[\s\S]*?\*\/\s*)+)/);
|
|
140
|
+
let leadingComments = leadingCommentsMatch ? leadingCommentsMatch[1].trim() : "";
|
|
141
|
+
if (leadingComments) {
|
|
142
|
+
const commentBlocks = leadingComments.match(/\/\*[\s\S]*?\*\//g) || [];
|
|
143
|
+
const uniqueBlocks = new Set(commentBlocks.map((block) => block.trim()));
|
|
144
|
+
leadingComments = Array.from(uniqueBlocks).join("\n");
|
|
145
|
+
}
|
|
146
|
+
const importStatements = sourceFile.statements.filter((stmt) => ts__namespace.isImportDeclaration(stmt));
|
|
147
|
+
const lastImport = importStatements[importStatements.length - 1];
|
|
148
|
+
const afterImportsPos = lastImport ? lastImport.getEnd() : leadingCommentsMatch ? leadingCommentsMatch[0].length : 0;
|
|
149
|
+
let restOfFile = fullText.substring(afterImportsPos);
|
|
150
|
+
if (restOfFile && !restOfFile.startsWith("\n")) {
|
|
151
|
+
restOfFile = "\n" + restOfFile;
|
|
152
|
+
}
|
|
153
|
+
restOfFile = restOfFile.replace(/^\n{2,}/, "\n");
|
|
154
|
+
const printer = ts__namespace.createPrinter({
|
|
155
|
+
newLine: ts__namespace.NewLineKind.LineFeed,
|
|
156
|
+
removeComments: false
|
|
157
|
+
});
|
|
158
|
+
const importLines = [];
|
|
159
|
+
let lastGroup = null;
|
|
160
|
+
for (const importInfo of imports) {
|
|
161
|
+
if (config?.separateGroups && lastGroup !== null && lastGroup !== importInfo.group) {
|
|
162
|
+
importLines.push("");
|
|
163
|
+
}
|
|
164
|
+
let importText = printer.printNode(ts__namespace.EmitHint.Unspecified, importInfo.statement, sourceFile);
|
|
165
|
+
importText = importText.replace(/^((?:\/\*[\s\S]*?\*\/\s*)+)/, "").trim();
|
|
166
|
+
importLines.push(importText);
|
|
167
|
+
lastGroup = importInfo.group;
|
|
168
|
+
}
|
|
169
|
+
const sections = [];
|
|
170
|
+
if (leadingComments) {
|
|
171
|
+
sections.push(leadingComments);
|
|
172
|
+
}
|
|
173
|
+
if (importLines.length > 0) {
|
|
174
|
+
sections.push(importLines.join("\n"));
|
|
175
|
+
}
|
|
176
|
+
if (restOfFile) {
|
|
177
|
+
sections.push(restOfFile);
|
|
178
|
+
}
|
|
179
|
+
let combined = sections.join("\n\n");
|
|
180
|
+
combined = combined.replace(/(;\n+)+;?\s*$/, "\n");
|
|
181
|
+
return combined;
|
|
182
|
+
}
|
|
183
|
+
apply(source, filePath) {
|
|
184
|
+
const config = this.getImportsConfig();
|
|
185
|
+
if (!config?.enabled) {
|
|
186
|
+
return source;
|
|
187
|
+
}
|
|
188
|
+
const sourceFile = this.createSourceFile(source);
|
|
189
|
+
const imports = this.extractImports(sourceFile);
|
|
190
|
+
let processedImports = this.filterUnusedImports(imports, sourceFile);
|
|
191
|
+
processedImports = this.sortImports(processedImports);
|
|
192
|
+
processedImports = this.groupImports(processedImports);
|
|
193
|
+
return this.reconstructSource(sourceFile, processedImports);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.ImportOrganizationRule = ImportOrganizationRule;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
6
|
+
function _interopNamespaceDefault(e) {
|
|
7
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
8
|
+
if (e) {
|
|
9
|
+
for (const k in e) {
|
|
10
|
+
if (k !== "default") {
|
|
11
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: () => e[k]
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
|
|
23
|
+
const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
|
|
24
|
+
class IndexGenerationRule extends BaseFormattingRule.BaseFormattingRule {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.defaultOptions = {
|
|
28
|
+
fileExtension: ".ts",
|
|
29
|
+
indexFileName: "index.ts",
|
|
30
|
+
recursive: true
|
|
31
|
+
};
|
|
32
|
+
this.name = "IndexGenerationRule";
|
|
33
|
+
}
|
|
34
|
+
findProjectRoot(filePath) {
|
|
35
|
+
let current = path__namespace.dirname(filePath);
|
|
36
|
+
while (current !== path__namespace.dirname(current)) {
|
|
37
|
+
if (fs__namespace.existsSync(path__namespace.join(current, "package.json"))) {
|
|
38
|
+
return current;
|
|
39
|
+
}
|
|
40
|
+
current = path__namespace.dirname(current);
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
isTestDirectory(dirName) {
|
|
45
|
+
const testDirectories = [
|
|
46
|
+
"__tests__",
|
|
47
|
+
"tests",
|
|
48
|
+
"test",
|
|
49
|
+
"__mocks__",
|
|
50
|
+
"__fixtures__",
|
|
51
|
+
".storybook"
|
|
52
|
+
];
|
|
53
|
+
return testDirectories.includes(dirName.toLowerCase()) || dirName.endsWith(".test") || dirName.endsWith(".spec");
|
|
54
|
+
}
|
|
55
|
+
isTestFile(fileName) {
|
|
56
|
+
const testPatterns = [
|
|
57
|
+
/\.test\.(ts|tsx|js|jsx)$/,
|
|
58
|
+
/\.spec\.(ts|tsx|js|jsx)$/,
|
|
59
|
+
/\.(test|spec)\.(ts|tsx|js|jsx)$/,
|
|
60
|
+
/__tests__/,
|
|
61
|
+
/\.stories\.(ts|tsx|js|jsx)$/
|
|
62
|
+
];
|
|
63
|
+
return testPatterns.some((pattern) => pattern.test(fileName));
|
|
64
|
+
}
|
|
65
|
+
generateSingleDirectoryIndex(dir, options) {
|
|
66
|
+
try {
|
|
67
|
+
const entries = fs__namespace.readdirSync(dir, { withFileTypes: true });
|
|
68
|
+
const exports$1 = [];
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (entry.name === options.indexFileName) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
if (this.isTestDirectory(entry.name)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const subIndexPath = path__namespace.join(dir, entry.name, options.indexFileName);
|
|
78
|
+
if (fs__namespace.existsSync(subIndexPath)) {
|
|
79
|
+
exports$1.push(`export * from "./${entry.name}";`);
|
|
80
|
+
}
|
|
81
|
+
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
82
|
+
if (entry.name.endsWith(".d.ts")) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (this.isTestFile(entry.name)) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const exportName = entry.name.replace(/\.(ts|tsx)$/, "");
|
|
89
|
+
exports$1.push(`export * from "./${exportName}";`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (exports$1.length === 0) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
exports$1.sort();
|
|
96
|
+
const content = `// Auto-generated exports - do not edit manually
|
|
97
|
+
// Run tsfmt to regenerate
|
|
98
|
+
|
|
99
|
+
${exports$1.join("\n")}
|
|
100
|
+
`;
|
|
101
|
+
const indexPath = path__namespace.join(dir, options.indexFileName);
|
|
102
|
+
fs__namespace.writeFileSync(indexPath, content, "utf8");
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn(`Warning: Failed to generate index for ${dir}: ${error.message}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
generateIndexExportRecursive(dir, options) {
|
|
108
|
+
try {
|
|
109
|
+
const entries = fs__namespace.readdirSync(dir, { withFileTypes: true });
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
if (entry.isDirectory()) {
|
|
112
|
+
if (this.isTestDirectory(entry.name)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const subDir = path__namespace.join(dir, entry.name);
|
|
116
|
+
this.generateIndexExportRecursive(subDir, options);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.generateSingleDirectoryIndex(dir, options);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.warn(`Warning: Failed to process directory ${dir}: ${error.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
generateIndexExport(dir, options) {
|
|
125
|
+
if (!fs__namespace.existsSync(dir)) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (options.recursive) {
|
|
129
|
+
this.generateIndexExportRecursive(dir, options);
|
|
130
|
+
} else {
|
|
131
|
+
this.generateSingleDirectoryIndex(dir, options);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
discoverExportableModules(srcDir) {
|
|
135
|
+
try {
|
|
136
|
+
const entries = fs__namespace.readdirSync(srcDir, { withFileTypes: true });
|
|
137
|
+
const modules = [];
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (entry.name === "index.ts") {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (entry.isDirectory()) {
|
|
143
|
+
if (this.isTestDirectory(entry.name)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const indexPath = path__namespace.join(srcDir, entry.name, "index.ts");
|
|
147
|
+
if (fs__namespace.existsSync(indexPath)) {
|
|
148
|
+
modules.push(entry.name);
|
|
149
|
+
}
|
|
150
|
+
} else if (entry.name.endsWith(".d.ts")) {
|
|
151
|
+
const moduleName = entry.name.slice(0, -3);
|
|
152
|
+
modules.push(moduleName);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return modules.sort();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.warn(`Warning: Failed to discover modules in ${srcDir}: ${error.message}`);
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
updateMainIndex(indexPath, modules) {
|
|
162
|
+
try {
|
|
163
|
+
const exports$1 = modules.map((mod) => `export * from "./${mod}";`).join("\n");
|
|
164
|
+
const content = `// Auto-generated exports - do not edit manually
|
|
165
|
+
// Run tsfmt to regenerate
|
|
166
|
+
|
|
167
|
+
${exports$1}
|
|
168
|
+
`;
|
|
169
|
+
fs__namespace.writeFileSync(indexPath, content, "utf8");
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.warn(`Warning: Failed to write main index file: ${error.message}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
generateIndexFiles(currentFilePath) {
|
|
175
|
+
try {
|
|
176
|
+
const projectRoot = this.findProjectRoot(currentFilePath);
|
|
177
|
+
if (!projectRoot) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const config = this.getIndexGenerationConfig();
|
|
181
|
+
const directories = config?.directories || [];
|
|
182
|
+
const options = { ...this.defaultOptions, ...config?.options };
|
|
183
|
+
for (const dir of directories) {
|
|
184
|
+
const fullDirPath = path__namespace.resolve(projectRoot, dir);
|
|
185
|
+
this.generateIndexExport(fullDirPath, options);
|
|
186
|
+
}
|
|
187
|
+
if (config?.updateMainIndex !== false) {
|
|
188
|
+
const srcDir = path__namespace.join(projectRoot, "src");
|
|
189
|
+
const mainIndexPath = path__namespace.join(srcDir, "index.ts");
|
|
190
|
+
if (fs__namespace.existsSync(srcDir)) {
|
|
191
|
+
const modules = this.discoverExportableModules(srcDir);
|
|
192
|
+
this.updateMainIndex(mainIndexPath, modules);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.warn(`Warning: Failed to generate index files: ${error.message}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
apply(source, filePath) {
|
|
200
|
+
const config = this.getIndexGenerationConfig();
|
|
201
|
+
if (!config?.enabled || !filePath) {
|
|
202
|
+
return source;
|
|
203
|
+
}
|
|
204
|
+
this.generateIndexFiles(filePath);
|
|
205
|
+
return source;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.IndexGenerationRule = IndexGenerationRule;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
4
|
+
class BlankLineBeforeReturnsRule extends BaseFormattingRule.BaseFormattingRule {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.name = "BlankLineBeforeReturnsRule";
|
|
8
|
+
}
|
|
9
|
+
apply(source, filePath) {
|
|
10
|
+
const config = this.getSpacingConfig();
|
|
11
|
+
if (!config?.beforeReturns) {
|
|
12
|
+
return source;
|
|
13
|
+
}
|
|
14
|
+
const lines = source.split("\n");
|
|
15
|
+
const result = [];
|
|
16
|
+
for (let i = 0; i < lines.length; i++) {
|
|
17
|
+
const currentLine = lines[i];
|
|
18
|
+
const trimmedCurrentLine = currentLine.trim();
|
|
19
|
+
const previousLine = i > 0 ? lines[i - 1] : "";
|
|
20
|
+
const trimmedPreviousLine = previousLine.trim();
|
|
21
|
+
const isReturnStatement = trimmedCurrentLine.startsWith("return ");
|
|
22
|
+
const previousIsComment = trimmedPreviousLine.startsWith("//") || trimmedPreviousLine.startsWith("/*") || trimmedPreviousLine.startsWith("*") || trimmedPreviousLine.endsWith("*/");
|
|
23
|
+
const previousIsBlank = trimmedPreviousLine === "";
|
|
24
|
+
if (isReturnStatement && !previousIsBlank && !previousIsComment && i > 0) {
|
|
25
|
+
result.push("");
|
|
26
|
+
}
|
|
27
|
+
result.push(currentLine);
|
|
28
|
+
}
|
|
29
|
+
return result.join("\n");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.BlankLineBeforeReturnsRule = BlankLineBeforeReturnsRule;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
4
|
+
class BlankLineBetweenDeclarationsRule extends BaseFormattingRule.BaseFormattingRule {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.name = "BlankLineBetweenDeclarationsRule";
|
|
8
|
+
}
|
|
9
|
+
/** Extracts the keyword from a declaration line */
|
|
10
|
+
getDeclarationKeyword(trimmedLine) {
|
|
11
|
+
if (trimmedLine.startsWith("export ")) {
|
|
12
|
+
return "export";
|
|
13
|
+
}
|
|
14
|
+
if (trimmedLine.startsWith("function ")) {
|
|
15
|
+
return "function";
|
|
16
|
+
}
|
|
17
|
+
if (trimmedLine.startsWith("const ")) {
|
|
18
|
+
return "const";
|
|
19
|
+
}
|
|
20
|
+
if (trimmedLine.startsWith("let ")) {
|
|
21
|
+
return "let";
|
|
22
|
+
}
|
|
23
|
+
if (trimmedLine.startsWith("var ")) {
|
|
24
|
+
return "var";
|
|
25
|
+
}
|
|
26
|
+
if (trimmedLine.startsWith("enum ")) {
|
|
27
|
+
return "enum";
|
|
28
|
+
}
|
|
29
|
+
if (trimmedLine.startsWith("interface ")) {
|
|
30
|
+
return "interface";
|
|
31
|
+
}
|
|
32
|
+
if (trimmedLine.startsWith("type ")) {
|
|
33
|
+
return "type";
|
|
34
|
+
}
|
|
35
|
+
if (trimmedLine.startsWith("class ")) {
|
|
36
|
+
return "class";
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
apply(source, filePath) {
|
|
41
|
+
const config = this.getSpacingConfig();
|
|
42
|
+
if (!config?.betweenDeclarations) {
|
|
43
|
+
return source;
|
|
44
|
+
}
|
|
45
|
+
const lines = source.split("\n");
|
|
46
|
+
const result = [];
|
|
47
|
+
let inImportSection = true;
|
|
48
|
+
let lastNonBlankLineWasDeclarationEnd = false;
|
|
49
|
+
let lastDeclarationKeyword = null;
|
|
50
|
+
for (let i = 0; i < lines.length; i++) {
|
|
51
|
+
const line = lines[i];
|
|
52
|
+
const trimmedLine = line.trim();
|
|
53
|
+
(line.match(/{/g) || []).length;
|
|
54
|
+
(line.match(/}/g) || []).length;
|
|
55
|
+
const isBlankLine = trimmedLine === "";
|
|
56
|
+
const isComment = trimmedLine.startsWith("//") || trimmedLine.startsWith("/*") || trimmedLine.startsWith("*") || trimmedLine === "*/";
|
|
57
|
+
const isBlockCommentStart = trimmedLine.startsWith("/*") && !trimmedLine.endsWith("*/");
|
|
58
|
+
const isImport = trimmedLine.startsWith("import ");
|
|
59
|
+
const declarationKeyword = !isComment && !isImport ? this.getDeclarationKeyword(trimmedLine) : null;
|
|
60
|
+
const isDeclarationStart = declarationKeyword !== null;
|
|
61
|
+
if (inImportSection && !isImport && !isBlankLine && !isComment) {
|
|
62
|
+
inImportSection = false;
|
|
63
|
+
}
|
|
64
|
+
if (!inImportSection) {
|
|
65
|
+
if (isBlockCommentStart && lastNonBlankLineWasDeclarationEnd && result.length > 0 && result[result.length - 1].trim() !== "") {
|
|
66
|
+
result.push("");
|
|
67
|
+
lastNonBlankLineWasDeclarationEnd = false;
|
|
68
|
+
} else if (isDeclarationStart && lastNonBlankLineWasDeclarationEnd && result.length > 0 && result[result.length - 1].trim() !== "" && declarationKeyword !== lastDeclarationKeyword) {
|
|
69
|
+
result.push("");
|
|
70
|
+
lastNonBlankLineWasDeclarationEnd = false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
result.push(line);
|
|
74
|
+
const hasClosingElement = trimmedLine === "}" || trimmedLine.endsWith("}") || trimmedLine.endsWith(";");
|
|
75
|
+
const isJustClosingBraces = /^[\s});]*$/.test(trimmedLine);
|
|
76
|
+
if (!isBlankLine && hasClosingElement) {
|
|
77
|
+
lastNonBlankLineWasDeclarationEnd = true;
|
|
78
|
+
if (isDeclarationStart) {
|
|
79
|
+
lastDeclarationKeyword = declarationKeyword;
|
|
80
|
+
}
|
|
81
|
+
} else if (!isBlankLine && !isComment) {
|
|
82
|
+
if (!isBlockCommentStart && trimmedLine !== "" && !isJustClosingBraces) {
|
|
83
|
+
lastNonBlankLineWasDeclarationEnd = isDeclarationStart;
|
|
84
|
+
if (isDeclarationStart) {
|
|
85
|
+
lastDeclarationKeyword = declarationKeyword;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return result.join("\n");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.BlankLineBetweenDeclarationsRule = BlankLineBetweenDeclarationsRule;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
4
|
+
class BlankLineBetweenStatementTypesRule extends BaseFormattingRule.BaseFormattingRule {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.name = "BlankLineBetweenStatementTypesRule";
|
|
8
|
+
}
|
|
9
|
+
/** Determine the type of a statement */
|
|
10
|
+
getStatementType(trimmedLine) {
|
|
11
|
+
if (trimmedLine.startsWith("if ") || trimmedLine.startsWith("if(") || trimmedLine.startsWith("else ") || trimmedLine.startsWith("else{") || trimmedLine.startsWith("switch ") || trimmedLine.startsWith("switch(") || trimmedLine.startsWith("case ") || trimmedLine.startsWith("default:")) {
|
|
12
|
+
return "control";
|
|
13
|
+
}
|
|
14
|
+
if (trimmedLine.startsWith("for ") || trimmedLine.startsWith("for(") || trimmedLine.startsWith("while ") || trimmedLine.startsWith("while(") || trimmedLine.startsWith("do ") || trimmedLine.startsWith("do{")) {
|
|
15
|
+
return "loop";
|
|
16
|
+
}
|
|
17
|
+
if (trimmedLine.startsWith("try ") || trimmedLine.startsWith("try{") || trimmedLine.startsWith("catch ") || trimmedLine.startsWith("catch(") || trimmedLine.startsWith("finally ") || trimmedLine.startsWith("finally{") || trimmedLine.startsWith("throw ")) {
|
|
18
|
+
return "exception";
|
|
19
|
+
}
|
|
20
|
+
if (trimmedLine.startsWith("const ") || trimmedLine.startsWith("let ") || trimmedLine.startsWith("var ") || trimmedLine.startsWith("function ") || trimmedLine.startsWith("class ") || trimmedLine.startsWith("interface ") || trimmedLine.startsWith("type ") || trimmedLine.startsWith("enum ") || trimmedLine.startsWith("export ")) {
|
|
21
|
+
return "declaration";
|
|
22
|
+
}
|
|
23
|
+
return "expression";
|
|
24
|
+
}
|
|
25
|
+
apply(source, filePath) {
|
|
26
|
+
const config = this.getSpacingConfig();
|
|
27
|
+
if (!config?.betweenStatementTypes) {
|
|
28
|
+
return source;
|
|
29
|
+
}
|
|
30
|
+
const lines = source.split("\n");
|
|
31
|
+
const result = [];
|
|
32
|
+
let lastStatementType = null;
|
|
33
|
+
let inImportSection = true;
|
|
34
|
+
for (let i = 0; i < lines.length; i++) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
const trimmedLine = line.trim();
|
|
37
|
+
const isBlankLine = trimmedLine === "";
|
|
38
|
+
const isComment = trimmedLine.startsWith("//") || trimmedLine.startsWith("/*") || trimmedLine.startsWith("*");
|
|
39
|
+
const isImport = trimmedLine.startsWith("import ");
|
|
40
|
+
if (inImportSection && !isImport && !isBlankLine && !isComment) {
|
|
41
|
+
inImportSection = false;
|
|
42
|
+
}
|
|
43
|
+
if (inImportSection || isBlankLine || isComment) {
|
|
44
|
+
result.push(line);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const currentStatementType = this.getStatementType(trimmedLine);
|
|
48
|
+
if (lastStatementType !== null && lastStatementType !== currentStatementType && result.length > 0 && result[result.length - 1].trim() !== "") {
|
|
49
|
+
result.push("");
|
|
50
|
+
}
|
|
51
|
+
result.push(line);
|
|
52
|
+
lastStatementType = currentStatementType;
|
|
53
|
+
}
|
|
54
|
+
return result.join("\n");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.BlankLineBetweenStatementTypesRule = BlankLineBetweenStatementTypesRule;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const BaseFormattingRule = require("../../BaseFormattingRule.js");
|
|
4
|
+
class BlockSpacingRule extends BaseFormattingRule.BaseFormattingRule {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.name = "BlockSpacingRule";
|
|
8
|
+
}
|
|
9
|
+
apply(source, filePath) {
|
|
10
|
+
let result = source;
|
|
11
|
+
result = result.replace(/\{\n\n+(\s*(?:\/\*\*|[a-zA-Z_]))/g, "{\n$1");
|
|
12
|
+
result = result.replace(/(\*\/)\n\n+(\s+[a-zA-Z_])/g, "$1\n$2");
|
|
13
|
+
result = result.replace(/\n\n+(\s*\})/g, "\n$1");
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.BlockSpacingRule = BlockSpacingRule;
|