Skip to content

Commit

Permalink
Merge pull request #157 from near/feat/export
Browse files Browse the repository at this point in the history
feat: add support for `export` keyword
  • Loading branch information
andy-haynes authored Dec 12, 2023
2 parents cbaf730 + c3b25d4 commit 7590b8e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 16 deletions.
11 changes: 9 additions & 2 deletions packages/compiler/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
buildComponentFunction,
buildComponentFunctionName,
} from './component';
import { extractExport } from './export';
import {
buildComponentImportStatements,
buildModuleImports,
Expand Down Expand Up @@ -133,19 +134,25 @@ export class ComponentCompiler {
trustedRoot,
}: ParseComponentTreeParams) {
// separate out import statements from Component source
const { imports, source: cleanComponentSource } =
const { imports, source: importlessSource } =
extractImportStatements(componentSource);

// get the exported reference's name and remove the export keyword(s) from Component source
// TODO halt parsing of the current Component if no export is found
const { exported, source: cleanComponentSource } =
extractExport(importlessSource);

const componentImports = imports
.map((moduleImport) => buildComponentImportStatements(moduleImport))
.flat()
.filter((statement) => !!statement) as string[];

// wrap the Component's JSX body source in a function to be rendered as a Component
// assign a known alias to the exported Component
const componentFunctionSource = buildComponentFunction({
componentPath,
componentSource: cleanComponentSource,
componentImports,
exported,
isRoot,
});

Expand Down
29 changes: 22 additions & 7 deletions packages/compiler/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,49 @@ interface BuildComponentFunctionParams {
componentImports: string[];
componentPath: string;
componentSource: string;
exported: string | null;
isRoot: boolean;
}

export function buildComponentFunction({
componentImports,
componentPath,
componentSource,
exported,
isRoot,
}: BuildComponentFunctionParams) {
const functionName = buildComponentFunctionName(isRoot ? '' : componentPath);
const importAssignments = componentImports.join('\n');
const commentHeader = `${componentPath} ${isRoot ? '(root)' : ''}`;

// TODO remove once export is required
if (!exported) {
if (isRoot) {
return `
function ${functionName}() {
${importAssignments}
${componentSource}
}
`;
}

if (isRoot) {
return `
function ${functionName}() {
/************************* ${componentPath} *************************/
function ${functionName}(__bweInlineComponentProps) {
${importAssignments}
const { __bweMeta, props: __componentProps } = __bweInlineComponentProps;
const props = Object.assign({ __bweMeta }, __componentProps);
${componentSource}
}
`;
}

return `
/************************* ${componentPath} *************************/
function ${functionName}(__bweInlineComponentProps) {
/************************* ${commentHeader} *************************/
const ${functionName} = (() => {
${importAssignments}
const { __bweMeta, props: __componentProps } = __bweInlineComponentProps;
const props = Object.assign({ __bweMeta }, __componentProps);
${componentSource}
}
return ${exported};
})();
`;
}
31 changes: 31 additions & 0 deletions packages/compiler/src/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Supported export syntax:
* - export default X;
* - export function X...
* - export const X...
*/
const EXPORT_REGEX =
/^export\s+(const|default|function)\s+(?<identifier>[\w$_]+)/g;

/**
* Extract the name of the exported reference and strip the export keyword(s) from the source
* @param source BOS Component source
*/
export const extractExport = (source: string) => {
const [match, ...matches] = [...source.matchAll(EXPORT_REGEX)];
if (matches.length) {
throw new Error(`Multiple exports not permitted: ${matches.join(', ')}`);
}

if (!match?.groups?.identifier) {
return { exported: null, source };
}

return {
exported: match.groups.identifier,
source: source.replace(
match[0],
match[0].replace(/export(\s+default)?\s+/, '')
),
};
};
14 changes: 7 additions & 7 deletions packages/iframe/src/SandboxedIframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ function buildSandboxedComponent({
const { createElement } = Preact;
/******** BEGIN BOS SOURCE ********/
/******** The root Component definition is inlined here as [function BWEComponent() {...}] ********/
${scriptSrc}
/******** END BOS SOURCE ********/
const initContainer = ${initContainer.toString()};
// placeholder function to bind to Component/Widget references
Expand Down Expand Up @@ -91,7 +96,7 @@ function buildSandboxedComponent({
// if nothing has changed, the same [props] object will be returned
props = updateProps(props);
if (props !== originalProps) {
Preact.render(createElement(BWEComponent), document.body);
Preact.render(createElement(BWEComponent, props), document.body);
}
},
Widget,
Expand All @@ -101,11 +106,6 @@ function buildSandboxedComponent({
// intialize props
props = containerProps;
/******** BEGIN BOS SOURCE ********/
/******** The root Component definition is inlined here as [function BWEComponent() {...}] ********/
${scriptSrc}
/******** END BOS SOURCE ********/
const oldCommit = Preact.options.__c;
Preact.options.__c = (vnode, commitQueue) => {
commit(vnode);
Expand All @@ -114,7 +114,7 @@ ${scriptSrc}
window.addEventListener('message', processEvent);
Preact.render(createElement(BWEComponent), document.body);
Preact.render(createElement(BWEComponent, props), document.body);
</script>
</body>
</html>
Expand Down

0 comments on commit 7590b8e

Please sign in to comment.