[READ-ONLY] Mirror of https://github.com/danielroe/siroc. Zero-config build tooling for Node
bundle node package rollup typescript
0

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove `changelog` command and rethink presets

BREAKING CHANGE: `changelog` is no longer a valid command and `@siroc/jest-preset` and `@siroc/eslint-config` must be installed separately

Daniel Roe (Jul 27, 2020, 11:29 AM +0100) 9fd5e8a0 13338cd7

+41 -276
+41 -27
README.md
··· 22 22 23 23 - 💯 **Zero-config required**: Intelligent support for your package 24 24 - Supports running and compiling TypeScript and the latest JavaScript syntax 25 - - Autoconfigured `jest` and `eslint` 25 + - Autoconfigured `jest` and `eslint` with optional presets 26 26 - ⚒️ **Extensible**: Write your own commands and build hooks 27 27 - 💪 **Typescript**: Fully typed and self-documenting 28 28 ··· 120 120 121 121 Running `siroc dev` will replace your package entrypoints with stubs that point to your source files. Your binaries will run your source files directly using `jiti`. 122 122 123 - ### `siroc eslint` 124 - 125 - Rather than configure `eslint`, you can run it directly using `siroc eslint`, with support for TypeScript (and prettier, if you have it installed within your package dev dependencies). 126 - 127 - If you would like to extend or modify the siroc base config you can do so with the following `.eslintrc.js` 128 - 129 - ```js 130 - module.exports = { 131 - extends: ['@siroc'], 132 - // Your rules/plugins here 133 - } 134 - ``` 135 - 136 - ### `siroc jest` 137 - 138 - Rather than configure `jest`, you can run it directly using `siroc jest`, with support for TypeScript test and source files. By default it will include any settings from a local `jest.config.js`. 139 - 140 - If you would like to extend or modify the siroc base config (for example, to run jest directly with `yarn jest`) you can do so with the following `jest.config.js` 141 - 142 - ```js 143 - module.exports = { 144 - preset: '@siroc/jest-preset', 145 - // Your customisations here 146 - } 147 - ``` 148 - 149 123 ### `siroc run` 150 124 151 125 You can run arbitrary shell commands or node scripts using the power of [the `jiti` runtime](https://github.com/nuxt-contrib/jiti). ··· 159 133 # You can run a command in all your workspaces 160 134 yarn siroc run ls --workspaces 161 135 ``` 136 + 137 + ## Presets 138 + 139 + ### eslint 140 + 141 + Rather than configure `eslint`, you can extend `@siroc/eslint-config`, with zero-config support for TypeScript (and prettier, if you have it installed within your package dev dependencies). 142 + 143 + 1. Add the eslint config: 144 + 145 + ```bash 146 + yarn add --dev @siroc/eslint-config 147 + ``` 148 + 149 + 2. Add the following `.eslintrc.js` to your project: 150 + 151 + ```js 152 + module.exports = { 153 + extends: ['@siroc'], 154 + // Your rules/plugins here 155 + } 156 + ``` 157 + 158 + ### jest 159 + 160 + Rather than configure `jest`, you can extend `@siroc/jest-preset`, with zero-config support for TypeScript test and source files. By default it will also include any settings from a local `jest.config.js` (e.g. in a package directory). 161 + 162 + 1. Add the jest preset: 163 + 164 + ```bash 165 + yarn add --dev @siroc/jest-preset 166 + ``` 167 + 168 + 2. Add the following `jest.config.js` to your project: 169 + 170 + ```js 171 + module.exports = { 172 + preset: '@siroc/jest-preset', 173 + // Your customisations here 174 + } 175 + ``` 162 176 163 177 ## Contributors 164 178
-2
packages/cli/package.json
··· 29 29 }, 30 30 "dependencies": { 31 31 "@siroc/core": "0.2.0", 32 - "@siroc/eslint-config": "0.2.0", 33 - "@siroc/jest-preset": "0.2.0", 34 32 "cac": "^6.6.1", 35 33 "chalk": "^4.1.0", 36 34 "consola": "^2.14.0",
-20
packages/cli/src/index.ts
··· 9 9 import { version } from '../package.json' 10 10 11 11 import { build, BuildCommandOptions } from './commands/build' 12 - import { changelog } from './commands/changelog' 13 12 import { dev, DevCommandOptions } from './commands/dev' 14 13 import { run as runFile } from './commands/run' 15 - import { test } from './commands/testing' 16 14 17 15 import { time, timeEnd, RemoveFirst } from './utils' 18 16 ··· 69 67 ) 70 68 71 69 cli 72 - .command('changelog', 'Generate changelog') 73 - .action(() => run('changelog', changelog)) 74 - 75 - cli 76 70 .command('dev [...packages]', 'Generate package stubs for quick development') 77 71 .example(bin => ` ${bin} dev`) 78 72 .example(bin => ` ${bin} dev ${exampleProject} -w`) ··· 89 83 .example(bin => ` ${bin} --workspaces ls`) 90 84 .action((file, args, options) => 91 85 run('running', runFile, { file, args, options }) 92 - ) 93 - 94 - cli 95 - .command('jest [...packages]', 'Run jest ') 96 - .example(bin => ` ${bin} jest`) 97 - .example(bin => ` ${bin} jest @siroc/cli`) 98 - .action(packages => run('starting jest', test, { packages, command: 'jest' })) 99 - 100 - cli 101 - .command('eslint [...packages]', 'Run eslint ') 102 - .example(bin => ` ${bin} eslint`) 103 - .example(bin => ` ${bin} eslint @siroc/cli`) 104 - .action(packages => 105 - run('starting eslint', test, { packages, command: 'eslint' }) 106 86 ) 107 87 108 88 Object.entries(rootPackage.options.commands).forEach(([command, action]) => {
-9
packages/cli/src/commands/changelog.ts
··· 1 - import { writeFile } from 'fs-extra' 2 - import { getChangelog, Package } from '@siroc/core' 3 - 4 - export async function changelog(rootPackage: Package) { 5 - const changelog = await getChangelog(rootPackage) 6 - 7 - process.stdout.write('\n\n' + changelog + '\n\n') 8 - await writeFile('CHANGELOG.md', changelog, 'utf-8') 9 - }
-72
packages/cli/src/commands/testing.ts
··· 1 - import { join } from 'path' 2 - 3 - import { Package } from '@siroc/core' 4 - import { bold, gray } from 'chalk' 5 - 6 - const runJest = (pkg: Package) => { 7 - let jestConfig 8 - try { 9 - jestConfig = join( 10 - require.resolve('@siroc/jest-preset'), 11 - '../jest.config.js' 12 - ) 13 - pkg.execInteractive(`yarn jest --passWithNoTests -c ${jestConfig}`) 14 - } catch (e) { 15 - if (!jestConfig) { 16 - pkg.logger.error(`Couldn't resolve jest config.\n`, gray(e)) 17 - } else { 18 - pkg.logger.error( 19 - `Error running ${bold('jest')} -c ${jestConfig}\n`, 20 - gray(e) 21 - ) 22 - } 23 - } 24 - } 25 - 26 - const runEslint = (pkg: Package) => { 27 - let eslintConfig 28 - try { 29 - eslintConfig = join( 30 - require.resolve('@siroc/eslint-config'), 31 - '../.eslintrc.js' 32 - ) 33 - const { stdout } = pkg.execInteractive( 34 - `yarn eslint -c ${eslintConfig} --ext .js,.ts .` 35 - ) 36 - if (stdout) stdout.pipe(process.stdout) 37 - } catch (e) { 38 - if (!eslintConfig) { 39 - pkg.logger.error(`Couldn't resolve eslint config.\n`, gray(e)) 40 - } else { 41 - pkg.logger.error( 42 - `Error running ${bold('eslint')} -c ${eslintConfig}\n`, 43 - gray(e) 44 - ) 45 - } 46 - } 47 - } 48 - 49 - const commands = { 50 - jest: runJest, 51 - eslint: runEslint, 52 - } as const 53 - 54 - export type Command = keyof typeof commands 55 - 56 - interface CommandOptions { 57 - command: Command 58 - packages: string[] 59 - options?: Record<string, any> 60 - } 61 - 62 - export async function test( 63 - rootPackage: Package, 64 - { packages, command }: CommandOptions 65 - ) { 66 - if (packages.length) { 67 - const workspacePackages = await rootPackage.getWorkspacePackages(packages) 68 - workspacePackages.forEach(async pkg => commands[command](pkg)) 69 - } else { 70 - commands[command](rootPackage) 71 - } 72 - }
-146
packages/core/src/version/changelog.ts
··· 1 - import { Package, PackageJsonPerson } from '../package' 2 - import { ensureUnique, groupBy } from '../utils' 3 - 4 - const types = { 5 - fix: { title: '🐛 Bug Fixes' }, 6 - feat: { title: '🚀 Features' }, 7 - refactor: { title: '💅 Refactors' }, 8 - perf: { title: '🔥 Performance' }, 9 - examples: { title: '📝 Examples' }, 10 - chore: { title: '🏡 Chore' }, 11 - test: { title: '👓 Tests' }, 12 - types: { title: '🇹 Types' }, 13 - } as const 14 - 15 - type CommitType = keyof typeof types 16 - const allowedTypes = Object.keys(types) as CommitType[] 17 - 18 - interface Commit { 19 - message: string 20 - commit: string 21 - authorName: string 22 - authorEmail: string 23 - } 24 - 25 - interface ConventionalCommit extends Commit { 26 - type: CommitType 27 - scope: string 28 - references: string[] 29 - } 30 - 31 - export async function getChangelog(pkg: Package) { 32 - // Get last git tag and current branch 33 - const { lastGitTag, branch, contributors } = pkg 34 - 35 - // Get all commits from last release to current branch 36 - pkg.logger.info(`${branch}...${lastGitTag}`) 37 - const commits = getGitDiff(pkg, branch, lastGitTag) 38 - 39 - // Parse commits as conventional commits 40 - const conventionalCommits = parseCommits(commits).filter( 41 - c => allowedTypes.includes(c.type) && c.scope !== 'deps' 42 - ) 43 - 44 - // Generate markdown 45 - return generateMarkDown(conventionalCommits, contributors) 46 - } 47 - 48 - function getGitDiff(pkg: Package, from: string, to: string) { 49 - // # https://git-scm.com/docs/pretty-formats 50 - const { stdout: r } = pkg.exec( 51 - `git --no-pager log ${from}...${to} --pretty=%s|%h|%an|%ae`, 52 - { 53 - silent: true, 54 - } 55 - ) 56 - return r.split('\n').map(line => { 57 - const [message, commit, authorName, authorEmail] = line.split('|') 58 - 59 - return { message, commit, authorName, authorEmail } 60 - }) 61 - } 62 - 63 - function parseCommits(commits: Commit[]): ConventionalCommit[] { 64 - return commits 65 - .filter(c => c.message.includes(':')) 66 - .map(commit => { 67 - const [type, ...messages] = commit.message.split(':') 68 - let message = messages.join(':') 69 - 70 - // Extract references from message 71 - message = message.replace(/\((fixes) #\d+\)/g, '') 72 - const references = [] 73 - const referencesRegex = /#[0-9]+/g 74 - let m 75 - while ((m = referencesRegex.exec(message))) { 76 - // eslint-disable-line no-cond-assign 77 - references.push(m[0]) 78 - } 79 - 80 - // Remove references and normalize 81 - message = message.replace(referencesRegex, '').replace(/\(\)/g, '').trim() 82 - 83 - // Extract scope from type 84 - const matches = type.match(/\((.*)\)/) 85 - const scope = (matches && matches[1]) || 'general' 86 - 87 - return { 88 - ...commit, 89 - message, 90 - type: type.split('(')[0] as CommitType, 91 - scope, 92 - references, 93 - } 94 - }) 95 - } 96 - 97 - function generateMarkDown( 98 - commits: ConventionalCommit[], 99 - knownAuthors: Exclude<PackageJsonPerson, string>[] = [] 100 - ) { 101 - const isKnownAuthor = (name: string, email: string) => 102 - knownAuthors.some( 103 - ({ name: n, email: e }) => 104 - (n && name.toLowerCase().includes(n)) || 105 - (e && email.toLowerCase().includes(e)) 106 - ) 107 - 108 - const typeGroups = groupBy(commits, 'type') 109 - 110 - let markdown = '' 111 - 112 - for (const type of allowedTypes) { 113 - const group = typeGroups[type] 114 - if (!group || !group.length) continue 115 - 116 - const { title } = types[type] 117 - markdown += '\n\n' + '### ' + title + '\n\n' 118 - 119 - const scopeGroups = groupBy(group, 'scope') 120 - for (const scopeName in scopeGroups) { 121 - markdown += '- `' + scopeName + '`' + '\n' 122 - for (const commit of scopeGroups[scopeName]) { 123 - markdown += 124 - ' - ' + 125 - commit.references.join(', ') + 126 - (commit.references.length ? ' ' : '') + 127 - commit.message.replace(/^(.)/, v => v.toUpperCase()) + 128 - '\n' 129 - } 130 - } 131 - } 132 - const authors = ensureUnique( 133 - commits 134 - .filter( 135 - ({ authorName, authorEmail }) => !isKnownAuthor(authorName, authorEmail) 136 - ) 137 - .map(commit => commit.authorName) 138 - ).sort() 139 - 140 - if (authors.length) { 141 - markdown += '\n\n' + '### ' + '💖 Thanks to' + '\n\n' 142 - markdown += authors.map(name => '- ' + name).join('\n') 143 - } 144 - 145 - return markdown.trim() 146 - }