├── apps # Contains all the applications
│ └── desktop # CySync desktop application, contains all electron code
│ └── cli # CySync cli application
│
├── packages # All packages required for apps
│ └── ui # UI library for cysync containing all components
│ └── interfaces # Contains all `types` which needs to be shared between packages
│ └── desktop-ui # Renderer part of desktop application
│ └── coins # Static coin information
│ └── coin-support-* # Coin support functionalities
│ └── cysync-core # Contains all business logic of cysync, like pages, context etc
│ └── db-interfaces # Interface for `database`
│ └── database # Database implementation for electron
│ └── util-* # Common utilities shared between packages
│
├── submodules # Packages used by cysync but exist on different repository
│ └── sdk # SDK for communicating with Cypherock hardware
│
├── scripts # Contains scripts to be used by the build system
├── package.json
packages/ui
packages/coins
packages/interfaces
packages/utils
packages/db-interfaces
packages/database
packages/cysync-core
packages/desktop-ui
apps/desktop
NOTE: There might be cases where these guidelines do not apply. It is upto the developer and the maintainer to make sure these guidelines are followed whereever possible, and ignore the ones that don't apply at a particualar case.
- Follow
DRY
,KISS
, andYAGNI
- Use
PascalCase
for type names. - Use
PascalCase
for enum values. - Use
camelCase
for function names. - Use
camelCase
for property names and local variables. - Use
camelCase
for file names. Except for react components, which should be inPascalCase
. - Do not use _ as a prefix for private properties.
- Use whole words in names when possible.
boolean
variables should start withis
,has
,do
or similar, to indicate it's a boolean value.- function name should indicate an action.
- example:
- ❌:
isPasswordCorrect
- ✅:
checkPassword
,createUser
,showSnakbar
,validateInput
,getConfig
- ❌:
- example:
- Use
undefined
. Do not usenull
.
- Try to keep your files under
250
lines of code.
Try to avoid nesting code too many levels deep. For example, in the loop, it’s sometimes a good idea to use the continue directive to avoid extra nesting.
For example, instead of adding a nested if conditional like this:
// ❌
for (let i = 0; i < 10; i++) {
if (cond) {
... // <- one more nesting level
}
}
We can write:
// ✅
for (let i = 0; i < 10; i++) {
if (!cond) continue;
... // <- no extra nesting level
}
A similar thing can be done with if/else and return.
Try to create sections in your functions by using line breaks.
// ❌
const runAlgorithm = () => {
const config = getConfig();
const userInputs = getUserInputs();
const { error, inputs } = validateInputs(userInputs);
if (error) {
throw new ValidationError();
}
let result = [];
for (const key in inputs) {
// ... algorithm code
}
return result;
};
// ✅
const runAlgorithm = () => {
// Section to declare variables
const config = getConfig();
const userInputs = getUserInputs();
// Section to validate inputs
const { error, inputs } = validateInputs(userInputs);
if (error) {
throw new ValidationError();
}
// Section to execute the algorithm
let result = [];
for (const key in inputs) {
// ... algorithm code
}
// Section to return result
return result;
};
NOTE: The comments above are just to explain the different sections and should not exist in the actual code.
- Do not ❌
- comment out code that is not used.
- comment what the code already states
- Example
i = i + 1; // Add one to i
- explain unclear code in comments, rather refactor the code to make it clear.
- Do ✅
- use comments explain why this code is necessary.
- explain unidiomatic code in comments.
- provide links to the original source of copied code.
- include links to external references where they will be most helpful.
- add comments when fixing bugs which explains the edge case that caused the bug.
- use comments to mark incomplete implementations.
-
Prefer using
nullish coalescing operator
over ofternary
or&& / ||
operators.// ❌ const displayName = user.firstName ? user.firstName : user.lastName;
// ❌ const displayName = user.firstName || user.lastName;
// ✅ const displayName = user.firstName ?? user.lastName;
-
Do not use
ternary
operator for more than one condition// ✅ const connectionState = device.connected ? 'connected' : 'disconnected';
// ❌ const connectionState = device.connected ? 'connected' : device.isBootloader ? 'bootloader' : 'disconnected';
// ✅ let connectionState = 'disconnected'; if (device.connected) { connectionState = 'connected'; } else if(device.isBootloader) { connectionState = 'bootloader'; }
-
Use object for mapping variables into different format.
// ❌ let fontWeightNumber: number; if(fontWeight === 'light') { fontWeightNumber = 300; } else if (fontWeight === 'normal') { fontWeightNumber = 400; } else if (fontWeight === 'bold') { fontWeightNumber = 700; } else { fontWeightNumber = 400; }
// ✅ const fontWeightMap = { light: 300, normal: 400, bold: 700 }; const fontWeightNumber = fontWeightMap[fontWeight] ?? fontWeightMap.normal;
-
Use
styled-components
while creating UI components. -
Use props on UI components to modify the styling, over directly changing the css.
// ❌ <Button variant="primary" style={{ border: 'none' }}>Continue</Button>
// ✅ <Button variant="primary" noBorder={true}>Continue</Button>
-
Create reusable hooks where possible.
-
Global states should be defined in Redux store.
-
Separate business logic from UI.
// ❌ const SetPassword = () => { const handleSetPassword = (password: string) => { const db = getDB(); const passwordHash = createHash(password); db.setPassword(passwordHash); db.encryptWithPassword(passwordHash); } return ( <div> {/* ... */} </div> ); }
// ✅ import { setDatabasePassword } from '~/database'; const SetPassword = () => { const handleSetPassword = (password: string) => { setDatabasePassword(password); } return ( <div> {/* ... */} </div> ); }