Skip to content

Commit

Permalink
feat: new command no-x-above
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Nov 27, 2024
1 parent 10cb238 commit e0a7037
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { keepSorted } from './keep-sorted'
import { keepUnique } from './keep-unique'
import { noShorthand } from './no-shorthand'
import { noType } from './no-type'
import { noXAbove } from './no-x-above'
import { regex101 } from './regex101'
import { toArrow } from './to-arrow'
import { toDestructuring } from './to-destructuring'
Expand All @@ -24,6 +25,7 @@ export {
keepUnique,
noShorthand,
noType,
noXAbove,
regex101,
toArrow,
toDestructuring,
Expand All @@ -45,6 +47,7 @@ export const builtinCommands = [
keepUnique,
noShorthand,
noType,
noXAbove,
regex101,
toArrow,
toDestructuring,
Expand Down
30 changes: 30 additions & 0 deletions src/commands/no-x-above.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# `no-x-above`

Disallow certain syntaxes above or below the comment, with in the current block.

## Triggers

- `// @no-await-above` - Disallow `await` above the comment.
- `// @no-await-below` - Disallow `await` below the comment.

## Examples

```js
const foo = syncOp()
const bar = await asyncOp() // <-- this is not allowed
// @no-await-above
const baz = await asyncOp() // <-- this is ok
```

The effect will only affect the current scope, for example:

```js
console.log(await foo()) // <-- this is not checked, as it's not in the function scope where the comment is

async function foo() {
const bar = syncOp()
const baz = await asyncOp() // <-- this is not allowed
// @no-await-above
const qux = await asyncOp() // <-- this is ok
}
```
44 changes: 44 additions & 0 deletions src/commands/no-x-above.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { $, run } from './_test-utils'
import { noXAbove as command } from './no-x-above'

run(
command,
// {
// code: $`
// /// no-await-below
// const obj = await foo()
// `,
// errors: ['command-error'],
// },
// $`
// const obj = await foo()
// /// no-await-below
// const obj = foo()
// `,
// {
// code: $`
// const obj = await foo()
// /// no-await-above
// const obj = foo()
// `,
// errors: ['command-fix'],
// },
// // Don't count outside of scope
// $`
// await foo()
// async function foo() {
// /// no-await-above
// const obj = await Promise.all([])
// }
// `,
// Don't count inside
$`
async function foo() {
/// no-await-below
console.log('foo')
const bar = async () => {
const obj = await Promise.all([])
}
}
`,
)
56 changes: 56 additions & 0 deletions src/commands/no-x-above.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Command } from '../types'

const types = [
'await',

// TODO: implement
// 'statements',
// 'functions',
] as const

export const noXAbove: Command = {
name: 'no-x-above',
match: new RegExp(`^\\s*[/:@]\\s*no-(${types.join('|')})-(above|below)$`),
action(ctx) {
const type = ctx.matches[1] as (typeof types)[number]
const direction = ctx.matches[2] as 'above' | 'below'

const node = ctx.findNodeBelow(() => true)
const parent = node?.parent
if (!parent)
return ctx.reportError('No parent node found')

if (parent.type !== 'Program' && parent.type !== 'BlockStatement')
return ctx.reportError('Parent node is not a block')

const children = parent.body

const targetNodes = direction === 'above'
? children.filter(c => c.range[1] <= ctx.comment.range[0])
: children.filter(c => c.range[0] >= ctx.comment.range[1])

if (!targetNodes.length)
return

switch (type) {
case 'await':
for (const target of targetNodes) {
ctx.traverse(target, (path, { SKIP }) => {
if (path.node.type === 'FunctionDeclaration' || path.node.type === 'FunctionExpression' || path.node.type === 'ArrowFunctionExpression') {
return SKIP
}
if (path.node.type === 'AwaitExpression') {
ctx.report({
node: path.node,
message: 'Disallowed await expression',
})
}
})
}
return
default:
return ctx.reportError(`Unknown type: ${type}`)
}
// console.log({ targetRange: targetNodes })
},
}

0 comments on commit e0a7037

Please sign in to comment.