Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(npm): add programmatic API for TypeScript #523

Merged
merged 8 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion npm/git-cliff/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ dist
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
# yarn berry
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
Expand Down
893 changes: 893 additions & 0 deletions npm/git-cliff/.yarn/releases/yarn-4.1.0.cjs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions npm/git-cliff/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
enableGlobalCache: true

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.1.0.cjs
54 changes: 39 additions & 15 deletions npm/git-cliff/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,32 @@
"name": "git-cliff",
"version": "2.1.0-rc.0",
"description": "A highly customizable Changelog Generator that follows Conventional Commit specifications ⛰️",
"bin": "lib/index.js",
"type": "module",
"main": "lib/cjs/index.d.cts",
"module": "lib/esm/index.d.ts",
"types": "lib/cjs/index.d.cts",
"bin": "lib/cli/cli.js",
"exports": {
"./cli": {
"import": "./lib/cli/cli.js"
},
".": {
"import": {
"types": "./lib/esm/index.d.ts",
"default": "./lib/esm/index.js"
},
"require": {
"types": "./lib/cjs/index.d.cts",
"default": "./lib/cjs/index.cjs"
}
}
},
"scripts": {
"typecheck": "tsc --noEmit",
"typecheck": "tsc",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"build": "tsc",
"dev": "yarn build && node lib/index.js"
"build": "tsup",
"dev": "yarn build && node lib/cli/cli.js"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -54,20 +73,24 @@
"url": "https://github.com/orhun/git-cliff/issues"
},
"homepage": "https://github.com/orhun/git-cliff#readme",
"dependencies": {
"execa": "^8.0.1"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"eslint": "^8.31.0",
"typescript": "^4.9.4"
"@types/node": "^20.11.22",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"eslint": "^8.57.0",
"tsup": "^8.0.2",
"typescript": "^5.3.3"
},
"optionalDependencies": {
"git-cliff-linux-x64": "2.1.0-rc.0",
"git-cliff-linux-arm64": "2.1.0-rc.0",
"git-cliff-darwin-x64": "2.1.0-rc.0",
"git-cliff-darwin-arm64": "2.1.0-rc.0",
"git-cliff-windows-x64": "2.1.0-rc.0",
"git-cliff-windows-arm64": "2.1.0-rc.0"
"git-cliff-darwin-x64": "2.1.0-rc.0",
"git-cliff-linux-arm64": "2.1.0-rc.0",
"git-cliff-linux-x64": "2.1.0-rc.0",
"git-cliff-windows-arm64": "2.1.0-rc.0",
"git-cliff-windows-x64": "2.1.0-rc.0"
},
"eslintConfig": {
"extends": [
Expand All @@ -82,5 +105,6 @@
"lib/*"
],
"root": true
}
},
"packageManager": "[email protected]"
}
12 changes: 12 additions & 0 deletions npm/git-cliff/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env node

import { runGitCliff } from "./index.js";

async function run() {
const args = process.argv.slice(2);
const processResult = await runGitCliff(args);

process.exit(processResult.exitCode ?? 0);
}

void run();
33 changes: 33 additions & 0 deletions npm/git-cliff/src/getExePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { arch as getArch, platform as getPlatform } from "os";

/**
* Returns the executable path for git-cliff located inside node_modules
* The naming convention is git-cliff-${os}-${arch}
* If the platform is `win32` or `cygwin`, executable will include a `.exe` extension
* @see https://nodejs.org/api/os.html#osarch
* @see https://nodejs.org/api/os.html#osplatform
* @example "x/xx/node_modules/git-cliff-darwin-arm64"
*/
export async function getExePath() {
const platform = getPlatform();
const arch = getArch();

let os = platform as string;
let extension = "";

if (platform === "win32" || platform === "cygwin") {
os = "windows";
extension = ".exe";
}

try {
// Since the bin will be located inside `node_modules`, we can simply call import.meta.resolve
return import.meta.resolve(
`git-cliff-${os}-${arch}/bin/git-cliff${extension}`,
);
} catch (e) {
throw new Error(
`Couldn't find git-cliff binary inside node_modules for ${os}-${arch} (${e})`,
);
}
}
90 changes: 56 additions & 34 deletions npm/git-cliff/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
#!/usr/bin/env node
import { execa, type Options as ExecaOptions, type ExecaReturnValue, } from "execa";
import { fileURLToPath } from "node:url";
import { getExePath } from "./getExePath.js";
import type { Options } from "./options.js";
import { optionsToStringArgs } from "./optionsToStringArgs.js";

import { spawnSync } from "child_process"
export type { Options } from "./options.js";

