2023-04-25 11:01:25 +00:00
|
|
|
/* 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: [],
|
|
|
|
}),
|
2024-04-24 14:36:08 +00:00
|
|
|
'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: [],
|
|
|
|
}),
|
2023-04-25 11:01:25 +00:00
|
|
|
}
|