Files
interview-demo-code/.cursor/rules/javascript.md
Nikita Kiselev 3cc82e45f0
Some checks are pending
Telegram Mini App Shop Builder / Compute version metadata (push) Waiting to run
Telegram Mini App Shop Builder / Run Frontend tests (push) Waiting to run
Telegram Mini App Shop Builder / Run Backend tests (push) Waiting to run
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Waiting to run
Telegram Mini App Shop Builder / Build module. (push) Blocked by required conditions
Telegram Mini App Shop Builder / release (push) Blocked by required conditions
Squashed commit message
2026-03-11 23:02:54 +03:00

333 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# JavaScript/TypeScript Code Style Rules
## JavaScript Version
- ES2020+ features
- Modern async/await
- Optional chaining (`?.`)
- Nullish coalescing (`??`)
- Template literals
## Code Style
### Variable Declarations
```javascript
// ✅ Use const by default
const customers = [];
const totalRecords = 0;
// ✅ Use let only when reassignment is needed
let currentPage = 1;
currentPage = 2;
// ❌ Do not use var
var oldVariable = 'bad';
```
### Arrow Functions
```javascript
// ✅ Preferred for short functions
const filtered = items.filter(item => item.isActive);
// ✅ For object methods
const api = {
get: async (url) => {
return await fetch(url);
}
};
// ✅ For complex logic use regular functions
function complexCalculation(data) {
// many lines of code
return result;
}
```
### Template Literals
```javascript
// ✅ Preferred
const message = `User ${userId} not found`;
const url = `${baseUrl}/api/${endpoint}`;
// ❌ Do not use concatenation
const message = 'User ' + userId + ' not found';
```
### Optional Chaining
```javascript
// ✅ Use optional chaining
const name = user?.profile?.name;
const count = data?.items?.length ?? 0;
// ❌ Avoid long nested checks
const name = user && user.profile && user.profile.name;
```
### Nullish Coalescing
```javascript
// ✅ Use ?? for default values
const page = params.page ?? 1;
const name = user.name ?? 'Unknown';
// ❌ Do not use || for numbers/booleans
const page = params.page || 1; // 0 will be replaced with 1
```
### Destructuring
```javascript
// ✅ Use destructuring
const { data, totalRecords } = response.data;
const [first, second] = items;
// ✅ In function parameters
function processUser({ id, name, email }) {
// ...
}
// ✅ With default values
const { page = 1, limit = 20 } = params;
```
### Async/Await
```javascript
// ✅ Preferred
async function loadCustomers() {
try {
const response = await apiGet('getCustomers', params);
return response.data;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// ❌ Avoid .then() chains
function loadCustomers() {
return apiGet('getCustomers', params)
.then(response => response.data)
.catch(error => console.error(error));
}
```
## Vue.js 3 Composition API
### Script Setup
```vue
<script setup>
// ✅ Use <script setup>
import { ref, computed, onMounted } from 'vue';
import { apiGet } from '@/utils/http.js';
const customers = ref([]);
const loading = ref(false);
const totalRecords = computed(() => customers.value.length);
async function loadCustomers() {
loading.value = true;
try {
const result = await apiGet('getCustomers');
customers.value = result.data || [];
} finally {
loading.value = false;
}
}
onMounted(() => {
loadCustomers();
});
</script>
```
### Reactive State
```javascript
// ✅ Use ref for primitives
const count = ref(0);
const name = ref('');
// ✅ Use reactive for objects
import { reactive } from 'vue';
const state = reactive({
customers: [],
loading: false
});
// ✅ Or ref for objects (preferred)
const state = ref({
customers: [],
loading: false
});
```
### Computed Properties
```javascript
// ✅ Use computed for derived values
const filteredCustomers = computed(() => {
return customers.value.filter(c => c.isActive);
});
// ❌ Do not use methods for derived values
function filteredCustomers() {
return customers.value.filter(c => c.isActive);
}
```
### Props
```vue
<script setup>
// ✅ Define props with types
const props = defineProps({
customerId: {
type: Number,
required: true
},
showDetails: {
type: Boolean,
default: false
}
});
</script>
```
### Emits
```vue
<script setup>
// ✅ Define emits
const emit = defineEmits(['update', 'delete']);
function handleUpdate() {
emit('update', data);
}
</script>
```
## Pinia Stores
```javascript
// ✅ Use setup stores
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCustomersStore = defineStore('customers', () => {
const customers = ref([]);
const loading = ref(false);
const totalRecords = computed(() => customers.value.length);
async function loadCustomers() {
loading.value = true;
try {
const result = await apiGet('getCustomers');
customers.value = result.data || [];
} finally {
loading.value = false;
}
}
return {
customers,
loading,
totalRecords,
loadCustomers
};
});
```
## Error Handling
```javascript
// ✅ Always handle errors
async function loadData() {
try {
const result = await apiGet('endpoint');
if (result.success) {
return result.data;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Failed to load data:', error);
toast.error('Failed to load data');
throw error;
}
}
```
## Naming Conventions
### Variables and Functions
```javascript
// ✅ camelCase
const customerData = {};
const totalRecords = 0;
function loadCustomers() {}
// ✅ Constants in UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = '/api';
```
### Components
```vue
<!-- PascalCase for components -->
<CustomerCard />
<ProductsList />
```
### Files
```javascript
// ✅ Use kebab-case for files
// customers-view.vue
// http-utils.js
// customer-service.js
```
## Imports
```javascript
// ✅ Group imports
// 1. Vue core
import { ref, computed, onMounted } from 'vue';
// 2. Third-party
import { apiGet } from '@/utils/http.js';
import { useToast } from 'primevue';
// 3. Local components
import CustomerCard from '@/components/CustomerCard.vue';
// 4. Types (if using TypeScript)
import type { Customer } from '@/types';
```
## TypeScript (where used)
```typescript
// ✅ Use types
interface Customer {
id: number;
name: string;
email?: string;
}
function getCustomer(id: number): Promise<Customer> {
return apiGet(`customers/${id}`);
}
```