chrome-devtools-frontend
Version:
Chrome DevTools UI
86 lines (78 loc) • 2.73 kB
text/typescript
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type {TSESLint, TSESTree} from '@typescript-eslint/utils';
import {createRule} from './utils/ruleCreator.ts';
type ImportDeclaration = TSESTree.ImportDeclaration;
type RuleFix = TSESLint.RuleFix;
export default createRule({
name: 'html-tagged-template',
meta: {
type: 'problem',
docs: {
description: 'Usage of Lit.html',
category: 'Possible Errors',
},
messages: {
useUnqualifiedHtmlTaggedTemplate: 'Use unqualified html tagged template for compatibility with lit-analyzer',
},
fixable: 'code',
schema: [], // no options
},
defaultOptions: [],
create: function(context) {
const sourceCode = context.sourceCode ?? context.getSourceCode();
let lastImport: ImportDeclaration|null = null;
let shorthandDefined = false;
return {
ImportDeclaration(node) {
lastImport = node;
},
VariableDeclarator(node) {
const scope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope();
if (scope.type !== 'module') {
return;
}
if (node.id.type === 'Identifier' && node.id.name === 'html') {
shorthandDefined = true;
}
if (node.id.type !== 'ObjectPattern') {
return;
}
for (const property of node.id.properties || []) {
if (property.type === 'Property' && property.key.type === 'Identifier' && property.key.name === 'html') {
shorthandDefined = true;
}
}
},
TaggedTemplateExpression(node) {
const tag = node.tag;
if (tag.type === 'MemberExpression' && tag.object.type === 'Identifier' && tag.object.name === 'Lit' &&
tag.property.type === 'Identifier' && tag.property.name === 'html') {
context.report({
node,
messageId: 'useUnqualifiedHtmlTaggedTemplate',
fix(fixer) {
const result: RuleFix[] = [];
if (tag.object?.range?.[0] && tag.property?.range?.[0]) {
result.push(
fixer.removeRange([
tag.object.range[0],
tag.property.range[0],
]),
);
}
if (lastImport && !shorthandDefined) {
result.push(
fixer.insertTextAfter(lastImport, '\n\nconst {html} = Lit;'),
);
shorthandDefined = true;
}
return result;
},
});
}
},
};
},
});