25d895d 🐛 fix(gitea_workflow): clean up temp repos after job steps 2bc3b11 🐛 fix(gitea_workflow): clean up temporary repo dirs in workflows 98c3f30 📝 docs(agent_rules): allow plan execution on current branch 16c7230 📝 docs(prompts): define custom verify layering 8efc4dd 🐛 fix(skills): quote commit-message description bc8498f 🐛 fix(ci): install tomli for gitea tests 55cda3b 🐛 fix(tests): report missing toml parser clearly c0729c7 🐛 fix(playbook): import Optional for cli compatibility 63e24bf 📦 deps(skills): sync thirdparty skills d2f9356 🐛 fix(ci): isolate gitea workflow repos 588b81d 🐛 fix(ci): inline gitea workflow bootstrap e0b1c3a ♻️ refactor(skills): standardize first-party skill contracts 2c5050d ♻️ refactor(skills): rename repo skills source dir f049dfb 📦 deps(skills): drop duplicate first-party superpowers skills 234b335 ✨ feat(workflow): add superpowers planning and execution state tracking c1702a6 📝 docs(markdown): format tracked markdown and drop stale templates 2325409 📝 docs(markdown): clarify optional markdownlint usage 214c44e 🔧 chore(markdown): add markdownlint baseline and lint fixes a22b324 📝 docs(templates): add execution and memory-bank prompt templates 223a797 📝 docs(templates): update README for Claude Code and current features 4ac8672 📝 docs: simplify README + platform-agnostic tools + auto-create local rules 2431c9d 📝 docs: add claude_md config and use cross-platform paths d64b248 📝 docs: fix README.md inaccuracies and add Claude Code info c8d6bf2 🐛 fix(playbook): use relative paths in CLAUDE.md when not at project root 6518f0f ✨ feat(playbook): auto-create CLAUDE.md with path discovery 6ec9a45 ✨ feat(skills): add skill_link symlink support + platform-agnostic prompt 9f8b6b5 📝 docs: update README and config example for Claude Code support 79cff6c 📝 docs(skills): add Claude Code platform support 452c6f5 ✨ feat(playbook): auto-inject AGENTS.md into CLAUDE.md e1dbf3c 🐛 fix(skills): remove dual-path from commit-message skill f3a7259 🔧 chore(ci): use prepare_repo.sh in both workflows da08212 🔧 chore(ci): extract prepare_repo.sh and clean up workflows 7ade85e 🗑️ remove(tsl): drop syntax_book/, data/ source and build script f94dba0 ♻️ refactor(skills): update playbook.py and tests for thirdparty/ layout b3df412 ♻️ refactor(skills): separate thirdparty skills into thirdparty/ subdirectory 64950e7 📦 deps(skills): sync thirdparty skills a2e3cb0 ✨ feat(playbook): add no_backup deploy controls 8609d59 🐛 fix(docs): repair reference catalog source links 956da11 🐛 fix(playbook): publish hidden ci test fixes 3f67754 📦 deps(skills): sync thirdparty skills 08ca87b 📦 deps(skills): add karpathy thirdparty sync 96b705b 📝 docs(tsl): rebuild canonical syntax and routing manual 3ed5052 📦 deps(skills): sync thirdparty skills 60108dd 📦 deps(skills): sync thirdparty skills da85d4e 🐛 fix(thirdparty): prune nested project snapshots a2a697e 📦 deps(skills): sync thirdparty skills 9df610a 🐛 fix(thirdparty): exclude duplicated superpowers skills 33dd5bb 🐛 fix(thirdparty): preserve optional manifest fields 91b0ea7 🐛 fix(thirdparty): preserve manifest during snapshot update 2e26f98 🔧 chore(thirdparty): generalize skills sync pipeline 5b9c1e3 📦 deps(skills): sync superpowers 2f2d34a 📝 docs(readme): normalize subtree command spacing 62db7db 🐛 fix(ci): serialize superpowers update and sync 3463223 🐛 fix(ci): use literal superpowers sync paths 48f6de8 📦 deps(skills): sync superpowers 4b23529 🔧 chore(ci): merge superpowers update and sync workflow a56d75b 📦 deps(skills): sync superpowers 84bcefa 🔧 chore(ci): use ci[bot] commit author name 00a07e5 📦 deps(skills): sync superpowers 7b84daf 🐛 fix(templates): enforce main loop progress tracking 51373d7 🔧 chore(ci): automate superpowers sync workflow eaaa39c 🐛 fix(ci): prevent stale superpowers sync from restoring skills block 79755c6 📦 deps(skills): sync superpowers 836d878 📦 deps(skills): sync superpowers 8216c9f 📦 deps(skills): sync superpowers 9439505 🐛 fix(playbook): address reported repo issues git-subtree-dir: docs/standards/playbook git-subtree-split: 25d895d8b3f56624ccfe99ad7289e9eb49e0f316
11 KiB
11 KiB
| 1 | No | Category | Guideline | Description | Do | Don't | Code Good | Code Bad | Severity | Docs URL |
|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 1 | Composition | Use Composition API for new projects | Composition API offers better TypeScript support and logic reuse | <script setup> for components | Options API for new projects | <script setup> | export default { data() } | Medium | https://vuejs.org/guide/extras/composition-api-faq.html |
| 3 | 2 | Composition | Use script setup syntax | Cleaner syntax with automatic exports | <script setup> with defineProps | setup() function manually | <script setup> | <script> setup() { return {} } | Low | https://vuejs.org/api/sfc-script-setup.html |
| 4 | 3 | Reactivity | Use ref for primitives | ref() for primitive values that need reactivity | ref() for strings numbers booleans | reactive() for primitives | const count = ref(0) | const count = reactive(0) | Medium | https://vuejs.org/guide/essentials/reactivity-fundamentals.html |
| 5 | 4 | Reactivity | Use reactive for objects | reactive() for complex objects and arrays | reactive() for objects with multiple properties | ref() for complex objects | const state = reactive({ user: null }) | const state = ref({ user: null }) | Medium | |
| 6 | 5 | Reactivity | Access ref values with .value | Remember .value in script unwrap in template | Use .value in script | Forget .value in script | count.value++ | count++ (in script) | High | |
| 7 | 6 | Reactivity | Use computed for derived state | Computed properties cache and update automatically | computed() for derived values | Methods for derived values | const doubled = computed(() => count.value * 2) | const doubled = () => count.value * 2 | Medium | https://vuejs.org/guide/essentials/computed.html |
| 8 | 7 | Reactivity | Use shallowRef for large objects | Avoid deep reactivity for performance | shallowRef for large data structures | ref for large nested objects | const bigData = shallowRef(largeObject) | const bigData = ref(largeObject) | Medium | https://vuejs.org/api/reactivity-advanced.html#shallowref |
| 9 | 8 | Watchers | Use watchEffect for simple cases | Auto-tracks dependencies | watchEffect for simple reactive effects | watch with explicit deps when not needed | watchEffect(() => console.log(count.value)) | watch(count, (val) => console.log(val)) | Low | https://vuejs.org/guide/essentials/watchers.html |
| 10 | 9 | Watchers | Use watch for specific sources | Explicit control over what to watch | watch with specific refs | watchEffect for complex conditional logic | watch(userId, fetchUser) | watchEffect with conditionals | Medium | |
| 11 | 10 | Watchers | Clean up side effects | Return cleanup function in watchers | Return cleanup in watchEffect | Leave subscriptions open | watchEffect((onCleanup) => { onCleanup(unsub) }) | watchEffect without cleanup | High | |
| 12 | 11 | Props | Define props with defineProps | Type-safe prop definitions | defineProps with TypeScript | Props without types | defineProps<{ msg: string }>() | defineProps(['msg']) | Medium | https://vuejs.org/guide/typescript/composition-api.html#typing-component-props |
| 13 | 12 | Props | Use withDefaults for default values | Provide defaults for optional props | withDefaults with defineProps | Defaults in destructuring | withDefaults(defineProps<Props>(), { count: 0 }) | const { count = 0 } = defineProps() | Medium | |
| 14 | 13 | Props | Avoid mutating props | Props should be read-only | Emit events to parent for changes | Direct prop mutation | emit('update:modelValue', newVal) | props.modelValue = newVal | High | |
| 15 | 14 | Emits | Define emits with defineEmits | Type-safe event emissions | defineEmits with types | Emit without definition | defineEmits<{ change: [id: number] }>() | emit('change', id) without define | Medium | https://vuejs.org/guide/typescript/composition-api.html#typing-component-emits |
| 16 | 15 | Emits | Use v-model for two-way binding | Simplified parent-child data flow | v-model with modelValue prop | :value + @input manually | <Child v-model="value"/> | <Child :value="value" @input="value = $event"/> | Low | https://vuejs.org/guide/components/v-model.html |
| 17 | 16 | Lifecycle | Use onMounted for DOM access | DOM is ready in onMounted | onMounted for DOM operations | Access DOM in setup directly | onMounted(() => el.value.focus()) | el.value.focus() in setup | High | https://vuejs.org/api/composition-api-lifecycle.html |
| 18 | 17 | Lifecycle | Clean up in onUnmounted | Remove listeners and subscriptions | onUnmounted for cleanup | Leave listeners attached | onUnmounted(() => window.removeEventListener()) | No cleanup on unmount | High | |
| 19 | 18 | Lifecycle | Avoid onBeforeMount for data | Use onMounted or setup for data fetching | Fetch in onMounted or setup | Fetch in onBeforeMount | onMounted(async () => await fetchData()) | onBeforeMount(async () => await fetchData()) | Low | |
| 20 | 19 | Components | Use single-file components | Keep template script style together | .vue files for components | Separate template/script files | Component.vue with all parts | Component.js + Component.html | Low | |
| 21 | 20 | Components | Use PascalCase for components | Consistent component naming | PascalCase in imports and templates | kebab-case in script | <MyComponent/> | <my-component/> | Low | https://vuejs.org/style-guide/rules-strongly-recommended.html |
| 22 | 21 | Components | Prefer composition over mixins | Composables replace mixins | Composables for shared logic | Mixins for code reuse | const { data } = useApi() | mixins: [apiMixin] | Medium | |
| 23 | 22 | Composables | Name composables with use prefix | Convention for composable functions | useFetch useAuth useForm | getData or fetchApi | export function useFetch() | export function fetchData() | Medium | https://vuejs.org/guide/reusability/composables.html |
| 24 | 23 | Composables | Return refs from composables | Maintain reactivity when destructuring | Return ref values | Return reactive objects that lose reactivity | return { data: ref(null) } | return reactive({ data: null }) | Medium | |
| 25 | 24 | Composables | Accept ref or value params | Use toValue for flexible inputs | toValue() or unref() for params | Only accept ref or only value | const val = toValue(maybeRef) | const val = maybeRef.value | Low | https://vuejs.org/api/reactivity-utilities.html#tovalue |
| 26 | 25 | Templates | Use v-bind shorthand | Cleaner template syntax | :prop instead of v-bind:prop | Full v-bind syntax | <div :class="cls"> | <div v-bind:class="cls"> | Low | |
| 27 | 26 | Templates | Use v-on shorthand | Cleaner event binding | @event instead of v-on:event | Full v-on syntax | <button @click="handler"> | <button v-on:click="handler"> | Low | |
| 28 | 27 | Templates | Avoid v-if with v-for | v-if has higher priority causes issues | Wrap in template or computed filter | v-if on same element as v-for | <template v-for><div v-if> | <div v-for v-if> | High | https://vuejs.org/style-guide/rules-essential.html#avoid-v-if-with-v-for |
| 29 | 28 | Templates | Use key with v-for | Proper list rendering and updates | Unique key for each item | Index as key for dynamic lists | v-for="item in items" :key="item.id" | v-for="(item, i) in items" :key="i" | High | |
| 30 | 29 | State | Use Pinia for global state | Official state management for Vue 3 | Pinia stores for shared state | Vuex for new projects | const store = useCounterStore() | Vuex with mutations | Medium | https://pinia.vuejs.org/ |
| 31 | 30 | State | Define stores with defineStore | Composition API style stores | Setup stores with defineStore | Options stores for complex state | defineStore('counter', () => {}) | defineStore('counter', { state }) | Low | |
| 32 | 31 | State | Use storeToRefs for destructuring | Maintain reactivity when destructuring | storeToRefs(store) | Direct destructuring | const { count } = storeToRefs(store) | const { count } = store | High | https://pinia.vuejs.org/core-concepts/#destructuring-from-a-store |
| 33 | 32 | Routing | Use useRouter and useRoute | Composition API router access | useRouter() useRoute() in setup | this.$router this.$route | const router = useRouter() | this.$router.push() | Medium | https://router.vuejs.org/guide/advanced/composition-api.html |
| 34 | 33 | Routing | Lazy load route components | Code splitting for routes | () => import() for components | Static imports for all routes | component: () => import('./Page.vue') | component: Page | Medium | https://router.vuejs.org/guide/advanced/lazy-loading.html |
| 35 | 34 | Routing | Use navigation guards | Protect routes and handle redirects | beforeEach for auth checks | Check auth in each component | router.beforeEach((to) => {}) | Check auth in onMounted | Medium | |
| 36 | 35 | Performance | Use v-once for static content | Skip re-renders for static elements | v-once on never-changing content | v-once on dynamic content | <div v-once>{{ staticText }}</div> | <div v-once>{{ dynamicText }}</div> | Low | https://vuejs.org/api/built-in-directives.html#v-once |
| 37 | 36 | Performance | Use v-memo for expensive lists | Memoize list items | v-memo with dependency array | Re-render entire list always | <div v-for v-memo="[item.id]"> | <div v-for> without memo | Medium | https://vuejs.org/api/built-in-directives.html#v-memo |
| 38 | 37 | Performance | Use shallowReactive for flat objects | Avoid deep reactivity overhead | shallowReactive for flat state | reactive for simple objects | shallowReactive({ count: 0 }) | reactive({ count: 0 }) | Low | |
| 39 | 38 | Performance | Use defineAsyncComponent | Lazy load heavy components | defineAsyncComponent for modals dialogs | Import all components eagerly | defineAsyncComponent(() => import()) | import HeavyComponent from | Medium | https://vuejs.org/guide/components/async.html |
| 40 | 39 | TypeScript | Use generic components | Type-safe reusable components | Generic with defineComponent | Any types in components | <script setup lang="ts" generic="T"> | <script setup> without types | Medium | https://vuejs.org/guide/typescript/composition-api.html |
| 41 | 40 | TypeScript | Type template refs | Proper typing for DOM refs | ref<HTMLInputElement>(null) | ref(null) without type | const input = ref<HTMLInputElement>(null) | const input = ref(null) | Medium | |
| 42 | 41 | TypeScript | Use PropType for complex props | Type complex prop types | PropType<User> for object props | Object without type | type: Object as PropType<User> | type: Object | Medium | |
| 43 | 42 | Testing | Use Vue Test Utils | Official testing library | mount shallowMount for components | Manual DOM testing | import { mount } from '@vue/test-utils' | document.createElement | Medium | https://test-utils.vuejs.org/ |
| 44 | 43 | Testing | Test component behavior | Focus on inputs and outputs | Test props emit and rendered output | Test internal implementation | expect(wrapper.text()).toContain() | expect(wrapper.vm.internalState) | Medium | |
| 45 | 44 | Forms | Use v-model modifiers | Built-in input handling | .lazy .number .trim modifiers | Manual input parsing | <input v-model.number="age"> | <input v-model="age"> then parse | Low | https://vuejs.org/guide/essentials/forms.html#modifiers |
| 46 | 45 | Forms | Use VeeValidate or FormKit | Form validation libraries | VeeValidate for complex forms | Manual validation logic | useField useForm from vee-validate | Custom validation in each input | Medium | |
| 47 | 46 | Accessibility | Use semantic elements | Proper HTML elements in templates | button nav main for purpose | div for everything | <button @click> | <div @click> | High | |
| 48 | 47 | Accessibility | Bind aria attributes dynamically | Keep ARIA in sync with state | :aria-expanded="isOpen" | Static ARIA values | :aria-expanded="menuOpen" | aria-expanded="true" | Medium | |
| 49 | 48 | SSR | Use Nuxt for SSR | Full-featured SSR framework | Nuxt 3 for SSR apps | Manual SSR setup | npx nuxi init my-app | Custom SSR configuration | Medium | https://nuxt.com/ |
| 50 | 49 | SSR | Handle hydration mismatches | Client/server content must match | ClientOnly for browser-only content | Different content server/client | <ClientOnly><BrowserWidget/></ClientOnly> | <div>{{ Date.now() }}</div> | High |