Skip to content

Commit

Permalink
feat: import user vars
Browse files Browse the repository at this point in the history
  • Loading branch information
kellyjosephprice committed Dec 9, 2024
1 parent 4616fb3 commit 5849d4a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 24 deletions.
36 changes: 36 additions & 0 deletions __tests__/variables/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { execute } from '../helpers';

describe('variables', () => {
it('renders a variable', async () => {
const md = `{user.name}`;
const Content = await execute(md, {}, { variables: { user: { name: 'Testing' } } });

render(<Content />);

expect(screen.getByText('Testing')).toBeVisible();
});

it('renders a default value', async () => {
const md = `{user.name}`;
const Content = await execute(md);

render(<Content />);

expect(screen.getByText('NAME')).toBeVisible();
});

it('supports user variables in ESM', async () => {
const md = `
export const Hello = () => <p>{user.name}</p>;
<Hello />
`;
const Content = await execute(md, {}, { variables: { user: { name: 'Owlbert' } } });

render(<Content />);

expect(screen.getByText('Owlbert')).toBeVisible();
});
});
20 changes: 7 additions & 13 deletions contexts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import React from 'react';
import GlossaryContext from './GlossaryTerms';
import BaseUrlContext from './BaseUrl';
import { VariablesContext } from '@readme/variable';
import { RunOpts } from '../lib/run';

type Props = React.PropsWithChildren & Pick<RunOpts, 'baseUrl' | 'terms' | 'variables'>;
type Props = React.PropsWithChildren & Pick<RunOpts, 'baseUrl' | 'terms'>;

const compose = (
children: React.ReactNode,
...contexts: [React.Context<typeof VariablesContext | typeof GlossaryContext>, unknown][]
) => {
return contexts.reduce((content, [Context, value]) => {
return <Context.Provider value={value}>{content}</Context.Provider>;
}, children);
};

const Contexts = ({ children, terms = [], variables = { user: {}, defaults: [] }, baseUrl = '/' }: Props) => {
return compose(children, [GlossaryContext, terms], [VariablesContext, variables], [BaseUrlContext, baseUrl]);
const Contexts = ({ children, terms = [], baseUrl = '/' }: Props) => {
return (
<GlossaryContext.Provider value={terms}>
<BaseUrlContext.Provider value={baseUrl}>{children}</BaseUrlContext.Provider>
</GlossaryContext.Provider>
);
};

export default Contexts;
9 changes: 5 additions & 4 deletions lib/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ const compile = (text: string, { components, copyButtons, ...opts }: CompileOpts
remarkGfm,
...Object.values(transforms),
[codeTabsTransformer, { copyButtons }],
variablesTransformer,
],
rehypePlugins: [...rehypePlugins, [rehypeToc, { components }]],
...opts,
});

return String(vfile).replace(
/await import\(_resolveDynamicMdxSpecifier\(('react'|"react")\)\)/,
'arguments[0].imports.React',
return (
String(vfile).replace(
/await import\(_resolveDynamicMdxSpecifier\(('react'|"react")\)\)/,
'arguments[0].imports.React',
).replace('"use strict";', '"use strict";\nconst { user } = arguments[0].imports;'),
);
} catch (error) {
throw error.line ? new MdxSyntaxError(error, text) : error;
Expand Down
10 changes: 3 additions & 7 deletions lib/run.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import { Depth } from '../components/Heading';
import { tocToMdx } from '../processor/plugin/toc';
import compile from './compile';
import { CustomComponents, RMDXModule } from '../types';

interface Variables {
user: Record<string, string>;
defaults: { name: string; default: string }[];
}
import User, { Variables } from '../utils/user';

export type RunOpts = Omit<RunOptions, 'Fragment'> & {
components?: CustomComponents;
Expand Down Expand Up @@ -63,7 +59,7 @@ const run = async (string: string, _opts: RunOpts = {}) => {
...runtime,
Fragment,
baseUrl: import.meta.url,
imports: { React },
imports: { React, user: User(variables) },
useMDXComponents,
...opts,
}) as Promise<RMDXModule>;
Expand All @@ -76,7 +72,7 @@ const run = async (string: string, _opts: RunOpts = {}) => {

return {
default: () => (
<Contexts terms={terms} variables={variables} baseUrl={baseUrl}>
<Contexts terms={terms} baseUrl={baseUrl}>
<Content />
</Contexts>
),
Expand Down
31 changes: 31 additions & 0 deletions utils/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
interface Default {
name: string;
default: string;
}

export interface Variables {
user: Record<string, string>;
defaults: Default[];
}

const User = (variables?: Variables) => {
const { user = {}, defaults = [] } = variables || {};

return new Proxy(user, {
get(target, attribute) {
if (typeof attribute === 'symbol') {
return '';
}

if (attribute in target) {
return target[attribute];
}

const def = defaults.find((d: Default) => d.name === attribute);

return def ? def.default : attribute.toUpperCase();
},
});
};

export default User;

0 comments on commit 5849d4a

Please sign in to comment.