corsa-oxlint 0.40.1 → 0.41.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/dist/stylistic.js +80 -3
- package/dist/stylistic.js.map +1 -1
- package/package.json +2 -2
package/dist/stylistic.js
CHANGED
|
@@ -106,9 +106,12 @@ function diagnosticsForRule(context, ruleName) {
|
|
|
106
106
|
diagnosticsCache.set(sourceCode, sourceCache);
|
|
107
107
|
}
|
|
108
108
|
const cached = sourceCache.get(key);
|
|
109
|
-
if (cached) return cached;
|
|
110
|
-
const diagnostics = runNativeStylisticLint(sourceText, { rules: config });
|
|
111
|
-
sourceCache.set(key,
|
|
109
|
+
if (cached?.sourceText === sourceText) return cached.diagnostics;
|
|
110
|
+
const diagnostics = mapNativeDiagnosticRanges(runNativeStylisticLint(sourceText, { rules: config }), sourceText);
|
|
111
|
+
sourceCache.set(key, {
|
|
112
|
+
sourceText,
|
|
113
|
+
diagnostics
|
|
114
|
+
});
|
|
112
115
|
return diagnostics;
|
|
113
116
|
}
|
|
114
117
|
function stylisticRunConfig(context, currentRuleName) {
|
|
@@ -144,6 +147,80 @@ function rangeNode(program, range) {
|
|
|
144
147
|
function oxlintRange(range) {
|
|
145
148
|
return [range.start, range.end];
|
|
146
149
|
}
|
|
150
|
+
function mapNativeDiagnosticRanges(diagnostics, sourceText) {
|
|
151
|
+
const byteToUtf16 = createByteToUtf16Mapper(sourceText);
|
|
152
|
+
return diagnostics.map((diagnostic) => ({
|
|
153
|
+
...diagnostic,
|
|
154
|
+
range: mapNativeRange(diagnostic.range, byteToUtf16),
|
|
155
|
+
...diagnostic.suggestions?.length ? { suggestions: diagnostic.suggestions.map((suggestion) => mapNativeSuggestion(suggestion, byteToUtf16)) } : {}
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
function mapNativeSuggestion(suggestion, byteToUtf16) {
|
|
159
|
+
return {
|
|
160
|
+
...suggestion,
|
|
161
|
+
fixes: suggestion.fixes.map((fix) => mapNativeFix(fix, byteToUtf16))
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function mapNativeFix(fix, byteToUtf16) {
|
|
165
|
+
return {
|
|
166
|
+
...fix,
|
|
167
|
+
range: mapNativeRange(fix.range, byteToUtf16)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function mapNativeRange(range, byteToUtf16) {
|
|
171
|
+
return {
|
|
172
|
+
start: byteToUtf16(range.start),
|
|
173
|
+
end: byteToUtf16(range.end)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function createByteToUtf16Mapper(sourceText) {
|
|
177
|
+
const nonAsciiSpans = [];
|
|
178
|
+
let byteOffset = 0;
|
|
179
|
+
let utf16Offset = 0;
|
|
180
|
+
while (utf16Offset < sourceText.length) {
|
|
181
|
+
const codePoint = sourceText.codePointAt(utf16Offset);
|
|
182
|
+
if (codePoint === void 0) break;
|
|
183
|
+
const utf16Length = codePoint > 65535 ? 2 : 1;
|
|
184
|
+
const byteLength = utf8ByteLength(codePoint);
|
|
185
|
+
const byteEnd = byteOffset + byteLength;
|
|
186
|
+
const utf16End = utf16Offset + utf16Length;
|
|
187
|
+
if (byteLength !== utf16Length) nonAsciiSpans.push({
|
|
188
|
+
byteStart: byteOffset,
|
|
189
|
+
byteEnd,
|
|
190
|
+
utf16Start: utf16Offset,
|
|
191
|
+
deltaAfter: byteEnd - utf16End
|
|
192
|
+
});
|
|
193
|
+
byteOffset = byteEnd;
|
|
194
|
+
utf16Offset = utf16End;
|
|
195
|
+
}
|
|
196
|
+
if (nonAsciiSpans.length === 0) return (offset) => clampOffset(offset, sourceText.length);
|
|
197
|
+
const totalBytes = byteOffset;
|
|
198
|
+
return (offset) => {
|
|
199
|
+
const byteOffset = clampOffset(offset, totalBytes);
|
|
200
|
+
let low = 0;
|
|
201
|
+
let high = nonAsciiSpans.length;
|
|
202
|
+
while (low < high) {
|
|
203
|
+
const mid = Math.floor((low + high) / 2);
|
|
204
|
+
if (nonAsciiSpans[mid].byteEnd <= byteOffset) low = mid + 1;
|
|
205
|
+
else high = mid;
|
|
206
|
+
}
|
|
207
|
+
const nextSpan = nonAsciiSpans[low];
|
|
208
|
+
if (nextSpan && byteOffset >= nextSpan.byteStart && byteOffset < nextSpan.byteEnd) return nextSpan.utf16Start;
|
|
209
|
+
return clampOffset(byteOffset - (nonAsciiSpans[low - 1]?.deltaAfter ?? 0), sourceText.length);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function utf8ByteLength(codePoint) {
|
|
213
|
+
if (codePoint <= 127) return 1;
|
|
214
|
+
if (codePoint <= 2047) return 2;
|
|
215
|
+
if (codePoint <= 65535) return 3;
|
|
216
|
+
return 4;
|
|
217
|
+
}
|
|
218
|
+
function clampOffset(offset, max) {
|
|
219
|
+
if (!Number.isFinite(offset)) return 0;
|
|
220
|
+
if (offset <= 0) return 0;
|
|
221
|
+
if (offset >= max) return max;
|
|
222
|
+
return Math.trunc(offset);
|
|
223
|
+
}
|
|
147
224
|
function sourceTextForContext(context) {
|
|
148
225
|
const text = context.sourceCode.text;
|
|
149
226
|
if (typeof text === "string") return text;
|
package/dist/stylistic.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stylistic.js","names":[],"sources":["../ts/stylistic.ts"],"sourcesContent":["import {\n nativeStylisticRuleMetas,\n runNativeStylisticLint,\n type NativeLintDiagnostic,\n type NativeLintRange,\n type NativeLintRuleMeta,\n type NativeStylisticRuleConfig,\n} from \"@corsa-bind/napi\";\n\nimport { definePlugin, defineRule } from \"./plugin\";\nimport type { ContextWithParserOptions } from \"./types\";\n\ntype ProgramNode = {\n readonly type: string;\n readonly range?: readonly [number, number];\n};\n\nexport type CorsaStylisticRuleName =\n | \"eol-last\"\n | \"linebreak-style\"\n | \"no-multiple-empty-lines\"\n | \"no-tabs\"\n | \"no-trailing-spaces\"\n | \"quotes\"\n | \"unicode-bom\"\n | \"arrow-spacing\"\n | \"comma-spacing\"\n | \"semi-spacing\"\n | \"space-in-parens\"\n | \"template-curly-spacing\"\n | \"rest-spread-spacing\"\n | \"no-multi-spaces\"\n | \"no-whitespace-before-property\"\n | \"dot-location\"\n | \"spaced-comment\"\n | \"object-curly-spacing\"\n | \"array-bracket-spacing\"\n | \"computed-property-spacing\"\n | \"block-spacing\"\n | \"space-before-blocks\"\n | \"function-call-spacing\"\n | \"space-before-function-paren\"\n | \"no-floating-decimal\"\n | \"template-tag-spacing\"\n | \"yield-star-spacing\"\n | \"generator-star-spacing\"\n | \"comma-dangle\"\n | \"space-infix-ops\"\n | \"max-len\"\n | \"semi-style\"\n | \"comma-style\"\n | \"arrow-parens\"\n | \"switch-colon-spacing\"\n | \"no-extra-semi\"\n | \"new-parens\"\n | \"space-unary-ops\"\n | \"wrap-regex\"\n | \"implicit-arrow-linebreak\"\n | \"operator-linebreak\"\n | \"keyword-spacing\";\n\nexport type CorsaStylisticRuleOptions = readonly unknown[];\n\nexport interface CorsaStylisticSettings {\n /**\n * Rule options used by the native batch runner.\n *\n * Keep this in sync with enabled Oxlint rules when several stylistic rules\n * are active; the JS bridge can then perform one native scan and share the\n * diagnostics across individual rule reports.\n */\n readonly rules?: Partial<Record<CorsaStylisticRuleName, CorsaStylisticRuleOptions>>;\n}\n\nconst stylisticMetas = nativeStylisticRuleMetas();\nconst stylisticMetasByName = new Map(stylisticMetas.map((meta) => [meta.name, meta]));\nconst diagnosticsCache = new WeakMap<object, Map<string, readonly NativeLintDiagnostic[]>>();\n\n/**\n * Native stylistic rule names exported by `corsa-oxlint/stylistic`.\n */\nexport const implementedStylisticRuleNames = [\n \"eol-last\",\n \"linebreak-style\",\n \"no-multiple-empty-lines\",\n \"no-tabs\",\n \"no-trailing-spaces\",\n \"quotes\",\n \"unicode-bom\",\n \"arrow-spacing\",\n \"comma-spacing\",\n \"semi-spacing\",\n \"space-in-parens\",\n \"template-curly-spacing\",\n \"rest-spread-spacing\",\n \"no-multi-spaces\",\n \"no-whitespace-before-property\",\n \"dot-location\",\n \"spaced-comment\",\n \"object-curly-spacing\",\n \"array-bracket-spacing\",\n \"computed-property-spacing\",\n \"block-spacing\",\n \"space-before-blocks\",\n \"function-call-spacing\",\n \"space-before-function-paren\",\n \"no-floating-decimal\",\n \"template-tag-spacing\",\n \"yield-star-spacing\",\n \"generator-star-spacing\",\n \"comma-dangle\",\n \"space-infix-ops\",\n \"max-len\",\n \"semi-style\",\n \"comma-style\",\n \"arrow-parens\",\n \"switch-colon-spacing\",\n \"no-extra-semi\",\n \"new-parens\",\n \"space-unary-ops\",\n \"wrap-regex\",\n \"implicit-arrow-linebreak\",\n \"operator-linebreak\",\n \"keyword-spacing\",\n] as const satisfies readonly CorsaStylisticRuleName[];\n\n/**\n * Oxlint-compatible stylistic rules backed by the Rust source scanner.\n */\nexport const corsaStylisticRules = Object.freeze(\n Object.fromEntries(\n implementedStylisticRuleNames.map((ruleName) => [ruleName, createStylisticRule(ruleName)]),\n ),\n) as Readonly<Record<CorsaStylisticRuleName, ReturnType<typeof createStylisticRule>>>;\n\n/**\n * Oxlint plugin exposing Corsa's Rust-backed stylistic rules.\n *\n * Register it under any namespace, then enable rules such as\n * `stylistic/quotes` or `stylistic/no-trailing-spaces`.\n */\nexport const corsaStylisticPlugin = definePlugin({\n meta: { name: \"oxlint-plugin-corsa-stylistic\" },\n rules: corsaStylisticRules,\n});\n\nexport default corsaStylisticPlugin;\n\nfunction createStylisticRule(ruleName: CorsaStylisticRuleName) {\n const meta = stylisticRuleMeta(ruleName);\n return defineRule({\n defaultOptions: [],\n meta: {\n type: \"layout\",\n docs: {\n description: meta.docsDescription,\n requiresTypeChecking: false,\n url: `https://github.com/ubugeeei-prod/corsa-bind/tree/main/src/bindings/nodejs/corsa_oxlint/ts/stylistic.ts`,\n },\n fixable: \"whitespace\",\n hasSuggestions: meta.hasSuggestions,\n messages: meta.messages,\n schema: { type: \"array\" },\n },\n create(context: ContextWithParserOptions) {\n return {\n Program(node: ProgramNode) {\n reportStylisticDiagnostics(\n context,\n node,\n diagnosticsForRule(context, ruleName).filter(\n (diagnostic) => diagnostic.ruleName === ruleName,\n ),\n );\n },\n };\n },\n });\n}\n\nfunction diagnosticsForRule(\n context: ContextWithParserOptions,\n ruleName: CorsaStylisticRuleName,\n): readonly NativeLintDiagnostic[] {\n const sourceCode = context.sourceCode as unknown as object;\n const sourceText = sourceTextForContext(context);\n const config = stylisticRunConfig(context, ruleName);\n const key = JSON.stringify(config);\n let sourceCache = diagnosticsCache.get(sourceCode);\n if (!sourceCache) {\n sourceCache = new Map();\n diagnosticsCache.set(sourceCode, sourceCache);\n }\n\n const cached = sourceCache.get(key);\n if (cached) {\n return cached;\n }\n\n const diagnostics = runNativeStylisticLint(sourceText, { rules: config });\n sourceCache.set(key, diagnostics);\n return diagnostics;\n}\n\nfunction stylisticRunConfig(\n context: ContextWithParserOptions,\n currentRuleName: CorsaStylisticRuleName,\n): readonly NativeStylisticRuleConfig[] {\n const settingsRules = context.settings?.corsaStylistic?.rules;\n const rules = new Map<CorsaStylisticRuleName, CorsaStylisticRuleOptions>();\n\n if (settingsRules) {\n for (const [name, options] of Object.entries(settingsRules)) {\n assertKnownStylisticRuleName(name);\n rules.set(name, normalizeOptions(options));\n }\n }\n\n const currentOptions = currentRuleOptions(context);\n if (!rules.has(currentRuleName) || currentOptions.length > 0) {\n rules.set(currentRuleName, currentOptions);\n }\n\n return implementedStylisticRuleNames\n .filter((ruleName) => rules.has(ruleName))\n .map((ruleName) => ({\n name: ruleName,\n options: rules.get(ruleName) ?? [],\n }));\n}\n\nfunction reportStylisticDiagnostics(\n context: ContextWithParserOptions,\n program: ProgramNode,\n diagnostics: readonly NativeLintDiagnostic[],\n): void {\n for (const diagnostic of diagnostics) {\n context.report({\n node: rangeNode(program, diagnostic.range),\n messageId: diagnostic.messageId,\n ...(diagnostic.suggestions?.length\n ? {\n suggest: diagnostic.suggestions.map((suggestion) => ({\n messageId: suggestion.messageId,\n fix: (fixer: any) =>\n suggestion.fixes.map((fix) =>\n fixer.replaceTextRange(oxlintRange(fix.range), fix.replacementText),\n ),\n })),\n }\n : {}),\n } as never);\n }\n}\n\nfunction rangeNode(program: ProgramNode, range: NativeLintRange): ProgramNode {\n return {\n ...program,\n range: oxlintRange(range),\n };\n}\n\nfunction oxlintRange(range: NativeLintRange): [number, number] {\n return [range.start, range.end];\n}\n\nfunction sourceTextForContext(context: ContextWithParserOptions): string {\n const text = (context.sourceCode as { text?: unknown }).text;\n if (typeof text === \"string\") {\n return text;\n }\n return context.sourceCode.getText({ type: \"Program\" } as never);\n}\n\nfunction currentRuleOptions(context: ContextWithParserOptions): CorsaStylisticRuleOptions {\n return normalizeOptions((context as { options?: unknown }).options);\n}\n\nfunction normalizeOptions(options: unknown): CorsaStylisticRuleOptions {\n if (Array.isArray(options)) {\n return options;\n }\n if (options == null) {\n return [];\n }\n return [options];\n}\n\nfunction assertKnownStylisticRuleName(name: string): asserts name is CorsaStylisticRuleName {\n if (!(implementedStylisticRuleNames as readonly string[]).includes(name)) {\n throw new Error(`unknown corsa stylistic rule: ${name}`);\n }\n}\n\nfunction stylisticRuleMeta(ruleName: CorsaStylisticRuleName): NativeLintRuleMeta {\n const meta = stylisticMetasByName.get(ruleName);\n if (!meta) {\n throw new Error(`corsa stylistic native Rust rule is not registered: ${ruleName}`);\n }\n return meta;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stylistic.js","names":[],"sources":["../ts/stylistic.ts"],"sourcesContent":["import {\n nativeStylisticRuleMetas,\n runNativeStylisticLint,\n type NativeLintDiagnostic,\n type NativeLintFix,\n type NativeLintRange,\n type NativeLintRuleMeta,\n type NativeLintSuggestion,\n type NativeStylisticRuleConfig,\n} from \"@corsa-bind/napi\";\n\nimport { definePlugin, defineRule } from \"./plugin\";\nimport type { ContextWithParserOptions } from \"./types\";\n\ntype ProgramNode = {\n readonly type: string;\n readonly range?: readonly [number, number];\n};\n\nexport type CorsaStylisticRuleName =\n | \"eol-last\"\n | \"linebreak-style\"\n | \"no-multiple-empty-lines\"\n | \"no-tabs\"\n | \"no-trailing-spaces\"\n | \"quotes\"\n | \"unicode-bom\"\n | \"arrow-spacing\"\n | \"comma-spacing\"\n | \"semi-spacing\"\n | \"space-in-parens\"\n | \"template-curly-spacing\"\n | \"rest-spread-spacing\"\n | \"no-multi-spaces\"\n | \"no-whitespace-before-property\"\n | \"dot-location\"\n | \"spaced-comment\"\n | \"object-curly-spacing\"\n | \"array-bracket-spacing\"\n | \"computed-property-spacing\"\n | \"block-spacing\"\n | \"space-before-blocks\"\n | \"function-call-spacing\"\n | \"space-before-function-paren\"\n | \"no-floating-decimal\"\n | \"template-tag-spacing\"\n | \"yield-star-spacing\"\n | \"generator-star-spacing\"\n | \"comma-dangle\"\n | \"space-infix-ops\"\n | \"max-len\"\n | \"semi-style\"\n | \"comma-style\"\n | \"arrow-parens\"\n | \"switch-colon-spacing\"\n | \"no-extra-semi\"\n | \"new-parens\"\n | \"space-unary-ops\"\n | \"wrap-regex\"\n | \"implicit-arrow-linebreak\"\n | \"operator-linebreak\"\n | \"keyword-spacing\";\n\nexport type CorsaStylisticRuleOptions = readonly unknown[];\n\nexport interface CorsaStylisticSettings {\n /**\n * Rule options used by the native batch runner.\n *\n * Keep this in sync with enabled Oxlint rules when several stylistic rules\n * are active; the JS bridge can then perform one native scan and share the\n * diagnostics across individual rule reports.\n */\n readonly rules?: Partial<Record<CorsaStylisticRuleName, CorsaStylisticRuleOptions>>;\n}\n\nconst stylisticMetas = nativeStylisticRuleMetas();\nconst stylisticMetasByName = new Map(stylisticMetas.map((meta) => [meta.name, meta]));\ntype CachedStylisticDiagnostics = {\n readonly sourceText: string;\n readonly diagnostics: readonly NativeLintDiagnostic[];\n};\n\ntype ByteToUtf16Mapper = (offset: number) => number;\n\ntype NonAsciiSpan = {\n readonly byteStart: number;\n readonly byteEnd: number;\n readonly utf16Start: number;\n readonly deltaAfter: number;\n};\n\nconst diagnosticsCache = new WeakMap<object, Map<string, CachedStylisticDiagnostics>>();\n\n/**\n * Native stylistic rule names exported by `corsa-oxlint/stylistic`.\n */\nexport const implementedStylisticRuleNames = [\n \"eol-last\",\n \"linebreak-style\",\n \"no-multiple-empty-lines\",\n \"no-tabs\",\n \"no-trailing-spaces\",\n \"quotes\",\n \"unicode-bom\",\n \"arrow-spacing\",\n \"comma-spacing\",\n \"semi-spacing\",\n \"space-in-parens\",\n \"template-curly-spacing\",\n \"rest-spread-spacing\",\n \"no-multi-spaces\",\n \"no-whitespace-before-property\",\n \"dot-location\",\n \"spaced-comment\",\n \"object-curly-spacing\",\n \"array-bracket-spacing\",\n \"computed-property-spacing\",\n \"block-spacing\",\n \"space-before-blocks\",\n \"function-call-spacing\",\n \"space-before-function-paren\",\n \"no-floating-decimal\",\n \"template-tag-spacing\",\n \"yield-star-spacing\",\n \"generator-star-spacing\",\n \"comma-dangle\",\n \"space-infix-ops\",\n \"max-len\",\n \"semi-style\",\n \"comma-style\",\n \"arrow-parens\",\n \"switch-colon-spacing\",\n \"no-extra-semi\",\n \"new-parens\",\n \"space-unary-ops\",\n \"wrap-regex\",\n \"implicit-arrow-linebreak\",\n \"operator-linebreak\",\n \"keyword-spacing\",\n] as const satisfies readonly CorsaStylisticRuleName[];\n\n/**\n * Oxlint-compatible stylistic rules backed by the Rust source scanner.\n */\nexport const corsaStylisticRules = Object.freeze(\n Object.fromEntries(\n implementedStylisticRuleNames.map((ruleName) => [ruleName, createStylisticRule(ruleName)]),\n ),\n) as Readonly<Record<CorsaStylisticRuleName, ReturnType<typeof createStylisticRule>>>;\n\n/**\n * Oxlint plugin exposing Corsa's Rust-backed stylistic rules.\n *\n * Register it under any namespace, then enable rules such as\n * `stylistic/quotes` or `stylistic/no-trailing-spaces`.\n */\nexport const corsaStylisticPlugin = definePlugin({\n meta: { name: \"oxlint-plugin-corsa-stylistic\" },\n rules: corsaStylisticRules,\n});\n\nexport default corsaStylisticPlugin;\n\nfunction createStylisticRule(ruleName: CorsaStylisticRuleName) {\n const meta = stylisticRuleMeta(ruleName);\n return defineRule({\n defaultOptions: [],\n meta: {\n type: \"layout\",\n docs: {\n description: meta.docsDescription,\n requiresTypeChecking: false,\n url: `https://github.com/ubugeeei-prod/corsa-bind/tree/main/src/bindings/nodejs/corsa_oxlint/ts/stylistic.ts`,\n },\n fixable: \"whitespace\",\n hasSuggestions: meta.hasSuggestions,\n messages: meta.messages,\n schema: { type: \"array\" },\n },\n create(context: ContextWithParserOptions) {\n return {\n Program(node: ProgramNode) {\n reportStylisticDiagnostics(\n context,\n node,\n diagnosticsForRule(context, ruleName).filter(\n (diagnostic) => diagnostic.ruleName === ruleName,\n ),\n );\n },\n };\n },\n });\n}\n\nfunction diagnosticsForRule(\n context: ContextWithParserOptions,\n ruleName: CorsaStylisticRuleName,\n): readonly NativeLintDiagnostic[] {\n const sourceCode = context.sourceCode as unknown as object;\n const sourceText = sourceTextForContext(context);\n const config = stylisticRunConfig(context, ruleName);\n const key = JSON.stringify(config);\n let sourceCache = diagnosticsCache.get(sourceCode);\n if (!sourceCache) {\n sourceCache = new Map();\n diagnosticsCache.set(sourceCode, sourceCache);\n }\n\n const cached = sourceCache.get(key);\n if (cached?.sourceText === sourceText) {\n return cached.diagnostics;\n }\n\n const diagnostics = mapNativeDiagnosticRanges(\n runNativeStylisticLint(sourceText, { rules: config }),\n sourceText,\n );\n sourceCache.set(key, { sourceText, diagnostics });\n return diagnostics;\n}\n\nfunction stylisticRunConfig(\n context: ContextWithParserOptions,\n currentRuleName: CorsaStylisticRuleName,\n): readonly NativeStylisticRuleConfig[] {\n const settingsRules = context.settings?.corsaStylistic?.rules;\n const rules = new Map<CorsaStylisticRuleName, CorsaStylisticRuleOptions>();\n\n if (settingsRules) {\n for (const [name, options] of Object.entries(settingsRules)) {\n assertKnownStylisticRuleName(name);\n rules.set(name, normalizeOptions(options));\n }\n }\n\n const currentOptions = currentRuleOptions(context);\n if (!rules.has(currentRuleName) || currentOptions.length > 0) {\n rules.set(currentRuleName, currentOptions);\n }\n\n return implementedStylisticRuleNames\n .filter((ruleName) => rules.has(ruleName))\n .map((ruleName) => ({\n name: ruleName,\n options: rules.get(ruleName) ?? [],\n }));\n}\n\nfunction reportStylisticDiagnostics(\n context: ContextWithParserOptions,\n program: ProgramNode,\n diagnostics: readonly NativeLintDiagnostic[],\n): void {\n for (const diagnostic of diagnostics) {\n context.report({\n node: rangeNode(program, diagnostic.range),\n messageId: diagnostic.messageId,\n ...(diagnostic.suggestions?.length\n ? {\n suggest: diagnostic.suggestions.map((suggestion) => ({\n messageId: suggestion.messageId,\n fix: (fixer: any) =>\n suggestion.fixes.map((fix) =>\n fixer.replaceTextRange(oxlintRange(fix.range), fix.replacementText),\n ),\n })),\n }\n : {}),\n } as never);\n }\n}\n\nfunction rangeNode(program: ProgramNode, range: NativeLintRange): ProgramNode {\n return {\n ...program,\n range: oxlintRange(range),\n };\n}\n\nfunction oxlintRange(range: NativeLintRange): [number, number] {\n return [range.start, range.end];\n}\n\nfunction mapNativeDiagnosticRanges(\n diagnostics: readonly NativeLintDiagnostic[],\n sourceText: string,\n): readonly NativeLintDiagnostic[] {\n const byteToUtf16 = createByteToUtf16Mapper(sourceText);\n return diagnostics.map((diagnostic) => ({\n ...diagnostic,\n range: mapNativeRange(diagnostic.range, byteToUtf16),\n ...(diagnostic.suggestions?.length\n ? {\n suggestions: diagnostic.suggestions.map((suggestion) =>\n mapNativeSuggestion(suggestion, byteToUtf16),\n ),\n }\n : {}),\n }));\n}\n\nfunction mapNativeSuggestion(\n suggestion: NativeLintSuggestion,\n byteToUtf16: ByteToUtf16Mapper,\n): NativeLintSuggestion {\n return {\n ...suggestion,\n fixes: suggestion.fixes.map((fix) => mapNativeFix(fix, byteToUtf16)),\n };\n}\n\nfunction mapNativeFix(fix: NativeLintFix, byteToUtf16: ByteToUtf16Mapper): NativeLintFix {\n return {\n ...fix,\n range: mapNativeRange(fix.range, byteToUtf16),\n };\n}\n\nfunction mapNativeRange(range: NativeLintRange, byteToUtf16: ByteToUtf16Mapper): NativeLintRange {\n return {\n start: byteToUtf16(range.start),\n end: byteToUtf16(range.end),\n };\n}\n\nfunction createByteToUtf16Mapper(sourceText: string): ByteToUtf16Mapper {\n const nonAsciiSpans: NonAsciiSpan[] = [];\n let byteOffset = 0;\n let utf16Offset = 0;\n\n while (utf16Offset < sourceText.length) {\n const codePoint = sourceText.codePointAt(utf16Offset);\n if (codePoint === undefined) {\n break;\n }\n const utf16Length = codePoint > 0xffff ? 2 : 1;\n const byteLength = utf8ByteLength(codePoint);\n const byteEnd = byteOffset + byteLength;\n const utf16End = utf16Offset + utf16Length;\n if (byteLength !== utf16Length) {\n nonAsciiSpans.push({\n byteStart: byteOffset,\n byteEnd,\n utf16Start: utf16Offset,\n deltaAfter: byteEnd - utf16End,\n });\n }\n byteOffset = byteEnd;\n utf16Offset = utf16End;\n }\n\n if (nonAsciiSpans.length === 0) {\n return (offset) => clampOffset(offset, sourceText.length);\n }\n\n const totalBytes = byteOffset;\n return (offset) => {\n const byteOffset = clampOffset(offset, totalBytes);\n let low = 0;\n let high = nonAsciiSpans.length;\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n if (nonAsciiSpans[mid].byteEnd <= byteOffset) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n const nextSpan = nonAsciiSpans[low];\n if (nextSpan && byteOffset >= nextSpan.byteStart && byteOffset < nextSpan.byteEnd) {\n return nextSpan.utf16Start;\n }\n\n const previousSpan = nonAsciiSpans[low - 1];\n const delta = previousSpan?.deltaAfter ?? 0;\n return clampOffset(byteOffset - delta, sourceText.length);\n };\n}\n\nfunction utf8ByteLength(codePoint: number): number {\n if (codePoint <= 0x7f) {\n return 1;\n }\n if (codePoint <= 0x7ff) {\n return 2;\n }\n if (codePoint <= 0xffff) {\n return 3;\n }\n return 4;\n}\n\nfunction clampOffset(offset: number, max: number): number {\n if (!Number.isFinite(offset)) {\n return 0;\n }\n if (offset <= 0) {\n return 0;\n }\n if (offset >= max) {\n return max;\n }\n return Math.trunc(offset);\n}\n\nfunction sourceTextForContext(context: ContextWithParserOptions): string {\n const text = (context.sourceCode as { text?: unknown }).text;\n if (typeof text === \"string\") {\n return text;\n }\n return context.sourceCode.getText({ type: \"Program\" } as never);\n}\n\nfunction currentRuleOptions(context: ContextWithParserOptions): CorsaStylisticRuleOptions {\n return normalizeOptions((context as { options?: unknown }).options);\n}\n\nfunction normalizeOptions(options: unknown): CorsaStylisticRuleOptions {\n if (Array.isArray(options)) {\n return options;\n }\n if (options == null) {\n return [];\n }\n return [options];\n}\n\nfunction assertKnownStylisticRuleName(name: string): asserts name is CorsaStylisticRuleName {\n if (!(implementedStylisticRuleNames as readonly string[]).includes(name)) {\n throw new Error(`unknown corsa stylistic rule: ${name}`);\n }\n}\n\nfunction stylisticRuleMeta(ruleName: CorsaStylisticRuleName): NativeLintRuleMeta {\n const meta = stylisticMetasByName.get(ruleName);\n if (!meta) {\n throw new Error(`corsa stylistic native Rust rule is not registered: ${ruleName}`);\n }\n return meta;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "corsa-oxlint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.1",
|
|
4
4
|
"description": "Type-aware Oxlint helpers powered by Corsa",
|
|
5
5
|
"homepage": "https://github.com/ubugeeei-prod/corsa-bind/tree/main/src/bindings/nodejs/corsa_oxlint",
|
|
6
6
|
"bugs": {
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"dependencies": {
|
|
104
104
|
"@oxlint/plugins": "1.66.0",
|
|
105
105
|
"oxlint": "1.66.0",
|
|
106
|
-
"@corsa-bind/napi": "0.
|
|
106
|
+
"@corsa-bind/napi": "0.41.1"
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
109
|
"@typescript-eslint/utils": "8.59.3"
|