When implementing JavaScript code, follow these guidelines.
Code format guide:
Use tabs and double quotes for strings
Make sure to follow style guide from eslint or/and editorconfig if present in the project
Use Common.JS syntax for imports and exports
I do not like to use this format const { recordEvent } = require("./event-log");, instead, do this const recordEvent = require("./event-log").recordEvent;
Write exports directly in module.exports = {};
Expose constants at the top of the file, after imports, for easier configuration
Use JSDoc when function parameters are ambiguous (e.g., options objects with multiple properties)
Prefer if/else over ternaries for non-trivial logic - readability over cleverness
Project structure
Make sure to always create folder for each module, and create index.js inside, it helps with organization and reduces chance of conflict
I like to keep code for talking to other services in src/services folder
I like to keep helper code that is specification specific in src/utils folder. If it is not logically part of application, just something that is needed to make things work, it should go to utils
I create entrypoints into project in bin/ folder (e.g., bin/pull.js, bin/sync.js)
All entrypoints must be:
- Started with
forever (e.g., forever bin/pull.js)
- Added to
package.json scripts (e.g., "pull": "forever bin/pull.js")
- Added to
Procfile for herokuish (e.g., pull: yarn pull)
- Have a
-watch variant using nodemon for development (e.g., "pull-watch": "nodemon bin/pull.js")
If nodemon is not in package.json, install it as dev dependency (yarn add -D nodemon)
Scripts run in heroku/herokuish environment
Technical guidelines
Use Promise instead of async/await for asynchronous operations
Chain promises sequentially with .then() rather than nesting:
return doFirst()
.then(() => {
return doSecond();
})
.then(() => {
return doThird();
});
Avoid using ES6+ features that are not widely supported in Node.js environments
I like functional JS, map/reduce/foreach/filter should be preferred over for loops
I like to use wrappers for repeating code, like rate limiting, cachine, etc.
Never use var, always const/let. Unless you really need to change value, use const
Never change parameters of functions, always create new variables if you need to change something
Handle errors at the last possible moment to avoid losing error data when rebuilding. Catch earlier only when it makes sense for the logic
Architectural guidelines
Try to encapsulate complex logic in modules and expose logic so that final code looks almost like pseudocode
Name modules based off their functionality, not how they are implemented (for example, module for logging stuff to mongo should be called logger, not mongo)
Where it makes sense, if there is array getter, also implement getter that returns map, calling original getter and transforming result to map
Service pattern
Services should be defined as objects with methods, not separate functions
Use _client for the HTTP client (private by convention), do not export it
Reference the service object by name inside methods
Example:
const got = require("got-verbose");
const config = require("../../config");
const myService = {
_client: got.extend({
prefixUrl: "https://api.example.com",
headers: {
authorization: "Bearer " + config.get("MY_API_KEY")
}
}),
getItems: () => {
return myService._client.get("items").then((response) => {
return JSON.parse(response.body).items;
});
},
getItemsMap: () => {
return myService.getItems().then((items) => {
const map = {};
items.forEach((item) => {
map[item.id] = item;
});
return map;
});
}
};
module.exports = myService;
Package manager
Always use yarn instead of npm, unless there is a package-lock.json present (then use npm)
Never guess npm package versions — use yarn add <package> (or yarn add -D <package> for dev dependencies) and let yarn resolve the correct version. Do not manually edit dependency versions in package.json.
Version control
Libraries and tools
Lib I like to use for rate limiting (how many calls of method should happen at the same time) is queue-promised
Install it, package name is queue-promised
Import method wrapper from queue-promised (const wrapper = require("queue-promised").wrapper;)
Use it like this const limitedFunction = wrapper(originalFunction, 5); where 5 is how many calls can happen at the same time
I like to use uuid package for generating uuids. I like to use v4 method from it. and I import it like this: const uuid = require("uuid").v4;
I like to use node-cron for cron jobs. I import it like this: const cron = require("node-cron");
I like to use got-verbose, which is a wrapper around got library for HTTP requests. It exposes identical API as got, but has built-in logging and error handling. I import it like this: const got = require("got-verbose");
Note: got-verbose does not work with streams. For streaming, use got directly (const got = require("got");)
Avoid using .json() method of got-verbose and json option, instead use .body and parse JSON manually, it does have some unexpected behavior
I like to use forever for running Node.js applications. Use it in the start script: "start": "forever src/index.js"
Claude notice
Add note to CLAUDE.md that this skill should be always used
Suggest changes to this skill, when I suggest code style changes
If you notice a pattern in my instructions, suggest adding it to this skill
Try to keep CLAUDE.md in sync with project changes
If you are writing a pseudocode (calling method or API endpoint you are not sure exists), add TODO comment so I know I should fix it
Building container
It is usual for me to use herokuish build like this
FROM gliderlabs/herokuish:latest
COPY . /app
WORKDIR /app
RUN /bin/herokuish buildpack build
ENV PORT 3000
EXPOSE 3000
Cleanup time
When I tell you it is cleanup time, follow this checklist:
1---2name: implement-js3description: Implement JavaScript code based on user requirements.4---56When implementing JavaScript code, follow these guidelines.78## Code format guide:910 * Use tabs and double quotes for strings1112 * Make sure to follow style guide from eslint or/and editorconfig if present in the project1314 * Use Common.JS syntax for imports and exports1516 * I do not like to use this format `const { recordEvent } = require("./event-log");`, instead, do this `const recordEvent = require("./event-log").recordEvent;`1718 * Write exports directly in `module.exports = {};`1920 * Expose constants at the top of the file, after imports, for easier configuration2122 * Use JSDoc when function parameters are ambiguous (e.g., options objects with multiple properties)2324 * Prefer if/else over ternaries for non-trivial logic - readability over cleverness2526## Project structure2728 * Make sure to always create folder for each module, and create index.js inside, it helps with organization and reduces chance of conflict2930 * I like to keep code for talking to other services in `src/services` folder3132 * I like to keep helper code that is specification specific in `src/utils` folder. If it is not logically part of application, just something that is needed to make things work, it should go to utils3334 * I create entrypoints into project in `bin/` folder (e.g., `bin/pull.js`, `bin/sync.js`)3536 * All entrypoints must be:37 * Started with `forever` (e.g., `forever bin/pull.js`)38 * Added to `package.json` scripts (e.g., `"pull": "forever bin/pull.js"`)39 * Added to `Procfile` for herokuish (e.g., `pull: yarn pull`)40 * Have a `-watch` variant using `nodemon` for development (e.g., `"pull-watch": "nodemon bin/pull.js"`)4142 * If `nodemon` is not in package.json, install it as dev dependency (`yarn add -D nodemon`)4344 * Scripts run in heroku/herokuish environment4546## Technical guidelines4748 * Use Promise instead of async/await for asynchronous operations4950 * Chain promises sequentially with `.then()` rather than nesting:5152 ```javascript53 return doFirst()54 .then(() => {55 return doSecond();56 })57 .then(() => {58 return doThird();59 });60 ```6162 * Avoid using ES6+ features that are not widely supported in Node.js environments6364 * I like functional JS, map/reduce/foreach/filter should be preferred over for loops6566 * I like to use wrappers for repeating code, like rate limiting, cachine, etc.6768 * Never use `var`, always `const`/`let`. Unless you really need to change value, use `const`6970 * Never change parameters of functions, always create new variables if you need to change something7172 * Handle errors at the last possible moment to avoid losing error data when rebuilding. Catch earlier only when it makes sense for the logic7374## Architectural guidelines7576 * Try to encapsulate complex logic in modules and expose logic so that final code looks almost like pseudocode7778 * Name modules based off their functionality, not how they are implemented (for example, module for logging stuff to mongo should be called logger, not mongo)7980 * Where it makes sense, if there is array getter, also implement getter that returns map, calling original getter and transforming result to map8182## Service pattern8384 * Services should be defined as objects with methods, not separate functions8586 * Use `_client` for the HTTP client (private by convention), do not export it8788 * Reference the service object by name inside methods8990 * Example:9192 ```javascript93 const got = require("got-verbose");94 const config = require("../../config");9596 const myService = {97 _client: got.extend({98 prefixUrl: "https://api.example.com",99 headers: {100 authorization: "Bearer " + config.get("MY_API_KEY")101 }102 }),103104 getItems: () => {105 return myService._client.get("items").then((response) => {106 return JSON.parse(response.body).items;107 });108 },109110 getItemsMap: () => {111 return myService.getItems().then((items) => {112 const map = {};113 items.forEach((item) => {114 map[item.id] = item;115 });116 return map;117 });118 }119 };120121 module.exports = myService;122 ```123124## Package manager125126 * Always use `yarn` instead of `npm`, unless there is a `package-lock.json` present (then use `npm`)127128 * Never guess npm package versions — use `yarn add <package>` (or `yarn add -D <package>` for dev dependencies) and let yarn resolve the correct version. Do not manually edit dependency versions in `package.json`.129130## Version control131132 * Make sure there is `.gitignore` file present133134 * Make sure to ignore `node_modules`135136## Libraries and tools137138 * Lib I like to use for rate limiting (how many calls of method should happen at the same time) is queue-promised139140 * Install it, package name is `queue-promised`141142 * Import method `wrapper` from `queue-promised` (`const wrapper = require("queue-promised").wrapper;`)143144 * Use it like this `const limitedFunction = wrapper(originalFunction, 5);` where 5 is how many calls can happen at the same time145146 * I like to use `uuid` package for generating uuids. I like to use `v4` method from it. and I import it like this: `const uuid = require("uuid").v4;`147148 * I like to use `node-cron` for cron jobs. I import it like this: `const cron = require("node-cron");`149150 * I like to use `got-verbose`, which is a wrapper around `got` library for HTTP requests. It exposes identical API as `got`, but has built-in logging and error handling. I import it like this: `const got = require("got-verbose");`151152 * **Note:** `got-verbose` does not work with streams. For streaming, use `got` directly (`const got = require("got");`)153154 * Avoid using .json() method of got-verbose and json option, instead use .body and parse JSON manually, it does have some unexpected behavior155156 * I like to use `forever` for running Node.js applications. Use it in the start script: `"start": "forever src/index.js"`157158## Claude notice159160 * Add note to CLAUDE.md that this skill should be always used161162 * Suggest changes to this skill, when I suggest code style changes163164 * If you notice a pattern in my instructions, suggest adding it to this skill165166 * Try to keep CLAUDE.md in sync with project changes167168 * If you are writing a pseudocode (calling method or API endpoint you are not sure exists), add TODO comment so I know I should fix it169170## Building container171172It is usual for me to use herokuish build like this173174```175FROM gliderlabs/herokuish:latest176177COPY . /app178179WORKDIR /app180181RUN /bin/herokuish buildpack build182183ENV PORT 3000184185EXPOSE 3000186```187188## Cleanup time189190When I tell you it is cleanup time, follow this checklist:191192 * /implement-js193194 * update docs (README.md)195196 * update your docs (CLAUDE.md)197198 * update missing jsdoc...199200 * check tests201202 * check linter