Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: more detailed docs for memorable moniker #166

Merged
merged 5 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ jobs:
uses: actions/github-script@v3
with:
script: |
const release = require(`${process.env.GITHUB_WORKSPACE}/tools/builder/dist/github-release`)
return release.createGitHubRelease({ context, github })
const builder = require(`${process.env.GITHUB_WORKSPACE}/tools/builder`)
return builder.createGitHubRelease({ context, github })
11 changes: 11 additions & 0 deletions common/changes/memorable-moniker/moniker-docs_pr_166.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "chore: more detailed docs for memorable moniker (#166)",
"type": "patch",
"packageName": "memorable-moniker"
}
],
"packageName": "memorable-moniker",
"email": "mmkal@users.noreply.github.com"
}
66 changes: 65 additions & 1 deletion packages/memorable-moniker/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,71 @@ men.next() // Stanley Coronado
people.next() // Javion Farrar
```

The `.modify` function allows tweaking the behavior of the generators. Here are some usage examples:
<!-- codegen:start {preset: markdownFromJsdoc, source: src/index.ts, export: nicknames} -->
#### [nicknames](./src/index.ts#L134)

The easiest way to get a name-generator is to import the `nicknames` generator and customise it as necessary. The `.modify(...)` method returns a new instance of a generator which extends the original. It receives a partial dictionary of parameters, or a function which returns one - the function receives the parent's configuration as an input. Parameters that can be modified:

**dictionaries** -- A list of "dictionaries" that words should be chosen from. These can be one of the preset values ('animal', 'femaleName', 'maleName', 'lastName', 'positiveAdjective'), or an object with a property called `words` which should be an array of strings. It's also possible to pass a list of dictionaries, in the same format. Some examples:

##### Example

```typescript
const animalGenerator = nicknames.modify({
dictionaries: ['animal']
})
const formalAnimalGenerator = nicknames.modify({
dictionaries: ['animal', 'lastName']
})
const veryFormalAnimalGenerator = nicknames.modify({
dictionaries: [{words: ['Mr', 'Ms', 'Mrs']}, 'animal', 'lastName']
})
```

**rng** -- A random-number generator. A function that should return a value between 0 and 1. The lower bound should be inclusive and the upper bound exclusive. As a convenience, the default random-number generator has an `rng.seed('...')` function to allow getting a seeded rng based on the original. Usage:

##### Example

```typescript
const myNameGenerator = nicknames.modify(params => ({ rng: params.rng.seed('my-seed-value') }))
console.log(myNameGenerator.next()) // always returns the same value
```

**format** -- A function which transforms dictionary words before returning them from the generator. For example, you could convert from kebab-case to snake_case with:

##### Example

```typescript
const myGenerator = nicknames.modify({
format: word => word.replace(/-/g, '_')
})
```

**choose** -- A function which receives a list of words, and a random-number generator function, and should return a single word. Typically this wouldn't need to be modified.

**join** -- A function which receives one word from each dictionary, and is responsible for joining them into a single value. Usually the return value is a string, but if another format is returned the type will be correctly inferred.

##### Example

```typescript
const informalPeople = nicknames.modify({
dictionaries: [['maleName', 'femaleName'], 'lastName']
join: (firstName, lastName) => `${firstName} ${lastName}`,
})
const formalPeople = nicknames.modify({
dictionaries: [['maleName', 'femaleName'], 'lastName']
join: (firstName, lastName) => `${lastName}, ${firstName}`,
})
const structuredPeople = nicknames.modify({
dictionaries: [['maleName', 'femaleName'], 'lastName']
join: (firstName, lastName) => ({ name: { first: firstName, last: lastName } }),
})
```
<!-- codegen:end -->

___

Some usage examples of the `.modify` function tweaking generator behavior:

<!-- codegen:start {preset: markdownFromTests, source: src/__tests__/index.test.ts} -->
Nicknames/handles:
Expand Down
73 changes: 72 additions & 1 deletion packages/memorable-moniker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export type Dictionary = WordList | {words: string[]} | Dictionary[]

export interface Params<T> {
dictionaries: Dictionary[]
format: (word: string) => string
rng: Rng
format: (word: string) => string
choose: (params: {dict: string[]; rng: () => number}) => string
join: (parts: string[]) => T
}
Expand All @@ -18,6 +18,7 @@ export type InputParams<T> =
Partial<Omit<Params<T>, 'rng'> & {
rng: () => number;
}>

export interface NameGenerator<T> {
params: Params<T>
modify: <U = T>(changes: InputParams<U> | ((original: Params<T>) => InputParams<U>)) => NameGenerator<U>
Expand Down Expand Up @@ -60,6 +61,76 @@ export const createNameGenerator = <T>(params: Params<T>): NameGenerator<T> => {
}
}

/**
* The easiest way to get a name-generator is to import the `nicknames` generator and customise it as necessary.
* The `.modify(...)` method returns a new instance of a generator which extends the original.
* It receives a partial dictionary of parameters, or a function which returns one - the function receives the
* parent's configuration as an input.
*
* Parameters that can be modified:
*
* @description **dictionaries** --
*
* A list of "dictionaries" that words should be chosen from. These can be one of the preset
* values ('animal', 'femaleName', 'maleName', 'lastName', 'positiveAdjective'), or an object with a property
* called `words` which should be an array of strings. It's also possible to pass a list of dictionaries, in the
* same format. Some examples:
*
* @example
* const animalGenerator = nicknames.modify({
* dictionaries: ['animal']
* })
* const formalAnimalGenerator = nicknames.modify({
* dictionaries: ['animal', 'lastName']
* })
* const veryFormalAnimalGenerator = nicknames.modify({
* dictionaries: [{words: ['Mr', 'Ms', 'Mrs']}, 'animal', 'lastName']
* })
*
* @description **rng** --
*
* A random-number generator. A function that should return a value between 0 and 1. The lower bound
* should be inclusive and the upper bound exclusive. As a convenience, the default random-number generator
* has an `rng.seed('...')` function to allow getting a seeded rng based on the original. Usage:
*
* @example
* const myNameGenerator = nicknames.modify(params => ({ rng: params.rng.seed('my-seed-value') }))
* console.log(myNameGenerator.next()) // always returns the same value
*
* @description **format** --
*
* A function which transforms dictionary words before returning them from the generator. For example,
* you could convert from kebab-case to snake_case with:
*
* @example
* const myGenerator = nicknames.modify({
* format: word => word.replace(/-/g, '_')
* })
*
* @description **choose** --
*
* A function which receives a list of words, and a random-number generator function, and should return
* a single word. Typically this wouldn't need to be modified.
*
* @description **join** --
*
* A function which receives one word from each dictionary, and is responsible for joining them into a single
* value. Usually the return value is a string, but if another format is returned the type will be correctly inferred.
*
* @example
* const informalPeople = nicknames.modify({
* dictionaries: [['maleName', 'femaleName'], 'lastName']
* join: (firstName, lastName) => `${firstName} ${lastName}`,
* })
* const formalPeople = nicknames.modify({
* dictionaries: [['maleName', 'femaleName'], 'lastName']
* join: (firstName, lastName) => `${lastName}, ${firstName}`,
* })
* const structuredPeople = nicknames.modify({
* dictionaries: [['maleName', 'femaleName'], 'lastName']
* join: (firstName, lastName) => ({ name: { first: firstName, last: lastName } }),
* })
*/
export const nicknames = createNameGenerator({
dictionaries: ['positiveAdjective', 'animal'],
// prettier-ignore
Expand Down
14 changes: 7 additions & 7 deletions scripts/badges.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const dedent = require('dedent')
const readPkgUp = require('read-pkg-up')
const path = require('path')
const dedent = require('../packages/eslint-plugin-codegen/node_modules/dedent')
const {getRushJson} = require('../tools/builder')

/** @type {import('eslint-plugin-codegen').Preset<{}>} */
/** @type {import('../packages/eslint-plugin-codegen').Preset<{}>} */
module.exports = params => {
const {path: rootPath} = readPkgUp.sync()
const {path: leafPath, packageJson: leafPkg} = readPkgUp.sync({cwd: params.meta.filename})
const relativePath = path.relative(path.dirname(rootPath), path.dirname(leafPath)).replace(/\\/g, '/')
const {rush} = getRushJson()
const matchedProject = rush.projects.find(p => params.meta.filename.replace(/\\/g, '/').includes(p.projectFolder))
const relativePath = matchedProject.projectFolder
const leafPkg = {name: matchedProject.packageName}

const repo = 'https://github.com/mmkal/ts'

Expand Down
2 changes: 1 addition & 1 deletion scripts/permalink.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const glob = require('glob')
const fs = require('fs')
const path = require('path')
const readPkgUp = require('read-pkg-up')
const readPkgUp = require('../packages/eslint-plugin-codegen/node_modules/read-pkg-up')
const childProcess = require('child_process')

const readmes = glob.sync('**/*.md', {ignore: ['**/node_modules/**', '**/CHANGELOG.md']})
Expand Down
7 changes: 5 additions & 2 deletions tools/builder/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ module.exports = {
rules: {
'prettier/prettier': ['warn', require('./.prettierrc')],

// todo: enable
// 'codegen/codegen': ['warn', {presets: {badges: require('./scripts/badges')}}],
// todo: move ../../scripts somewhere that makes more sense
'codegen/codegen': ['warn', {presets: {badges: require('../../scripts/badges')}}],

'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
Expand Down Expand Up @@ -158,6 +158,9 @@ function patchModuleResolver() {
if (!ModuleResolver.originalResolve) {
ModuleResolver.originalResolve = ModuleResolver.resolve
ModuleResolver.resolve = (req, relTo) => {
if (req === 'codegen') {
return require('../../packages/eslint-plugin-codegen')
}
try {
return ModuleResolver.originalResolve(req, relTo)
} catch (error) {
Expand Down
2 changes: 2 additions & 0 deletions tools/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"run": "./run.js",
"init": "./init.js"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "node run tsc -p .",
"lint": "node run eslint --cache .",
Expand Down
4 changes: 4 additions & 0 deletions tools/builder/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// codegen:start {preset: barrel}
export * from './github-release'
export * from './rush'
// codegen:end