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
5.8 KiB
5.8 KiB
JavaScript/TypeScript Code Style Rules
JavaScript Version
- ES2020+ features
- Modern async/await
- Optional chaining (
?.) - Nullish coalescing (
??) - Template literals
Code Style
Variable Declarations
// ✅ 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
// ✅ 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
// ✅ Preferred
const message = `User ${userId} not found`;
const url = `${baseUrl}/api/${endpoint}`;
// ❌ Do not use concatenation
const message = 'User ' + userId + ' not found';
Optional Chaining
// ✅ 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
// ✅ 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
// ✅ 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
// ✅ 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
<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
// ✅ 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
// ✅ 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
<script setup>
// ✅ Define props with types
const props = defineProps({
customerId: {
type: Number,
required: true
},
showDetails: {
type: Boolean,
default: false
}
});
</script>
Emits
<script setup>
// ✅ Define emits
const emit = defineEmits(['update', 'delete']);
function handleUpdate() {
emit('update', data);
}
</script>
Pinia Stores
// ✅ 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
// ✅ 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
// ✅ camelCase
const customerData = {};
const totalRecords = 0;
function loadCustomers() {}
// ✅ Constants in UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = '/api';
Components
<!-- ✅ PascalCase for components -->
<CustomerCard />
<ProductsList />
Files
// ✅ Use kebab-case for files
// customers-view.vue
// http-utils.js
// customer-service.js
Imports
// ✅ 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)
// ✅ Use types
interface Customer {
id: number;
name: string;
email?: string;
}
function getCustomer(id: number): Promise<Customer> {
return apiGet(`customers/${id}`);
}