resultar-check 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Giorgio Delgado
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # Resultar Check
2
+
3
+ TypeScript 7 diagnostics for Resultar.
4
+
5
+ `resultar-check` is the canonical Resultar diagnostics package and command. It runs TypeScript 7
6
+ first, then runs Resultar diagnostics over the same `tsconfig.json`. Oxlint integration and TS6
7
+ patching are no longer shipped as public lint surfaces.
8
+
9
+ Until TypeScript 7 exposes the stable programmatic type-checker API Resultar needs, the package keeps
10
+ a TypeScript 6 diagnostics API as an internal bridge. Projects should still standardize on the
11
+ TypeScript 7 `resultar-check` command.
12
+
13
+ ## Install
14
+
15
+ For editor diagnostics and CLI checks, install `resultar-check` with a project-local TypeScript RC:
16
+
17
+ ```sh
18
+ pnpm add -D resultar-check typescript@rc
19
+ ```
20
+
21
+ Add one check script:
22
+
23
+ ```json
24
+ {
25
+ "scripts": {
26
+ "check": "resultar-check -p tsconfig.json --noEmit"
27
+ }
28
+ }
29
+ ```
30
+
31
+ Configure Resultar rules in `tsconfig.json`:
32
+
33
+ ```json
34
+ {
35
+ "compilerOptions": {
36
+ "plugins": [
37
+ {
38
+ "name": "resultar-check",
39
+ "noDiscard": "error",
40
+ "preferMapErr": "error",
41
+ "preferAndThen": "error"
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ ```
47
+
48
+ `resultar-check` resolves a project-local `typescript@7` first, then `typescript-7`. If a project
49
+ cannot replace its `typescript` package yet and only needs the CLI path, use the compatibility alias:
50
+
51
+ ```sh
52
+ pnpm add -D resultar-check typescript-7@npm:typescript@rc
53
+ ```
54
+
55
+ ## Editor Integration
56
+
57
+ `resultar-check` is a TypeScript language-service plugin. Editors must run a TypeScript server that
58
+ can resolve the local `resultar-check` package and see the `compilerOptions.plugins` entry above.
59
+
60
+ ### Zed
61
+
62
+ Zed uses `vtsls` for TypeScript by default. Add this to your Zed settings when working in pnpm
63
+ monorepos or when the bundled TypeScript server does not activate the plugin:
64
+
65
+ ```json
66
+ {
67
+ "lsp": {
68
+ "vtsls": {
69
+ "settings": {
70
+ "vtsls": {
71
+ "autoUseWorkspaceTsdk": true
72
+ },
73
+ "typescript": {
74
+ "tsserver": {
75
+ "pluginPaths": ["./node_modules"]
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ If diagnostics do not appear, temporarily add `"log": "normal"` under `typescript.tsserver`, restart
85
+ the TypeScript server, and check the Zed log. A working setup reports diagnostics whose source is
86
+ `resultar` and whose message starts with `[resultar/noDiscard]`.
87
+
88
+ If you use `typescript-language-server` in Zed instead of `vtsls`, pass the plugin through
89
+ `initialization_options.plugins` and set `location` to the project root, not `./node_modules`.
90
+ `typescript-language-server` resolves plugin packages from `${location}/node_modules`.
91
+
92
+ ```json
93
+ {
94
+ "lsp": {
95
+ "typescript-language-server": {
96
+ "initialization_options": {
97
+ "plugins": [
98
+ {
99
+ "name": "resultar-check",
100
+ "location": "/absolute/path/to/project"
101
+ }
102
+ ]
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### VS Code
110
+
111
+ Configure VS Code to use the workspace TypeScript version:
112
+
113
+ ```json
114
+ {
115
+ "typescript.tsdk": "node_modules/typescript/lib",
116
+ "typescript.enablePromptUseWorkspaceTsdk": true
117
+ }
118
+ ```
119
+
120
+ Then run `TypeScript: Select TypeScript Version` and choose the workspace version. In pnpm monorepos
121
+ where the plugin still does not activate, add this setting:
122
+
123
+ ```json
124
+ {
125
+ "typescript.tsserver.pluginPaths": ["./node_modules"]
126
+ }
127
+ ```
128
+
129
+ ## Rules
130
+
131
+ | Rule | tsconfig option | Purpose |
132
+ | ----------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------- |
133
+ | `resultar/no-discard` | `noDiscard` | Require `Result` and `ResultAsync` values to be handled or explicitly discarded. |
134
+ | `resultar/prefer-map-err` | `preferMapErr` | Prefer `mapErr` when `orElse` only returns another `Err`. |
135
+ | `resultar/prefer-and-then` | `preferAndThen` | Prefer `andThen` / `asyncAndThen` when `map` returns a Resultar value. |
136
+ | `resultar/typed-catch-mapper` | `typedCatchMapper` | Require catch conversion helpers to map caught values to typed errors. |
137
+ | `resultar/no-unsafe-await` | `noUnsafeAwait` | Require raw Promise awaits in Resultar async contexts to use Resultar boundaries. |
138
+ | `resultar/no-try-catch-in-safe-try` | `noTryCatchInSafeTry` | Avoid raw `try/catch` inside `safeTry` generators. |
139
+ | `resultar/yield-star-in-safe-try` | `yieldStarInSafeTry` | Require `yield*` for Resultar values inside `safeTry`. |
140
+ | `resultar/unsafe-result-type-assertion` | `unsafeResultTypeAssertion` | Prevent assertions that narrow Resultar error channels. |
141
+ | `resultar/prefer-tagged-error` | `preferTaggedError` | Prefer `createTaggedError` over plain `Error` subclasses or `err(new Error(...))`. |
142
+ | `resultar/tagged-error-name-match` | `taggedErrorNameMatch` | Require `createTaggedError({ name })` to match the class name. |
143
+ | `resultar/no-tagged-error-constructor-override` | `noTaggedErrorConstructorOverride` | Keep the generated tagged-error constructor intact. |
144
+ | `resultar/no-useless-recovery` | `noUselessRecovery` | Flag recovery calls on `Result<T, never>` / `ResultAsync<T, never>`. |
145
+
146
+ Each option accepts `"error"`, `"warning"`, `"suggestion"`, `"message"`, or `"off"`.
147
+ `noUnsafeAwait` defaults to `"off"` because it is an architectural rule and may require migration in
148
+ existing async code. Enable it explicitly when a project is ready to enforce Resultar async
149
+ boundaries. By default, `noUnsafeAwait` uses `noUnsafeAwaitMode: "resultar-context"` and checks
150
+ functions returning `ResultAsync` or `Promise<Result>`, plus `safeTry` bodies. Raw Promise awaits are
151
+ allowed in async catch helpers such as `tryAsync`, `tryResultAsync`, `tryCatchAsync`, and
152
+ `fromThrowableAsync`; inside `safeTry`, prefer `yield*` with Resultar values. Use
153
+ `noUnsafeAwaitMode: "all"` to also report framework/bootstrap awaits such as Fastify plugin
154
+ registration.
155
+
156
+ The default `noDiscard` mode is neverthrow-style `must-use`: it reports discarded Resultar
157
+ expressions and assigned `Result` values that are passed around but never consumed with `match`,
158
+ `unwrapOr`, `_unsafeUnwrap`, `isOk`, `isErr`, returned, or explicitly discarded. Use
159
+ `--mode direct` for the lower-noise expression-only check.
160
+
161
+ ```sh
162
+ pnpm exec resultar-check -p tsconfig.json --noEmit
163
+ pnpm exec resultar-check -p tsconfig.json --noEmit --mode direct
164
+ ```
165
+
166
+ ## Deprecated Packages
167
+
168
+ `resultar-lint` and `resultar-tsgo` are compatibility wrappers. New projects should install
169
+ `resultar-check` directly and use plugin name `"resultar-check"`.
package/dist/cli.cjs ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ const require_lint = require("./lint-D-D2dmLi.cjs");
3
+ //#region src/cli.ts
4
+ const usage = `Usage: resultar-check -p tsconfig.json --noEmit
5
+
6
+ Runs TypeScript 7 first, then all enabled Resultar diagnostics from tsconfig plugin options.
7
+ `;
8
+ const run = (args = process.argv.slice(2)) => {
9
+ const [command] = args;
10
+ if (command === "check") {
11
+ process.stderr.write("The check subcommand was removed. Use resultar-check -p tsconfig.json --noEmit.\n");
12
+ return 1;
13
+ }
14
+ if (command === "help" || command === "--help" || command === "-h" || command === void 0) {
15
+ process.stdout.write(usage);
16
+ return 0;
17
+ }
18
+ if (command === "patch" || command === "doctor" || command === "unpatch") {
19
+ process.stderr.write(`${command} was removed. Use resultar-check with TypeScript 7.\n`);
20
+ return 1;
21
+ }
22
+ return require_lint.runResultarCheckCli(args);
23
+ };
24
+ try {
25
+ process.exitCode = run();
26
+ } catch (error) {
27
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
28
+ process.exitCode = 1;
29
+ }
30
+ //#endregion
31
+
32
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.cjs","names":["runResultarCheckCli"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runResultarCheckCli } from \"./lint.js\";\n\nconst usage = `Usage: resultar-check -p tsconfig.json --noEmit\n\nRuns TypeScript 7 first, then all enabled Resultar diagnostics from tsconfig plugin options.\n`;\n\nconst run = (args: readonly string[] = process.argv.slice(2)): number => {\n const [command] = args;\n\n if (command === \"check\") {\n process.stderr.write(\n \"The check subcommand was removed. Use resultar-check -p tsconfig.json --noEmit.\\n\",\n );\n return 1;\n }\n\n if (command === \"help\" || command === \"--help\" || command === \"-h\" || command === undefined) {\n process.stdout.write(usage);\n return 0;\n }\n\n if (command === \"patch\" || command === \"doctor\" || command === \"unpatch\") {\n process.stderr.write(`${command} was removed. Use resultar-check with TypeScript 7.\\n`);\n return 1;\n }\n\n return runResultarCheckCli(args);\n};\n\ntry {\n process.exitCode = run();\n} catch (error: unknown) {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n}\n"],"mappings":";;;AAGA,MAAM,QAAQ;;;;AAKd,MAAM,OAAO,OAA0B,QAAQ,KAAK,MAAM,CAAC,MAAc;CACvE,MAAM,CAAC,WAAW;CAElB,IAAI,YAAY,SAAS;EACvB,QAAQ,OAAO,MACb,mFACF;EACA,OAAO;CACT;CAEA,IAAI,YAAY,UAAU,YAAY,YAAY,YAAY,QAAQ,YAAY,KAAA,GAAW;EAC3F,QAAQ,OAAO,MAAM,KAAK;EAC1B,OAAO;CACT;CAEA,IAAI,YAAY,WAAW,YAAY,YAAY,YAAY,WAAW;EACxE,QAAQ,OAAO,MAAM,GAAG,QAAQ,sDAAsD;EACtF,OAAO;CACT;CAEA,OAAOA,aAAAA,oBAAoB,IAAI;AACjC;AAEA,IAAI;CACF,QAAQ,WAAW,IAAI;AACzB,SAAS,OAAgB;CACvB,QAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG;CAClF,QAAQ,WAAW;AACrB"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.js ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { n as runResultarCheckCli } from "./lint-FMWf8UEv.js";
3
+ //#region src/cli.ts
4
+ const usage = `Usage: resultar-check -p tsconfig.json --noEmit
5
+
6
+ Runs TypeScript 7 first, then all enabled Resultar diagnostics from tsconfig plugin options.
7
+ `;
8
+ const run = (args = process.argv.slice(2)) => {
9
+ const [command] = args;
10
+ if (command === "check") {
11
+ process.stderr.write("The check subcommand was removed. Use resultar-check -p tsconfig.json --noEmit.\n");
12
+ return 1;
13
+ }
14
+ if (command === "help" || command === "--help" || command === "-h" || command === void 0) {
15
+ process.stdout.write(usage);
16
+ return 0;
17
+ }
18
+ if (command === "patch" || command === "doctor" || command === "unpatch") {
19
+ process.stderr.write(`${command} was removed. Use resultar-check with TypeScript 7.\n`);
20
+ return 1;
21
+ }
22
+ return runResultarCheckCli(args);
23
+ };
24
+ try {
25
+ process.exitCode = run();
26
+ } catch (error) {
27
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
28
+ process.exitCode = 1;
29
+ }
30
+ //#endregion
31
+ export {};
32
+
33
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runResultarCheckCli } from \"./lint.js\";\n\nconst usage = `Usage: resultar-check -p tsconfig.json --noEmit\n\nRuns TypeScript 7 first, then all enabled Resultar diagnostics from tsconfig plugin options.\n`;\n\nconst run = (args: readonly string[] = process.argv.slice(2)): number => {\n const [command] = args;\n\n if (command === \"check\") {\n process.stderr.write(\n \"The check subcommand was removed. Use resultar-check -p tsconfig.json --noEmit.\\n\",\n );\n return 1;\n }\n\n if (command === \"help\" || command === \"--help\" || command === \"-h\" || command === undefined) {\n process.stdout.write(usage);\n return 0;\n }\n\n if (command === \"patch\" || command === \"doctor\" || command === \"unpatch\") {\n process.stderr.write(`${command} was removed. Use resultar-check with TypeScript 7.\\n`);\n return 1;\n }\n\n return runResultarCheckCli(args);\n};\n\ntry {\n process.exitCode = run();\n} catch (error: unknown) {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n}\n"],"mappings":";;;AAGA,MAAM,QAAQ;;;;AAKd,MAAM,OAAO,OAA0B,QAAQ,KAAK,MAAM,CAAC,MAAc;CACvE,MAAM,CAAC,WAAW;CAElB,IAAI,YAAY,SAAS;EACvB,QAAQ,OAAO,MACb,mFACF;EACA,OAAO;CACT;CAEA,IAAI,YAAY,UAAU,YAAY,YAAY,YAAY,QAAQ,YAAY,KAAA,GAAW;EAC3F,QAAQ,OAAO,MAAM,KAAK;EAC1B,OAAO;CACT;CAEA,IAAI,YAAY,WAAW,YAAY,YAAY,YAAY,WAAW;EACxE,QAAQ,OAAO,MAAM,GAAG,QAAQ,sDAAsD;EACtF,OAAO;CACT;CAEA,OAAO,oBAAoB,IAAI;AACjC;AAEA,IAAI;CACF,QAAQ,WAAW,IAAI;AACzB,SAAS,OAAgB;CACvB,QAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG;CAClF,QAAQ,WAAW;AACrB"}
package/dist/index.cjs ADDED
@@ -0,0 +1,95 @@
1
+ const require_lint = require("./lint-D-D2dmLi.cjs");
2
+ //#region src/diagnostics.ts
3
+ const RESULTAR_DIAGNOSTIC_SOURCE = "resultar";
4
+ const RESULTAR_RULE_DIAGNOSTIC_CODES = {
5
+ "no-discard": 91001,
6
+ "no-tagged-error-constructor-override": 91010,
7
+ "no-try-catch-in-safe-try": 91006,
8
+ "no-unsafe-await": 91012,
9
+ "no-useless-recovery": 91011,
10
+ "prefer-and-then": 91003,
11
+ "prefer-map-err": 91002,
12
+ "prefer-tagged-error": 91008,
13
+ "tagged-error-name-match": 91009,
14
+ "typed-catch-mapper": 91004,
15
+ "unsafe-result-type-assertion": 91007,
16
+ "yield-star-in-safe-try": 91005
17
+ };
18
+ const isExternalSourceFile = (sourceFile) => sourceFile.isDeclarationFile || sourceFile.fileName.includes("/node_modules/") || sourceFile.fileName.includes("\\node_modules\\");
19
+ const getDiagnosticCategory = (tsApi, severity) => {
20
+ if (severity === "error") return tsApi.DiagnosticCategory.Error;
21
+ if (severity === "message") return tsApi.DiagnosticCategory.Message;
22
+ if (severity === "suggestion") return tsApi.DiagnosticCategory.Suggestion;
23
+ return tsApi.DiagnosticCategory.Warning;
24
+ };
25
+ const createResultarDiagnostic = (context, finding) => {
26
+ const diagnosticRuleName = finding.rule === "no-discard" ? "noDiscard" : finding.rule;
27
+ return {
28
+ category: getDiagnosticCategory(context.tsApi, finding.severity),
29
+ code: RESULTAR_RULE_DIAGNOSTIC_CODES[finding.rule],
30
+ file: context.sourceFile,
31
+ length: finding.length,
32
+ messageText: `[resultar/${diagnosticRuleName}] ${finding.message}`,
33
+ source: RESULTAR_DIAGNOSTIC_SOURCE,
34
+ start: finding.start
35
+ };
36
+ };
37
+ const getResultarDiagnostics = (input) => {
38
+ const options = require_lint.normalizeResultarRulesOptions(input.options);
39
+ if (isExternalSourceFile(input.sourceFile)) return [];
40
+ const context = {
41
+ sourceFile: input.sourceFile,
42
+ tsApi: input.tsApi
43
+ };
44
+ return require_lint.getSourceFileResultarFindings(input.tsApi, input.program.getTypeChecker(), input.sourceFile, options).map((finding) => createResultarDiagnostic(context, finding));
45
+ };
46
+ const getProgramResultarDiagnostics = (tsApi, program, options = {}) => program.getSourceFiles().flatMap((sourceFile) => getResultarDiagnostics({
47
+ options,
48
+ program,
49
+ sourceFile,
50
+ tsApi
51
+ }));
52
+ //#endregion
53
+ //#region src/plugin.ts
54
+ const pluginMarker = "__resultarLanguageServicePlugin";
55
+ const createLanguageServicePlugin = (modules) => {
56
+ const tsApi = modules.typescript;
57
+ const create = (info) => {
58
+ if (info.languageService[pluginMarker] === true) return info.languageService;
59
+ const options = require_lint.parsePluginOptions(info.config);
60
+ const proxy = Object.create(null);
61
+ const proxyRecord = proxy;
62
+ const serviceRecord = info.languageService;
63
+ proxy[pluginMarker] = true;
64
+ for (const key of Object.keys(serviceRecord)) {
65
+ const property = serviceRecord[key];
66
+ if (typeof property === "function") proxyRecord[key] = (...args) => Reflect.apply(property, info.languageService, args);
67
+ }
68
+ proxy.getSemanticDiagnostics = (fileName, ...args) => {
69
+ const diagnostics = info.languageService.getSemanticDiagnostics(fileName, ...args);
70
+ const program = info.languageService.getProgram();
71
+ const sourceFile = program?.getSourceFile(fileName);
72
+ if (program === void 0 || sourceFile === void 0) return diagnostics;
73
+ return [...diagnostics, ...getResultarDiagnostics({
74
+ options,
75
+ program,
76
+ sourceFile,
77
+ tsApi
78
+ })];
79
+ };
80
+ return proxy;
81
+ };
82
+ return { create };
83
+ };
84
+ //#endregion
85
+ //#region src/index.ts
86
+ const plugin = Object.assign(createLanguageServicePlugin, {
87
+ createLanguageServicePlugin,
88
+ findResultarLintFindings: require_lint.findResultarLintFindings,
89
+ getProgramResultarDiagnostics,
90
+ runResultarCheckCli: require_lint.runResultarCheckCli
91
+ });
92
+ //#endregion
93
+ module.exports = plugin;
94
+
95
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["normalizeResultarRulesOptions","getSourceFileResultarFindings","parsePluginOptions"],"sources":["../src/diagnostics.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type * as ts from \"typescript\";\n\nimport type { ResultarLintFinding, ResultarRuleName, ResultarRuleSeverity } from \"./finding.js\";\nimport {\n type ResultarRulesOptions,\n getSourceFileResultarFindings,\n normalizeResultarRulesOptions,\n onlyResultarRule,\n} from \"./rules-core.js\";\n\nexport const RESULTAR_DIAGNOSTIC_SOURCE = \"resultar\";\nexport const RESULTAR_NO_DISCARD_DIAGNOSTIC_CODE = 91_001;\nexport const RESULTAR_RULE_DIAGNOSTIC_CODES: Record<ResultarRuleName, number> = {\n \"no-discard\": RESULTAR_NO_DISCARD_DIAGNOSTIC_CODE,\n \"no-tagged-error-constructor-override\": 91_010,\n \"no-try-catch-in-safe-try\": 91_006,\n \"no-unsafe-await\": 91_012,\n \"no-useless-recovery\": 91_011,\n \"prefer-and-then\": 91_003,\n \"prefer-map-err\": 91_002,\n \"prefer-tagged-error\": 91_008,\n \"tagged-error-name-match\": 91_009,\n \"typed-catch-mapper\": 91_004,\n \"unsafe-result-type-assertion\": 91_007,\n \"yield-star-in-safe-try\": 91_005,\n};\n\ntype TypeScriptApi = typeof ts;\n\ntype ResultarLanguageServiceOptions = Partial<ResultarRulesOptions>;\n\ninterface DiagnosticContext {\n readonly sourceFile: ts.SourceFile;\n readonly tsApi: TypeScriptApi;\n}\n\nexport interface ResultarDiagnosticInput {\n readonly options?: ResultarLanguageServiceOptions;\n readonly program: ts.Program;\n readonly sourceFile: ts.SourceFile;\n readonly tsApi: TypeScriptApi;\n}\n\nconst isExternalSourceFile = (sourceFile: ts.SourceFile): boolean =>\n sourceFile.isDeclarationFile ||\n sourceFile.fileName.includes(\"/node_modules/\") ||\n sourceFile.fileName.includes(\"\\\\node_modules\\\\\");\n\nconst getDiagnosticCategory = (\n tsApi: TypeScriptApi,\n severity: Exclude<ResultarRuleSeverity, \"off\">,\n): ts.DiagnosticCategory => {\n if (severity === \"error\") {\n return tsApi.DiagnosticCategory.Error;\n }\n\n if (severity === \"message\") {\n return tsApi.DiagnosticCategory.Message;\n }\n\n if (severity === \"suggestion\") {\n return tsApi.DiagnosticCategory.Suggestion;\n }\n\n return tsApi.DiagnosticCategory.Warning;\n};\n\nconst createResultarDiagnostic = (\n context: DiagnosticContext,\n finding: ResultarLintFinding,\n): ts.Diagnostic => {\n const diagnosticRuleName = finding.rule === \"no-discard\" ? \"noDiscard\" : finding.rule;\n\n return {\n category: getDiagnosticCategory(context.tsApi, finding.severity),\n code: RESULTAR_RULE_DIAGNOSTIC_CODES[finding.rule],\n file: context.sourceFile,\n length: finding.length,\n messageText: `[resultar/${diagnosticRuleName}] ${finding.message}`,\n source: RESULTAR_DIAGNOSTIC_SOURCE,\n start: finding.start,\n };\n};\n\nexport const getResultarDiagnostics = (\n input: ResultarDiagnosticInput,\n): readonly ts.Diagnostic[] => {\n const options = normalizeResultarRulesOptions(input.options);\n\n if (isExternalSourceFile(input.sourceFile)) {\n return [];\n }\n\n const context: DiagnosticContext = { sourceFile: input.sourceFile, tsApi: input.tsApi };\n const diagnostics = getSourceFileResultarFindings(\n input.tsApi,\n input.program.getTypeChecker(),\n input.sourceFile,\n options,\n ).map((finding) => createResultarDiagnostic(context, finding));\n\n return diagnostics;\n};\n\nexport const getProgramResultarDiagnostics = (\n tsApi: TypeScriptApi,\n program: ts.Program,\n options: ResultarLanguageServiceOptions = {},\n): readonly ts.Diagnostic[] =>\n program\n .getSourceFiles()\n .flatMap((sourceFile) => getResultarDiagnostics({ options, program, sourceFile, tsApi }));\n\nexport const getNoDiscardDiagnostics = (input: ResultarDiagnosticInput): readonly ts.Diagnostic[] =>\n getResultarDiagnostics({\n ...input,\n options: {\n ...onlyResultarRule(\"no-discard\", input.options?.noDiscard ?? \"error\"),\n noDiscardMode: input.options?.noDiscardMode,\n },\n });\n\nexport const getProgramNoDiscardDiagnostics = (\n tsApi: TypeScriptApi,\n program: ts.Program,\n options: ResultarLanguageServiceOptions = {},\n): readonly ts.Diagnostic[] =>\n getProgramResultarDiagnostics(tsApi, program, {\n ...onlyResultarRule(\"no-discard\", options.noDiscard ?? \"error\"),\n noDiscardMode: options.noDiscardMode,\n });\n","import type * as ts from \"typescript\";\n\nimport { getResultarDiagnostics } from \"./diagnostics.js\";\nimport { parsePluginOptions } from \"./plugin-options.js\";\n\nconst pluginMarker = \"__resultarLanguageServicePlugin\";\n\nexport const createLanguageServicePlugin = (modules: {\n readonly typescript: typeof ts;\n}): ts.server.PluginModule => {\n const tsApi = modules.typescript;\n\n const create = (info: ts.server.PluginCreateInfo): ts.LanguageService => {\n if ((info.languageService as unknown as Record<string, unknown>)[pluginMarker] === true) {\n return info.languageService;\n }\n\n const options = parsePluginOptions(info.config);\n const proxy = Object.create(null) as ts.LanguageService & Record<string, unknown>;\n const proxyRecord = proxy as unknown as Record<string, unknown>;\n const serviceRecord = info.languageService as unknown as Record<string, unknown>;\n proxy[pluginMarker] = true;\n\n for (const key of Object.keys(serviceRecord)) {\n const property = serviceRecord[key];\n\n if (typeof property === \"function\") {\n proxyRecord[key] = (...args: readonly unknown[]) =>\n Reflect.apply(property, info.languageService, args) as unknown;\n }\n }\n\n proxy.getSemanticDiagnostics = (fileName, ...args) => {\n const diagnostics = info.languageService.getSemanticDiagnostics(fileName, ...args);\n\n const program = info.languageService.getProgram();\n const sourceFile = program?.getSourceFile(fileName);\n\n if (program === undefined || sourceFile === undefined) {\n return diagnostics;\n }\n\n return [...diagnostics, ...getResultarDiagnostics({ options, program, sourceFile, tsApi })];\n };\n\n return proxy;\n };\n\n return { create };\n};\n","import { getProgramResultarDiagnostics } from \"./diagnostics.js\";\nimport { findResultarLintFindings, runResultarCheckCli } from \"./lint.js\";\nimport { createLanguageServicePlugin } from \"./plugin.js\";\n\ntype ResultarLanguageServicePlugin = typeof createLanguageServicePlugin & {\n readonly createLanguageServicePlugin: typeof createLanguageServicePlugin;\n readonly findResultarLintFindings: typeof findResultarLintFindings;\n readonly getProgramResultarDiagnostics: typeof getProgramResultarDiagnostics;\n readonly runResultarCheckCli: typeof runResultarCheckCli;\n};\n\nconst plugin: ResultarLanguageServicePlugin = Object.assign(createLanguageServicePlugin, {\n createLanguageServicePlugin,\n findResultarLintFindings,\n getProgramResultarDiagnostics,\n runResultarCheckCli,\n});\n\nexport default plugin;\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAE1C,MAAa,iCAAmE;CAC9E,cAAc;CACd,wCAAwC;CACxC,4BAA4B;CAC5B,mBAAmB;CACnB,uBAAuB;CACvB,mBAAmB;CACnB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,sBAAsB;CACtB,gCAAgC;CAChC,0BAA0B;AAC5B;AAkBA,MAAM,wBAAwB,eAC5B,WAAW,qBACX,WAAW,SAAS,SAAS,gBAAgB,KAC7C,WAAW,SAAS,SAAS,kBAAkB;AAEjD,MAAM,yBACJ,OACA,aAC0B;CAC1B,IAAI,aAAa,SACf,OAAO,MAAM,mBAAmB;CAGlC,IAAI,aAAa,WACf,OAAO,MAAM,mBAAmB;CAGlC,IAAI,aAAa,cACf,OAAO,MAAM,mBAAmB;CAGlC,OAAO,MAAM,mBAAmB;AAClC;AAEA,MAAM,4BACJ,SACA,YACkB;CAClB,MAAM,qBAAqB,QAAQ,SAAS,eAAe,cAAc,QAAQ;CAEjF,OAAO;EACL,UAAU,sBAAsB,QAAQ,OAAO,QAAQ,QAAQ;EAC/D,MAAM,+BAA+B,QAAQ;EAC7C,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,aAAa,aAAa,mBAAmB,IAAI,QAAQ;EACzD,QAAQ;EACR,OAAO,QAAQ;CACjB;AACF;AAEA,MAAa,0BACX,UAC6B;CAC7B,MAAM,UAAUA,aAAAA,8BAA8B,MAAM,OAAO;CAE3D,IAAI,qBAAqB,MAAM,UAAU,GACvC,OAAO,CAAC;CAGV,MAAM,UAA6B;EAAE,YAAY,MAAM;EAAY,OAAO,MAAM;CAAM;CAQtF,OAPoBC,aAAAA,8BAClB,MAAM,OACN,MAAM,QAAQ,eAAe,GAC7B,MAAM,YACN,OACF,EAAE,KAAK,YAAY,yBAAyB,SAAS,OAAO,CAE3C;AACnB;AAEA,MAAa,iCACX,OACA,SACA,UAA0C,CAAC,MAE3C,QACG,eAAe,EACf,SAAS,eAAe,uBAAuB;CAAE;CAAS;CAAS;CAAY;AAAM,CAAC,CAAC;;;AC1G5F,MAAM,eAAe;AAErB,MAAa,+BAA+B,YAEd;CAC5B,MAAM,QAAQ,QAAQ;CAEtB,MAAM,UAAU,SAAyD;EACvE,IAAK,KAAK,gBAAuD,kBAAkB,MACjF,OAAO,KAAK;EAGd,MAAM,UAAUC,aAAAA,mBAAmB,KAAK,MAAM;EAC9C,MAAM,QAAQ,OAAO,OAAO,IAAI;EAChC,MAAM,cAAc;EACpB,MAAM,gBAAgB,KAAK;EAC3B,MAAM,gBAAgB;EAEtB,KAAK,MAAM,OAAO,OAAO,KAAK,aAAa,GAAG;GAC5C,MAAM,WAAW,cAAc;GAE/B,IAAI,OAAO,aAAa,YACtB,YAAY,QAAQ,GAAG,SACrB,QAAQ,MAAM,UAAU,KAAK,iBAAiB,IAAI;EAExD;EAEA,MAAM,0BAA0B,UAAU,GAAG,SAAS;GACpD,MAAM,cAAc,KAAK,gBAAgB,uBAAuB,UAAU,GAAG,IAAI;GAEjF,MAAM,UAAU,KAAK,gBAAgB,WAAW;GAChD,MAAM,aAAa,SAAS,cAAc,QAAQ;GAElD,IAAI,YAAY,KAAA,KAAa,eAAe,KAAA,GAC1C,OAAO;GAGT,OAAO,CAAC,GAAG,aAAa,GAAG,uBAAuB;IAAE;IAAS;IAAS;IAAY;GAAM,CAAC,CAAC;EAC5F;EAEA,OAAO;CACT;CAEA,OAAO,EAAE,OAAO;AAClB;;;ACtCA,MAAM,SAAwC,OAAO,OAAO,6BAA6B;CACvF;CACA,0BAAA,aAAA;CACA;CACA,qBAAA,aAAA;AACF,CAAC"}
@@ -0,0 +1,80 @@
1
+ import * as ts from "typescript";
2
+
3
+ //#region src/finding.d.ts
4
+ type ResultarRuleName = "no-discard" | "no-tagged-error-constructor-override" | "no-try-catch-in-safe-try" | "no-unsafe-await" | "no-useless-recovery" | "prefer-and-then" | "prefer-map-err" | "prefer-tagged-error" | "tagged-error-name-match" | "typed-catch-mapper" | "unsafe-result-type-assertion" | "yield-star-in-safe-try";
5
+ type ResultarRuleSeverity = "error" | "message" | "off" | "suggestion" | "warning";
6
+ interface ResultarLintFinding {
7
+ readonly column: number;
8
+ readonly file: string;
9
+ readonly length: number;
10
+ readonly line: number;
11
+ readonly message: string;
12
+ readonly rule: ResultarRuleName;
13
+ readonly severity: Exclude<ResultarRuleSeverity, "off">;
14
+ readonly start: number;
15
+ readonly type?: string;
16
+ }
17
+ //#endregion
18
+ //#region src/result-usage-core.d.ts
19
+ type NoDiscardMode = "direct" | "must-use";
20
+ //#endregion
21
+ //#region src/rules-core.d.ts
22
+ type NoUnsafeAwaitMode = "all" | "resultar-context";
23
+ interface ResultarRulesOptions {
24
+ readonly noDiscard: ResultarRuleSeverity;
25
+ readonly noDiscardMode: NoDiscardMode;
26
+ readonly noTaggedErrorConstructorOverride: ResultarRuleSeverity;
27
+ readonly noTryCatchInSafeTry: ResultarRuleSeverity;
28
+ readonly noUnsafeAwait: ResultarRuleSeverity;
29
+ readonly noUnsafeAwaitMode: NoUnsafeAwaitMode;
30
+ readonly noUselessRecovery: ResultarRuleSeverity;
31
+ readonly preferAndThen: ResultarRuleSeverity;
32
+ readonly preferMapErr: ResultarRuleSeverity;
33
+ readonly preferTaggedError: ResultarRuleSeverity;
34
+ readonly taggedErrorNameMatch: ResultarRuleSeverity;
35
+ readonly typedCatchMapper: ResultarRuleSeverity;
36
+ readonly unsafeResultTypeAssertion: ResultarRuleSeverity;
37
+ readonly yieldStarInSafeTry: ResultarRuleSeverity;
38
+ }
39
+ //#endregion
40
+ //#region src/diagnostics.d.ts
41
+ type TypeScriptApi = typeof ts;
42
+ type ResultarLanguageServiceOptions = Partial<ResultarRulesOptions>;
43
+ declare const getProgramResultarDiagnostics: (tsApi: TypeScriptApi, program: ts.Program, options?: ResultarLanguageServiceOptions) => readonly ts.Diagnostic[];
44
+ //#endregion
45
+ //#region src/lint.d.ts
46
+ interface NoDiscardOptions {
47
+ readonly mode?: NoDiscardMode;
48
+ readonly project?: string;
49
+ readonly rootDir?: string;
50
+ }
51
+ type NoDiscardFailure = {
52
+ readonly error: Error;
53
+ readonly ok: false;
54
+ };
55
+ interface ResultarLintOptions extends NoDiscardOptions {
56
+ readonly rules?: Partial<ResultarRulesOptions>;
57
+ }
58
+ type ResultarLintResult = NoDiscardFailure | {
59
+ readonly findings: readonly ResultarLintFinding[];
60
+ readonly ok: true;
61
+ };
62
+ declare const findResultarLintFindings: (options?: ResultarLintOptions) => ResultarLintResult;
63
+ declare const runResultarCheckCli: (args?: readonly string[]) => number;
64
+ //#endregion
65
+ //#region src/plugin.d.ts
66
+ declare const createLanguageServicePlugin: (modules: {
67
+ readonly typescript: typeof ts;
68
+ }) => ts.server.PluginModule;
69
+ //#endregion
70
+ //#region src/index.d.ts
71
+ type ResultarLanguageServicePlugin = typeof createLanguageServicePlugin & {
72
+ readonly createLanguageServicePlugin: typeof createLanguageServicePlugin;
73
+ readonly findResultarLintFindings: typeof findResultarLintFindings;
74
+ readonly getProgramResultarDiagnostics: typeof getProgramResultarDiagnostics;
75
+ readonly runResultarCheckCli: typeof runResultarCheckCli;
76
+ };
77
+ declare const plugin: ResultarLanguageServicePlugin;
78
+ //#endregion
79
+ export { plugin as default };
80
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,95 @@
1
+ import { a as normalizeResultarRulesOptions, i as getSourceFileResultarFindings, n as runResultarCheckCli, r as parsePluginOptions, t as findResultarLintFindings } from "./lint-FMWf8UEv.js";
2
+ //#region src/diagnostics.ts
3
+ const RESULTAR_DIAGNOSTIC_SOURCE = "resultar";
4
+ const RESULTAR_RULE_DIAGNOSTIC_CODES = {
5
+ "no-discard": 91001,
6
+ "no-tagged-error-constructor-override": 91010,
7
+ "no-try-catch-in-safe-try": 91006,
8
+ "no-unsafe-await": 91012,
9
+ "no-useless-recovery": 91011,
10
+ "prefer-and-then": 91003,
11
+ "prefer-map-err": 91002,
12
+ "prefer-tagged-error": 91008,
13
+ "tagged-error-name-match": 91009,
14
+ "typed-catch-mapper": 91004,
15
+ "unsafe-result-type-assertion": 91007,
16
+ "yield-star-in-safe-try": 91005
17
+ };
18
+ const isExternalSourceFile = (sourceFile) => sourceFile.isDeclarationFile || sourceFile.fileName.includes("/node_modules/") || sourceFile.fileName.includes("\\node_modules\\");
19
+ const getDiagnosticCategory = (tsApi, severity) => {
20
+ if (severity === "error") return tsApi.DiagnosticCategory.Error;
21
+ if (severity === "message") return tsApi.DiagnosticCategory.Message;
22
+ if (severity === "suggestion") return tsApi.DiagnosticCategory.Suggestion;
23
+ return tsApi.DiagnosticCategory.Warning;
24
+ };
25
+ const createResultarDiagnostic = (context, finding) => {
26
+ const diagnosticRuleName = finding.rule === "no-discard" ? "noDiscard" : finding.rule;
27
+ return {
28
+ category: getDiagnosticCategory(context.tsApi, finding.severity),
29
+ code: RESULTAR_RULE_DIAGNOSTIC_CODES[finding.rule],
30
+ file: context.sourceFile,
31
+ length: finding.length,
32
+ messageText: `[resultar/${diagnosticRuleName}] ${finding.message}`,
33
+ source: RESULTAR_DIAGNOSTIC_SOURCE,
34
+ start: finding.start
35
+ };
36
+ };
37
+ const getResultarDiagnostics = (input) => {
38
+ const options = normalizeResultarRulesOptions(input.options);
39
+ if (isExternalSourceFile(input.sourceFile)) return [];
40
+ const context = {
41
+ sourceFile: input.sourceFile,
42
+ tsApi: input.tsApi
43
+ };
44
+ return getSourceFileResultarFindings(input.tsApi, input.program.getTypeChecker(), input.sourceFile, options).map((finding) => createResultarDiagnostic(context, finding));
45
+ };
46
+ const getProgramResultarDiagnostics = (tsApi, program, options = {}) => program.getSourceFiles().flatMap((sourceFile) => getResultarDiagnostics({
47
+ options,
48
+ program,
49
+ sourceFile,
50
+ tsApi
51
+ }));
52
+ //#endregion
53
+ //#region src/plugin.ts
54
+ const pluginMarker = "__resultarLanguageServicePlugin";
55
+ const createLanguageServicePlugin = (modules) => {
56
+ const tsApi = modules.typescript;
57
+ const create = (info) => {
58
+ if (info.languageService[pluginMarker] === true) return info.languageService;
59
+ const options = parsePluginOptions(info.config);
60
+ const proxy = Object.create(null);
61
+ const proxyRecord = proxy;
62
+ const serviceRecord = info.languageService;
63
+ proxy[pluginMarker] = true;
64
+ for (const key of Object.keys(serviceRecord)) {
65
+ const property = serviceRecord[key];
66
+ if (typeof property === "function") proxyRecord[key] = (...args) => Reflect.apply(property, info.languageService, args);
67
+ }
68
+ proxy.getSemanticDiagnostics = (fileName, ...args) => {
69
+ const diagnostics = info.languageService.getSemanticDiagnostics(fileName, ...args);
70
+ const program = info.languageService.getProgram();
71
+ const sourceFile = program?.getSourceFile(fileName);
72
+ if (program === void 0 || sourceFile === void 0) return diagnostics;
73
+ return [...diagnostics, ...getResultarDiagnostics({
74
+ options,
75
+ program,
76
+ sourceFile,
77
+ tsApi
78
+ })];
79
+ };
80
+ return proxy;
81
+ };
82
+ return { create };
83
+ };
84
+ //#endregion
85
+ //#region src/index.ts
86
+ const plugin = Object.assign(createLanguageServicePlugin, {
87
+ createLanguageServicePlugin,
88
+ findResultarLintFindings,
89
+ getProgramResultarDiagnostics,
90
+ runResultarCheckCli
91
+ });
92
+ //#endregion
93
+ export { plugin as default };
94
+
95
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/diagnostics.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type * as ts from \"typescript\";\n\nimport type { ResultarLintFinding, ResultarRuleName, ResultarRuleSeverity } from \"./finding.js\";\nimport {\n type ResultarRulesOptions,\n getSourceFileResultarFindings,\n normalizeResultarRulesOptions,\n onlyResultarRule,\n} from \"./rules-core.js\";\n\nexport const RESULTAR_DIAGNOSTIC_SOURCE = \"resultar\";\nexport const RESULTAR_NO_DISCARD_DIAGNOSTIC_CODE = 91_001;\nexport const RESULTAR_RULE_DIAGNOSTIC_CODES: Record<ResultarRuleName, number> = {\n \"no-discard\": RESULTAR_NO_DISCARD_DIAGNOSTIC_CODE,\n \"no-tagged-error-constructor-override\": 91_010,\n \"no-try-catch-in-safe-try\": 91_006,\n \"no-unsafe-await\": 91_012,\n \"no-useless-recovery\": 91_011,\n \"prefer-and-then\": 91_003,\n \"prefer-map-err\": 91_002,\n \"prefer-tagged-error\": 91_008,\n \"tagged-error-name-match\": 91_009,\n \"typed-catch-mapper\": 91_004,\n \"unsafe-result-type-assertion\": 91_007,\n \"yield-star-in-safe-try\": 91_005,\n};\n\ntype TypeScriptApi = typeof ts;\n\ntype ResultarLanguageServiceOptions = Partial<ResultarRulesOptions>;\n\ninterface DiagnosticContext {\n readonly sourceFile: ts.SourceFile;\n readonly tsApi: TypeScriptApi;\n}\n\nexport interface ResultarDiagnosticInput {\n readonly options?: ResultarLanguageServiceOptions;\n readonly program: ts.Program;\n readonly sourceFile: ts.SourceFile;\n readonly tsApi: TypeScriptApi;\n}\n\nconst isExternalSourceFile = (sourceFile: ts.SourceFile): boolean =>\n sourceFile.isDeclarationFile ||\n sourceFile.fileName.includes(\"/node_modules/\") ||\n sourceFile.fileName.includes(\"\\\\node_modules\\\\\");\n\nconst getDiagnosticCategory = (\n tsApi: TypeScriptApi,\n severity: Exclude<ResultarRuleSeverity, \"off\">,\n): ts.DiagnosticCategory => {\n if (severity === \"error\") {\n return tsApi.DiagnosticCategory.Error;\n }\n\n if (severity === \"message\") {\n return tsApi.DiagnosticCategory.Message;\n }\n\n if (severity === \"suggestion\") {\n return tsApi.DiagnosticCategory.Suggestion;\n }\n\n return tsApi.DiagnosticCategory.Warning;\n};\n\nconst createResultarDiagnostic = (\n context: DiagnosticContext,\n finding: ResultarLintFinding,\n): ts.Diagnostic => {\n const diagnosticRuleName = finding.rule === \"no-discard\" ? \"noDiscard\" : finding.rule;\n\n return {\n category: getDiagnosticCategory(context.tsApi, finding.severity),\n code: RESULTAR_RULE_DIAGNOSTIC_CODES[finding.rule],\n file: context.sourceFile,\n length: finding.length,\n messageText: `[resultar/${diagnosticRuleName}] ${finding.message}`,\n source: RESULTAR_DIAGNOSTIC_SOURCE,\n start: finding.start,\n };\n};\n\nexport const getResultarDiagnostics = (\n input: ResultarDiagnosticInput,\n): readonly ts.Diagnostic[] => {\n const options = normalizeResultarRulesOptions(input.options);\n\n if (isExternalSourceFile(input.sourceFile)) {\n return [];\n }\n\n const context: DiagnosticContext = { sourceFile: input.sourceFile, tsApi: input.tsApi };\n const diagnostics = getSourceFileResultarFindings(\n input.tsApi,\n input.program.getTypeChecker(),\n input.sourceFile,\n options,\n ).map((finding) => createResultarDiagnostic(context, finding));\n\n return diagnostics;\n};\n\nexport const getProgramResultarDiagnostics = (\n tsApi: TypeScriptApi,\n program: ts.Program,\n options: ResultarLanguageServiceOptions = {},\n): readonly ts.Diagnostic[] =>\n program\n .getSourceFiles()\n .flatMap((sourceFile) => getResultarDiagnostics({ options, program, sourceFile, tsApi }));\n\nexport const getNoDiscardDiagnostics = (input: ResultarDiagnosticInput): readonly ts.Diagnostic[] =>\n getResultarDiagnostics({\n ...input,\n options: {\n ...onlyResultarRule(\"no-discard\", input.options?.noDiscard ?? \"error\"),\n noDiscardMode: input.options?.noDiscardMode,\n },\n });\n\nexport const getProgramNoDiscardDiagnostics = (\n tsApi: TypeScriptApi,\n program: ts.Program,\n options: ResultarLanguageServiceOptions = {},\n): readonly ts.Diagnostic[] =>\n getProgramResultarDiagnostics(tsApi, program, {\n ...onlyResultarRule(\"no-discard\", options.noDiscard ?? \"error\"),\n noDiscardMode: options.noDiscardMode,\n });\n","import type * as ts from \"typescript\";\n\nimport { getResultarDiagnostics } from \"./diagnostics.js\";\nimport { parsePluginOptions } from \"./plugin-options.js\";\n\nconst pluginMarker = \"__resultarLanguageServicePlugin\";\n\nexport const createLanguageServicePlugin = (modules: {\n readonly typescript: typeof ts;\n}): ts.server.PluginModule => {\n const tsApi = modules.typescript;\n\n const create = (info: ts.server.PluginCreateInfo): ts.LanguageService => {\n if ((info.languageService as unknown as Record<string, unknown>)[pluginMarker] === true) {\n return info.languageService;\n }\n\n const options = parsePluginOptions(info.config);\n const proxy = Object.create(null) as ts.LanguageService & Record<string, unknown>;\n const proxyRecord = proxy as unknown as Record<string, unknown>;\n const serviceRecord = info.languageService as unknown as Record<string, unknown>;\n proxy[pluginMarker] = true;\n\n for (const key of Object.keys(serviceRecord)) {\n const property = serviceRecord[key];\n\n if (typeof property === \"function\") {\n proxyRecord[key] = (...args: readonly unknown[]) =>\n Reflect.apply(property, info.languageService, args) as unknown;\n }\n }\n\n proxy.getSemanticDiagnostics = (fileName, ...args) => {\n const diagnostics = info.languageService.getSemanticDiagnostics(fileName, ...args);\n\n const program = info.languageService.getProgram();\n const sourceFile = program?.getSourceFile(fileName);\n\n if (program === undefined || sourceFile === undefined) {\n return diagnostics;\n }\n\n return [...diagnostics, ...getResultarDiagnostics({ options, program, sourceFile, tsApi })];\n };\n\n return proxy;\n };\n\n return { create };\n};\n","import { getProgramResultarDiagnostics } from \"./diagnostics.js\";\nimport { findResultarLintFindings, runResultarCheckCli } from \"./lint.js\";\nimport { createLanguageServicePlugin } from \"./plugin.js\";\n\ntype ResultarLanguageServicePlugin = typeof createLanguageServicePlugin & {\n readonly createLanguageServicePlugin: typeof createLanguageServicePlugin;\n readonly findResultarLintFindings: typeof findResultarLintFindings;\n readonly getProgramResultarDiagnostics: typeof getProgramResultarDiagnostics;\n readonly runResultarCheckCli: typeof runResultarCheckCli;\n};\n\nconst plugin: ResultarLanguageServicePlugin = Object.assign(createLanguageServicePlugin, {\n createLanguageServicePlugin,\n findResultarLintFindings,\n getProgramResultarDiagnostics,\n runResultarCheckCli,\n});\n\nexport default plugin;\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAE1C,MAAa,iCAAmE;CAC9E,cAAc;CACd,wCAAwC;CACxC,4BAA4B;CAC5B,mBAAmB;CACnB,uBAAuB;CACvB,mBAAmB;CACnB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,sBAAsB;CACtB,gCAAgC;CAChC,0BAA0B;AAC5B;AAkBA,MAAM,wBAAwB,eAC5B,WAAW,qBACX,WAAW,SAAS,SAAS,gBAAgB,KAC7C,WAAW,SAAS,SAAS,kBAAkB;AAEjD,MAAM,yBACJ,OACA,aAC0B;CAC1B,IAAI,aAAa,SACf,OAAO,MAAM,mBAAmB;CAGlC,IAAI,aAAa,WACf,OAAO,MAAM,mBAAmB;CAGlC,IAAI,aAAa,cACf,OAAO,MAAM,mBAAmB;CAGlC,OAAO,MAAM,mBAAmB;AAClC;AAEA,MAAM,4BACJ,SACA,YACkB;CAClB,MAAM,qBAAqB,QAAQ,SAAS,eAAe,cAAc,QAAQ;CAEjF,OAAO;EACL,UAAU,sBAAsB,QAAQ,OAAO,QAAQ,QAAQ;EAC/D,MAAM,+BAA+B,QAAQ;EAC7C,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,aAAa,aAAa,mBAAmB,IAAI,QAAQ;EACzD,QAAQ;EACR,OAAO,QAAQ;CACjB;AACF;AAEA,MAAa,0BACX,UAC6B;CAC7B,MAAM,UAAU,8BAA8B,MAAM,OAAO;CAE3D,IAAI,qBAAqB,MAAM,UAAU,GACvC,OAAO,CAAC;CAGV,MAAM,UAA6B;EAAE,YAAY,MAAM;EAAY,OAAO,MAAM;CAAM;CAQtF,OAPoB,8BAClB,MAAM,OACN,MAAM,QAAQ,eAAe,GAC7B,MAAM,YACN,OACF,EAAE,KAAK,YAAY,yBAAyB,SAAS,OAAO,CAE3C;AACnB;AAEA,MAAa,iCACX,OACA,SACA,UAA0C,CAAC,MAE3C,QACG,eAAe,EACf,SAAS,eAAe,uBAAuB;CAAE;CAAS;CAAS;CAAY;AAAM,CAAC,CAAC;;;AC1G5F,MAAM,eAAe;AAErB,MAAa,+BAA+B,YAEd;CAC5B,MAAM,QAAQ,QAAQ;CAEtB,MAAM,UAAU,SAAyD;EACvE,IAAK,KAAK,gBAAuD,kBAAkB,MACjF,OAAO,KAAK;EAGd,MAAM,UAAU,mBAAmB,KAAK,MAAM;EAC9C,MAAM,QAAQ,OAAO,OAAO,IAAI;EAChC,MAAM,cAAc;EACpB,MAAM,gBAAgB,KAAK;EAC3B,MAAM,gBAAgB;EAEtB,KAAK,MAAM,OAAO,OAAO,KAAK,aAAa,GAAG;GAC5C,MAAM,WAAW,cAAc;GAE/B,IAAI,OAAO,aAAa,YACtB,YAAY,QAAQ,GAAG,SACrB,QAAQ,MAAM,UAAU,KAAK,iBAAiB,IAAI;EAExD;EAEA,MAAM,0BAA0B,UAAU,GAAG,SAAS;GACpD,MAAM,cAAc,KAAK,gBAAgB,uBAAuB,UAAU,GAAG,IAAI;GAEjF,MAAM,UAAU,KAAK,gBAAgB,WAAW;GAChD,MAAM,aAAa,SAAS,cAAc,QAAQ;GAElD,IAAI,YAAY,KAAA,KAAa,eAAe,KAAA,GAC1C,OAAO;GAGT,OAAO,CAAC,GAAG,aAAa,GAAG,uBAAuB;IAAE;IAAS;IAAS;IAAY;GAAM,CAAC,CAAC;EAC5F;EAEA,OAAO;CACT;CAEA,OAAO,EAAE,OAAO;AAClB;;;ACtCA,MAAM,SAAwC,OAAO,OAAO,6BAA6B;CACvF;CACA;CACA;CACA;AACF,CAAC"}