# JavaScript/TypeScript Code Style Rules

## JavaScript Version

- ES2020+ features
- Modern async/await
- Optional chaining (`?.`)
- Nullish coalescing (`??`)
- Template literals

## Code Style

### Variable Declarations

```javascript
// ✅ Используй const по умолчанию
const customers = [];
const totalRecords = 0;

// ✅ let только когда нужно переназначение
let currentPage = 1;
currentPage = 2;

// ❌ Не используй var
var oldVariable = 'bad';
```

### Arrow Functions

```javascript
// ✅ Предпочтительно для коротких функций
const filtered = items.filter(item => item.isActive);

// ✅ Для методов объектов
const api = {
  get: async (url) => {
    return await fetch(url);
  }
};

// ✅ Для сложной логики - обычные функции
function complexCalculation(data) {
  // много строк кода
  return result;
}
```

### Template Literals

```javascript
// ✅ Предпочтительно
const message = `User ${userId} not found`;
const url = `${baseUrl}/api/${endpoint}`;

// ❌ Не используй конкатенацию
const message = 'User ' + userId + ' not found';
```

### Optional Chaining

```javascript
// ✅ Используй optional chaining
const name = user?.profile?.name;
const count = data?.items?.length ?? 0;

// ❌ Избегай длинных проверок
const name = user && user.profile && user.profile.name;
```

### Nullish Coalescing

```javascript
// ✅ Используй ?? для значений по умолчанию
const page = params.page ?? 1;
const name = user.name ?? 'Unknown';

// ❌ Не используй || для чисел/булевых
const page = params.page || 1; // 0 будет заменено на 1
```

### Destructuring

```javascript
// ✅ Используй деструктуризацию
const { data, totalRecords } = response.data;
const [first, second] = items;

// ✅ В параметрах функций
function processUser({ id, name, email }) {
  // ...
}

// ✅ С значениями по умолчанию
const { page = 1, limit = 20 } = params;
```

### Async/Await

```javascript
// ✅ Предпочтительно
async function loadCustomers() {
  try {
    const response = await apiGet('getCustomers', params);
    return response.data;
  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

// ❌ Избегай .then() цепочек
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>
// ✅ Используй <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
// ✅ Используй ref для примитивов
const count = ref(0);
const name = ref('');

// ✅ Используй reactive для объектов
import { reactive } from 'vue';
const state = reactive({
  customers: [],
  loading: false
});

// ✅ Или ref для объектов (предпочтительно)
const state = ref({
  customers: [],
  loading: false
});
```

### Computed Properties

```javascript
// ✅ Используй computed для производных значений
const filteredCustomers = computed(() => {
  return customers.value.filter(c => c.isActive);
});

// ❌ Не используй методы для вычислений
function filteredCustomers() {
  return customers.value.filter(c => c.isActive);
}
```

### Props

```vue
<script setup>
// ✅ Определяй props с типами
const props = defineProps({
  customerId: {
    type: Number,
    required: true
  },
  showDetails: {
    type: Boolean,
    default: false
  }
});
</script>
```

### Emits

```vue
<script setup>
// ✅ Определяй emits
const emit = defineEmits(['update', 'delete']);

function handleUpdate() {
  emit('update', data);
}
</script>
```

## Pinia Stores

```javascript
// ✅ Используй 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
// ✅ Всегда обрабатывай ошибки
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('Не удалось загрузить данные');
    throw error;
  }
}
```

## Naming Conventions

### Variables and Functions

```javascript
// ✅ camelCase
const customerData = {};
const totalRecords = 0;
function loadCustomers() {}

// ✅ Константы UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = '/api';
```

### Components

```vue
<!-- ✅ PascalCase для компонентов -->
<CustomerCard />
<ProductsList />
```

### Files

```javascript
// ✅ kebab-case для файлов
// customers-view.vue
// http-utils.js
// customer-service.js
```

## Imports

```javascript
// ✅ Группируй импорты
// 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 (если TypeScript)
import type { Customer } from '@/types';
```

## TypeScript (где используется)

```typescript
// ✅ Используй типы
interface Customer {
  id: number;
  name: string;
  email?: string;
}

function getCustomer(id: number): Promise<Customer> {
  return apiGet(`customers/${id}`);
}
```

