@orkestrel/contribute
v1.2.1
Published
A CLI tool to help contribute to Orkestrel open source projects
Maintainers
Readme
@orkestrel/contribute
Strict, reusable configs and a scaffolder for building @orkestrel TypeScript libraries (optionally with a CLI). Ships ESM-only, Node ≥ 20, Vitest, Vite, and ESLint flat config. Includes type guards via @orkestrel/validator and re-exports them for convenience.
What’s included
- Vite/Vitest config builder: library-first defaults, Node builtins externalized, alias mapping for @orkestrel/ → ./src/index.ts.
- ESLint flat config builder: strict TS rules, stylistic tweaks, optional JSDoc/TSDoc.
- Project scaffolder: generate a minimal library (and optional CLI) with sensible tsconfig, vite, and ESLint.
- Type guards and validation helpers: all exports from @orkestrel/validator are re-exported here.
Requirements
- Node: ≥ 20
- Package manager: npm (scripts provided)
Install (peers you bring)
npm install -D eslint typescript vite vitest @types/nodeCLI
- Start interactive mode (wizard):
contribute- Help and version:
contribute help
contribute version- Scaffold in the current directory:
contribute scaffold --name my-lib
contribute scaffold --name my-cli --cli
contribute scaffold --forceNotes
- If --name is omitted, we default to the folder name. If --cli is set and no name is provided, we default to "cli".
- Generated packages are named and published as @orkestrel/ (unscoped names are scoped for you). Scoped @orkestrel/ values are respected.
- Scaffolded projects include a path alias @orkestrel/ → ./src/index.ts in tsconfig, and the same alias is set in Vite.
- We copy this repo’s .github folder (text files only) into scaffolded projects to bootstrap docs and workflows.
Library API
eslintConfig(options?: EslintOptions): readonly unknown[]
- Builds a strict ESLint flat config with TypeScript rules, stylistic tweaks, and optional JSDoc/TSDoc.
- Options
- disableJsdoc?: boolean (default=false) — when true, JSDoc rules are not added.
- disableTsdoc?: boolean (default=false) — when true, TSDoc syntax checks are not added.
- ignores?: readonly string[] — additional ignore globs to merge with defaults (dist/, node_modules/, guides/**).
- extra?: readonly unknown[] — extra flat config entries appended at the end.
- Details
- JSDoc applies to exported functions/classes/methods in src. Functions that are TS type guards (with return type predicates) are exempted from @returns checks by design.
- Type alias/interface declarations are restricted to src/types.ts by default.
- Usage
import { eslintConfig } from '@orkestrel/contribute'; export default eslintConfig();
viteConfig(options?: ViteOptions): UserConfig
- Produces a Vite config tailored for libraries with Vitest defaults.
- Merges your overrides last; externalizes Node builtins and node: imports.
- Options
- packageName?: string — if provided, creates a resolve.alias for @orkestrel/ (accepts already-scoped forms like @orkestrel/xyz).
- srcEntry?: string — defaults to \src\index.ts.
- outDir?: string — defaults to \dist.
- Usage
import { viteConfig } from '@orkestrel/contribute'; export default viteConfig({ packageName: 'your-package-name' });
scaffoldProject(options?: ScaffoldOptions): Promise
- Programmatic scaffolding used by the CLI.
- Options
- name?: string — base name; unscoped becomes @orkestrel/.
- cli?: boolean — include a CLI entrypoint and bin mapping.
- force?: boolean — overwrite existing files (otherwise skip existing).
- Behavior
- Derives a safe, kebab-case base name from the provided name or current folder (helpers: derivePackageBaseName, toKebabSafe, unscopedName).
- Writes package.json with exports { ".": { types: "./dist/index.d.ts", import: "./dist/index.js" } } and, when cli=true, { bin: { : "dist/cli.js" } }.
- Copies tsconfig.json, tsconfig.build.json, eslint.config.ts, vite.config.ts, README.md, .gitignore, src stubs, tests, and this repo’s .github contents (text files) into the target.
- Returns { dir, written, skipped }.
- Minimal example
import { scaffoldProject } from '@orkestrel/contribute'; await scaffoldProject({ name: 'example', cli: true });
Helpers (src/helpers.ts)
- tokenize(line: string): readonly string[] — split a simple shell-like line into tokens (supports single/double quotes).
- replaceTemplateVars(input: string, vars: Record<string, string>): string — replace ${VAR} placeholders.
- toCRLF(s: string): string — normalize newlines to CRLF.
- unscopedName(name: string): string — drop an npm scope from a package name.
- baseNameFromPath(p: string): string — last segment from a path (handles \ and /).
- toKebabSafe(input: string): string — lower-case and sanitize to letters, digits, dot, underscore, and dash; spaces → dash.
- derivePackageBaseName(dir: string, providedName: string | undefined, cli: boolean): string — decide final base name.
- resolveOrkestrelAlias(packageName?: string, defaultBase = 'contribute'): string — build @orkestrel/ alias key used by Vite.
Types (src/types.ts)
- EslintOptions, ViteOptions, ScaffoldOptions, ScaffoldResult — see method signatures above for fields.
Validation and type guards (re-exports)
- This package re-exports everything from @orkestrel/validator so you can import guards and combinators directly:
- Primitives: isString, isNumber, isBoolean, isFunction, isDate, isPromiseLike, …
- Collections: isRecord, isObject, isMap, isSet, …
- Emptiness: isNonEmptyString, isEmptyArray, isNonEmptyObject, …
- Function shape: isZeroArg, isAsyncFunction, …
- Schema/combinators: objectOf, recordOf, arrayOf, tupleOf, unionOf, intersectionOf, andOf, orOf, notOf, complementOf, enumOf, keyOf, literalOf, pickOf, omitOf, whereOf, lazyOf, transformOf, iterableOf, setOf, mapOf, instanceOf, nullableOf
Configs you get in scaffolded projects
- tsconfig.json (strict ESM, bundler resolution, alias for @orkestrel/):
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ESNext"],
"types": ["node"],
"noEmit": true,
"strict": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@orkestrel/your-package-name": ["./src/index.ts"]
}
}
}- tsconfig.build.json (emit to dist with d.ts and source maps):
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"noEmit": false,
"sourceMap": true,
"declaration": true,
"declarationMap": true
},
"include": ["src"]
}- vite.config.ts:
import { viteConfig } from '@orkestrel/contribute';
export default viteConfig({ packageName: 'your-package-name' });- eslint.config.ts:
import { eslintConfig } from '@orkestrel/contribute';
export default eslintConfig();Scripts
npm run check
npm run format
npm test
npm run buildProgrammatic CLI entry (in scaffolded packages when cli=true)
- When you scaffold with --cli, src/index.ts includes:
export { main as cli } from './cli.js'; - Consumers can then import and run your CLI programmatically:
import { cli } from '@orkestrel/your-package-name'; // await cli(process.argv) - Or run directly after build:
node dist\cli.js --help
FAQ
- Why alias @orkestrel/? Consistent, monorepo-friendly imports and SSR-friendly build configs.
- Does this rely on Node APIs in library code? Library modules are environment-agnostic; Node built-ins are used only in CLI and tests. Vite externalizes Node builtins.
- Where are the scaffold stubs? src\stubs*.txt. They’re interpolated with simple ${VAR} placeholders at scaffold time.
License MIT
