Skip to content

Commit

Permalink
Adding basic Block and configuration builders (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
cohitre committed Feb 13, 2024
1 parent 2d46253 commit d41cab7
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 16 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"ecmaVersion": 2015,
"project": "./tsconfig.json",
"sourceType": "module"
},
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: CI - Code styles, unit tests
on:
push:
branches: [main]
pull_request:
branches:
- main
concurrency:
group: ${{ github.head_ref }}-codestyles
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx eslint .
- run: npx prettier . --check
- run: npm test
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*

dist
9 changes: 9 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.editorconfig
.envrc
.eslintignore
.eslintrc.json
.prettierrc
jest.config.ts
src
tests
tsconfig.json
6 changes: 3 additions & 3 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Config } from "jest";
import type { Config } from 'jest';

const config: Config = {
preset: "ts-jest",
testEnvironment: "jsdom",
preset: 'ts-jest',
testEnvironment: 'jsdom',
};

export default config;
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"description": "Tools to render waypoint-style documents.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"target": "ES2022",
"files": [
"lib"
"dist"
],
"scripts": {
"prepublish": "./node_modules/.bin/tsc",
"build": "npx tsc",
"prepublish": "npx tsc --project tsconfig.build.json",
"test": "npx jest"
},
"author": "carlos@usewaypoint.com",
Expand Down
41 changes: 41 additions & 0 deletions src/builders/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { z } from 'zod';

export type DocumentBlocksDictionary<T extends { [name: string]: z.AnyZodObject }> = {
[K in keyof T]: {
schema: T[K];
Component: (props: z.infer<T[K]>) => React.ReactNode;
};
};

export function buildBlockConfigurationSchema<T extends { [name: string]: z.AnyZodObject }>(
blocks: DocumentBlocksDictionary<T>
) {
type BaseBlockComponentProps<TType extends keyof T> = {
id: string;
type: TType;
data: z.infer<T[TType]>;
};

const blockObjects = Object.keys(blocks).map((type: keyof T) =>
z.object({
id: z.string(),
type: z.literal(type),
data: blocks[type].schema,
})
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
return z.discriminatedUnion('type', blockObjects as any).transform((v) => v as BaseBlockComponentProps<keyof T>);
}

export function buildBlockComponent<T extends { [name: string]: z.AnyZodObject }>(blocks: DocumentBlocksDictionary<T>) {
type BaseBlockComponentProps<TType extends keyof T> = {
type: TType;
data: z.infer<T[TType]>;
};

return function BlockComponent({ type, data }: BaseBlockComponentProps<keyof T>): React.ReactNode {
return React.createElement(blocks[type].Component, data);
};
}
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './builders';
9 changes: 9 additions & 0 deletions tests/builder/__snapshots__/index.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`builders buildBlockComponent renders the specified component 1`] = `
<DocumentFragment>
<div>
TEST TEXT!
</div>
</DocumentFragment>
`;
48 changes: 48 additions & 0 deletions tests/builder/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { z } from 'zod';

import { render } from '@testing-library/react';

import { buildBlockComponent, buildBlockConfigurationSchema } from '../../src/builders';

describe('builders', () => {
describe('buildBlockComponent', () => {
it('renders the specified component', () => {
const BlockComponent = buildBlockComponent({
SampleBlock: {
schema: z.object({ text: z.string() }),
Component: ({ text }) => <div>{text.toUpperCase()}</div>,
},
});
expect(
render(<BlockComponent type="SampleBlock" data={{ text: 'Test text!' }} />).asFragment()
).toMatchSnapshot();
});
});

describe('buildBlockConfigurationSchema', () => {
it('adds an id, data, and type to the provided schema', () => {
const blockConfigurationSchema = buildBlockConfigurationSchema({
SampleBlock: {
schema: z.object({ text: z.string() }),
Component: ({ text }) => <div>{text.toUpperCase()}</div>,
},
});

const sampleValidData = {
id: 'my id',
type: 'SampleBlock',
data: { text: 'Test text!' },
};
const parsedData = blockConfigurationSchema.safeParse(sampleValidData);
expect(parsedData).toEqual({
success: true,
data: {
id: 'my id',
type: 'SampleBlock',
data: { text: 'Test text!' },
},
});
});
});
});
4 changes: 4 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["tests/**/*.spec.ts", "tests/**/*.spec.tsx", "jest.config.ts"]
}
13 changes: 3 additions & 10 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2015",
"module": "esnext",
"lib": [],
"moduleResolution": "node",
"jsx": "react",
"outDir": "dist",
"strict": true,
"sourceMap": true,
"noImplicitAny": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"declarationMap": true,
"declaration": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"inlineSources": true,
"strictPropertyInitialization": true,
"strictNullChecks": true
"noFallthroughCasesInSwitch": true
},
"include": ["./jest.config.ts", "src/**/*.ts", "tests/**/*.ts", "src/**/*.tsx", "tests/**/*.tsx"],
"include": ["jest.config.ts", "src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
"exclude": ["node_modules", "dist"]
}

0 comments on commit d41cab7

Please sign in to comment.