diff --git a/src/components/navigation.ts b/src/components/navigation.ts index eac49dd..25ebae0 100644 --- a/src/components/navigation.ts +++ b/src/components/navigation.ts @@ -89,6 +89,10 @@ export const navigation = [ label: "Contributor Covenant", link: "/dev/covenant" }, + { + label: "Style Guide", + link: "/dev/style" + }, { label: "Issue/PR Labels", link: "/dev/labels" diff --git a/src/content/docs/dev/contributing.md b/src/content/docs/dev/contributing.md index 93e4431..111d30f 100644 --- a/src/content/docs/dev/contributing.md +++ b/src/content/docs/dev/contributing.md @@ -329,10 +329,16 @@ Implement JWT-based authentication for API endpoints. ### 5.7 Testing Your Changes +- Run the linter to ensure your code complies with [our style guidelines](/dev/style). + + ```bash + pnpm lint # or the appropriate lint command for your project + ``` + - Run any existing tests to ensure your changes haven't broken anything: ```bash - pnpm test # or the appropriate test command for your project + pnpm test # or the appropriate test command for your project ``` - Add new tests for your changes if applicable. @@ -383,7 +389,8 @@ git push -u origin - A clear description of the changes - The issue number(s) your pull request addresses - Any additional context or explanations -3. If your changes include visual elements, consider adding screenshots or GIFs to illustrate the modifications. +3. Fill out the rest of the pull request form *completely*. +4. If your changes include visual elements, consider adding screenshots or GIFs to illustrate the modifications. ### 6.4 Pull Request Best Practices diff --git a/src/content/docs/dev/style.md b/src/content/docs/dev/style.md new file mode 100644 index 0000000..4f480ee --- /dev/null +++ b/src/content/docs/dev/style.md @@ -0,0 +1,595 @@ +--- +title: Style Guide +--- + +This document outlines the style guide that applies to all of our projects. + +## 1. Global Conventions + +These sections apply to all code in any of our projects. + +### 1.1. Copyright Notice + +All code files should begin with a comment section containing the copyright information: + +```js +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ +``` + +Note that `copyright` _must_ be assigned to `nhcarrigan`, and our `license` must be applied, but when checking in new code you may attribute yourself as the author, or add yourself to the list for existing code. + +## 2. JavaScript Projects + +The following sections apply to our JavaScript/TypeScript projects. Style conventions are enforced through our [custom ESLint package](/projects/eslint). + +:::caution +We do _not_ use Prettier in any of our projects. Instead, our linter package also handles code styling. + +If you are using VSCode, you can add this to your `.vscode/settings.json` file in the project directory to enable auto-formatting on save. + +```json +{ + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "eslint.validate": ["typescript"] +} +``` + +Because of this, our style guide will not cover the formatting section of our linter package. +::: + +## 2.1. Main Rules + +These rules apply to all TypeScript code, and will run on files in `src/**/*.ts`. + +### 2.1.1. `eslint` Enforced Rules + +- Setters must have a corresponding getter. +- Array methods which return a value must return a value in the callback. +- Arrow functions should always use curly braces. +- Variables must be used within the scope they are defined. +- Comments should always start with a capital letter. +- Avoid overly complex functions. +- `return` statements must either never return a value, or always return a value. +- `if` statements and similar control blocks should always use curly braces. +- Switch statements must always have a default case, and the default case must always come last. +- Never use loose equality. +- A `for` loops iteration direction must match the conditional bound. +- Functions assigned to a property must match the name of the property. +- With the exception of callback functions, all functions should be assigned a name. +- When using the `function` keyword, prefer `function name()` declarations over `const name = function()` expressions. +- Getters should always return a value. +- Getters and setters should be grouped together. +- You should never use logical assignment operators. +- You should never have more than one class per file. +- Logical blocks should not be nested more than five levels deep. Prefer extracting into separate functions. +- Files should not have more than 300 lines. Prefer extracting into modular functions. +- Functions should not have more than 50 lines. Prefer breaking down into smaller logic. +- Callbacks should not be nested more than two levels. +- Functions should not have more than 20 logical statements/branches. +- Constructor names should begin with a capital letter. +- Do not use the `alert` API. +- Promise executor functions should not be async. +- Do not use `await` within loops. +- Do not use bitwise operators. +- Do not use `arguments.caller` or `arguments.callee`. +- Do not declare variables within switch case statements. +- Do not reassign class definitions. +- Do not compare with `-0`. +- Do not perform assignments in conditions e.g. `if (name = "Naomi")`. +- Do not use the `console` API, prefer our custom logger. +- Avoid confusing operator combinations e.g. `a + b ?? c`. +- Avoid constant conditions e.g. `if(false)` or `while(true)`. +- Constructors should not return a value. They implicitly return the instance. +- Do not use control characters `\x00` in regular expressions. +- Do not use `debugger` statements. +- Do not use `delete` on variables. +- Do not start a regular expression with `=` (confusing with `/=` operator). +- Functions should not have multiple parameters with the same name. +- Classes should not have multiple members with the same name. +- Objects should not have multiple keys with the same name. +- If/else statements should not use the same condition. +- Switch statements should not have duplicate case conditions. +- Import statements should not have duplicate imports. +- Prefer using early return over if/else. +- Block statements should not be empty. +- Character classes in regular expressions should not be empty. +- Destructured values should not be empty. +- Static class blocks should not be empty. +- You should not use loose equality with `null`. +- You should not use `eval`. +- Do not reassign the error parameter in a catch block. +- Do not extend native prototypes. +- Do not call `bind` unnecessarily. +- Do not cast to a boolean in conditions. +- Do not use `continue` or `break` unnecessarily. +- All case statements should have a break statement. +- Do not reassign function declarations. +- Do not reassign global values (e.g. `window`). +- Do not use implicit coercion (e.g. `!!bool`, `+num`). +- Do not declare global variables. All values should be scoped to a module. +- Do not reassign to imported variables. +- Do not declare functions in logical blocks. +- Do not pass invalid regular expression strings to `RegExp()`. +- Do not use `this` outside of classes. +- Do not use unusual space characters. +- Do not access `__iterator__`. +- Do not use loop labels. +- Do not create unnecessary blocks. +- Do not nest `if` within `else`, use `else if`. +- Do not use multi-code characters (such as emotes) within character classes. +- Do not chain assignment operators. +- Do not use `\` to create multi-line strings. Use concatenation or template strings. +- `if` conditions should not be in the negative (e.g. `!bool`). +- Do not nest ternary statements. +- Do not use `new` outside of an assignment. +- Do not use `new` with `BigInt` or `Symbol`. +- Do not use `new` with `String`, `Number`, or `Boolean`. +- Do not use octal escapes (e.g. `\8`, `\2`). +- Do not call the `Math`, `JSON`, `Reflect`, `Atomics`, or `Intl` objects as functions or constructors. +- Do not call `new Object()` without an argument. +- Do not use octal literals e.g. `071`. +- Do not reassign function parameters. +- Do not use the `++` operator. +- Do not use `return` in promise executors. +- Do not use the `__proto__` property. +- Prefer calling the Object prototype over builtins (e.g. `Object.prototype.hasOwnProperty.call(foo, "bar")` over `foo.hasOwnProperty("bar")`). +- Do not use literal spaces in regular expressions, use the escape sequence `\s`. +- Do not return assignment operations. +- Do not use `javascript:void` URLs. +- Do not assign a variable to itself. +- Do not compare a variable with itself. +- Do not use the comma operator to evaluate multiple expressions. +- Setters should not return a value. +- Do not allow sparse arrays. +- Do not use `${foo}` template interpolation in regular strings. +- Do not reference `this` before calling `super` in constructors that call `super`. +- Do not reference variables that are not declared. +- Do not initialise variables to `undefined`. +- With the exception of trailing underscores for unused variables, do not use dangling underscores. +- Do not insert line breaks in confusing locations, such as the middle of a variable assignment. +- Do not use a variable in a loop condition that is not modified within the loop. +- Do not use a ternary if a simpler approach exists. +- There should be no unreachable code. +- Do not use control statements in `finally` blocks. +- You must use parentheses when negating `in` or `instanceOf`, e.g. `if (!(key in obj))`. +- Do not use optional chaining where an undefined value is not allowed. +- Do not declare private class members that are not consumed by the class. +- Do not declare variables that are unused. +- Avoid backreferences in regular expressions when they would match nothing. +- Do not use `.call()` or `.apply()` unnecessarily. +- `catch` statements should _handle_ an error, not turn around and throw the error. +- Do not use computed-key syntax for literal keys e.g. `{["a"]: "b"}`. +- Do not concatenate string literals without variables. +- Do not escape characters unnecessarily. +- Do not rename a reference to the same name e.g. `let { a: a } = b;`. +- Do not use redundant `return` statements. +- No use of the `var` keyword. +- Do not merge `TODO` or `FIX` comments into the main branch. +- Do not use the `with` statement. +- An object must use either all long-form definitions `{a : a}` or all short-form definitions `{ a }`, but never a mix of the two `{ a, b: c}`. +- Avoid shorthand operators `+=`, prefer the explicit `x = x + y`. +- Callback functions should be anonymous arrow functions. +- Use `const` for all variables that are not reassigned. +- Capture groups should be named. +- Prefer `Object.hasOwn()`. +- Prefer the spread operator over `Object.assign`. +- Prefer regular expression literals over the RegExp constructor. +- Prefer using the `...` operator instead of `arguments`. +- Prefer the spread operator over `.apply()`. +- Prefer template literals over string concatenation. +- `parseInt()` should always be given a radix. +- When an asynchronous function relies on an argument that might change (such as an object reference), care must be taken to avoid race conditions within that function. +- Generator functions must use the `yield` keyword. +- Object keys must be sorted alphabetically. +- Variables within the same declaration block must be sorted alphabetically. +- If using the `Symbol` function, you must include a description. +- Do not compare to `NaN`, use `Number.isNaN()`. +- `typeof` comparators must be a vaild return type of `typeof`. +- Conditions should always start with the variable, not the constant. + +### 2.1.2. `typescript-eslint` Enforced Rules + +- Do not use `await` on functions that do not return a Promise. +- Exported type definitions should use the `export type` keyword. +- Use dot notation for property access, unless such syntax would be invalid. +- Do not use the `delete` keyword with arrays. +- Do not use `.toString()` on objects. Prefer `JSON.stringify()`. +- Do not assign void values to variables, such as `const log = console.log("Bad");`. +- Do not duplicate types (e.g. `type myType = "A" | "A"`). +- Promises should always be awaited. +- Do not implicitly evaluate code, such as with `new Function()`. +- Do not use `void` with functions that do not return a value. +- Do not use Promises in places that do not consume them (such as callbacks). +- Do not combine string and number values in an enum. +- Do not use unions/intersections with overriding values (such as `any` or `unknown`). +- Do not use comparison operators with boolean values (e.g. `variable === false`). +- Do not pass values to a conditional statement that are always truthy or falsy. +- Do not use unnecessary namespace references. +- Do not use template strings without interpolated values. +- Do not pass type arguments to a function that match the default value of that parameter. +- Do not define unused type parameters in a function. +- Values with an `any` type should not be passed to function calls. +- Values with an `any` type should not be assigned to variables. +- Values which have an `any` type should not be called as functions. +- Do not merge declarations (instead of `interface Foo` and `class Foo`, use `interface Foo` and `class Bar implements Foo`). +- Do not compare enum values against arbitrary values. +- Do not use the `Function` type. Functions should have a specific type signature. +- Values with an `any` type cannot have properties, and such properties should not be accessed. +- Functions should not return an `any` value. +- The unary minus operator should only be used on numbers. +- `throw` statements should only throw an `Error` instance. +- Object properties should be destructured, rather than assigned to variables via direct access. +- Use `.find()` instead of `.filter()[0]` to find an element in an array. +- Use `.includes()` instead of `.indexOf() === -1`. +- Use `??` instead of `||`. +- Use optional chaining when possible. +- Promises that reject should always return an Error. +- Class members that are not modified outside of the constructor should be `readonly`. +- The `.reduce()` callback should have typed parameters. +- When using a non-global regular expression, use `.exec` over `.match()`. +- Class methods that return `this` should have `this` as the return type, not the class. +- When testing the beginning or end of a string, use `.startsWith()` or `.endsWith()`. +- Functions which return a Promise must use the `async` keyword. +- `.sort()` should always be given a compare function. +- `async` functions must use `await`, or be rewritten without the promise. +- The `+` operator can only be used with operands of the same type. +- Values interpolated in a template string must be of type `string`. +- Functions which return a promise should await that return value. +- Conditions should not use nullable values - you must always explicitly compare against `null` or `undefined`. +- Switch statements are not preferred, but when you must use them it should have exhaustive cases. +- Unbound class methods must be called with the expected scope (e.g. `myClass.method.bind(myClass)`). +- The `error` parameter in a catch statement is of type `unknown`. +- Function overload signatures must be grouped together. +- Array type definitions should use the generic `Array` over `T[]`. +- `@ts` directives are disallowed, except for `@ts-expect-error` which requires a description. +- Classes with static public properties should have a getter for each property. +- Class methods which are not static must make use of `this` or be converted to static. +- Prefer passing type arguments to a constructor instead of a type annotation. +- Prefer `Record` over `{ [key: string]: T}`. +- Do not use any type assertions (`x as T`). +- Object types should be defined with `interface` over `type`. +- Imported values which are only used as types should be imported with `type`. +- Function parameters which are optional or have a default value should come after all mandatory parameters. +- Functions should always have an explicit return type. +- All class members should have an accessibility modifier (`public`, `protected`, `private`). +- All exported functions and public class methods should have explicit parameter and return types. +- Variables should always be initialised with a value. +- Functions which take more than three arguments should take a single object instead. +- Class members should be ordered as `constructor`, `fields`, `statics`, `getters`, `setters`, then `methods`. +- Method types should use the property signature `func: (arg: string) => string`. +- Variables should use `camelCase`, types and classes should use `PascalCase`. Only variables may use a leading underscore to indicate they are unused. +- Never use the `Array` constructor. +- Do not use non-null assertions. +- Enums should not have duplicate values. +- Do not use the `delete` operator on dynamic property accesses. +- Functions, interfaces, and object types should never be empty. +- Do not use `any`. +- Classes should not consist solely of static members. +- The `for...in` loop should not be used. +- When all imported members are type imports, use `import type { a, b }` over `import { type a, type b }`. +- Do not use type annotations for variables with a string, number, or boolean value. These can be inferred. +- The `void` type should only be used as the _sole_ return type of a function. `(): void | string` is invalid. +- Do not reference unsafe values in a loop. +- Do not use number literals which would lose precision due to memory constraints. +- Classes should use `constructor()`, not `new()`. Interfaces for the class should use `new()`, not `constructor()`. +- Do not use namespaces. +- Do not use `require()`. +- Do not declare variables in an inner scope that share a name with a variable in the outer scope. +- Do not alias `this`. +- Do not needlessly assign constructor parameters to class members of the same name. +- Do not `extends` `any` or `unknown`. +- Unused expressions should be removed. +- Unused variables should be removed. +- Do not access a variable before its definition. +- Do not define empty constructors. +- Do not define empty exports. +- Do not use wrapper types (e.g. use `boolean`, not `Boolean`). +- Use `as const` over literal types. +- Enum values should always be explicitly initialised. +- The `for...of` loop should be used over the `for` loop, when the index _value_ is not needed. +- Enum values should always be literal values. +- Do not use TypeScript's `///` reference. +- Do not use overloads when the same result can be achieved via union types or optional parameters. + +### 2.1.3. `eslint-comments` Enforced Rules + +- Do not use blanket `eslint-disable` directives. All `disable` directives must target specific rules. +- All `disable` directives must include a comment explaining why the linter is being bypassed. + +### 2.1.4. `deprecation` Enforced Rules + +- Do not use deprecated methods/features, even if the package still supports them. + +### 2.1.5. `import` Enforced Rules + +- Do not use default imports if the module does not have a default export. +- Do not import modules simply to re-export them. +- Exports should always be at the end of the file. +- With the exception of packages, imports should always have a file extension. +- Imports should always be at the beginning of the file. +- If a module has multiple named exports, group them in a single `export { a, b }` declaration. +- Import statements should be followed by a newline. +- Import paths should never be absolute +- You should not use AMD syntax +- You should not use CJS syntax +- You should not define cyclical imports (if file a imports file b, file b CANNOT import file a) +- Modules should not use a default export. +- A module should not import the same file multiple times. +- You should not use dynamic `require` calls. +- Named import blocks cannot be empty. +- You should not import packages that are not included in the `package.json` file. +- You cannot `import` a CommonJS module. +- Exports must always be declared with `const`. +- You cannot use a named export as the default export. +- You cannot use a named export as the property of a default export. +- You should not have orphaned modules (modules without any exports, or a module which is never imported). +- You cannot use webpack loader syntax. +- Imports must be sorted alphabetically, first grouped by: builtin node modules, external packages, internal packages, modules in parent directory, modules in current directory, type-only imports. + - There should be no new lines between these groups. + +### 2.1.6. `jsdoc` Enforced Rules + +- `@access` tags should be one of `package`, `private`, `protected`, or `public`. +- Asterisks should be aligned. +- Lines should not be improperly indented. +- `@param` names should reflect the actual parameters. +- `@property` names should reflect the actual properties. +- Should not use `=` (GCC syntax). +- All tags must be valid JSDoc tags. +- `@template` names should be used in the `@typedef`. +- `@license` tag MUST be set to `Naomi's Public License`. +- Tags that do not expect content should not have content. +- `@implements` should only be used on constructors or classes. +- Tag descriptions should not be just a reflection of the name. +- Description tags must be complete sentences. +- JSDocs must be multiple lines. The first and last line cannot have text content. +- JSDoc syntax must be valid. +- JSDocs must have a description. +- JSDocs cannot be empty. +- A hyphen should separate the parameter name from the description. +- JSDocs are required on all public functions, classes, and methods. They are encouraged on all public exports. +- Parameters must have a name and description. +- Properties must have a name and description. +- If a function returns a value, it must be documented in `@returns`. +- If a function throws an unhandled error intentionally, it must be documented in `@throws`. +- If a generator yields a value, it must be documented in `@yields`. +- Tags must be sorted alphabetically. +- There should be no blank lines between tags. +- Any types referenced must be valid types. + +### 2.1.7. `unicorn` Enforced Rules + +- Regular expressions should use special shorthand where possible. +- `catch` blocks should always have `error` as the parameter. +- When destructuring an object, all consumed properties should be destructured. Do not perform direct property access on an object that is previously destructured. +- When spreading a ternary in an array, both sides of the expression must be of the same type. +- Functions should be declared in the highest scope possible. +- `Error()` constructor calls must always be given a message. +- Escape sequences must use uppercase text. +- Files should be named in camelCase. +- Do not pass function references as callbacks to array methods. +- Do not use `.forEach()`. +- Do not use `this` in array methods. +- Do not chain `.push()` calls. +- Do not use `.reduce()`. +- Do not access properties directly from an `await` expression. +- Do not use `await` in Promise methods such as `.all()`. +- Files should not be empty. +- Do not use a `for` loop when you can use a `for...of` loop. +- Use Unicode escape sequences over hexadecimal escape sequences. +- Use `Array.isArray()` over `instanceof Array`. +- `GET` or `HEAD` requests should never have a body. +- Do not declare variables that start with `new` or `class`. +- Do not use `.length` as the argument to `.slice()`. +- Use `Buffer.from()`, not `new Buffer()`. +- Do not use objects as default parameters. +- Do not pass single-element arrays to Promise methods. +- Do not define a class that only has static members. +- Do not use `.then()`. +- Do not assign to `this`. +- Do not use `typeof x === "undefined"`. +- `await` cannot be used on non-promise values. +- You cannot ignore consecutive values when destructuring an array, e.g. `[,,,, val]`. +- You cannot use IIFEs. +- Promises should not return `.resolve()` or `.reject()`. +- You should not spread an array into a new array without adding values. +- You should not associate any case statements with the default statement. +- Number literals cannot have trailing zeroes after the decimal place. +- Number literals must use proper case. +- Numbers over 9999 should use `_` to separate each group of three digits, e.g. `10_000`. +- If you need to flatten an array, use `Array.flat()`. +- Prefer `.flatMap()` over `.map().flat()`. +- Prefer `indexOf` over `findIndex`. +- Prefer `.some()` over `.filter().length`. +- Prefer `.at()` for accessing array and string indices. +- Prefer `.codePointAt()` over `.charCodeAt()`. +- Prefer `Date.now()` over `new Date().getTime()`. +- Use default parameters instead of reassigning undefined values. +- Use `Math.trunc` to round numbers, not bitwise operators. +- Use ESM modules, not CJS. +- Use coercion functions such as `String()` directly. +- Use a negative index instead of `.legnth - 1`. +- Use the `node:` protocol when importing built-in packages. +- Use `Number` properties instead of global helpers e.g. `Number.isNaN()` over `isNaN()`. +- Use `Object.fromEntries` to create an object from key-value pairs. +- If a `catch` block does not use the `error` parameter, the parameter should be omitted. +- Prefer calling prototype methods over instance methods. +- Prefer using `Set.has()` over `Array.includes` to check for existence. +- Prefer using `Set.size` over `Array.length`. +- Prefer using the spread operator over `Array.concat()` or `String.split("")`. +- Prefer using `String.replaceAll()` over regex searches. +- Prefer `String.slice()` over `String.substr[ing]()`. +- Prefer `String.startsWith()` or `.endsWith()` over `RegExp.test()`. +- Prefer `String.trim[Start|End]()` over `String.trim[Left|Right]()`. +- Use `structuredClone` to create a deep clone of an object. +- Use top-level await instead of IIFEs. +- Variable names should not be abbreviated. +- `Array.join()` must always be given a separator. +- `Number.toFixed()` must always be given a digits argument. + +## 2.2. React Rules + +These rules apply to TSX, and will run on files in `src/**/*.tsx`. + +- Boolean properties should be named accordingly, such as `isEnabled` instead of `enabled`. +- Buttons must always have a `type` attribute. +- If a radio button or checkbox is checked, it must be `readonly` or have an `onChange` handler. +- Default properties should match the property types. +- Properties, state, and context should always be destructured. +- Components must always have a nmae. +- A component cannot consume another component's propTypes. +- PropTypes cannot use `any`, `array`, or `object`. +- `forwardRef` components must use `ref`. +- Components should always be defined as named arrow functions. +- State should have matching names, e.g. `[color, setColor]`. +- `iframes` should always use the `sandbox` attribute. +- Boolean properties should always be explicitly written: ``. +- Spaces between JSX elements must be explicitly written: `{' '}`. +- Files that contain JSX must have the extension `.jsx` or `.tsx`. +- Fragments should always use the shorthand syntax. +- Event handlers must be appropriately named: `onChange={this.handleChange}` +- Iterators must always have a `key` prop, and it should never be the index. +- You should not use `.bind()` in component props +- You should not insert comments as text nodes. +- Contexts should not use mutable values (e.g. objects), to prevent re-renders. +- Components should not have duplicate properties. +- Avoid leaking conditional values. Prefer `condition ? : null` over `condition && `. +- Element text should always be wrapped in JSX containers. +- You should never use `javascript:` urls. +- `target=_blank` must always be accompanied with `rel=noreferrer`. +- You should not use variables that are not declared. +- You should not use fragments unless there is no singular wrapping element. +- Components should use PascalCase. +- You should not spread props multiple times. +- Props should be sorted alphabetically. +- You should not access `this.state` inside any `setState` functions. +- You should not use arrow functions for lifecycle methods. +- Children cannot be passed as props. +- You cannot use dangerous properties (`dangerouslySetInnerHTML`). +- You cannot use deprecated methods. +- You cannot use `setState` in `componentDidMount` or `componentDidUpdate` or `componentWillUpdate`. +- You cannot directly mutate `this.state`. +- You cannot use `findDOMNode`. +- You cannot use `isMounted`. +- Each file should have only one component. +- `ReactDOM.render`'s return value should not be used. +- You should not use string references. +- `this` cannot be used in stateless functional components. +- HTML entities must be escaped. +- You cannot use unknown HTML properties. +- You cannot use unsafe lifecycle methods. +- You cannot define a component within another component. +- Class components should not have unused methods. +- Components should not have unused propTypes or state +- Class components should use the ES6 `class Component extends React.Component` syntax. +- Props should be readonly. +- Stateless components should be pure functions. +- Property accesses must be reflected in the propTypes. +- Any optional property must have a default value. +- Classes using the `render` method MUST return a value. +- Components without children must still have a separate closing tag. +- State initialisation must always happen in the constructor. +- Static properties should be defined as `static name = `. +- The `style` property must always be an object. +- Void elements `img`, `br` etc. must never have children. + +## 2.3. Playwright Rules + +These files apply to Playwright End-to-end tests, and will run on `e2e/**/*.spec.ts`. + +- All tests must have at least one `expect` assertion. +- `describe` calls cannot be nested more than two levels deep. +- Playwright APIs must be `await`ed. +- Tests cannot be commented out. +- `expect` cannot be called conditionally. +- Tests cannot contain conditional logic. +- Setup and teardown hooks cannot be duplicated. +- You cannot use element handles (`page.$`). +- You cannot use `page.$eval()`. +- Tests cannot be focused with `.only()`. +- Tests cannot be forced with `{ force: true }`. +- You cannot use `getByTitle()`. +- You cannot use the `networkidle` option. +- You cannot use `first()`, `lat()`, or `nth()`. +- You cannot use `page.pause()`. +- You cannot use `page.locator()`. Prefer specific methods like `page.getByRole()`. +- Tests cannot be skipped with `.skip()`. +- `expect` can only be called within test blocks. +- You cannot reference variables in `page.evaluate()`. +- Some Playwright methods are synchronous - these cannot be `await`ed. +- You cannot use `.not()` when a specific matcher exists. +- You cannot use `page.waitForSelector()` or `page.waitForTimeout()`. +- Prefer `.toBeGreaterThan()` over `(x > 5).toBe(true)`. +- Prefer `.toBe(5)` over `(x === 5).toBe(true)` +- Hooks should be ordered as Playwright calls them: `beforeAll`, `beforeEach`, `afterEach`, `afterAll`. +- Hooks should be at the top of the test. +- Test names should be lowercase. +- Use `.toStrictEqual()` over `.toEqual()`. +- Use `.toBe()` over `.toStrictEqual()` for primitive values. +- Use `.toContain()` over `.includes()`. +- Use `.toHaveCount()` over `locator.count()` and `.toHaveLength()` over `.length`. +- Prefer assertions like `.toBeVisible()` over `(locator.isVisible()).toBe(true)`. +- Setup and teardown code must be in a hook. +- `.toThrow()` assertions require a message. +- Tests must be within a `describe` block. +- All `expect()` calls must have a custom message. +- Promises that contain an `expect` must be awaited. +- Tests must have a title that is not empty. + +## 2.4. Vitest Rules + +These files apply to Vitest unit tests, and will run on `test/**/*.spec.ts`. + +:::warn +We also mandate the use of `describe`, `it`, and `expect` over `suite`, `test`, and `assert`. +::: + +- Files must have `.spec.ts` extension. +- consistent-test-it +- Tests must have at least one `expect`. +- `describe` calls cannot be nested more than two levels deep. +- Prefer `.toHaveBeenCalled()` over `.toBeCalled()`. +- Tests cannot be commented out. +- `expect` cannot be called conditionally. +- Tests cannot contain conditional logic. +- Tests cannot be run conditionally. +- Tests cannot be disabled. +- You cannot use the `done()` callback. +- Setup and teardown hooks cannot be duplicated. +- Tests cannot be focused with `.only()`. +- Test titles must be unique. +- `node:test` cannot be imported. +- Snapshots cannot use string interpolation. +- `expect` must be within `it` or `test`. +- Tests cannot use `return`. +- Prefer `toHaveBeenCalledWith()` over `toHaveBeenCalled()`. +- Prefer `.toBeGreaterThan()` over `(x > 5).toBe(true)`. +- Use `describe.each` instead of manual loops. +- Prefer `.toBe(5)` over `(x === 5).toBe(true)`. +- All tests must start with `expect.assertions(number)`. +- Use `expect.resolves(fn)` over `expect(await fn)`. +- Hooks should be ordered as Vitest calls them: `beforeAll`, `beforeEach`, `afterEach`, `afterAll`. +- Hooks should be at the top of the test. +- Test titles should be lowercase. +- Prefer `vi.fn().mockResolvedValue(val)` over `vi.fn().mockImplementation(() => Promise.resolve(val))`. +- Prefer `vi.spyOn(Date, "now")` instead of overwriting the global `Date.now = vi.fn()`. +- Use `.toStrictEqual()` over `.toEqual()`. +- Use `.toBe()` over `.toStrictEqual()` for primitive values. +- Use `.toBeFalsy()` over `.toBe(false)`. +- Use `.toBeObject()` over `.toBeInstanceOf(Object)`. +- Use `.toBeTruthy()` over `.toBe(true)`. +- Use `.toContain()` over `.includes()`. +- Use `.toHaveLength()` over `.length`. +- Use `test.todo()` instead of `test.skip()`. +- Setup and teardown code must be in a hook. +- `.toThrow()` assertions require a message. +- Tests must be within a `describe` block. +- The `describe` callback should not have any parameters and cannot use `return`. +- All `expect()` calls must have a custom message. +- Tests must have a title that is not empty. diff --git a/src/content/docs/staff/apply.md b/src/content/docs/staff/apply.md index 31930aa..9cb9b92 100644 --- a/src/content/docs/staff/apply.md +++ b/src/content/docs/staff/apply.md @@ -6,14 +6,9 @@ title: Join Our Staff Team Unless explicitly stated otherwise in a separate written agreement, all positions within our organization are on a voluntary basis. No compensation, monetary or otherwise, should be expected for these roles. -## 2. Selection Process +## 2. Application Process -Our team member selection process is based on the following criteria: -1. Active participation in the community -2. Length of membership in the community -3. Quality and nature of interactions with other community members - -If you are selected as a potential team member, our representative, Naomi, will contact you directly with further information and instructions. +If you feel ready to apply to join our team, please complete the [application form](https://nhcarrigan.com/apply). ## 3. Legal Disclaimer