Skip to content

Commit

Permalink
Add checking of types in scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Jan 31, 2023
1 parent d302446 commit 824c4bd
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 38 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
*.d.ts
*.log
node_modules/
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@
],
"type": "module",
"devDependencies": {
"@types/mdast": "^3.0.0",
"mdast-comment-marker": "^2.0.0",
"mdast-zone": "^5.0.0",
"prettier": "^2.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"unist-builder": "^3.0.0",
"typescript": "^4.0.0",
"xo": "^0.53.0",
"yaml": "^2.0.0"
},
"scripts": {
"build": "tsc --build --clean && tsc --build",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test": "npm run format"
"test": "npm run build && npm run format"
},
"prettier": {
"tabWidth": 2,
Expand Down
147 changes: 111 additions & 36 deletions script/list-of-humans.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,51 @@
/**
* @typedef {import('mdast').BlockContent} BlockContent
* @typedef {import('mdast').List} List
* @typedef {import('mdast').ListItem} ListItem
* @typedef {import('mdast').PhrasingContent} PhrasingContent
* @typedef {import('mdast').Root} Root
*/

/**
* @typedef {'contributor' | 'merger' | 'maintainer' | 'releaser'} Role
*
* @typedef Team
* @property {string} name
* @property {boolean | undefined} [collective]
* @property {string | undefined} [lead]
* @property {Record<string, Role>} humans
*
* @typedef Human
* @property {string} name
* @property {string} email
* @property {string} url
* @property {string} github
* @property {string | undefined} [npm]
*/

import assert from 'node:assert/strict'
import fs from 'node:fs/promises'
import yaml from 'yaml'
import {zone} from 'mdast-zone'
import {commentMarker} from 'mdast-comment-marker'
import {u} from 'unist-builder'

/** @type {Array<Human>} */
const humans = yaml.parse(
String(await fs.readFile(new URL('../data/humans.yml', import.meta.url)))
)
/** @type {Array<Team>} */
const teams = yaml.parse(
String(await fs.readFile(new URL('../data/teams.yml', import.meta.url)))
)

const own = {}.hasOwnProperty

/** @type {import('unified').Plugin<[], Root>} */
export default function listOfHumans() {
return transform

function transform(tree, file) {
zone(tree, 'humans', onzone)

function onzone(start, nodes, end) {
const parameters = commentMarker(start).parameters
const shift = parameters.shift || 0
return function (tree, file) {
zone(tree, 'humans', function (start, nodes, end) {
const parameters = commentMarker(start)?.parameters || {}
const shift = Number(parameters.shift) || 0
const name = parameters.team

if (!name) {
Expand All @@ -32,82 +56,133 @@ export default function listOfHumans() {

if (!team) {
file.fail('Missing definition for team `' + name + '`', start)
return
}

const content = [u('heading', {depth: 1 + shift}, [u('text', 'Members')])]
/** @type {Array<BlockContent>} */
const content = [
{
type: 'heading',
// @ts-expect-error: fine.
depth: 1 + shift,
children: [{type: 'text', value: 'Members'}]
}
]
/** @type {Partial<Record<Role, Array<string>>>} */
const byRole = {}
let human

for (human in team.humans) {
if (own.call(team.humans, human)) {
byRole[team.humans[human]] = (
byRole[team.humans[human]] || []
).concat(human)
const role = team.humans[human]
const list = byRole[role]
if (Array.isArray(list)) {
list.push(human)
} else {
byRole[role] = [human]
}
}
}

if (team.collective) {
content.push(
byRole.maintainer
? list(team, byRole.maintainer)
: u('paragraph', [u('text', 'None.')])
: {type: 'paragraph', children: [{type: 'text', value: 'None.'}]}
)
} else {
content.push(
u('heading', {depth: 2 + shift}, [u('text', 'Releasers')]),
{
type: 'heading',
// @ts-expect-error: fine.
depth: 2 + shift,
children: [{type: 'text', value: 'Releasers'}]
},
byRole.releaser
? list(team, byRole.releaser)
: u('paragraph', [u('text', 'None.')]),
u('heading', {depth: 2 + shift}, [u('text', 'Mergers')]),
: {type: 'paragraph', children: [{type: 'text', value: 'None.'}]},
{
type: 'heading',
depth: 2 + shift,
children: [{type: 'text', value: 'Mergers'}]
},
byRole.merger
? list(team, byRole.merger)
: u('paragraph', [u('text', 'None.')])
: {type: 'paragraph', children: [{type: 'text', value: 'None.'}]}
)
}

if (byRole.contributor) {
content.push(
u('heading', {depth: 1 + shift}, [u('text', 'Contributors')]),
{
type: 'heading',
// @ts-expect-error: fine.
depth: 1 + shift,
children: [{type: 'text', value: 'Contributors'}]
},
list(team, byRole.contributor)
)
}

return [start].concat(content, end)
}
})
}
}

/**
* @param {Team} team
* @param {Array<string>} users
* @returns {List}
*/
function list(team, users) {
return u(
'list',
{ordered: false},
users
.map((github) => humans.find((p) => p.github === github))
return {
type: 'list',
ordered: false,
children: users
.map((github) => {
const human = humans.find((p) => p.github === github)
assert(human, 'expected human')
return human
})
.sort((a, b) => {
return a.name.localeCompare(b.name)
})
.map((human) => {
/** @type {Array<PhrasingContent>} */
const content = [
u('text', human.name + '\n('),
u('link', {url: 'https://github.com/' + human.github}, [
u('strong', [u('text', '@' + human.github)])
]),
u('text', ')')
{type: 'text', value: human.name + '\n('},
{
type: 'link',
url: 'https://github.com/' + human.github,
children: [
{
type: 'strong',
children: [{type: 'text', value: '@' + human.github}]
}
]
},
{type: 'text', value: ')'}
]

if (human.email) {
content.push(u('text', '\n<'), u('text', human.email), u('text', '>'))
content.push({type: 'text', value: '\n<' + human.email + '>'})
}

if (human.github === team.lead) {
content.push(
u('text', '\n('),
u('strong', [u('text', 'lead')]),
u('text', ')')
{type: 'text', value: '\n('},
{type: 'strong', children: [{type: 'text', value: 'lead'}]},
{type: 'text', value: ')'}
)
}

return u('listItem', [u('paragraph', content)])
/** @type {ListItem} */
const result = {
type: 'listItem',
children: [{type: 'paragraph', children: content}]
}

return result
})
)
}
}
17 changes: 17 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"include": ["**/*.js"],
"exclude": ["coverage/", "node_modules/"],
"compilerOptions": {
"checkJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"lib": ["es2020"],
"module": "node16",
"newLine": "lf",
"skipLibCheck": true,
"strict": true,
"target": "es2020"
}
}

0 comments on commit 824c4bd

Please sign in to comment.