Skip to content

Commit

Permalink
refactor: project structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Curve committed Nov 9, 2023
1 parent 5e5602e commit 9a4f50e
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 195 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
run_install: false

- name: 🔨 Build
run: "pnpm install && pnpm run build:executable"
run: "pnpm install && pnpm run bundle:executable"

- name: 🛒 Publish
run: pnpm publish --no-git-checks
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
node_modules
dist
build
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"keywords": [
"saucer"
],
"version": "4.1.1",
"version": "4.2.0",
"license": "MIT",
"author": "Curve (https://github.com/Curve)",
"type": "module",
Expand All @@ -17,13 +17,15 @@
},
"scripts": {
"build": "tsc",
"build:executable": "pnpm run build && chmod +x dist/index.js && cp -r src/templates dist"
"copy": "cp -r src/templates build",
"bundle": "pnpm run build && pnpm run copy",
"bundle:executable": "pnpm run bundle && chmod +x build/index.js"
},
"bin": {
"saucer": "dist/index.js"
"saucer": "build/index.js"
},
"files": [
"dist"
"build"
],
"dependencies": {
"commander": "^11.0.0",
Expand All @@ -41,6 +43,7 @@
"devDependencies": {
"@sindresorhus/tsconfig": "^3.0.1",
"@types/fs-extra": "^11.0.2",
"@types/ink-spinner": "^3.0.4",
"@types/mime-types": "^2.1.1",
"@types/node": "^20.6.1",
"@types/react": "^18.0.32",
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

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

145 changes: 145 additions & 0 deletions src/commands/embed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { Eta } from "eta";
import figureSet from "figures";
import { existsSync, lstatSync, statSync } from "fs";
import { outputFileSync } from "fs-extra/esm";
import { mkdir } from "fs/promises";
import { Newline, Text, render } from "ink";
import Spinner from "ink-spinner";
import { fromPromise, fromThrowable } from "neverthrow";
import path, { dirname, resolve } from "path";
import { Fragment, ReactNode } from "react";
import { Error } from "../components/error.js";
import { Table } from "../components/table.js";
import { File, parse } from "../file.js";
import theme from "../theme/index.js";
import { recursiveDirectoryIterator } from "../utils/fs.js";
import { fileURLToPath } from "url";
import { Line } from "../components/line.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export async function embed(source: string, destination: string)
{
const errors: ReactNode[] = [];
const { unmount, rerender } = render(<Fragment />);

const eta = new Eta({ views: path.join(__dirname, "..", "templates") });
const writeFile = fromThrowable(outputFileSync, error => (error as string));

if (!existsSync(destination))
{
const result = await fromPromise(mkdir(destination, { recursive: true }), error => (error as string));

if (result.isErr())
{
rerender(
<Error
description={["Failed to create destination (", [destination, "gray"], ")"]}
error={result.error}
/>
);

unmount(1);
return;
}
}

if (!existsSync(source) || !lstatSync(source).isDirectory())
{
rerender(
<Error
description={["Expected ", [source, "redBright"], " to be directory"]}
/>
);

unmount(1);
return;
}

const files: [string, File][] = [];

for await (const { absolute, relative } of recursiveDirectoryIterator(source))
{
const file = parse(absolute, relative);

if (file.isErr())
{
errors.push(
<Error
description={["Failed to embed ", [relative, "redBright"]]}
error={file.error}
/>
);

continue;
}

rerender(
<>
{...errors}
<Line
icon={
<Text color={theme.colors.purple} dimColor>
<Spinner type="arc" />
</Text>
}
text={["Embedding ", [relative, "greenBright"]]}
/>
</>
);

const target = resolve(destination, `${relative}.hpp`);
const result = writeFile(target, eta.render("embed", { name: file.value.name, data: file.value.data, size: file.value.size }));

if (result.isErr())
{
errors.push(
<Error
description={["Failed to write ", [target, "redBright"]]}
error={result.error}
/>
);

continue;
}

files.push([target, file.value]);
}

const result = writeFile(resolve(destination, "all.hpp"), eta.render("all", { files: files.map(x => x[1]) }));

if (result.isErr())
{
errors.push(
<Error description="Failed to write" error={result.error} />
);

unmount(1);
}

const table_data = files.map(([path, file]) => ({
File : file.path,
Mime : file.mime,
Header : path,
"Size (KB)": (statSync(path).size / 1024).toFixed(1),
}));

rerender(
<>
<Table
data={table_data}
distribution={[40, 15, 40, 5]}
colors={[undefined, "gray", undefined, theme.colors.purple]}
/>
<Newline />
{...errors}
<Line
icon={<Text color="greenBright">{figureSet.tick}</Text>}
text={["Embedded ", [files.length.toString(), theme.colors.purple], " file(s)\n"]}
/>
</>
);

unmount(0);
}
17 changes: 17 additions & 0 deletions src/components/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import figureSet from "figures";
import { Text } from "ink";
import { ColoredText, Line } from "./line.js";

interface ErrorProps
{
error?: string | ColoredText[];
description: string | ColoredText[];
}

export function Error({ description, error }: ErrorProps)
{
return <Line
icon={<Text color="red">{figureSet.cross}</Text>}
text={[...description, ...(error ? [": ", ...error] : [])]}
/>;
}
31 changes: 31 additions & 0 deletions src/components/line.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Text, TextProps } from "ink";

export type ColoredText = string | [text: string, color: TextProps["color"]];

interface LineProps
{
icon: React.JSX.Element;
text: string | ColoredText[];
}

function convert(item: ColoredText)
{
if (typeof item === "string")
{
return <Text>{item}</Text>;
}

return <Text color={item[1]}>{item[0]}</Text>;
}

export function Line({ icon, text }: LineProps)
{
return <Text>
{icon}
{" "}
{
Array.isArray(text) ?
text.map(convert) : convert(text)
}
</Text>;
}
57 changes: 37 additions & 20 deletions src/components/table.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import figureSet from "figures";
import { Box, BoxProps, Text, TextProps } from "ink";
import { ReactNode } from "react";
import colors from "../utils/colors.js";
import theme from "../theme/index.js";

function unique<T>(array: T[])
{
return [...new Set(array)];
}

export function Table({ data, distribution, color, ...props }: { data: any[], distribution: number[], color?: TextProps["color"][] } & BoxProps)
interface TableProps extends BoxProps
{
data: any[];
distribution: number[];
colors?: TextProps["color"][];
}

export function Table({ data, distribution, colors, ...props }: TableProps)
{
const headers = unique(data.map(item => Object.keys(item)).flat());
const width = (index: number) => `${distribution[index]}%`;
Expand Down Expand Up @@ -48,45 +55,55 @@ export function Table({ data, distribution, color, ...props }: { data: any[], di
{
const rtn = { ...style, borderBottom: false };

if (headers.length <= 1)
{
return rtn;
}

switch (index)
if (headers.length > 1 && index < headers.length - 1)
{
default:
case 0:
rtn.borderRight = true;
break;
case (headers.length - 1):
break;
}

return rtn;
};

const Cell = ({ index, children }: { index: number, children: ReactNode}) =>
<Box marginX={1} {...cell_style(index)} width={width(index)}>
<Box
marginX={1}
width={width(index)}
{...cell_style(index)}
>
{children}
</Box>;

return <Box flexDirection="column" borderStyle={border} {...props}>
return <Box
flexDirection="column"
borderStyle={border}
{...props}
>
<Box {...style}>
{headers.map((header, index) =>
<Cell key={header} index={index}>
<Text color={colors.purple} bold>
<Cell
key={header}
index={index}
>
<Text
color={theme.colors.purple}
bold
>
{header}
</Text>
</Cell>
)}
</Box>

{data.map((row, key) =>
<Box key={key} {...row_style(key)}>
<Box
key={key}
{...row_style(key)}
>
{headers.map((header, index) =>
<Cell key={`${header}-${key}`} index={index}>
<Text color={color?.[index]}>
<Cell
index={index}
key={`${header}-${key}`}
>
<Text color={colors?.[index]}>
{row[header]}
</Text>
</Cell>
Expand Down
Loading

0 comments on commit 9a4f50e

Please sign in to comment.