Files
interview-demo-code/.cursor/rules/javascript.md
Nikita Kiselev 0e48b9d56d
Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
Squashed commit message
2026-03-11 22:17:44 +03:00

6.6 KiB
Raw Blame History

JavaScript/TypeScript Code Style Rules

JavaScript Version

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

Code Style

Variable Declarations

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

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

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

Arrow Functions

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

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

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

Template Literals

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

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

Optional Chaining

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

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

Nullish Coalescing

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

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

Destructuring

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

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

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

Async/Await

// ✅ Предпочтительно
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

<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

// ✅ Используй 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

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

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

Props

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

Emits

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

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

Pinia Stores

// ✅ Используй 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

// ✅ Всегда обрабатывай ошибки
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

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

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

Components

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

Files

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

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 (если TypeScript)
import type { Customer } from '@/types';

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

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

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