Browse Source

Update serve and generate scripts

Make these scripts functional.
master
TheoryOfNekomata 1 year ago
parent
commit
391d1f744c
15 changed files with 310 additions and 66 deletions
  1. +9
    -0
      .amanuensis/components/Wrapper.tsx
  2. +8
    -0
      packages/amanuensis/.eslintrc
  3. +1
    -0
      packages/amanuensis/.gitignore
  4. +9
    -0
      packages/amanuensis/default/components/Wrapper.tsx
  5. +2
    -0
      packages/amanuensis/package.json
  6. +2
    -1
      packages/amanuensis/pages/_app.tsx
  7. +36
    -0
      packages/amanuensis/pages/index.tsx
  8. +37
    -19
      packages/amanuensis/src/commands/generate.ts
  9. +101
    -5
      packages/amanuensis/src/commands/serve.ts
  10. +35
    -0
      packages/amanuensis/src/data.ts
  11. +23
    -30
      packages/amanuensis/src/index.ts
  12. +0
    -9
      packages/amanuensis/src/pages/index.tsx
  13. +5
    -1
      packages/amanuensis/tsconfig.eslint.json
  14. +3
    -1
      packages/amanuensis/tsconfig.json
  15. +39
    -0
      pnpm-lock.yaml

+ 9
- 0
.amanuensis/components/Wrapper.tsx View File

@@ -0,0 +1,9 @@
export const Wrapper = ({
children,
}) => {
return (
<div className="amanuensis-wrapper">
{children}
</div>
)
};

+ 8
- 0
packages/amanuensis/.eslintrc View File

@@ -1,8 +1,16 @@
{
"root": true,
"ignorePatterns": [
"pages/**/*.tsx",
"components/**/*.tsx"
],
"extends": [
"lxsmnsyc/typescript"
],
"rules": {
"no-tabs": "off",
"indent": "off"
},
"parserOptions": {
"project": "./tsconfig.eslint.json"
}


+ 1
- 0
packages/amanuensis/.gitignore View File

@@ -108,3 +108,4 @@ dist
.next/
types/
.amanuensis/
components/

+ 9
- 0
packages/amanuensis/default/components/Wrapper.tsx View File

@@ -0,0 +1,9 @@
export const Wrapper = ({
children,
}) => {
return (
<div>
{children}
</div>
)
};

+ 2
- 0
packages/amanuensis/package.json View File

@@ -55,9 +55,11 @@
},
"dependencies": {
"execa": "^7.2.0",
"mkdirp": "^3.0.1",
"next": "13.4.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.7",
"typedoc": "^0.24.8",
"yargs": "^17.7.2"
},


packages/amanuensis/src/pages/_app.tsx → packages/amanuensis/pages/_app.tsx View File

@@ -1,6 +1,7 @@
import type { AppProps } from 'next/app';
import { FC } from 'react';

