diff --git a/docs/deep-dives/config.md b/docs/deep-dives/config.md new file mode 100644 index 000000000..b10aeb1cf --- /dev/null +++ b/docs/deep-dives/config.md @@ -0,0 +1,17 @@ +--- +parent: Deep dives +--- + +# Config + +**skuba** configuration can be specified in an optional `skuba.config.ts` file next to your `package.json`. + +```typescript +import { SkubaConfig } from 'skuba'; + +const config: SkubaConfig = { + assets: [...SkubaConfig.assets.default, '**/*.adoc'], +}; + +export default config; +``` diff --git a/package.json b/package.json index c2a26d0d7..a4cd1d033 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "ejs": "^3.1.6", "enquirer": "^2.3.6", "esbuild": "~0.17.0", + "esbuild-register": "^3.4.2", "eslint": "^8.11.0", "eslint-config-skuba": "2.0.2", "execa": "^5.0.0", @@ -117,7 +118,8 @@ "tsconfig-paths": "^4.0.0", "tsconfig-seek": "1.0.2", "typescript": "~5.0.0", - "validate-npm-package-name": "^5.0.0" + "validate-npm-package-name": "^5.0.0", + "zod": "^3.21.4" }, "devDependencies": { "@changesets/cli": "2.26.1", diff --git a/src/config/load.ts b/src/config/load.ts new file mode 100644 index 000000000..6512bdb5d --- /dev/null +++ b/src/config/load.ts @@ -0,0 +1,32 @@ +import path from 'path'; + +import { register } from 'esbuild-register/dist/node'; + +import { type SkubaConfig, skubaConfigSchema } from './types'; + +import { getDestinationManifest } from 'cli/configure/analysis/package'; +import { log } from 'utils/logging'; + +const CONFIG_FILENAME = 'skuba.config.ts'; + +export const loadSkubaConfig = async (cwd?: string): Promise => { + // FIXME: remove underlying `process.exit` + const manifest = await getDestinationManifest({ cwd }); + + const configPath = path.join(manifest.path, '..', CONFIG_FILENAME); + + const esbuildRegistration = register({ target: 'node16' }); + + try { + const rawConfig: unknown = await import(configPath); + + return skubaConfigSchema.parse(rawConfig); + } catch (err) { + log.warn(`Failed to load ${log.bold(configPath)}.`); + log.subtle(err); + + return {}; + } finally { + esbuildRegistration.unregister(); + } +}; diff --git a/src/config/types.ts b/src/config/types.ts new file mode 100644 index 000000000..878e8686b --- /dev/null +++ b/src/config/types.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; + +export const skubaConfigSchema = z.object({ + /** + * Files to copy from the working directory to the output directory after + * compilation. This feature is useful to bundle non-JavaScript assets in an + * npm package, back-end deployment package or container image. + * + * Supports `picomatch` glob patterns with dotfile matching. + * + * - https://github.com/micromatch/picomatch#globbing-features + * - https://github.com/micromatch/picomatch#picomatch-options + * + * Commands: + * + * - `skuba build` + * - `skuba build-package` + */ + assets: z.array(z.string()).optional(), +}); + +export const SkubaConfig = { + assets: { + /** + * The default list of `assets` that are applied if your project does not + * specify the configuration property. + * + * Currently includes: + * + * - JSON translation files for https://github.com/seek-oss/vocab + */ + default: ['**/*.vocab/*translations.json'], + }, +}; + +export type SkubaConfig = z.infer; diff --git a/src/index.test.ts b/src/index.test.ts index f4a80c515..2451f33ee 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -2,6 +2,50 @@ import * as skuba from '.'; describe('skuba', () => { it('exports', () => { - expect(skuba).toHaveProperty('Net'); + expect(skuba).toMatchInlineSnapshot(` + { + "Buildkite": { + "annotate": [Function], + "md": { + "terminal": [Function], + }, + }, + "Git": { + "commit": [Function], + "commitAllChanges": [Function], + "currentBranch": [Function], + "fastForwardBranch": [Function], + "getChangedFiles": [Function], + "getHeadCommitId": [Function], + "getHeadCommitMessage": [Function], + "getOwnerAndRepo": [Function], + "push": [Function], + "reset": [Function], + }, + "GitHub": { + "buildNameFromEnvironment": [Function], + "createCheckRun": [Function], + "enabledFromEnvironment": [Function], + "getPullRequestNumber": [Function], + "putIssueComment": [Function], + "readFileChanges": [Function], + "uploadAllFileChanges": [Function], + "uploadFileChanges": [Function], + }, + "Jest": { + "mergePreset": [Function], + }, + "Net": { + "waitFor": [Function], + }, + "SkubaConfig": { + "assets": { + "default": [ + "**/*.vocab/*translations.json", + ], + }, + }, + } + `); }); }); diff --git a/src/index.ts b/src/index.ts index 3a9c8233a..4cfd281d6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ export * as Git from './api/git'; export * as GitHub from './api/github'; export * as Jest from './api/jest'; export * as Net from './api/net'; +export { SkubaConfig } from './config/types'; // evanw/esbuild#2388 declare global { diff --git a/yarn.lock b/yarn.lock index ed0487e4a..61185ab7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3611,6 +3611,13 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild-register@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.4.2.tgz#1e39ee0a77e8f320a9790e68c64c3559620b9175" + integrity sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q== + dependencies: + debug "^4.3.4" + esbuild@~0.17.0: version "0.17.18" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746" @@ -10025,6 +10032,11 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +zod@^3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== + zwitch@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"