Tldraw/scripts/lib/eslint-plugin.ts

107 wiersze
2.8 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-var-requires */
// eslint plugins can't use esm
const { ESLintUtils } =
require('@typescript-eslint/utils') as typeof import('@typescript-eslint/utils')
const { SymbolFlags } = require('typescript') as typeof import('typescript')
exports.rules = {
'no-export-star': ESLintUtils.RuleCreator.withoutDocs({
create(context) {
return {
ExportAllDeclaration(node) {
if (node.exported !== null) {
// we're exporting a specific name, so that's OK!
return
}
// 1. Grab the TypeScript program from parser services
const parserServices = ESLintUtils.getParserServices(context)
const checker = parserServices.program.getTypeChecker()
// 2. Find the backing TS node for the ES node, then the symbol for the imported file
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node)
const importedFileSymbol = checker.getSymbolAtLocation(originalNode.moduleSpecifier!)!
// 3. Find all the imported names from the file
const importedNames = checker.getExportsOfModule(importedFileSymbol).map((imported) => ({
name: imported.getEscapedName(),
isType: !(imported.flags & SymbolFlags.Value),
}))
// report the error and offer a fix (listing imported names)
context.report({
messageId: 'named',
node,
fix: (fixer) => {
return fixer.replaceText(
node,
[
'export {',
...importedNames.map(
(imported) => ` ${imported.isType ? 'type ' : ''}${imported.name},`
),
`} from ${JSON.stringify(node.source.value)};`,
].join('\n')
)
},
})
},
}
},
meta: {
messages: {
named: 'Use specific named exports instead of export *',
},
type: 'suggestion',
schema: [],
fixable: 'code',
},
defaultOptions: [],
}),
'no-internal-imports': ESLintUtils.RuleCreator.withoutDocs({
create(context) {
return {
ImportDeclaration(node) {
const path = node.source.value
const parts = path.split('/')
switch (parts[0]) {
case 'tldraw':
// 'tldraw'
if (parts.length === 1) return
// 'tldraw/**/*.css'
if (path.endsWith('.css')) return
break
case '@tldraw':
// '@tldraw/*'
if (parts.length === 2) return
// '@tldraw/**/*.css'
if (path.endsWith('.css')) return
// '@tldraw/assets/*'
if (parts[1] === 'assets' && parts.length === 3) return
break
default:
return
}
context.report({
messageId: 'internal',
node: node.source,
data: { path },
})
},
}
},
meta: {
messages: {
internal: "Don't import from internal tldraw source ({{path}})",
},
type: 'problem',
schema: [],
},
defaultOptions: [],
}),
}