const App = ({ Component, pageProps }: AppProps) => {
const App: FC = ({ Component, pageProps }: AppProps) => {
return (
<Component {...pageProps} />
);

+ 36
- 0
packages/amanuensis/pages/index.tsx View File

@@ -0,0 +1,36 @@
import {GetStaticProps, NextPage} from 'next';
import {getReadmeText} from '../src/data';
import ReactMarkdown from 'react-markdown';
import {Wrapper} from '../components/Wrapper';

interface IndexPageProps {
readmeType: 'markdown';
readmeText: string;
}

const IndexPage: NextPage<IndexPageProps> = ({
readmeType,
readmeText,
}) => {
return (
<Wrapper>
{readmeType === 'markdown' && (
<ReactMarkdown>
{readmeText}
</ReactMarkdown>
)}
</Wrapper>
);
};

export const getStaticProps: GetStaticProps<IndexPageProps> = async () => {
const readmeText = await getReadmeText();
return {
props: {
readmeType: 'markdown',
readmeText,
},
};
};

export default IndexPage;

+ 37
- 19
packages/amanuensis/src/commands/generate.ts View File

@@ -1,27 +1,25 @@
import { stat } from 'fs/promises';
import { resolve } from 'path';
import { Argv } from 'yargs';
import {Stats} from 'fs';
import { Stats } from 'fs';

export const description = 'Generate documentation from typedoc.json' as const;

interface GenerateArgs {
typedocJsonPath: string;
}

const ensureTypedocJson = async (typedocPath = resolve(process.cwd(), 'typedoc.json')) => {
const ensureTypedocJson = async (typedocPath: string) => {
const trueTypedocPath = resolve(typedocPath);
process.stdout.write(`In path: ${trueTypedocPath}\n`);
process.stdout.write(`Using typedoc.json path: ${trueTypedocPath}\n`);
process.stdout.write('Does the file exist? ');
let statResult: Stats;
try {
statResult = await stat(trueTypedocPath);
} catch (errRaw) {
if (errRaw.code === 'ENOENT') {
const err = errRaw as NodeJS.ErrnoException;
if (err.code === 'ENOENT') {
process.stdout.write('no\n');
process.stderr.write('Could not find typedoc.json\n');
throw new Error('Could not find typedoc.json');
}
process.stdout.write('maybe?\n');
process.stderr.write('Could not ensure typedoc.json\n');
throw err;
}
if (statResult.isDirectory()) {
process.stdout.write('no\n');
@@ -31,38 +29,58 @@ const ensureTypedocJson = async (typedocPath = resolve(process.cwd(), 'typedoc.j
process.stdout.write('yes\n');
};

const generateTypedocData = async (cwd = process.cwd()) => {
const generateTypedocData = async () => {
process.stdout.write('Generating typedoc data...\n');

const outPath = resolve(__dirname, '..', '..', '..', '.amanuensis', 'data.json');
const typedocBinPath = resolve(__dirname, '..', '..', '..', 'node_modules', '.bin', 'typedoc');
const { execa } = await import('execa');
await execa(typedocBinPath, ['--json', outPath])
.pipeStdout(process.stdout)
.pipeStderr(process.stderr)

await execa(typedocBinPath, ['--json', outPath], {
stdout: 'inherit',
stderr: 'inherit',
});

process.stdout.write('done\n');
};

export const description = 'Generate documentation from typedoc.json' as const;

export enum GenerateReturnCode {
SUCCESS = 0,
NO_TYPEDOC_JSON = -1,
COULD_NOT_GENERATE_TYPEDOC_DATA = -2,
}

export interface GenerateArgs {
typedocJsonPath?: string;
subcommands?: string[];
}

export const builder = (yargs: Argv) => yargs
.option('typedocJsonPath', {
type: 'string',
default: 'typedoc.json',
alias: 't',
});

const generate = async (args: GenerateArgs) => {
const {
typedocJsonPath = resolve(process.cwd(), 'typedoc.json'),
} = args;

try {
await ensureTypedocJson(args.typedocJsonPath);
await ensureTypedocJson(typedocJsonPath);
} catch {
return -1;
return GenerateReturnCode.NO_TYPEDOC_JSON;
}

try {
await generateTypedocData();
} catch {
return -2;
return GenerateReturnCode.COULD_NOT_GENERATE_TYPEDOC_DATA;
}

return 0;
return GenerateReturnCode.SUCCESS;
};

export default generate;

+ 101
- 5
packages/amanuensis/src/commands/serve.ts View File

@@ -1,12 +1,108 @@
import {Argv} from 'yargs';
import { Argv } from 'yargs';
import { resolve, dirname } from 'path';
import { cp, stat, unlink } from 'fs/promises';
import { mkdirp } from 'mkdirp';

const DEFAULT_PORT = 3000 as const;

const linkComponents = async () => {
process.stdout.write('Linking components...\n');

const projectCwd = resolve(process.cwd(), '.amanuensis');
const defaultCwd = resolve(__dirname, '..', '..', '..', 'default');
const destCwd = resolve(__dirname, '..', '..', '..');
const componentsList = [
'components/Wrapper.tsx',
];

await Promise.all(componentsList.map(async (componentPath) => {
const destPath = resolve(destCwd, componentPath);
try {
await unlink(destPath);
} catch {
// noop
}

let baseCwd = projectCwd;

try {
await stat(resolve(baseCwd, componentPath));
} catch (errRaw) {
const err = errRaw as NodeJS.ErrnoException;
if (err.code === 'ENOENT') {
baseCwd = defaultCwd;
}
}

await mkdirp(dirname(destPath));
await cp(
resolve(baseCwd, componentPath),
destPath,
);
process.stdout.write(`Linked ${componentPath}\n`);
}));

process.stdout.write('done\n');
};

const buildApp = async () => {
process.stdout.write('Building app...\n');

const cwd = resolve(__dirname, '..', '..', '..');
const nextBinPath = resolve(__dirname, '..', '..', '..', 'node_modules', '.bin', 'next');
const { execa } = await import('execa');

await execa(nextBinPath, ['build'], {
stdout: 'inherit',
stderr: 'inherit',
cwd,
});

process.stdout.write('done\n');
};

const serveApp = async (port: number) => {
process.stdout.write(`Using port: ${port}...\n`);
process.stdout.write('Serving app...\n');

const cwd = resolve(__dirname, '..', '..', '..');
const nextBinPath = resolve(__dirname, '..', '..', '..', 'node_modules', '.bin', 'next');
const { execa } = await import('execa');

await execa(nextBinPath, ['start', '-p', port.toString()], {
stdout: 'inherit',
stderr: 'inherit',
cwd,
});
};

export const description = 'Start a development server' as const;

export const builder = (yargs: Argv) => yargs;
export enum ServeReturnCode {
SUCCESS = 0,
}

export interface ServeArgs {
port?: number;
subcommands?: string[];
}

export const builder = (yargs: Argv) => yargs
.option('port', {
type: 'number',
default: DEFAULT_PORT,
alias: 'p',
});

const serve = async (args: ServeArgs) => {
const {
port = DEFAULT_PORT,
} = args;

const serve = async (args: Record<string, unknown>) => {
console.log('serve', args);
return 0;
await linkComponents();
await buildApp();
await serveApp(port);
return ServeReturnCode.SUCCESS;
};

export default serve;

+ 35
- 0
packages/amanuensis/src/data.ts View File

@@ -0,0 +1,35 @@
import { readFile } from 'fs/promises';
import { resolve } from 'path';

interface TypedocDataTextNode {
kind: 'text';
text: string;
}

interface TypedocDataInlineTagNode {
kind: 'inline-tag';
tag: string;
text: string;
target: number;
tsLinkText: string;
}

type TypedocDataNode = TypedocDataTextNode | TypedocDataInlineTagNode;

export interface TypedocData {
readme: TypedocDataNode[];
}

export const getReadmeText = async () => {
const typedocDataJson = await readFile(resolve('.amanuensis', 'data.json'), 'utf-8');
const typedocData = JSON.parse(typedocDataJson) as TypedocData;
return typedocData.readme.reduce(
(theText, node) => {
if (node.kind === 'text') {
return `${theText}${node.text}`;
}
return theText;
},
'',
);
};

+ 23
- 30
packages/amanuensis/src/index.ts View File

@@ -3,56 +3,49 @@
import { hideBin } from 'yargs/helpers';
import yargs from 'yargs';

import * as serve from './commands/serve';
import * as generate from './commands/generate';

const COMMANDS = {
serve,
generate,
};

type CommandName = keyof typeof COMMANDS;

const main = async (args: string[]) => {
const COMMANDS = {
serve: await import('./commands/serve'),
generate: await import('./commands/generate'),
};

const yargsBuilder = Object.entries(COMMANDS).reduce(
(theYargs, [name, command]) => {
return theYargs.command(
(theYargs, [name, command]) => theYargs.command(
name,
command.description ?? '',
command.builder ?? (yargs => yargs),
);
},
command.builder ?? ((commandYargs) => commandYargs),
),
yargs
.scriptName('amanuensis'),
);

const { _: commandNamesRaw, ...etcArgs } = await yargsBuilder.parse(args);

const [commandName, ...subcommands] = commandNamesRaw as [CommandName, ...string[]];
const [commandName, ...subcommands] = commandNamesRaw as [keyof typeof COMMANDS, ...string[]];
if (typeof commandName === 'undefined') {
yargsBuilder.showHelp();
return;
return -1;
}

const { [commandName]: commandDef } = COMMANDS;
if (typeof commandDef === 'undefined') {
process.stderr.write(`Unknown command: ${commandName}\n`);
yargsBuilder.showHelp();
process.exit(-1);
return;
return -1;
}

const { default: handler } = commandDef;

try {
const returnCode = await handler({
...etcArgs,
_: subcommands,
});
process.exit(returnCode);
} catch {
process.exit(-1);
}
return handler({
...etcArgs,
subcommands,
});
};

void main(hideBin(process.argv));
main(hideBin(process.argv))
.then((code = 0) => {
// noop
process.exit(code);
})
.catch(() => {
process.exit(-1);
});

+ 0
- 9
packages/amanuensis/src/pages/index.tsx View File

@@ -1,9 +0,0 @@
const IndexPage = () => {
return (
<div>
Hello
</div>
);
};

export default IndexPage;

+ 5
- 1
packages/amanuensis/tsconfig.eslint.json View File

@@ -1,5 +1,9 @@
{
"exclude": ["node_modules"],
"exclude": [
"node_modules",
"pages/**",
"components/**"
],
"include": ["src", "types", "test"],
"compilerOptions": {
"module": "ESNext",


+ 3
- 1
packages/amanuensis/tsconfig.json View File

@@ -1,6 +1,8 @@
{
"exclude": [
"node_modules"
"node_modules",
"pages/**",
"components/**",
],
"include": [
"src",


+ 39
- 0
pnpm-lock.yaml View File

@@ -715,6 +715,9 @@ importers:
execa:
specifier: ^7.2.0
version: 7.2.0
mkdirp:
specifier: ^3.0.1
version: 3.0.1
next:
specifier: 13.4.7
version: 13.4.7(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)
@@ -724,6 +727,9 @@ importers:
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-markdown:
specifier: ^8.0.7
version: 8.0.7(@types/react@18.2.18)(react@18.2.0)
typedoc:
specifier: ^0.24.8
version: 0.24.8(typescript@4.9.5)
@@ -5741,6 +5747,12 @@ packages:
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}

/mkdirp@3.0.1:
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
engines: {node: '>=10'}
hasBin: true
dev: false

/mlly@1.4.0:
resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==}
dependencies:
@@ -6461,6 +6473,33 @@ packages:
- supports-color
dev: false

/react-markdown@8.0.7(@types/react@18.2.18)(react@18.2.0):
resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==}
peerDependencies:
'@types/react': '>=16'
react: '>=16'
dependencies:
'@types/hast': 2.3.4
'@types/prop-types': 15.7.5
'@types/react': 18.2.18
'@types/unist': 2.0.6
comma-separated-tokens: 2.0.3
hast-util-whitespace: 2.0.1
prop-types: 15.8.1
property-information: 6.2.0
react: 18.2.0
react-is: 18.2.0
remark-parse: 10.0.2
remark-rehype: 10.1.0
space-separated-tokens: 2.0.2
style-to-object: 0.4.1
unified: 10.1.2
unist-util-visit: 4.1.2
vfile: 5.3.7
transitivePeerDependencies:
- supports-color
dev: false

/react-phone-number-input@3.3.0(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-6d1lq9parRGnVz6laEN7ijU7MeUCkFEJsTnzB/97nVrm/WE48EDEV5/2bu08mzfZjvX6shpryqG0DUCNiP07Cg==}
peerDependencies:


Loading…
Cancel
Save