Skip to content

Commit 4080c1a

Browse files
authored
Add browser support to demo renderer (#834)
1 parent e5e9077 commit 4080c1a

19 files changed

+210
-150
lines changed

.changeset/cool-things-bathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@codama/renderers-demo': patch
3+
---
4+
5+
Add browser support

packages/renderers-demo/package.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,23 @@
44
"description": "Demo renderer to help creating new ones",
55
"exports": {
66
"types": "./dist/types/index.d.ts",
7+
"react-native": "./dist/index.react-native.mjs",
8+
"browser": {
9+
"import": "./dist/index.browser.mjs",
10+
"require": "./dist/index.browser.cjs"
11+
},
712
"node": {
813
"import": "./dist/index.node.mjs",
914
"require": "./dist/index.node.cjs"
1015
}
1116
},
17+
"browser": {
18+
"./dist/index.node.cjs": "./dist/index.browser.cjs",
19+
"./dist/index.node.mjs": "./dist/index.browser.mjs"
20+
},
1221
"main": "./dist/index.node.cjs",
1322
"module": "./dist/index.node.mjs",
23+
"react-native": "./dist/index.react-native.mjs",
1424
"types": "./dist/types/index.d.ts",
1525
"type": "commonjs",
1626
"files": [
@@ -27,15 +37,17 @@
2737
],
2838
"scripts": {
2939
"build": "rimraf dist && pnpm build:src && pnpm build:types",
30-
"build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs node",
40+
"build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs package",
3141
"build:types": "zx ../../node_modules/@codama/internals/scripts/build-types.mjs",
3242
"dev": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node --watch",
3343
"lint": "zx ../../node_modules/@codama/internals/scripts/lint.mjs",
3444
"lint:fix": "zx ../../node_modules/@codama/internals/scripts/lint.mjs --fix",
35-
"test": "pnpm test:types && pnpm test:treeshakability && pnpm test:node && pnpm test:e2e && pnpm test:exports",
45+
"test": "pnpm test:types && pnpm test:treeshakability && pnpm test:browser && pnpm test:node && pnpm test:react-native && pnpm test:e2e && pnpm test:exports",
46+
"test:browser": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs browser",
3647
"test:e2e": "./test/e2e/test.sh",
3748
"test:exports": "node ./test/exports/module.mjs && node ./test/exports/commonjs.cjs",
3849
"test:node": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node",
50+
"test:react-native": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs react-native",
3951
"test:treeshakability": "zx ../../node_modules/@codama/internals/scripts/test-treeshakability.mjs",
4052
"test:types": "zx ../../node_modules/@codama/internals/scripts/test-types.mjs"
4153
},

packages/renderers-demo/src/fragments/accountPage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ export function getAccountPageFragment(
2525
[
2626
getFrontmatterFragment(title, `Overview of the ${title} account`),
2727
getTitleAndDescriptionFragment(title, node.docs),
28-
fragment('## Account data'),
28+
fragment`## Account data`,
2929
getCodeBlockFragment(type, 'ts'),
30-
...(size ? [fragment(`This account has a fixed size of ${size} bytes.`)] : []),
31-
...(pda ? [fragment('## PDA'), getCodeBlockFragment(getPdaFunctionUsageFragment(pda), 'ts')] : []),
30+
...(size ? [fragment`This account has a fixed size of ${size} bytes.`] : []),
31+
...(pda ? [fragment`## PDA`, getCodeBlockFragment(getPdaFunctionUsageFragment(pda), 'ts')] : []),
3232
],
3333
// Generated accounts are within the same directory.
3434
{ generatedAccounts: '.' },

packages/renderers-demo/src/fragments/definedTypePage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function getDefinedTypePageFragment(node: DefinedTypeNode, typeVisitor: T
1919
[
2020
getFrontmatterFragment(title, `Overview of the ${title} type`),
2121
getTitleAndDescriptionFragment(title, node.docs),
22-
fragment('## Type definition'),
22+
fragment`## Type definition`,
2323
getCodeBlockFragment(type, 'ts'),
2424
],
2525
// Generated types are within the same directory.

packages/renderers-demo/src/fragments/instructionPage.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export function getInstructionPageFragment(node: InstructionNode, typeVisitor: T
2222
[
2323
getFrontmatterFragment(title, `Overview of the ${title} instruction`),
2424
getTitleAndDescriptionFragment(title, node.docs),
25-
fragment('## Instruction accounts'),
26-
accountsFragment ? accountsFragment : fragment('_This instruction has no accounts._'),
27-
fragment('## Instruction arguments'),
28-
hasArguments ? getCodeBlockFragment(type, 'ts') : fragment('_This instruction has no arguments._'),
25+
fragment`## Instruction accounts`,
26+
accountsFragment ? accountsFragment : fragment`_This instruction has no accounts._`,
27+
fragment`## Instruction arguments`,
28+
hasArguments ? getCodeBlockFragment(type, 'ts') : fragment`_This instruction has no arguments._`,
2929
],
3030
// Generated instructions are within the same directory.
3131
{ generatedInstructions: '.' },

packages/renderers-demo/src/fragments/pdaFunctionUsage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function getPdaFunctionUsageFragment(node: PdaNode): Fragment {
1010
? `{\n${variableSeedNames.join(',\n')},\n}`
1111
: `{ ${variableSeedNames.join(', ')} }`;
1212
return addFragmentImports(
13-
fragment(`const [address, bump] = await ${functionName}(${seedObject});`),
13+
fragment`const [address, bump] = await ${functionName}(${seedObject});`,
1414
'generatedPdas',
1515
pascalCase(node.name),
1616
);

packages/renderers-demo/src/fragments/pdaPage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export function getPdaPageFragment(node: PdaNode, typeVisitor: TypeVisitor, valu
1313
[
1414
getFrontmatterFragment(title, `Overview of the ${title}`),
1515
getTitleAndDescriptionFragment(title, node.docs),
16-
fragment('## Seeds'),
17-
seeds ? seeds : fragment('_This PDA has no seeds._'),
16+
fragment`## Seeds`,
17+
seeds ? seeds : fragment`_This PDA has no seeds._`,
1818
],
1919
// Generated PDAs are within the same directory.
2020
{ generatedPdas: '.' },
Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { camelCase, ProgramNode, titleCase } from '@codama/nodes';
22
import { joinPath } from '@codama/renderers-core';
33

4-
import { Fragment, fragment, getFrontmatterFragment, getPageFragment, getTitleAndDescriptionFragment } from '../utils';
4+
import {
5+
Fragment,
6+
fragment,
7+
getFrontmatterFragment,
8+
getPageFragment,
9+
getTitleAndDescriptionFragment,
10+
mergeFragments,
11+
} from '../utils';
512
import { getProgramErrorsFragment } from './programErrors';
613

714
export function getProgramPageFragment(node: ProgramNode): Fragment {
@@ -12,18 +19,18 @@ export function getProgramPageFragment(node: ProgramNode): Fragment {
1219
[
1320
getFrontmatterFragment(title, `Overview of the ${title}`),
1421
getTitleAndDescriptionFragment(title, node.docs),
15-
fragment('## Information'),
16-
fragment([`- Address: \`${node.publicKey}\``, `- Version: \`${node.version}\``].join('\n')),
17-
fragment('## Accounts'),
22+
fragment`## Information`,
23+
fragment`- Address: \`${node.publicKey}\`\n- Version: \`${node.version}\``,
24+
fragment`## Accounts`,
1825
getLinksFragment(node.accounts, 'accounts'),
19-
fragment('## Instructions'),
26+
fragment`## Instructions`,
2027
getLinksFragment(node.instructions, 'instructions'),
21-
fragment('## PDAs'),
28+
fragment`## PDAs`,
2229
getLinksFragment(node.pdas, 'pdas', 'PDAs'),
23-
fragment('## Defined types'),
30+
fragment`## Defined types`,
2431
getLinksFragment(node.definedTypes, 'definedTypes', 'defined types'),
25-
fragment('## Errors'),
26-
errors ? errors : fragment('_This program has no errors._'),
32+
fragment`## Errors`,
33+
errors ? errors : fragment`_This program has no errors._`,
2734
],
2835
// Generated items are nested in sibling directories.
2936
{
@@ -36,10 +43,10 @@ export function getProgramPageFragment(node: ProgramNode): Fragment {
3643
}
3744

3845
function getLinksFragment(items: { name: string }[], folder: string, identifier?: string): Fragment {
39-
if (items.length === 0) return fragment(`_This program has no ${identifier ?? folder}._`);
46+
if (items.length === 0) return fragment`_This program has no ${identifier ?? folder}._`;
4047
const links = items.map(item => {
4148
const link = joinPath(folder, `${camelCase(item.name)}.md`);
42-
return `- [${titleCase(item.name)}](${link})`;
49+
return fragment`- [${titleCase(item.name)}](${link})`;
4350
});
44-
return fragment(links.join('\n'));
51+
return mergeFragments(links, cs => cs.join('\n'));
4552
}
Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
11
import { Docs } from '@codama/nodes';
2-
import { BaseFragment, mapFragmentContent, Path } from '@codama/renderers-core';
2+
import { BaseFragment, createFragmentTemplate, mapFragmentContent, Path } from '@codama/renderers-core';
33

4-
import { addToImportMap, getImportMapLinks, ImportMap, importMap, mergeImportMaps, PathOverrides } from './importMap';
4+
import {
5+
addToImportMap,
6+
createImportMap,
7+
getImportMapLinks,
8+
ImportMap,
9+
mergeImportMaps,
10+
PathOverrides,
11+
} from './importMap';
512

613
export type Fragment = BaseFragment & Readonly<{ imports: ImportMap }>;
714

8-
export function fragment(content: string): Fragment {
9-
return Object.freeze({ content, imports: importMap() });
15+
function createFragment(content: string): Fragment {
16+
return Object.freeze({ content, imports: createImportMap() });
1017
}
1118

12-
export function mergeFragments(fragments: Fragment[], mergeContent: (contents: string[]) => string) {
19+
function isFragment(value: unknown): value is Fragment {
20+
return typeof value === 'object' && value !== null && 'content' in value;
21+
}
22+
23+
export function fragment(template: TemplateStringsArray, ...items: unknown[]): Fragment {
24+
return createFragmentTemplate(template, items, isFragment, mergeFragments);
25+
}
26+
27+
export function mergeFragments(
28+
fragments: (Fragment | undefined)[],
29+
mergeContent: (contents: string[]) => string,
30+
): Fragment {
31+
const filteredFragments = fragments.filter((f): f is Fragment => f !== undefined);
1332
return Object.freeze({
14-
content: mergeContent(fragments.map(fragment => fragment.content)),
15-
imports: mergeImportMaps(fragments.map(fragment => fragment.imports)),
33+
content: mergeContent(filteredFragments.map(fragment => fragment.content)),
34+
imports: mergeImportMaps(filteredFragments.map(fragment => fragment.imports)),
1635
});
1736
}
1837

@@ -21,12 +40,12 @@ export function addFragmentImports(fragment: Fragment, path: Path, names: string
2140
}
2241

2342
export function getFrontmatterFragment(title: string, description: string): Fragment {
24-
return fragment(`---\ntitle: ${title}\ndescription: ${description}\n---`);
43+
return fragment`---\ntitle: ${title}\ndescription: ${description}\n---`;
2544
}
2645

2746
export function getTitleAndDescriptionFragment(title: string, docs?: Docs): Fragment {
2847
return mergeFragments(
29-
[fragment(`# ${title}`), ...(docs && docs.length > 0 ? [fragment(docs.join('\n'))] : [])],
48+
[fragment`# ${title}`, docs && docs.length > 0 ? fragment`${docs.join('\n')}` : undefined],
3049
cs => cs.join('\n\n'),
3150
);
3251
}
@@ -36,7 +55,7 @@ export function getCodeBlockFragment(code: Fragment, language: string = ''): Fra
3655
}
3756

3857
export function getTableFragment(headers: (Fragment | string)[], rows: (Fragment | string)[][]): Fragment {
39-
const toFragment = (cell: Fragment | string) => (typeof cell === 'string' ? fragment(cell) : cell);
58+
const toFragment = (cell: Fragment | string) => (typeof cell === 'string' ? createFragment(cell) : cell);
4059
const headerFragments = headers.map(toFragment);
4160
const rowFragments = rows.map(row => row.map(toFragment));
4261
const colWidths = headerFragments.map((header, colIndex) =>
@@ -46,7 +65,7 @@ export function getTableFragment(headers: (Fragment | string)[], rows: (Fragment
4665
const mergeCells = (fs: Fragment[]) => mergeFragments(fs, cs => cs.join(' | '));
4766
const lines = [
4867
mergeCells(headerFragments.map(padCells)),
49-
mergeCells(headerFragments.map((_, colIndex) => fragment('-'.repeat(colWidths[colIndex])))),
68+
mergeCells(headerFragments.map((_, colIndex) => createFragment('-'.repeat(colWidths[colIndex])))),
5069
...rowFragments.map(row => mergeCells(row.map(padCells))),
5170
];
5271
return mergeFragments(
@@ -56,12 +75,12 @@ export function getTableFragment(headers: (Fragment | string)[], rows: (Fragment
5675
}
5776

5877
export function getCommentFragment(lines: string[]): Fragment {
59-
return fragment(`<!--\n${lines.join('\n')}\n-->`);
78+
return fragment`<!--\n${lines.join('\n')}\n-->`;
6079
}
6180

6281
export function getPageFragment(fragments: Fragment[], pathOverrides: PathOverrides = {}): Fragment {
6382
const page = mergeFragments(fragments, cs => cs.join('\n\n'));
6483
const links = getImportMapLinks(page.imports, pathOverrides);
6584
if (links.length === 0) return page;
66-
return mapFragmentContent(page, c => `${c}\n\n## See also\n\n${links.join('\n')}`);
85+
return fragment`${page}\n\n## See also\n\n${links.join('\n')}`;
6786
}

packages/renderers-demo/src/utils/importMap.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { joinPath, Path } from '@codama/renderers-core';
33

44
export type ImportMap = ReadonlyMap<Path, ReadonlySet<string>>;
55

6-
export function importMap(imports: [Path, string[] | string][] = []): ImportMap {
6+
export function createImportMap(imports: [Path, string[] | string][] = []): ImportMap {
77
return Object.freeze(
88
new Map(imports.map(([path, names]) => [path, new Set(typeof names === 'string' ? [names] : names)])),
99
);
1010
}
1111

1212
export function addToImportMap(map: ImportMap, path: Path, names: string[] | string): ImportMap {
13-
return mergeImportMaps([map, importMap([[path, names]])]);
13+
return mergeImportMaps([map, createImportMap([[path, names]])]);
1414
}
1515

1616
export function mergeImportMaps(importMaps: ImportMap[]): ImportMap {

0 commit comments

Comments
 (0)