Coding Style Guide
This guide defines the shared coding style across LIVON repositories. Use it to keep implementation style consistent across packages and apps.
Core principles
- Functional and deterministic code.
- Immutable-by-default updates.
- ES6-first syntax.
- Schema-first validation and typing.
- Clear naming where function name and parameter names describe one coherent intent.
Language and syntax
- Use English for identifiers, comments, docs, and public APIs.
- Use lambda-first style (arrow functions only).
- Do not use classes or
this. - Avoid loop keywords (
for,while) when declarative methods are practical.
const activeUsers = users.filter((user) => user.active);
const names = activeUsers.map((user) => user.name);
Loop policy
- Default: no
for/whileloops. - Preferred:
map,filter,reduce,find,forEach. - Allowed exception: small async flow functions where iterator-driven control is required.
const collectMessages = async (stream: AsyncIterable<string>): Promise<string[]> => {
const values: string[] = [];
for await (const value of stream) {
values.push(value);
}
return values;
};
Immutability and object updates
- Never mutate shared inputs or shared state.
- Merge and override objects with spread.
const nextUser = {...user, age: 3};
- If fields must be excluded, destructure first.
const {password: _unwantedPassword, ...safeUser} = user;
const response = {...safeUser, role: 'member'};
Function design
- Functions should be small and do one thing.
- Prefer max two parameters for new code.
- If inputs are simple primitives, always group them into one semantic config object.
- Keep existing public callback signatures where external interfaces require them.
interface RequestUserInput {
userId: string;
includePosts: boolean;
}
const requestUser = ({includePosts, userId}: RequestUserInput) =>
apiRequest({includePosts, userId});
Avoid primitive multi-arg signatures:
// avoid
const requestUser = (userId: string, includePosts: boolean) =>
apiRequest({userId, includePosts});
Function typing rules
- No inline object types for function parameters.
- No inline function type signatures for reusable function interfaces.
- Define function interfaces as named
interfacetypes.
interface BuildDisplayNameInput {
firstName: string;
lastName: string;
}
interface BuildDisplayName {
(input: BuildDisplayNameInput): string;
}
const buildDisplayName: BuildDisplayName = ({firstName, lastName}) =>
`${firstName} ${lastName}`;
Parameter and property ordering
Order fields by complexity:
- primitive
- array
- object
- function
interface ModuleInput {
name: string;
tags: readonly string[];
metadata: Readonly<Record<string, unknown>>;
onError: (error: unknown) => void;
}
Types and validation
- Avoid
any. If unavoidable, document why. - Use
interfacefor object shapes. - Do not use manual
parseX...ortoX...validation helpers. - Use schema composition and
schema.parse. - Use
PascalCasefor schema constants in examples and docs (User,MessageInput,ApiSchema). - Keep operation/resolver runtime functions in
camelCase(sendMessage,userGreetingResolver).
const CreateUserInput = object({
name: 'CreateUserInput',
shape: {
name: string(),
age: number(),
},
});
const value = CreateUserInput.parse(input);
ES6-first patterns
const statusLabel = isReady ? 'ready' : 'waiting';
const sorted = [...values].sort((left, right) => left - right);
const moduleName = input.name ?? 'runtime-module';