Skip to content

Latest commit

 

History

History
331 lines (248 loc) · 11.3 KB

CONTRIBUTING.md

File metadata and controls

331 lines (248 loc) · 11.3 KB

A lot of effort has been put into Faker to create a useful and handy library. There are still a lot of things to be done, so all contributions are welcome! If you want to make Faker a better, please read the following contribution guide.

Important

  • Please make sure that you run pnpm install, pnpm run build and pnpm run test before making a PR to ensure that everything is working from the start.

Good to know

  • The project is being built by esbuild (see bundle.ts)
  • The documentation is running via VitePress. Make sure you build the project before running the docs, cause some files depend on dist. Use pnpm run docs:dev to edit them in live mode.
  • The tests are executing vitest against test/**/*.spec.ts
  • If you update the locales, make sure to run pnpm run generate:locales to generate/update the related files.

Architecture

The sources are located in the src directory. All fake data generators are divided into namespaces (each namespace being a separate module). Most of the generators use the definitions, which are just plain JavaScript objects/arrays/strings that are separate for each locale.

Building Faker

The project is being built by esbuild (see bundle.ts)

pnpm install
pnpm run build

Testing

Before you can run the tests, you need to install all dependencies and build the project, because some tests depend on the bundled content.

pnpm install
pnpm run build

pnpm run test
# or
pnpm run coverage

You can view a generated code coverage report at coverage/index.html.

Adding new locale or updating existing one

After adding new or updating existing locale data, you need to run pnpm run generate:locales to generate/update the related files.

Deprecation workflow

If you ever find yourself deprecating something in the source code, you can follow these steps to save yourself (and the reviewers) some trouble.

If the code you want to deprecate is a property, convert it to a getter first. Now that you have a function, the first thing you want to do is call the internal deprecated function. Afterwards, add a @deprecated parameter to the end of the JSDoc with a human readable description message with a suitable replacement for the deprecated function. Lastly, add a @see parameter to the JSDoc with a link to the replacement in the faker library (if it exists). The syntax for the link is faker.[module].[function].

Example:

/**
 * @see faker.cat.random()
 *
 * @deprecated Use faker.cat.random() instead.
 */
get cat() {
  deprecated({
    deprecated: 'faker.animal.cat',
  });
  return 'cat';
}

JSDocs

JSDoc are comments above any code structure (variable, function, class, etc.) that begin with /** and end with */. Multiline comments start (if not being the start or end line) with a *. For more info checkout jsdoc.app.

JSDoc will be read and automatically processed by generate:api-docs and therefore need to follow some project conventions. Other standards are in place because we think they increase the code quality.

We use eslint-plugin-jsdoc to test for basic styling and sorting of doc-tags.

This is in place so all JSDoc tags will get sorted automatically, so you don't have to bother with it. This also means that most rules in this section can get auto fixed by the eslint formatter.

JSDocs should always be multiline

While single line JSDoc are technically valid, we decided to follow this rule since it makes changes in the git diff much more clear and easier to understand.

Do Dont
/**
 * This is a good JSDoc description.
 */
function foo() {
  // implementation
}
/** This is a bad JSDoc description. */
function foo() {
  // implementation
}

Everything that can be accessed directly by a user should have JSDoc.

This rule is aimed to target anything that is exported from the faker library. This includes types, interfaces, functions, classes and variables. So if you introduce anything new that is not internal, write JSDoc for it.

If a @param has a default value, it needs to be mentioned at the end of the sentence.

/**
 * This is a good JSDoc description.
 *
 * @param bar this is a parameter description. Defaults to `0`.
 */
function foo(bar: number = 0) {
  // implementation
}

If a function can throw an error (FakerError) you have to include the @throws tag with an explanation when an error could be thrown

/**
 * This is a good JSDoc description.
 *
 * @param bar this is a parameter description. Defaults to `0`.
 *
 * @throws If bar is negative.
 */
function foo(bar: number = 0) {
  // implementation
}

Sentences should always end with a period.

This rule ensures minimal grammatical correctness in the comments and ensures that all comments look the same.

Different tags have to be separated by an empty line.

This rule improves the comments readability by grouping equivalent tags and making them more distinguishable from others.

