@wrongstack/plugins 0.293.0 → 0.295.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.
- package/README.md +7 -71
- package/dist/accessibility-auditor/index.d.ts +1 -1
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +50 -33
- package/dist/agent-handoff/index.d.ts +1 -1
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/api-compatibility-gate/index.d.ts +1 -1
- package/dist/api-compatibility-gate/index.d.ts.map +1 -1
- package/dist/api-compatibility-gate.js +21 -16
- package/dist/audit/index.d.ts +386 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit.d.ts +1 -0
- package/dist/audit.js +454 -0
- package/dist/auto-doc/index.d.ts +1 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-escalate/index.d.ts +1 -1
- package/dist/auto-escalate/index.d.ts.map +1 -1
- package/dist/auto-i18n-extractor/index.d.ts +1 -1
- package/dist/auto-i18n-extractor/index.d.ts.map +1 -1
- package/dist/auto-i18n-extractor.js +7 -1
- package/dist/branch-guard/index.d.ts +1 -1
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +111 -1
- package/dist/catalog.d.ts +5 -30
- package/dist/catalog.d.ts.map +1 -1
- package/dist/changelog-writer/index.d.ts +1 -1
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +3 -1
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +41 -16
- package/dist/code-metrics/index.d.ts +1 -1
- package/dist/code-metrics/index.d.ts.map +1 -1
- package/dist/code-metrics.js +34 -29
- package/dist/commit-validator/index.d.ts +1 -1
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +17 -7
- package/dist/config-validator/index.d.ts +1 -1
- package/dist/config-validator/index.d.ts.map +1 -1
- package/dist/context-pins/index.d.ts +1 -1
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts +1 -1
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +109 -2
- package/dist/cron/index.d.ts +1 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector/index.d.ts +1 -1
- package/dist/dead-code-detector/index.d.ts.map +1 -1
- package/dist/dead-code-detector.js +31 -18
- package/dist/dep-guard/index.d.ts +1 -1
- package/dist/dep-guard/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate/index.d.ts +1 -1
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +67 -20
- package/dist/diff-summary/index.d.ts +1 -1
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +128 -30
- package/dist/doc-sync-guard/index.d.ts +1 -1
- package/dist/doc-sync-guard/index.d.ts.map +1 -1
- package/dist/doc-sync-guard.js +7 -1
- package/dist/duplicate-code-detector/index.d.ts +26 -1
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +280 -69
- package/dist/error-lens/index.d.ts +1 -1
- package/dist/error-lens/index.d.ts.map +1 -1
- package/dist/factories/index.d.ts +4 -0
- package/dist/factories/index.d.ts.map +1 -0
- package/dist/factories.d.ts +1 -0
- package/dist/factories.js +74 -0
- package/dist/feature-flag-tracker/index.d.ts +1 -1
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +59 -33
- package/dist/file-watcher/index.d.ts +1 -1
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +3 -1
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +289 -59
- package/dist/generated-plugin-exports.d.ts +65 -0
- package/dist/generated-plugin-exports.d.ts.map +1 -0
- package/dist/git-autocommit/index.d.ts +1 -1
- package/dist/git-autocommit/index.d.ts.map +1 -1
- package/dist/import-organizer/index.d.ts +1 -1
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +141 -20
- package/dist/index.d.ts +4 -183
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18298 -17279
- package/dist/injection-shield/index.d.ts +1 -1
- package/dist/injection-shield/index.d.ts.map +1 -1
- package/dist/interface-contract-guard/index.d.ts +1 -1
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +87 -53
- package/dist/knowledge-graph/index.d.ts +1 -1
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/license-audit-gate/index.d.ts +1 -1
- package/dist/license-audit-gate/index.d.ts.map +1 -1
- package/dist/lint-gate/index.d.ts +1 -1
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +112 -1
- package/dist/llm-cache/index.d.ts +5 -1
- package/dist/llm-cache/index.d.ts.map +1 -1
- package/dist/llm-cache.js +16 -8
- package/dist/loop-breaker/index.d.ts +1 -1
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +25 -9
- package/dist/manifest/index.d.ts +16 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest.d.ts +1 -0
- package/dist/manifest.js +152 -0
- package/dist/migration-planner/index.d.ts +1 -1
- package/dist/migration-planner/index.d.ts.map +1 -1
- package/dist/migration-planner.js +5 -1
- package/dist/model-router/index.d.ts +1 -1
- package/dist/model-router/index.d.ts.map +1 -1
- package/dist/notify-hub/index.d.ts +1 -1
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub/webhook-channel.d.ts +1 -1
- package/dist/notify-hub/webhook-channel.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/path-guard/index.d.ts +1 -1
- package/dist/path-guard/index.d.ts.map +1 -1
- package/dist/performance-regression-gate/index.d.ts +1 -1
- package/dist/performance-regression-gate/index.d.ts.map +1 -1
- package/dist/plugin-stack-observer/index.d.ts +1 -1
- package/dist/plugin-stack-observer/index.d.ts.map +1 -1
- package/dist/pr-drafter/index.d.ts +1 -1
- package/dist/pr-drafter/index.d.ts.map +1 -1
- package/dist/pr-drafter.js +28 -29
- package/dist/process-guard/index.d.ts +1 -1
- package/dist/process-guard/index.d.ts.map +1 -1
- package/dist/prompt-firewall/index.d.ts +1 -1
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts +1 -1
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +148 -33
- package/dist/release-notes-generator/index.d.ts +1 -1
- package/dist/release-notes-generator/index.d.ts.map +1 -1
- package/dist/release-notes-generator.js +29 -22
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +18 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/llm.d.ts +1 -1
- package/dist/runtime/llm.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +332 -22
- package/dist/schema-evolution-guard/index.d.ts +1 -1
- package/dist/schema-evolution-guard/index.d.ts.map +1 -1
- package/dist/schema-evolution-guard.js +7 -1
- package/dist/secret-scanner/index.d.ts +1 -1
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +181 -48
- package/dist/security-hotspot-scanner/index.d.ts +1 -1
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +158 -20
- package/dist/semantic-search-indexer/index.d.ts +1 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts +1 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +97 -43
- package/dist/session-recap/index.d.ts +1 -1
- package/dist/session-recap/index.d.ts.map +1 -1
- package/dist/shell-check/index.d.ts +1 -1
- package/dist/shell-check/index.d.ts.map +1 -1
- package/dist/smart-rename/index.d.ts +1 -1
- package/dist/smart-rename/index.d.ts.map +1 -1
- package/dist/spec-linker/index.d.ts +1 -1
- package/dist/spec-linker/index.d.ts.map +1 -1
- package/dist/spec-linker.js +222 -20772
- package/dist/template-engine/index.d.ts +1 -1
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +34 -8
- package/dist/test-coverage-gate/index.d.ts +1 -1
- package/dist/test-coverage-gate/index.d.ts.map +1 -1
- package/dist/test-coverage-gate.js +34 -14
- package/dist/test-flake-detector/index.d.ts +1 -1
- package/dist/test-flake-detector/index.d.ts.map +1 -1
- package/dist/test-flake-detector.js +31 -20
- package/dist/test-generator/index.d.ts +1 -1
- package/dist/test-generator/index.d.ts.map +1 -1
- package/dist/test-runner-gate/index.d.ts +1 -1
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +132 -9
- package/dist/todo-listener/index.d.ts +1 -32
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +30 -1
- package/dist/todo-tracker/index.d.ts +1 -1
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-budget/index.d.ts +1 -1
- package/dist/token-budget/index.d.ts.map +1 -1
- package/dist/token-throttle/index.d.ts +1 -1
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts +1 -1
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +106 -19
- package/package.json +80 -68
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// src/feature-flag-tracker/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/runtime/index.ts
|
|
6
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
7
6
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/index.ts
|
|
8
12
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
9
13
|
function hasLeadingDash(arg) {
|
|
10
14
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -17,44 +21,45 @@ function withinProjectPath(projectRoot, candidate) {
|
|
|
17
21
|
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
18
22
|
}
|
|
19
23
|
function withinProject(p) {
|
|
20
|
-
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
21
26
|
}
|
|
22
27
|
var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
|
|
23
|
-
function
|
|
28
|
+
async function collectSourceFilesAsync(root, opts) {
|
|
29
|
+
const { readdir, stat } = await import("node:fs/promises");
|
|
24
30
|
const files = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
try {
|
|
32
|
+
const s = await stat(root);
|
|
33
|
+
if (s.isFile()) {
|
|
34
|
+
if (matchesExtension(root, opts.extensions)) files.push(root);
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
if (!s.isDirectory()) return files;
|
|
38
|
+
} catch {
|
|
29
39
|
return files;
|
|
30
40
|
}
|
|
31
|
-
if (!s.isDirectory()) return files;
|
|
32
41
|
const exclude = opts.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
|
|
33
|
-
|
|
42
|
+
const excludeSet = new Set(exclude);
|
|
43
|
+
async function walk(dir, depth) {
|
|
34
44
|
if (opts.maxDepth !== void 0 && depth > opts.maxDepth) return;
|
|
35
45
|
let entries;
|
|
36
46
|
try {
|
|
37
|
-
entries =
|
|
47
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
38
48
|
} catch {
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
51
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
41
52
|
for (const entry of entries) {
|
|
42
|
-
if (
|
|
43
|
-
const full = resolve(dir, entry);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} catch {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (st.isDirectory()) {
|
|
51
|
-
walk(full, depth + 1);
|
|
52
|
-
} else if (st.isFile() && matchesExtension(full, opts.extensions)) {
|
|
53
|
+
if (excludeSet.has(entry.name)) continue;
|
|
54
|
+
const full = resolve(dir, entry.name);
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
await walk(full, depth + 1);
|
|
57
|
+
} else if (entry.isFile() && matchesExtension(full, opts.extensions)) {
|
|
53
58
|
files.push(full);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
|
-
walk(root, 0);
|
|
62
|
+
await walk(root, 0);
|
|
58
63
|
return files;
|
|
59
64
|
}
|
|
60
65
|
function matchesExtension(p, exts) {
|
|
@@ -103,8 +108,14 @@ function relativePath(p) {
|
|
|
103
108
|
return toPosix(relative2(process.cwd(), p));
|
|
104
109
|
}
|
|
105
110
|
function compilePatterns(patterns) {
|
|
106
|
-
const
|
|
107
|
-
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const src of [...DEFAULT_PATTERNS, ...patterns]) {
|
|
113
|
+
try {
|
|
114
|
+
out.push(new RegExp(src, "g"));
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
108
119
|
}
|
|
109
120
|
function scanFile(filePath, content, patterns, maxFindings) {
|
|
110
121
|
const usages = [];
|
|
@@ -128,22 +139,33 @@ function scanFile(filePath, content, patterns, maxFindings) {
|
|
|
128
139
|
}
|
|
129
140
|
return usages.slice(0, maxFindings);
|
|
130
141
|
}
|
|
131
|
-
function scanPath(rawPath, cfg) {
|
|
142
|
+
async function scanPath(rawPath, cfg) {
|
|
132
143
|
const root = process.cwd();
|
|
133
144
|
const resolved = isAbsolute2(rawPath) ? resolve2(rawPath) : resolve2(root, rawPath);
|
|
134
145
|
const exts = normalizeExtensions(cfg.extensions);
|
|
135
|
-
const files =
|
|
146
|
+
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
136
147
|
const patterns = compilePatterns(cfg.patterns);
|
|
137
148
|
const usages = [];
|
|
149
|
+
let scannedFiles = 0;
|
|
150
|
+
let truncated = false;
|
|
138
151
|
for (const p of files) {
|
|
139
152
|
try {
|
|
140
|
-
const content =
|
|
153
|
+
const content = await readFile(p, "utf-8");
|
|
154
|
+
scannedFiles += 1;
|
|
141
155
|
usages.push(...scanFile(p, content, patterns, cfg.maxFindings));
|
|
142
|
-
if (usages.length >= cfg.maxFindings)
|
|
156
|
+
if (usages.length >= cfg.maxFindings) {
|
|
157
|
+
truncated = scannedFiles < files.length;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
143
160
|
} catch {
|
|
144
161
|
}
|
|
145
162
|
}
|
|
146
|
-
return {
|
|
163
|
+
return {
|
|
164
|
+
usages: usages.slice(0, cfg.maxFindings),
|
|
165
|
+
scannedFiles,
|
|
166
|
+
discoveredFiles: files.length,
|
|
167
|
+
truncated
|
|
168
|
+
};
|
|
147
169
|
}
|
|
148
170
|
var plugin = {
|
|
149
171
|
name: "feature-flag-tracker",
|
|
@@ -191,7 +213,7 @@ var plugin = {
|
|
|
191
213
|
state.hookUnregister = null;
|
|
192
214
|
}
|
|
193
215
|
const cfg = readConfig(api.config.extensions?.["feature-flag-tracker"]);
|
|
194
|
-
const hook = (input) => {
|
|
216
|
+
const hook = async (input) => {
|
|
195
217
|
if (!cfg.enabled) return;
|
|
196
218
|
if (input.toolResult?.isError) return;
|
|
197
219
|
const inp = input.toolInput ?? {};
|
|
@@ -204,7 +226,7 @@ var plugin = {
|
|
|
204
226
|
const resolved = resolve2(process.cwd(), sourcePath);
|
|
205
227
|
let content;
|
|
206
228
|
try {
|
|
207
|
-
content =
|
|
229
|
+
content = await readFile(resolved, "utf-8");
|
|
208
230
|
} catch {
|
|
209
231
|
state.errorCount += 1;
|
|
210
232
|
return;
|
|
@@ -242,7 +264,7 @@ Make sure flag behavior is intentional and consider updating flag inventory/docs
|
|
|
242
264
|
state.scanCount += 1;
|
|
243
265
|
let result;
|
|
244
266
|
try {
|
|
245
|
-
result = scanPath(rawPath, cfg);
|
|
267
|
+
result = await scanPath(rawPath, cfg);
|
|
246
268
|
} catch (err) {
|
|
247
269
|
state.errorCount += 1;
|
|
248
270
|
return { ok: false, error: String(err) };
|
|
@@ -252,6 +274,10 @@ Make sure flag behavior is intentional and consider updating flag inventory/docs
|
|
|
252
274
|
ok: true,
|
|
253
275
|
path: relativePath(resolve2(process.cwd(), rawPath)),
|
|
254
276
|
scannedFiles: result.scannedFiles,
|
|
277
|
+
discoveredFiles: result.discoveredFiles,
|
|
278
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
279
|
+
// that reports few findings must not read as a clean result.
|
|
280
|
+
truncated: result.truncated,
|
|
255
281
|
usages: result.usages
|
|
256
282
|
};
|
|
257
283
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - watch_stop: Stop a watch by ID
|
|
7
7
|
* - watch_list: List all active watches
|
|
8
8
|
*/
|
|
9
|
-
import type { Plugin } from '@wrongstack/core';
|
|
9
|
+
import type { Plugin } from '@wrongstack/core/types';
|
|
10
10
|
declare const plugin: Plugin;
|
|
11
11
|
export default plugin;
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file-watcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file-watcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAqErD,QAAA,MAAM,MAAM,EAAE,MA+Yb,CAAC;eAEa,MAAM"}
|
package/dist/file-watcher.js
CHANGED
|
@@ -80,13 +80,12 @@ var plugin = {
|
|
|
80
80
|
function debounceEvent(key, fn, ms) {
|
|
81
81
|
const existing = debounceTimers.get(key);
|
|
82
82
|
if (existing) clearTimeout(existing);
|
|
83
|
-
|
|
84
|
-
key
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
debounceTimers.delete(key);
|
|
85
|
+
fn();
|
|
86
|
+
}, ms);
|
|
87
|
+
timer.unref?.();
|
|
88
|
+
debounceTimers.set(key, timer);
|
|
90
89
|
}
|
|
91
90
|
const autoIndex = api.config.extensions?.["file-watcher"]?.["autoIndex"] ?? false;
|
|
92
91
|
const indexProjectRoot = api.config.extensions?.["file-watcher"]?.["indexProjectRoot"] ?? "";
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @public
|
|
29
29
|
*/
|
|
30
|
-
import type { Plugin } from '@wrongstack/core';
|
|
30
|
+
import type { Plugin } from '@wrongstack/core/types';
|
|
31
|
+
/** Which formatter is currently in use — surfaced by health()/status. */
|
|
32
|
+
export declare function activeFormatterLabel(): string | null;
|
|
31
33
|
declare const plugin: Plugin;
|
|
32
34
|
export default plugin;
|
|
33
35
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/format-on-save/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/format-on-save/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAmPrD,yEAAyE;AACzE,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAEpD;AAsGD,QAAA,MAAM,MAAM,EAAE,MAsPb,CAAC;eAEa,MAAM"}
|
package/dist/format-on-save.js
CHANGED
|
@@ -1,9 +1,200 @@
|
|
|
1
1
|
// src/format-on-save/index.ts
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
-
import {
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { access, readFile, stat } from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
// src/runtime/index.ts
|
|
7
|
+
import { basename, extname as extname2, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
8
|
+
|
|
9
|
+
// src/runtime/local-bin.ts
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
12
|
+
import { accessSync, constants, readFileSync } from "node:fs";
|
|
13
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
14
|
+
function resolveExecInvocation(command, args = []) {
|
|
15
|
+
const resolved = resolveWin32Command(command);
|
|
16
|
+
const normalizedResolved = resolved.toLowerCase();
|
|
17
|
+
const needsShell = process.platform === "win32" && (normalizedResolved.endsWith(".cmd") || normalizedResolved.endsWith(".bat"));
|
|
18
|
+
if (needsShell) {
|
|
19
|
+
const shim = buildWin32CmdShimInvocation(resolved, args);
|
|
20
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
21
|
+
}
|
|
22
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
23
|
+
}
|
|
24
|
+
function findOnPath(cmd) {
|
|
25
|
+
if (!cmd) return null;
|
|
26
|
+
const exists = (p) => {
|
|
27
|
+
try {
|
|
28
|
+
accessSync(p, constants.X_OK);
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
35
|
+
return exists(cmd) ? resolve(cmd) : null;
|
|
36
|
+
}
|
|
37
|
+
const suffixes = process.platform === "win32" && extname(cmd) === "" ? (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
38
|
+
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
39
|
+
if (!dir) continue;
|
|
40
|
+
const base = join(dir, cmd);
|
|
41
|
+
for (const suffix of suffixes) {
|
|
42
|
+
const candidate = `${base}${suffix}`;
|
|
43
|
+
if (exists(candidate)) return candidate;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function isInside(parent, candidate) {
|
|
49
|
+
const rel = relative(parent, candidate);
|
|
50
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
|
|
51
|
+
}
|
|
52
|
+
var binCache = /* @__PURE__ */ new Map();
|
|
53
|
+
var BIN_CACHE_MAX = 64;
|
|
54
|
+
var NEGATIVE_BIN_CACHE_TTL_MS = 5e3;
|
|
55
|
+
function cachePut(key, value) {
|
|
56
|
+
while (binCache.size >= BIN_CACHE_MAX) {
|
|
57
|
+
const oldest = binCache.keys().next().value;
|
|
58
|
+
if (oldest === void 0) break;
|
|
59
|
+
binCache.delete(oldest);
|
|
60
|
+
}
|
|
61
|
+
binCache.set(key, { value, cachedAt: Date.now() });
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
function clearLocalBinCache() {
|
|
65
|
+
binCache.clear();
|
|
66
|
+
}
|
|
67
|
+
function resolveNodeBin(packageName, binName, cwd, extraArgs = []) {
|
|
68
|
+
const key = `${packageName}|${binName}|${cwd}`;
|
|
69
|
+
const cached = binCache.get(key);
|
|
70
|
+
if (cached !== void 0) {
|
|
71
|
+
if (cached.value !== null || Date.now() - cached.cachedAt < NEGATIVE_BIN_CACHE_TTL_MS) {
|
|
72
|
+
return cached.value === null ? null : { ...cached.value, args: [cached.value.entry, ...extraArgs] };
|
|
73
|
+
}
|
|
74
|
+
binCache.delete(key);
|
|
75
|
+
}
|
|
76
|
+
let resolved = null;
|
|
77
|
+
try {
|
|
78
|
+
const requireFromProject = createRequire(resolve(cwd, "package.json"));
|
|
79
|
+
const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
|
|
80
|
+
const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
81
|
+
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[binName] ?? Object.values(packageJson.bin ?? {})[0];
|
|
82
|
+
if (relativeBin && !isAbsolute(relativeBin)) {
|
|
83
|
+
const packageDir = dirname(packagePath);
|
|
84
|
+
const entry = resolve(packageDir, relativeBin);
|
|
85
|
+
if (isInside(packageDir, entry)) {
|
|
86
|
+
resolved = { cmd: process.execPath, args: [entry], entry };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
resolved = null;
|
|
91
|
+
}
|
|
92
|
+
cachePut(key, resolved);
|
|
93
|
+
return resolved === null ? null : { ...resolved, args: [resolved.entry, ...extraArgs] };
|
|
94
|
+
}
|
|
95
|
+
function resolveFirstNodeBin(candidates, cwd) {
|
|
96
|
+
for (const c of candidates) {
|
|
97
|
+
const hit = resolveNodeBin(c.packageName, c.binName, cwd, c.args ?? []);
|
|
98
|
+
if (hit) return { ...hit, packageName: c.packageName, binName: c.binName };
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/runtime/bounded-map.ts
|
|
104
|
+
var BoundedMap = class {
|
|
105
|
+
map = /* @__PURE__ */ new Map();
|
|
106
|
+
max;
|
|
107
|
+
ttlMs;
|
|
108
|
+
now;
|
|
109
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
110
|
+
evictions = 0;
|
|
111
|
+
constructor(options) {
|
|
112
|
+
const normalizedMax = Math.floor(options.max);
|
|
113
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
114
|
+
this.ttlMs = options.ttlMs;
|
|
115
|
+
this.now = options.now ?? Date.now;
|
|
116
|
+
}
|
|
117
|
+
expired(entry) {
|
|
118
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
119
|
+
}
|
|
120
|
+
get(key) {
|
|
121
|
+
const entry = this.map.get(key);
|
|
122
|
+
if (entry === void 0) return void 0;
|
|
123
|
+
if (this.expired(entry)) {
|
|
124
|
+
this.map.delete(key);
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
this.map.delete(key);
|
|
128
|
+
this.map.set(key, entry);
|
|
129
|
+
return entry.value;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
133
|
+
* diagnostics that must not perturb the eviction order.
|
|
134
|
+
*/
|
|
135
|
+
peek(key) {
|
|
136
|
+
const entry = this.map.get(key);
|
|
137
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
138
|
+
return entry.value;
|
|
139
|
+
}
|
|
140
|
+
has(key) {
|
|
141
|
+
const entry = this.map.get(key);
|
|
142
|
+
if (entry === void 0) return false;
|
|
143
|
+
if (this.expired(entry)) {
|
|
144
|
+
this.map.delete(key);
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
set(key, value) {
|
|
150
|
+
this.map.delete(key);
|
|
151
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
152
|
+
while (this.map.size > this.max) {
|
|
153
|
+
const coldest = this.map.keys().next().value;
|
|
154
|
+
if (coldest === void 0) break;
|
|
155
|
+
this.map.delete(coldest);
|
|
156
|
+
this.evictions += 1;
|
|
157
|
+
}
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
delete(key) {
|
|
161
|
+
return this.map.delete(key);
|
|
162
|
+
}
|
|
163
|
+
clear() {
|
|
164
|
+
this.map.clear();
|
|
165
|
+
this.evictions = 0;
|
|
166
|
+
}
|
|
167
|
+
get size() {
|
|
168
|
+
return this.map.size;
|
|
169
|
+
}
|
|
170
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
171
|
+
get evictionCount() {
|
|
172
|
+
return this.evictions;
|
|
173
|
+
}
|
|
174
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
175
|
+
prune() {
|
|
176
|
+
if (this.ttlMs === void 0) return 0;
|
|
177
|
+
let removed = 0;
|
|
178
|
+
for (const [key, entry] of this.map) {
|
|
179
|
+
if (this.expired(entry)) {
|
|
180
|
+
this.map.delete(key);
|
|
181
|
+
removed += 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return removed;
|
|
185
|
+
}
|
|
186
|
+
/** Live (non-expired) entries, coldest first. */
|
|
187
|
+
*entries() {
|
|
188
|
+
for (const [key, entry] of this.map) {
|
|
189
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
[Symbol.iterator]() {
|
|
193
|
+
return this.entries();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
4
196
|
|
|
5
197
|
// src/runtime/index.ts
|
|
6
|
-
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
198
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
8
199
|
function hasLeadingDash(arg) {
|
|
9
200
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -11,12 +202,13 @@ function hasLeadingDash(arg) {
|
|
|
11
202
|
function withinProjectPath(projectRoot, candidate) {
|
|
12
203
|
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
13
204
|
if (hasLeadingDash(candidate)) return false;
|
|
14
|
-
const resolved =
|
|
15
|
-
const rel =
|
|
16
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
205
|
+
const resolved = isAbsolute2(candidate) ? resolve2(candidate) : resolve2(projectRoot, candidate);
|
|
206
|
+
const rel = relative2(projectRoot, resolved);
|
|
207
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
|
|
17
208
|
}
|
|
18
209
|
function withinProject(p) {
|
|
19
|
-
|
|
210
|
+
const cwd = process.cwd();
|
|
211
|
+
return withinProjectPath(cwd, p) || relative2(cwd, p) === ".";
|
|
20
212
|
}
|
|
21
213
|
|
|
22
214
|
// src/format-on-save/index.ts
|
|
@@ -55,7 +247,7 @@ function readConfig(raw) {
|
|
|
55
247
|
skipTtlMs: typeof r["skipTtlMs"] === "number" && r["skipTtlMs"] >= 0 ? r["skipTtlMs"] : DEFAULTS.skipTtlMs
|
|
56
248
|
};
|
|
57
249
|
}
|
|
58
|
-
var recentlyCovered =
|
|
250
|
+
var recentlyCovered = new BoundedMap({ max: 256 });
|
|
59
251
|
function clearRegistrations() {
|
|
60
252
|
if (state.hookUnregister) {
|
|
61
253
|
try {
|
|
@@ -78,6 +270,55 @@ function evictExpired(ttlMs) {
|
|
|
78
270
|
if (ts < cutoff) recentlyCovered.delete(path);
|
|
79
271
|
}
|
|
80
272
|
}
|
|
273
|
+
var FORMATTERS = [
|
|
274
|
+
{
|
|
275
|
+
packageName: "@biomejs/biome",
|
|
276
|
+
binName: "biome",
|
|
277
|
+
writeArgs: ["format", "--write"],
|
|
278
|
+
label: "biome"
|
|
279
|
+
},
|
|
280
|
+
{ packageName: "prettier", binName: "prettier", writeArgs: ["--write"], label: "prettier" },
|
|
281
|
+
{ packageName: "dprint", binName: "dprint", writeArgs: ["fmt"], label: "dprint" }
|
|
282
|
+
];
|
|
283
|
+
var activeFormatter;
|
|
284
|
+
function resetFormatter() {
|
|
285
|
+
activeFormatter = void 0;
|
|
286
|
+
clearLocalBinCache();
|
|
287
|
+
}
|
|
288
|
+
function resolveFormatter() {
|
|
289
|
+
if (activeFormatter !== void 0) return activeFormatter;
|
|
290
|
+
const cwd = process.cwd();
|
|
291
|
+
for (const f of FORMATTERS) {
|
|
292
|
+
const local = resolveNodeBinFor(f, cwd);
|
|
293
|
+
if (local) {
|
|
294
|
+
activeFormatter = local;
|
|
295
|
+
return local;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
for (const f of FORMATTERS) {
|
|
299
|
+
const onPath = findOnPath(f.binName);
|
|
300
|
+
if (!onPath) continue;
|
|
301
|
+
activeFormatter = { cmd: onPath, args: [...f.writeArgs], label: f.label };
|
|
302
|
+
return activeFormatter;
|
|
303
|
+
}
|
|
304
|
+
activeFormatter = null;
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
function resolveNodeBinFor(f, cwd) {
|
|
308
|
+
const hit = resolveFirstNodeBin([{ packageName: f.packageName, binName: f.binName }], cwd);
|
|
309
|
+
if (!hit) return null;
|
|
310
|
+
return { cmd: hit.cmd, args: [...hit.args, ...f.writeArgs], label: f.label };
|
|
311
|
+
}
|
|
312
|
+
function activeFormatterLabel() {
|
|
313
|
+
return activeFormatter?.label ?? null;
|
|
314
|
+
}
|
|
315
|
+
async function sha256File(filePath) {
|
|
316
|
+
try {
|
|
317
|
+
return createHash("sha256").update(await readFile(filePath)).digest("hex");
|
|
318
|
+
} catch {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
81
322
|
async function formatFile(filePath, timeoutMs) {
|
|
82
323
|
if (!withinProject(filePath)) return null;
|
|
83
324
|
try {
|
|
@@ -85,30 +326,40 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
85
326
|
} catch {
|
|
86
327
|
return null;
|
|
87
328
|
}
|
|
329
|
+
const formatter = resolveFormatter();
|
|
330
|
+
if (!formatter) return null;
|
|
88
331
|
let bytesBefore;
|
|
89
332
|
try {
|
|
90
333
|
bytesBefore = (await stat(filePath)).size;
|
|
91
334
|
} catch {
|
|
92
335
|
return null;
|
|
93
336
|
}
|
|
337
|
+
const hashBefore = await sha256File(filePath);
|
|
338
|
+
let invocation;
|
|
339
|
+
try {
|
|
340
|
+
invocation = resolveExecInvocation(formatter.cmd, [...formatter.args, filePath]);
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
94
344
|
try {
|
|
95
|
-
await new Promise((
|
|
345
|
+
await new Promise((resolve3, reject) => {
|
|
96
346
|
execFile(
|
|
97
|
-
|
|
98
|
-
|
|
347
|
+
invocation.cmd,
|
|
348
|
+
invocation.args,
|
|
99
349
|
{
|
|
100
350
|
encoding: "utf-8",
|
|
101
351
|
timeout: timeoutMs,
|
|
102
352
|
cwd: process.cwd(),
|
|
103
353
|
windowsHide: true,
|
|
104
|
-
maxBuffer: 16 * 1024 * 1024
|
|
354
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
355
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
105
356
|
},
|
|
106
357
|
(err) => {
|
|
107
358
|
if (err) {
|
|
108
359
|
const e = err;
|
|
109
360
|
if (e.killed) return reject(err);
|
|
110
361
|
}
|
|
111
|
-
|
|
362
|
+
resolve3();
|
|
112
363
|
}
|
|
113
364
|
);
|
|
114
365
|
});
|
|
@@ -124,28 +375,11 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
124
375
|
if (bytesAfter !== bytesBefore) {
|
|
125
376
|
return { changed: true, bytesBefore, bytesAfter };
|
|
126
377
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
execFile(
|
|
130
|
-
"npx",
|
|
131
|
-
["biome", "format", filePath],
|
|
132
|
-
{
|
|
133
|
-
encoding: "utf-8",
|
|
134
|
-
timeout: timeoutMs,
|
|
135
|
-
cwd: process.cwd(),
|
|
136
|
-
windowsHide: true,
|
|
137
|
-
maxBuffer: 16 * 1024 * 1024
|
|
138
|
-
},
|
|
139
|
-
(err) => {
|
|
140
|
-
if (err) return reject(err);
|
|
141
|
-
resolve2();
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
});
|
|
378
|
+
const hashAfter = await sha256File(filePath);
|
|
379
|
+
if (hashBefore === null || hashAfter === null) {
|
|
145
380
|
return { changed: false, bytesBefore, bytesAfter };
|
|
146
|
-
} catch {
|
|
147
|
-
return { changed: true, bytesBefore, bytesAfter };
|
|
148
381
|
}
|
|
382
|
+
return { changed: hashBefore !== hashAfter, bytesBefore, bytesAfter };
|
|
149
383
|
}
|
|
150
384
|
var plugin = {
|
|
151
385
|
name: "format-on-save",
|
|
@@ -191,32 +425,18 @@ var plugin = {
|
|
|
191
425
|
state.lastResult = null;
|
|
192
426
|
recentlyCovered.clear();
|
|
193
427
|
const cfg = readConfig(api.config.extensions?.["format-on-save"]);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
cwd: process.cwd(),
|
|
204
|
-
windowsHide: true
|
|
205
|
-
},
|
|
206
|
-
(err) => {
|
|
207
|
-
if (err) reject(err);
|
|
208
|
-
else resolve2();
|
|
209
|
-
}
|
|
210
|
-
);
|
|
211
|
-
});
|
|
212
|
-
biomeAvailable = true;
|
|
213
|
-
api.log.info("format-on-save: biome detected");
|
|
214
|
-
} catch {
|
|
215
|
-
biomeAvailable = false;
|
|
216
|
-
api.log.warn("format-on-save: biome not found \u2014 hook will be a no-op");
|
|
428
|
+
resetFormatter();
|
|
429
|
+
const formatter = resolveFormatter();
|
|
430
|
+
const formatterAvailable = formatter !== null;
|
|
431
|
+
if (formatter) {
|
|
432
|
+
api.log.info(`format-on-save: ${formatter.label} detected`);
|
|
433
|
+
} else {
|
|
434
|
+
api.log.warn(
|
|
435
|
+
"format-on-save: no formatter found (biome, prettier, dprint) \u2014 hook will be a no-op"
|
|
436
|
+
);
|
|
217
437
|
}
|
|
218
438
|
const hook = async (input) => {
|
|
219
|
-
if (!cfg.enabled || !
|
|
439
|
+
if (!cfg.enabled || !formatterAvailable) return;
|
|
220
440
|
if (input.toolResult?.isError) return;
|
|
221
441
|
const toolName = input.toolName ?? "";
|
|
222
442
|
const inp = input.toolInput ?? {};
|
|
@@ -277,7 +497,7 @@ var plugin = {
|
|
|
277
497
|
);
|
|
278
498
|
api.tools.register({
|
|
279
499
|
name: "format_on_save_status",
|
|
280
|
-
description: "Reports format-on-save state:
|
|
500
|
+
description: "Reports format-on-save state: which formatter is active, and per-session formatted/clean/error/skipped counters.",
|
|
281
501
|
inputSchema: { type: "object", properties: {} },
|
|
282
502
|
permission: "auto",
|
|
283
503
|
category: "Code Quality",
|
|
@@ -286,7 +506,14 @@ var plugin = {
|
|
|
286
506
|
return {
|
|
287
507
|
ok: true,
|
|
288
508
|
enabled: cfg.enabled,
|
|
289
|
-
|
|
509
|
+
formatterAvailable,
|
|
510
|
+
formatter: activeFormatterLabel(),
|
|
511
|
+
/**
|
|
512
|
+
* Back-compat alias for the pre-multi-formatter status shape.
|
|
513
|
+
* Now accurate rather than assumed: true only when the resolved
|
|
514
|
+
* formatter really is biome.
|
|
515
|
+
*/
|
|
516
|
+
biomeAvailable: activeFormatterLabel() === "biome",
|
|
290
517
|
timeoutMs: cfg.timeoutMs,
|
|
291
518
|
skipWhenCoveredBy: cfg.skipWhenCoveredBy,
|
|
292
519
|
skipTtlMs: cfg.skipTtlMs,
|
|
@@ -304,11 +531,13 @@ var plugin = {
|
|
|
304
531
|
api.log.info("format-on-save plugin loaded", {
|
|
305
532
|
version: "0.1.0",
|
|
306
533
|
enabled: cfg.enabled,
|
|
307
|
-
|
|
534
|
+
formatterAvailable,
|
|
535
|
+
formatter: activeFormatterLabel()
|
|
308
536
|
});
|
|
309
537
|
},
|
|
310
538
|
teardown(api) {
|
|
311
539
|
clearRegistrations();
|
|
540
|
+
resetFormatter();
|
|
312
541
|
const final = {
|
|
313
542
|
invocations: state.invocationCount,
|
|
314
543
|
formatted: state.formattedCount,
|
|
@@ -342,5 +571,6 @@ var plugin = {
|
|
|
342
571
|
};
|
|
343
572
|
var format_on_save_default = plugin;
|
|
344
573
|
export {
|
|
574
|
+
activeFormatterLabel,
|
|
345
575
|
format_on_save_default as default
|
|
346
576
|
};
|