[go: nahoru, domu]

Skip to content

Commit

Permalink
fix(eslint-plugin): [init-declarations] refine report locations (#8893)
Browse files Browse the repository at this point in the history
[init-declarations] refine report loc
  • Loading branch information
kirkwaiblinger committed Jun 5, 2024
1 parent a87ce50 commit fbff4ce
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 35 deletions.
69 changes: 68 additions & 1 deletion packages/eslint-plugin/src/rules/init-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,51 @@ export default createRule<Options, MessageIds>({
},
defaultOptions: ['always'],
create(context, [mode]) {
const rules = baseRule.create(context);
// Make a custom context to adjust the the loc of reports where the base
// rule's behavior is a bit too aggressive with TS-specific syntax (namely,
// type annotations).
function getBaseContextOverride(): typeof context {
const reportOverride: typeof context.report = descriptor => {
if ('node' in descriptor && descriptor.loc == null) {
const { node, ...rest } = descriptor;
// We only want to special case the report loc when reporting on
// variables declarations that are not initialized. Declarations that
// _are_ initialized get reported by the base rule due to a setting to
// prohibit initializing variables entirely, in which case underlining
// the whole node including the type annotation and initializer is
// appropriate.
if (
node.type === AST_NODE_TYPES.VariableDeclarator &&
node.init == null
) {
context.report({
...rest,
loc: getReportLoc(node),
});
return;
}
}

context.report(descriptor);
};

// `return { ...context, report: reportOverride }` isn't safe because the
// `context` object has some getters that need to be preserved.
//
// `return new Proxy(context, ...)` doesn't work because `context` has
// non-configurable properties that throw when constructing a Proxy.
//
// So, we'll just use Proxy on a dummy object and use the `get` trap to
// proxy `context`'s properties.
return new Proxy({} as typeof context, {
get: (target, prop, receiver): unknown =>
prop === 'report'
? reportOverride
: Reflect.get(context, prop, receiver),
});
}

const rules = baseRule.create(getBaseContextOverride());

return {
'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void {
Expand Down Expand Up @@ -65,3 +109,26 @@ export default createRule<Options, MessageIds>({
}
},
});

/**
* When reporting an uninitialized variable declarator, get the loc excluding
* the type annotation.
*/
function getReportLoc(
node: TSESTree.VariableDeclarator,
): TSESTree.SourceLocation {
const start: TSESTree.Position = structuredClone(node.loc.start);
const end: TSESTree.Position = {
line: node.loc.start.line,
// `if (id.type === AST_NODE_TYPES.Identifier)` is a condition for
// reporting in the base rule (as opposed to things like destructuring
// assignment), so the type assertion should always be valid.
column:
node.loc.start.column + (node.id as TSESTree.Identifier).name.length,
};

return {
start,
end,
};
}
Loading

0 comments on commit fbff4ce

Please sign in to comment.