Do Dont
/**
 * This is a bad JSDoc block, because it has no linebreaks between sections.
 * @param bar The first argument.
 * @param baz The second argument.
 * @example foo(1, 1) // [1, 1]
 * @example foo(13, 56) // [13, 56]
 */
function foo(bar: number, baz: number): [number, number] {
  // implementation
}
/**
 * This is a good JSDoc block, because it follows the Faker preferences.
 *
 * @param bar The first argument.
 * @param baz The second argument.
 *
 * @example foo(1, 1) // [1, 1]
 * @example foo(13, 56) // [13, 56]
 */
function foo(bar: number, baz: number): [number, number] {
  // implementation
}

Developing the docs

Before running the docs, build the Faker dist, it's used inside of certain routes.

pnpm run build

pnpm run docs:dev

Building and serving the docs statically

If you changed something heavily in the docs, like auto-generating content, you should check the docs statically, because it could differ from the dev version. Before running the docs, build the Faker dist, it's used inside of certain routes.

pnpm run build

pnpm run docs:build # Output docs to /dist
pnpm run docs:serve # Serve docs from /dist

Deploying documentation

See the netlify.toml for configuration.

Committing

Pull Request titles need to follow our semantic convention.

PR titles are written in following convention: type(scope): subject

type is required and indicates the intent of the PR

The types feat and fix will be shown in the changelog as ### Features or ### Bug Fixes
All other types wont show up except for breaking changes marked with the ! in front of :

Allowed types are:

type description
feat A new feature is introduced
fix A bug was fixed
chore No user affected code changes were made
refactor A refactoring that affected also user (e.g. log a deprecation warning)
docs Docs were changed
test Test were changed
ci CI were changed
build Build scripts were changed
infra Infrastructure related things were made (e.g. issue-template was updated)
revert A revert was triggered via git

scope is optional and indicates the scope of the PR

The scope will be shown in the changelog in front of the subject in bold text
Also as the commits are sorted alphabetically, the scope will group the commits indirectly into categories

Allowed scopes are:

scope description
<module-name> The specific module name that was affected by the PR
locale When only locale(s) are added/updated/removed
module When some modules where updates or something related to modules were changed
revert When a revert was made via git
deps Will mostly be used by Renovate
release Will be set by release process

The scope is not checkable via Semantic Pull Request action as this would limit the scopes to only existing modules,
but if we add a new module like color, then the PR author couldn't use the new module name as scope.
As such, we (the Faker team) must be mindful of valid scopes and we reserve the right to edit titles as we see fit.

subject is required and describes what the PR does

Please note that the PR title should not include a suffix of e.g. (#123) as this will be done automatically by GitHub while merging

Some examples of valid pull request titles:

feat: add casing option
feat(locale): extend Hebrew (he)
fix: lower target to support Webpack 4
chore: add naming convention rule
refactor(address): deprecate streetPrefix and streetSuffix
docs: remove unused playground
test: validate @see contents
ci: allow breaking change commits
build: add node v18 support
infra: rework bug-report template
revert: add more arabic names dataset (#362)

# Breaking changes
refactor!: remove faker default export
build!: remove node v12 support

# A release PR will look like this
chore(release): 7.4.0

# Renovate automatically generates these
chore(deps): update devdependencies
chore(deps): update typescript-eslint to ~5.33.0

Previous pull request titles that could have been written in a better way:

- feat: `datatype.hexadecimal` signature change
+ feat(datatype): hexadecimal signature change
  datatype is one of our modules and can be used as scope

- feat(image): add image via.placeholder provider
+ feat(image): add via.placeholder provider
  image was redundant in the subject

- feat(system.networkInterface): add networkInterface faker
+ feat(system): add networkInterface method
  networkInterface was redundant in the scope and made the whole commit message long
  also method in the subject explains a bit better what it is

- chore(bug-report-template): new design
+ infra: rework bug-report template
  the type infra tells that no actual code-changes were made
  the subject contains what the PR does

- chore: rename Gender to Sex
+ refactor(name): rename Gender to Sex
  this was not a chore as it touched runtime code that affected the end-user
  scope name can be used here to tell that the change affects only the name module