corsa-oxlint 0.41.0 → 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 CHANGED
@@ -107,7 +107,7 @@ function diagnosticsForRule(context, ruleName) {
107
107
  }
108
108
  const cached = sourceCache.get(key);
109
109
  if (cached?.sourceText === sourceText) return cached.diagnostics;
110
- const diagnostics = runNativeStylisticLint(sourceText, { rules: config });
110
+ const diagnostics = mapNativeDiagnosticRanges(runNativeStylisticLint(sourceText, { rules: config }), sourceText);
111
111
  sourceCache.set(key, {
112
112
  sourceText,
113
113
  diagnostics
@@ -147,6 +147,80 @@ function rangeNode(program, range) {
147
147
  function oxlintRange(range) {
148
148
  return [range.start, range.end];
149
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
+ }
150
224
  function sourceTextForContext(context) {
151
225
  const text = context.sourceCode.text;
152
226
  if (typeof text === "string") return text;
@@ -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]));\ntype CachedStylisticDiagnostics = {\n readonly sourceText: string;\n readonly diagnostics: readonly NativeLintDiagnostic[];\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 = runNativeStylisticLint(sourceText, { rules: config });\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 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.41.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.41.0"
106
+ "@corsa-bind/napi": "0.41.1"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@typescript-eslint/utils": "8.59.3"