Skip to content

Commit

Permalink
chore: more detailed docs for memorable moniker (#166)
Browse files Browse the repository at this point in the history
* chore: more docs for memorable moniker

* chore: change files

* fix: use builder to get project list

* fix: docs

Co-authored-by: mmkal <mmkal@users.noreply.github.com>
  • Loading branch information
mmkal and mmkal committed Sep 18, 2020
1 parent 965ac7d commit 51e7d01
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 14 deletions.
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

0 comments on commit 51e7d01

Please sign in to comment.