Skip to content

Commit

Permalink
documentation and finished cli
Browse files Browse the repository at this point in the history
  • Loading branch information
ieedan committed Sep 7, 2024
1 parent 2040e48 commit cc06631
Show file tree
Hide file tree
Showing 15 changed files with 339 additions and 31 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Publish

on:
push:
branches:
- main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
release:
name: Build & Publish Release
if: github.repository == 'ieedan/ts-blocks'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v3
with:
node-version: '20'

- name: Install dependencies
run: pnpm install

- name: Create Release Pull Request or Publish
id: changesets
uses: changesets/action@v1
with:
commit: 'chore(release): version package'
title: 'chore(release): version package'
publish: pnpm ci:release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_ENV: production
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
# ts-blocks
Building blocks for TypeScript applications.

Building blocks for TypeScript applications add code through the CLI and maintain full ownership.

```bash
npx ts-blocks init
```

## Setup

Run the `init` command to setup the path where the blocks will be added.

```bash
npx ts-blocks init
```

## Adding Blocks

```bash
npx ts-blocks add result

┌ ts-block
└ All done!
```

# Blocks

All blocks can be found under `./blocks` and are shipped well documented.

## Adding New Blocks

To add a new block add it under a category in the `./blocks` directory. Then make sure to go to `./src/blocks.ts` and update the `blocks` object.

```ts
const blocks: Record<string, Block> = {
result: {
category: "types",
},
// highlight-start
"to-map": {
category: "utilities",
},
// highlight-end
};
```
4 changes: 4 additions & 0 deletions blocks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"schema": "https://github.com/ieedan/ts-blocks/blob/main/src/config/schema.json",
"path": "test/blocks"
}
28 changes: 15 additions & 13 deletions blocks/types/result.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
/** A result option that contains a tuple with val and err.
*
/** A result option that contains a tuple with val and err.
*
* `T` Value on success
*
*
* `E` Value on failure
*
*
* ## Examples
* ```ts
* const functionThatCanFail = (): Result<number, string> => {
* //...
* }
*
*
* const [val, err] = functionThatCanFail();
*
*
* if (err == null) {
* // err is now `string` instead of `string | null`
* console.error(err);
* }
*
*
* // val is now `number` instead of `number | null`
* doSomethingWithVal(val);
* ```
*
*
*/
export type Result<T, E> = [val: T, err: null] | [val: null, err: E];
type Result<T, E> = [val: T, err: null] | [val: null, err: E];

/** A helper method for the `Result<T,E>` type to allow you to easily return a successful result from a function.
*
*
* @param val Success value
* @returns
*/
export const Ok = <T>(val: T): Result<T, never> => [val, null];
const Ok = <T>(val: T): Result<T, never> => [val, null];

/** A helper method for the `Result<T,E>` type to allow you to easily return an error result from a function.
*
*
* @param err Error value
* @returns
*/
export const Err = <E>(err: E): Result<never, E> => [null, err];
const Err = <E>(err: E): Result<never, E> => [null, err];

export { Result, Ok, Err };
12 changes: 7 additions & 5 deletions blocks/utilties/toMap.ts → blocks/utilties/to-map.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/** Maps the provided array into a map
*
*
* @param arr Array of items to be entered into a map
* @param fn A mapping function to transform each item into a key value pair
* @returns
*
* @returns
*
* ## Example
* ```ts
* const map = toMap([5,4,3,2,1], (item, i) => [i, item]);
*
*
* console.log(map); // Map(5) { 0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1 }
* ```
*/
Expand All @@ -21,4 +21,6 @@ const toMap = <T, K, V>(arr: T[], fn: (item: T, index: number) => [key: K, value
}

return map;
};
};

export { toMap };
2 changes: 1 addition & 1 deletion build.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineBuildConfig } from "unbuild";

export default defineBuildConfig({
entries: ["src/index"],
entries: ["src/index", "src/commands/add", "src/commands/init", "src/commands/index", "src/blocks", "src/config/index"],
failOnWarn: false,
declaration: true,
clean: true,
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"files": [
"bin.mjs",
"package.json",
"package-lock.json",
"pnpm-lock.yaml",
"README.md",
"templates",
"dist"
"dist/**/*",
"blocks/**/*"
],
"scripts": {
"start": "unbuild && node bin.mjs",
Expand All @@ -32,6 +32,9 @@
},
"dependencies": {
"@changesets/cli": "^2.27.8",
"commander": "^12.1.0"
"@clack/prompts": "^0.7.0",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"valibot": "^0.41.0"
}
}
45 changes: 45 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions src/blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export type Category = "types" | "utilities";

export type Block = {
dependencies?: Record<string, string>;
category: Category;
};

const blocks: Record<string, Block> = {
result: {
category: "types",
},
"to-map": {
category: "utilities",
},
};

export { blocks };
67 changes: 64 additions & 3 deletions src/commands/add.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,66 @@
import { Command } from "commander";
import { Command, program } from "commander";
import { boolean, InferInput, object, parse } from "valibot";
import fs from "node:fs";
import { blocks } from "../blocks";
import { cancel, confirm, intro, isCancel, outro } from "@clack/prompts";
import color from "chalk";
import path from "node:path";
import { getConfig } from "../config";

const add = new Command("add").argument("block", "Whichever block you want to add to your project.");
const schema = object({
yes: boolean(),
});

export { add }
type Options = InferInput<typeof schema>;

const add = new Command("add")
.argument("block", "Whichever block you want to add to your project.")
.option("-y, --yes", "Add and install any required dependencies.", false)
.action(async (block, opts) => {
const options = parse(schema, opts);

await _add(block, options);
});

const _add = async (blockName: string, options: Options) => {
intro(color.white.bgCyanBright("ts-block"));

const config = getConfig();

// in the future maybe we add a registry but for now it can just be fs
const block = blocks[blockName];

if (!block) {
program.error(color.red(`Invalid block! ${color.bold(blockName)} does not exist!`));
}

const p = path.join(import.meta.dirname, `../../blocks/${block.category}/${blockName}.ts`);

const newPath = path.join(config.path, `${block.category}/${blockName}.ts`);

fs.mkdirSync(path.join(config.path, block.category), { recursive: true });

fs.copyFileSync(p, newPath);

if (block.dependencies) {
if (!options.yes) {
const result = await confirm({ message: "Add and install dependencies?" });

if (isCancel(result)) {
cancel("Canceled!");
process.exit(0);
}

options.yes = result;
}

if (options.yes) {
// currently no functions require dependencies (lets try and keep it that way)
throw new Error("NOT IMPLEMENTED");
}
}

outro(color.green("All done!"));
};

export { add };
Loading

0 comments on commit cc06631

Please sign in to comment.