Skip to content

Commit e42d4bc

Browse files
feat: add filter (#673)
* feat: add filter fix #646 * feat: add rule list * feat: add better example link * feat: add langauge link to badge
1 parent e7c5f99 commit e42d4bc

File tree

6 files changed

+423
-49
lines changed

6 files changed

+423
-49
lines changed

website/_data/catalog.data.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { createContentLoader } from 'vitepress'
2+
3+
interface Rule {
4+
id: string
5+
name: string
6+
type: string
7+
link: string
8+
playgroundLink: string
9+
language: string
10+
hasFix: boolean
11+
rules: string[]
12+
features: string[]
13+
}
14+
15+
declare const data: Rule[]
16+
export { data }
17+
18+
export default createContentLoader('catalog/**/*.md', {
19+
includeSrc: true,
20+
transform(raw): Rule[] {
21+
return raw
22+
.filter(({ url }) => {
23+
return url.endsWith('.html') && !url.includes('rule-template')
24+
})
25+
.map(({ url, src }) => {
26+
const source = src!
27+
const id = url.split('/').pop()?.replace(/\.md$/, '') || ''
28+
const type = source.includes('```yml') || source.includes('```yaml')
29+
? 'YAML' : 'Pattern'
30+
const playgroundLink = /\[Playground Link\]\((.+)\)/.exec(source)?.[1] || ''
31+
const hasFix = source.includes('<Badge') && source.includes('Has Fix')
32+
const language = url.split('/')[2]
33+
const name = source.match(/##\s*([^<\n]+)/)?.[1] || ''
34+
35+
return {
36+
id,
37+
name,
38+
type,
39+
link: url,
40+
playgroundLink,
41+
language,
42+
hasFix,
43+
rules: [],
44+
features: [],
45+
}
46+
})
47+
.sort((a, b) => a.id.localeCompare(b.id))
48+
},
49+
})

website/catalog/index.md

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,52 +5,9 @@ Explore the power of ast-grep with these rewriting rules that can transform your
55

66
Feel free to join our [Discord](https://discord.gg/4YZjf6htSQ) channel and ask @ast-grep-bot to explain the rules for you line by line!
77

8-
* [C](/catalog/c/)
9-
* [Match Function Call](/catalog/c/#match-function-call)
10-
* [Rewrite Method to Function Call](/catalog/c/#rewrite-method-to-function-call)
11-
* [Rewrite Check to Yoda Condition](/catalog/c/#rewrite-check-to-yoda-condition)
12-
* [C++](/catalog/cpp/)
13-
* [Fix Format String Vulnerability](/catalog/cpp/#fix-format-string-vulnerability)
14-
* [Go](/catalog/go/)
15-
* [Match Function Call](/catalog/go/#match-function-call)
16-
* [Find function declarations with names of certain pattern](/catalog/go/#find-function-declarations-with-names-of-certain-pattern)
17-
* [HTML](/catalog/go/)
18-
* [Upgrade Ant Design Vue](/catalog/html/#upgrade-ant-design-vue)
19-
* [Extract i18n Keys](/catalog/html/#extract-i18n-keys)
20-
* [Java](/catalog/java/)
21-
* [No Unused Vars](/catalog/java/#no-unused-vars)
22-
* [Kotlin](/catalog/kotlin/)
23-
* [Ensure Clean Architecture](/catalog/kotlin/#ensure-clean-architecture)
24-
* [Python](/catalog/python/)
25-
* [Migrate OpenAi SDK](/catalog/python/#migrate-openai-sdk)
26-
* [Use Walrus Operator in `if` statement](/catalog/python/#use-walrus-operator-in-if-statement)
27-
* [Prefer Generator Expressions](/catalog/python/#prefer-generator-expressions)
28-
* [Remove `async` function](/catalog/python/#remove-async-function)
29-
* [Rewrite `Optional[Type]` to `Type | None`](/catalog/python/#rewrite-optional-type-to-type-none)
30-
* [Refactor pytest fixtures](/catalog/python/#refactor-pytest-fixtures)
31-
* [Ruby](/catalog/ruby/)
32-
* [Prefer Symbol over Proc](/catalog/ruby/#prefer-symbol-over-proc)
33-
* [Migrate action_filter in Ruby on Rails](/catalog/ruby/#migrate-action-filter-in-ruby-on-rails)
34-
* [Rust](/catalog/rust/)
35-
* [Avoid Duplicated Exports](/catalog/rust/#avoid-duplicated-exports)
36-
* [Get number of digits in a `usize`](/catalog/rust/#get-number-of-digits-in-a-usize)
37-
* [Beware of char offset when iterate over a string](/catalog/rust/#beware-of-char-offset-when-iterate-over-a-string)
38-
* [Rewrite `indoc!` macro](/catalog/rust/#rewrite-indoc-macro)
39-
* [TypeScript](/catalog/typescript/)
40-
* [Repository of ESLint rules 🔗](https://github.com/ast-grep/eslint/)
41-
* [No `await` in `Promise.all`](/catalog/typescript/#no-await-in-promise-all-array)
42-
* [No `console` except in `catch` block](/catalog/typescript/#no-console-except-in-catch-block)
43-
* [Find Import File without Extension](/catalog/typescript/#find-import-file-without-extension)
44-
* [Migrate XState to V5 from V4](/catalog/typescript/#migrate-xstate-to-v5-from-v4)
45-
* [Find Import Usage](/catalog/typescript/#find-import-usage)
46-
* [Switch Chai from `should` style to `expect`](/catalog/typescript/#switch-chai-from-should-style-to-expect)
47-
* [TSX](/catalog/tsx/)
48-
* [Avoid `&&` short circuit in JSX](/catalog/tsx/#avoid-short-circuit-in-jsx)
49-
* [Rewrite MobX Component Style](/catalog/tsx/#rewrite-mobx-component-style)
50-
* [Unnecessary React Hook](/catalog/tsx/#avoid-unnecessary-react-hook)
51-
* [Unnecessary `useState` Type](/catalog/tsx/#unnecessary-usestate-type)
52-
* [Reverse React Compiler™](/catalog/tsx/#reverse-react-compilertm)
53-
* [Avoid nested links](/catalog/tsx/#avoid-nested-links)
54-
* [Rename SVG Attribute](/catalog/tsx/#rename-svg-attribute)
55-
* [YAML](/catalog/yaml/)
56-
* [Find key/value and show message](/catalog/yaml/#find-key-value-and-show-message-using-those-key-vals)
8+
9+
<script setup>
10+
import Catalog from '../src/catalog/index.vue'
11+
</script>
12+
13+
<Catalog/>

website/src/catalog/RuleFilter.vue

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<script setup lang="ts">
2+
import { reactive } from 'vue'
3+
import {
4+
languages,
5+
ruleFilters,
6+
features,
7+
ruleTypes,
8+
} from './data'
9+
10+
const filter = reactive({
11+
selectedLanguages: [] as string[],
12+
selectedRuleFilters: [] as string[],
13+
selectedFeatures: [] as string[],
14+
selectedTypes: [] as string[],
15+
sortBy: 'name',
16+
})
17+
18+
</script>
19+
<template>
20+
<form class="filters">
21+
<details>
22+
<summary>Language Filters</summary>
23+
<div class="checkbox-group">
24+
<label v-for="lang in languages" :key="lang">
25+
<input type="checkbox" v-model="filter.selectedLanguages" :value="lang">
26+
<code class="option">{{ lang }}</code>
27+
</label>
28+
</div>
29+
</details>
30+
31+
<details class="filter-group">
32+
<summary>Rule Filters</summary>
33+
<div class="rule-group">
34+
<div v-for="rules, type in ruleFilters">
35+
<em style="text-transform: capitalize;">{{ type }}</em>
36+
<div class="checkbox-group">
37+
<label v-for="rule in rules" :key="rule">
38+
<input type="checkbox" v-model="filter.selectedRuleFilters" :value="rule">
39+
<code class="option">{{ rule }}</code>
40+
</label>
41+
</div>
42+
</div>
43+
</div>
44+
</details>
45+
46+
<details class="filter-group">
47+
<summary>More Filters</summary>
48+
<div class="rule-group">
49+
<div>
50+
<em>Type</em>
51+
<div class="checkbox-group">
52+
<label v-for="type in ruleTypes" :key="type">
53+
<input type="checkbox" v-model="filter.selectedTypes" :value="type">
54+
<code class="option">{{ type }}</code>
55+
</label>
56+
</div>
57+
</div>
58+
<div>
59+
<em>Features</em>
60+
<div class="checkbox-group">
61+
<label v-for="feature in features" :key="feature">
62+
<input type="checkbox" v-model="filter.selectedFeatures" :value="feature">
63+
<code class="option">{{ feature }}</code>
64+
</label>
65+
</div>
66+
</div>
67+
<div>
68+
<em>Sort By</em>
69+
<div>
70+
<label>
71+
<input value="name" type="radio" v-model="filter.sortBy"/>
72+
Name
73+
</label>
74+
<label>
75+
<input value="complexity" type="radio" v-model="filter.sortBy"/>
76+
Complexity
77+
</label>
78+
</div>
79+
</div>
80+
</div>
81+
</details>
82+
</form>
83+
</template>
84+
85+
<style scoped>
86+
.rule-group {
87+
display: grid;
88+
grid-template-columns: repeat(3, minmax(20%, 1fr));
89+
margin-top: -2px;
90+
}
91+
92+
.checkbox-group {
93+
margin-top: 0.2em;
94+
display: flex;
95+
gap: 5px;
96+
}
97+
98+
label {
99+
display: inline-block;
100+
}
101+
details {
102+
padding-bottom: 5px;
103+
border-radius: 5px;
104+
}
105+
summary {
106+
margin: 0;
107+
padding: 12px 0 6px;
108+
line-height: 24px;
109+
font-size: 18px;
110+
cursor: pointer;
111+
user-select: none;
112+
font-weight: 500;
113+
}
114+
summary:hover {
115+
text-decoration: underline;
116+
text-decoration-style: dashed;
117+
text-decoration-thickness: 1px;
118+
text-underline-offset: 3px;
119+
}
120+
input[type="checkbox"] {
121+
display: none;
122+
}
123+
124+
code.option {
125+
cursor: pointer;
126+
filter: saturate(0);
127+
opacity: 0.8;
128+
user-select: none;
129+
border: 1px solid var(--vp-code-bg);
130+
min-width: 3em;
131+
display: inline-block;
132+
height: 24px;
133+
line-height: 24px;
134+
text-align: center;
135+
padding-top: 0;
136+
}
137+
138+
input[type="checkbox"]:checked + code.option {
139+
filter: saturate(1);
140+
opacity: 1;
141+
border-color: currentColor;
142+
}
143+
144+
@keyframes details-show {
145+
from {
146+
opacity:0;
147+
transform: translateY(-0.5em);
148+
}
149+
}
150+
details[open] > *:not(summary) {
151+
animation: details-show 0.2s ease-in-out;
152+
}
153+
</style>

0 commit comments

Comments
 (0)