/**
* Returns the executable path for git-cliff located inside node_modules
* The naming convention is git-cliff-${os}-${arch}
* If the platform is `win32` or `cygwin`, executable will include a `.exe` extension
* @see https://nodejs.org/api/os.html#osarch
* @see https://nodejs.org/api/os.html#osplatform
* @example "x/xx/node_modules/git-cliff-darwin-arm64"
*/
function getExePath() {
const arch = process.arch;
let os = process.platform as string;
let extension = '';
if (['win32', 'cygwin'].includes(process.platform)) {
os = 'windows';
extension = '.exe';
}

try {
// Since the bin will be located inside `node_modules`, we can simply call require.resolve
return require.resolve(`git-cliff-${os}-${arch}/bin/git-cliff${extension}`)
} catch (e) {
throw new Error(`Couldn't find git-cliff binary inside node_modules for ${os}-${arch}`)
}
}

* Runs `git-cliff` with the provided options as a JavaScript object.
*
* @param options - The options to pass to `git-cliff`.
* These get transformed into an array strings.
* - Values that are `true` will be passed as flags (`--flag`).
* - Values that are `false` or `null` will be ignored.
* - All other values will be passed as options (`--option value`).
*
* @param execaOptions - Options to pass to {@link execa}.
*/
export async function runGitCliff(options: Options, execaOptions?: ExecaOptions): Promise<ExecaReturnValue<string>>;
/**
* Runs `git-cliff` with args using nodejs spawn
*/
function runGitCliff() {
const args = process.argv.slice(2)
const processResult = spawnSync(getExePath(), args, { stdio: "inherit" })
process.exit(processResult.status ?? 0)
}
* Runs the `git-cliff` with the provided arguments.
*
* @param args - The arguments to pass to `git-cliff`.
* These should be in an array of string format.
* Every option and their value should be its own entry in the array.
*
* @param execaOptions - Options to pass to {@link execa}.
*
* @returns A promise that resolves when the `git-cliff` has finished running.
*
* @example
* Options with values
* ```typescript
* await runGitCliff(["--tag", "1.0.0", "--config", "github"]);
* ```
*
* @example
* Boolean flags
* ```typescript
* await runGitCliff(["--unreleased", "--topo-order"]);
* ```
*
* @example
* Combining options and flags
* ```typescript
* await runGitCliff(["--tag", "1.0.0", "--config", "github", "--topo-order"]);
* ```
*/
export async function runGitCliff(args: string[], execaOptions?: ExecaOptions): Promise<ExecaReturnValue<string>>;
export async function runGitCliff(argsOrOptions: Options | string[], execaOptions?: ExecaOptions): Promise<ExecaReturnValue<string>> {
const exePath = await getExePath();
const args = Array.isArray(argsOrOptions)
? argsOrOptions
: optionsToStringArgs(argsOrOptions);

runGitCliff()
return execa(fileURLToPath(exePath), args, {
stdio: "inherit",
...execaOptions,
});
}
29 changes: 29 additions & 0 deletions npm/git-cliff/src/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export type Options = Partial<{
help: boolean;
version: boolean;
verbose: boolean;
init: boolean | string;
config: string;
workdir: string;
repository: string;
includePath: string;
excludePath: string;
withCommit: string;
skipCommit: string;
prepend: string;
output: string;
tag: string;
bump: boolean;
bumpedVersion: boolean;
body: string;
latest: boolean;
current: boolean;
unreleased: boolean;
topoOrder: boolean;
noExec: boolean;
context: boolean;
strip: "header" | "footer" | "all";
sort: "oldest" | "newest";
githubToken: string;
githubRepo: string;
}>;
26 changes: 26 additions & 0 deletions npm/git-cliff/src/optionsToStringArgs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Options } from "./options.js";

/**
* Transforms a JavaScript object of options into an array
* of strings that can be passed to {@link execa} for calling `git-cliff`
*
* @param options The options to transform
* @returns The options as an array of strings
*/
export function optionsToStringArgs(options: Options): string[] {
const args: string[] = [];

for (const [key, value] of Object.entries(options)) {
const hyphenCaseKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();

if (value === true) {
args.push(`--${hyphenCaseKey}`);
} else if (value === false || value === null) {
continue;
} else {
args.push(`--${hyphenCaseKey}`, value);
}
}

return args;
}
8 changes: 4 additions & 4 deletions npm/git-cliff/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"module": "node16",
"moduleResolution": "node16",
"esModuleInterop": true,
"baseUrl": "./",
"outDir": "lib",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
"resolveJsonModule": true,
"noEmit": true
}
}
36 changes: 36 additions & 0 deletions npm/git-cliff/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { defineConfig, type Options } from "tsup";
import { dependencies } from "./package.json";

const baseOptions: Options = {
clean: true,
dts: true,
entry: ["src/index.ts"],
minify: false,
external: Object.keys(dependencies),
sourcemap: true,
target: "es2020",
tsconfig: "tsconfig.json",
keepNames: true,
treeshake: true,
};

export default [
defineConfig({
...baseOptions,
outDir: "lib/cjs",
format: "cjs",
}),
defineConfig({
...baseOptions,
outDir: "lib/esm",
format: "esm",
}),
defineConfig({
...baseOptions,
outDir: "lib/cli",
entry: ["src/cli.ts"],
dts: false,
sourcemap: false,
format: "esm",
}),
];
Loading
Loading