UNPKG

auto-cr-rules

Version:

Extensible static analysis rule set for the auto-cr automated code review toolkit

132 lines (131 loc) 5.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.noDeepRelativeImports = void 0; var types_1 = require("../types"); var MAX_DEPTH = 2; exports.noDeepRelativeImports = (0, types_1.defineRule)('no-deep-relative-imports', { tag: 'base', severity: types_1.RuleSeverity.Warning }, function (_a) { var _b, _c; var ast = _a.ast, helpers = _a.helpers, messages = _a.messages, language = _a.language, source = _a.source; // Build a per-file line index so we can convert byte offsets emitted by SWC back to line numbers. var moduleStart = (_c = (_b = ast.span) === null || _b === void 0 ? void 0 : _b.start) !== null && _c !== void 0 ? _c : 0; var lineIndex = buildLineIndex(source); for (var _i = 0, _d = helpers.imports; _i < _d.length; _i++) { var reference = _d[_i]; if (!helpers.isRelativePath(reference.value)) { continue; } var depth = helpers.relativeDepth(reference.value); if (depth > MAX_DEPTH) { var description = messages.noDeepRelativeImports({ value: reference.value, maxDepth: MAX_DEPTH }); var suggestions = language === 'zh' ? [ { text: '使用别名路径(如 @shared/deep/utils)' }, { text: '或在上层聚合导出,避免过深相对路径。' }, ] : [ { text: 'Use a path alias (for example: @shared/deep/utils).' }, { text: 'Create an index file at a higher level to re-export the module and shorten the import.' }, ]; var computedLine = reference.span ? resolveLine(lineIndex, bytePosToCharIndex(source, moduleStart, reference.span.start)) : undefined; var fallbackLine = findImportLine(source, reference.value); // Prefer the larger value so we never point at leading block comments when the byte offset is truncated. var line = selectLineNumber(computedLine, fallbackLine); helpers.reportViolation({ description: description, code: reference.value, suggestions: suggestions, span: reference.span, line: line, }, reference.span); } } }); var buildLineIndex = function (source) { // Track every newline so we can binary-search the surrounding line for any byte position. var offsets = [0]; for (var index = 0; index < source.length; index += 1) { if (source[index] === '\n') { offsets.push(index + 1); } } return { offsets: offsets }; }; var resolveLine = function (_a, position) { var offsets = _a.offsets; var low = 0; var high = offsets.length - 1; while (low <= high) { var mid = Math.floor((low + high) / 2); var current = offsets[mid]; if (current === position) { return mid + 1; } if (current < position) { low = mid + 1; } else { high = mid - 1; } } return high + 1; }; var readUtf8Character = function (source, index, code) { if (code <= 0x7f) { return { bytes: 1, nextIndex: index + 1 }; } if (code <= 0x7ff) { return { bytes: 2, nextIndex: index + 1 }; } if (code >= 0xd800 && code <= 0xdbff && index + 1 < source.length) { var next = source.charCodeAt(index + 1); if (next >= 0xdc00 && next <= 0xdfff) { return { bytes: 4, nextIndex: index + 2 }; } } return { bytes: 3, nextIndex: index + 1 }; }; var bytePosToCharIndex = function (source, moduleStart, bytePos) { var target = Math.max(bytePos - moduleStart, 0); if (target === 0) { return 0; } var index = 0; var byteOffset = 0; while (index < source.length) { var code = source.charCodeAt(index); var _a = readUtf8Character(source, index, code), bytes = _a.bytes, nextIndex = _a.nextIndex; if (byteOffset + bytes > target) { return index; } byteOffset += bytes; index = nextIndex; } return source.length; }; var findImportLine = function (source, value) { var lines = source.split(/\r?\n/); for (var index = 0; index < lines.length; index += 1) { var line = lines[index]; // Look for the literal import string. This is slower than span math but provides a robust fallback. if (line.includes('import') && line.includes(value)) { return index + 1; } } return undefined; }; var selectLineNumber = function (computed, fallback) { // If one of the sources is missing, prefer the other. When both exist, use the larger line number so // we avoid pointing at comment blocks above the actual statement. if (fallback === undefined) { return computed; } if (computed === undefined) { return fallback; } if (computed < fallback) { return fallback; } return computed; };