Skip to content

Commit

Permalink
Update 3 files
Browse files Browse the repository at this point in the history
  • Loading branch information
danilowoz committed Sep 30, 2022
1 parent f8ce10b commit c924df2
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 76 deletions.
24 changes: 20 additions & 4 deletions sandpack-react/src/contexts/sandpackContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ export class SandpackProviderClass extends React.PureComponent<
super(props);

const { activeFile, visibleFiles, files, environment } =
getSandpackStateFromProps(props);
getSandpackStateFromProps({
template: props.template,
files: props.files,
customSetup: props.customSetup,
});

this.state = {
files,
Expand Down Expand Up @@ -272,7 +276,11 @@ export class SandpackProviderClass extends React.PureComponent<
* Custom setup derived from props
*/
const { activeFile, visibleFiles, files, environment } =
getSandpackStateFromProps(this.props);
getSandpackStateFromProps({
template: this.props.template,
files: this.props.files,
customSetup: this.props.customSetup,
});

/**
* What the changes on the customSetup props
Expand Down Expand Up @@ -600,7 +608,11 @@ export class SandpackProviderClass extends React.PureComponent<
};

resetFile = (path: string): void => {
const { files } = getSandpackStateFromProps(this.props);
const { files } = getSandpackStateFromProps({
template: this.props.template,
files: this.props.files,
customSetup: this.props.customSetup,
});

this.setState(
(prevState) => ({
Expand All @@ -611,7 +623,11 @@ export class SandpackProviderClass extends React.PureComponent<
};

resetAllFiles = (): void => {
const { files } = getSandpackStateFromProps(this.props);
const { files } = getSandpackStateFromProps({
template: this.props.template,
files: this.props.files,
customSetup: this.props.customSetup,
});

this.setState({ files }, this.updateClients);
};
Expand Down
21 changes: 0 additions & 21 deletions sandpack-react/src/utils/sandpackUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { REACT_TEMPLATE } from "../templates/react";

import {
getSandpackStateFromProps,
createSetupFromUserInput,
resolveFile,
convertedFilesToBundlerFiles,
} from "./sandpackUtils";
Expand Down Expand Up @@ -419,26 +418,6 @@ describe(getSandpackStateFromProps, () => {
});
});

describe(createSetupFromUserInput, () => {
test("convert `files` to a key/value format", () => {
const setup = createSetupFromUserInput({ files: { "App.js": "" } });

expect(setup).toStrictEqual({ files: { "App.js": { code: "" } } });
});

test("supports custom properties", () => {
const setup = createSetupFromUserInput({
files: { "App.js": "" },
customSetup: { environment: "create-react-app" },
});

expect(setup).toStrictEqual({
environment: "create-react-app",
files: { "App.js": { code: "" } },
});
});
});

describe(convertedFilesToBundlerFiles, () => {
it("converts regular files to bundler files", () => {
expect(convertedFilesToBundlerFiles({ name: "code" })).toEqual({
Expand Down
110 changes: 59 additions & 51 deletions sandpack-react/src/utils/sandpackUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ export interface SandpackContextInfo {
environment: SandboxEnvironment;
}

/**
* Creates a standard sandpack state given the setup,
* options, and files props. Using this function is
* the reliable way to ensure a consistent and predictable
* sandpack-content throughout application
*/
export const getSandpackStateFromProps = (
props: SandpackProviderProps
): SandpackContextInfo => {
const normalizedFilesPath = normalizePath(props.files);

// Merge predefined template with custom setup
const projectSetup = getSetup({
const projectSetup = combineTemplateFilesToSetup({
template: props.template,
customSetup: props.customSetup,
files: normalizedFilesPath,
Expand Down Expand Up @@ -109,20 +115,30 @@ export const getSandpackStateFromProps = (
};
};

/**
* Given a file tree and a file, it uses a couple of rules
* to tweak the filename to match with one of the inside of file tree
*
* - Adds the leading slash;
* - Tries to find the same filename with different extensions (js only);
* - Returns `null` if it doesn't satisfy any rule
*/
export const resolveFile = (
path: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
files: Record<string, any>
): string | undefined => {
files: SandpackFiles
): string | null => {
const normalizedFilesPath = normalizePath(files);
const normalizedPath = normalizePath(path);

if (normalizedPath in normalizedFilesPath) return normalizedPath;

if (!path) return undefined;
if (normalizedPath in normalizedFilesPath) {
return normalizedPath;
}

let resolvedPath = undefined;
if (!path) {
return null;
}

let resolvedPath = null;
let index = 0;
const strategies = [".js", ".jsx", ".ts", ".tsx"];

Expand All @@ -142,9 +158,10 @@ export const resolveFile = (

/**
* The template is predefined (eg: react, vue, vanilla)
* The setup can overwrite anything from the template (eg: files, dependencies, environment, etc.)
* The setup can overwrite anything from the template
* (eg: files, dependencies, environment, etc.)
*/
export const getSetup = ({
const combineTemplateFilesToSetup = ({
files,
template,
customSetup,
Expand All @@ -153,26 +170,23 @@ export const getSetup = ({
template?: SandpackPredefinedTemplate;
customSetup?: SandpackSetup;
}): SandboxTemplate => {
/**
* The input setup might have files in the simple form Record<string, string>
* so we convert them to the sandbox template format
*/
const setup = createSetupFromUserInput({ customSetup, files });

if (!template) {
// If not input, default to vanilla
if (!setup) {
if (!customSetup) {
return SANDBOX_TEMPLATES.vanilla as SandboxTemplate;
}

if (!setup.files || Object.keys(setup.files).length === 0) {
if (!files || Object.keys(files).length === 0) {
throw new Error(
`[sandpack-react]: without a template, you must pass at least one file`
);
}

// If not template specified, use the setup entirely
return setup as SandboxTemplate;
return {
...customSetup,
files: convertedFilesToBundlerFiles(files),
} as SandboxTemplate;
}

const baseTemplate = SANDBOX_TEMPLATES[template] as SandboxTemplate;
Expand All @@ -182,31 +196,48 @@ export const getSetup = ({
);
}

// If no setup, the template is used entirely
if (!setup) {
// If no setup and not files, the template is used entirely
if (!customSetup && !files) {
return baseTemplate;
}

// Merge the setup on top of the template
return {
files: { ...baseTemplate.files, ...setup.files },
/**
* The input setup might have files in the simple form Record<string, string>
* so we convert them to the sandbox template format
*/
files: convertedFilesToBundlerFiles({ ...baseTemplate.files, ...files }),
/**
* Merge template dependencies and user custom dependencies.
* As a rule, the custom dependencies must overwrite the template ones.
*/
dependencies: {
...baseTemplate.dependencies,
...setup.dependencies,
...customSetup?.dependencies,
},
devDependencies: {
...baseTemplate.devDependencies,
...setup.devDependencies,
...customSetup?.devDependencies,
},
entry: normalizePath(setup.entry || baseTemplate.entry),
main: setup.main || baseTemplate.main,
environment: setup.environment || baseTemplate.environment,
entry: normalizePath(customSetup?.entry || baseTemplate.entry),
main: baseTemplate.main,
environment: customSetup?.environment || baseTemplate.environment,
} as SandboxTemplate;
};

/**
* Transform an regular object, which contain files to
* an object that sandpack-client can understand
*
* From: Record<string, string>
* To: Record<string, { code: string }>
*/
export const convertedFilesToBundlerFiles = (
files: SandpackFiles
files?: SandpackFiles
): SandpackBundlerFiles => {
if (!files) return {};

return Object.keys(files).reduce((acc: SandpackBundlerFiles, key) => {
if (typeof files[key] === "string") {
acc[key] = { code: files[key] as string };
Expand All @@ -217,26 +248,3 @@ export const convertedFilesToBundlerFiles = (
return acc;
}, {});
};

export const createSetupFromUserInput = ({
files,
customSetup,
}: {
files?: SandpackFiles;
customSetup?: SandpackSetup;
}): Partial<SandboxTemplate> | null => {
if (!files && !customSetup) {
return null;
}

if (!files) {
return customSetup as Partial<SandboxTemplate>;
}

const convertedFiles = convertedFilesToBundlerFiles(files);

return {
...customSetup,
files: convertedFiles,
};
};

0 comments on commit c924df2

Please sign in to comment.