Skip to content

Commit

Permalink
feat(eslint-plugin): allow customize configPath via settings
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed May 10, 2024
1 parent d39a708 commit 9eb6e29
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 28 deletions.
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/index.ts
@@ -1,6 +1,7 @@
import configsRecommended from './configs/recommended'
import configsFlat from './configs/flat'
import { plugin } from './plugin'
import './types'

export default {
...plugin,
Expand Down
6 changes: 6 additions & 0 deletions packages/eslint-plugin/src/rules/blocklist.test.ts
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url'
import * as vueParser from 'vue-eslint-parser'
import { $ as html, run } from 'eslint-vitest-rule-tester'
import rule from './blocklist'
Expand All @@ -8,6 +9,11 @@ run({
languageOptions: {
parser: vueParser,
},
settings: {
unocss: {
configPath: fileURLToPath(new URL('./uno.config.ts', import.meta.url)),
},
},

valid: [
html`
Expand Down
15 changes: 13 additions & 2 deletions packages/eslint-plugin/src/rules/blocklist.ts
Expand Up @@ -25,7 +25,13 @@ export default createRule({
if (typeof node.value !== 'string' || !node.value.trim())
return
const input = node.value
const blocked = syncAction('blocklist', input, context.filename)

const blocked = syncAction(
context.settings.unocss?.configPath,
'blocklist',
input,
context.filename,
)
blocked.forEach(([name, meta]) => {
context.report({
node,
Expand Down Expand Up @@ -69,7 +75,12 @@ export default createRule({
for (const node of valueless) {
if (!node?.key?.name)
continue
const blocked = syncAction('blocklist', node.key.name, context.filename)
const blocked = syncAction(
context.settings.unocss?.configPath,
'blocklist',
node.key.name,
context.filename,
)
blocked.forEach(([name, meta]) => {
context.report({
node,
Expand Down
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url'
import * as vueParser from 'vue-eslint-parser'
import { $ as html, run } from 'eslint-vitest-rule-tester'
import rule from './enforce-class-compile'
Expand All @@ -8,6 +9,11 @@ run({
languageOptions: {
parser: vueParser,
},
settings: {
unocss: {
configPath: fileURLToPath(new URL('./uno.config.ts', import.meta.url)),
},
},

valid: [
html`
Expand Down
6 changes: 5 additions & 1 deletion packages/eslint-plugin/src/rules/order-attributify.ts
Expand Up @@ -32,7 +32,11 @@ export default createRule({
return

const input = valueless.map((i: any) => i.key.name).join(' ').trim()
const sorted = syncAction('sort', input)
const sorted = syncAction(
context.settings.unocss?.configPath,
'sort',
input,
)
if (sorted !== input) {
context.report({
node,
Expand Down
6 changes: 6 additions & 0 deletions packages/eslint-plugin/src/rules/order.test.ts
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url'
import * as vueParser from 'vue-eslint-parser'
import { $ as html, run } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'
Expand All @@ -9,6 +10,11 @@ run({
languageOptions: {
parser: vueParser,
},
settings: {
unocss: {
configPath: fileURLToPath(new URL('./uno.config.ts', import.meta.url)),
},
},

valid: [
html`
Expand Down
6 changes: 5 additions & 1 deletion packages/eslint-plugin/src/rules/order.ts
Expand Up @@ -24,7 +24,11 @@ export default createRule({
if (typeof node.value !== 'string' || !node.value.trim())
return
const input = node.value
const sorted = syncAction('sort', input).trim()
const sorted = syncAction(
context.settings.unocss?.configPath,
'sort',
input,
).trim()
if (sorted !== input) {
context.report({
node,
Expand Down
File renamed without changes.
17 changes: 17 additions & 0 deletions packages/eslint-plugin/src/types.ts
@@ -0,0 +1,17 @@
declare module 'eslint' {
interface SharedConfigurationSettings {
unocss?: {
configPath?: string
}
}
}

declare module '@typescript-eslint/utils/ts-eslint' {
interface SharedConfigurationSettings {
unocss?: {
configPath?: string
}
}
}

export {}
47 changes: 27 additions & 20 deletions packages/eslint-plugin/src/worker.ts
Expand Up @@ -5,13 +5,16 @@ import { createGenerator } from '@unocss/core'
import { runAsWorker } from 'synckit'
import { sortRules } from '../../shared-integration/src/sort-rules'

let promise: Promise<UnoGenerator<any>> | undefined
const promises = new Map<string | undefined, Promise<UnoGenerator<any>> | undefined>()

// bypass icon rules in ESLint
process.env.ESLINT ||= 'true'

async function _getGenerator() {
const { config, sources } = await loadConfig()
async function _getGenerator(configPath?: string) {
const { config, sources } = await loadConfig(
process.cwd(),
configPath,
)
if (!sources.length)
throw new Error('[@unocss/eslint-plugin] No config file found, create a `uno.config.ts` file in your project root and try again.')
return createGenerator({
Expand All @@ -20,21 +23,25 @@ async function _getGenerator() {
})
}

export async function getGenerator() {
promise = promise || _getGenerator()
export async function getGenerator(configPath?: string) {
let promise = promises.get(configPath)
if (!promise) {
promise = _getGenerator(configPath)
promises.set(configPath, promise)
}
return await promise
}

export function setGenerator(generator: Awaited<UnoGenerator<any>>) {
promise = Promise.resolve(generator)
export function setGenerator(generator: Awaited<UnoGenerator<any>>, configPath?: string | undefined) {
promises.set(configPath, Promise.resolve(generator))
}

async function actionSort(classes: string) {
return await sortRules(classes, await getGenerator())
async function actionSort(configPath: string | undefined, classes: string) {
return await sortRules(classes, await getGenerator(configPath))
}

async function actionBlocklist(classes: string, id?: string) {
const uno = await getGenerator()
async function actionBlocklist(configPath: string | undefined, classes: string, id?: string): Promise<[string, BlocklistMeta | undefined][]> {
const uno = await getGenerator(configPath)
const blocked = new Map<string, BlocklistMeta | undefined>()

const extracted = await uno.applyExtractors(classes, id)
Expand Down Expand Up @@ -62,24 +69,24 @@ async function actionBlocklist(classes: string, id?: string) {
return [...blocked]
}

export function runAsync(action: 'sort', classes: string): Promise<string>
export function runAsync(action: 'blocklist', classes: string, id?: string): Promise<string[]>
export async function runAsync(action: string, ...args: any[]): Promise<any> {
export function runAsync(configPath: string | undefined, action: 'sort', classes: string): Promise<string>
export function runAsync(configPath: string | undefined, action: 'blocklist', classes: string, id?: string): Promise<[string, BlocklistMeta | undefined][]>
export async function runAsync(configPath: string | undefined, action: string, ...args: any[]): Promise<any> {
switch (action) {
case 'sort':
// @ts-expect-error cast
return actionSort(...args)
return actionSort(configPath, ...args)
case 'blocklist':
// @ts-expect-error cast
return actionBlocklist(...args)
return actionBlocklist(configPath, ...args)
}
}

export function run(action: 'sort', classes: string): string
export function run(action: 'blocklist', classes: string, id?: string): [string, BlocklistMeta | undefined][]
export function run(action: string, ...args: any[]): any {
export function run(configPath: string | undefined, action: 'sort', classes: string): string
export function run(configPath: string | undefined, action: 'blocklist', classes: string, id?: string): [string, BlocklistMeta | undefined][]
export function run(configPath: string | undefined, action: string, ...args: any[]): any {
// @ts-expect-error cast
return runAsync(action, ...args)
return runAsync(configPath, action, ...args)
}

runAsWorker(run as any)
2 changes: 2 additions & 0 deletions test/__snapshots__/postcss.test.ts.snap
Expand Up @@ -2,6 +2,8 @@

exports[`postcss > @apply > basic 1`] = `"div{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}.dark div>:focus:hover{font-size:20px;}div:hover{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity));}"`;

exports[`postcss > @apply > media 1`] = `"div{}@media (min-width: 640px){div{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}}@media (min-width: 768px){div{--un-bg-opacity:1;background-color:rgb(96 165 250 / var(--un-bg-opacity));}}@media (min-width: 1024px){div{--un-bg-opacity:1;background-color:rgb(244 114 182 / var(--un-bg-opacity));}}@media (min-width: 1280px){div{--un-bg-opacity:1;background-color:rgb(255 255 255 / var(--un-bg-opacity));}}"`;

exports[`postcss > @screen 1`] = `
"@media (min-width: 768px) and (max-width: 1023.9px) {
div{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}
Expand Down
8 changes: 4 additions & 4 deletions test/eslint-plugin-worker.test.ts
Expand Up @@ -15,8 +15,8 @@ describe('worker', () => {
i => i.includes('green'),
],
})
setGenerator(uno)
const rs = await runAsync('blocklist', 'block !block w-3px bg-green-500 text-red-500')
setGenerator(uno, undefined)
const rs = await runAsync(undefined, 'blocklist', 'block !block w-3px bg-green-500 text-red-500')
expect(rs).toEqual([
['block', undefined],
['bg-green-500', undefined],
Expand All @@ -30,8 +30,8 @@ describe('worker', () => {
presetUno(),
],
})
setGenerator(uno)
const rs = await runAsync('sort', 'text-red-300 w-8')
setGenerator(uno, undefined)
const rs = await runAsync(undefined, 'sort', 'text-red-300 w-8')
expect(rs).toMatchInlineSnapshot(`"w-8 text-red-300"`)
})
})

0 comments on commit 9eb6e29

Please sign in to comment.