Skip to content

Commit

Permalink
!fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
Haroenv committed Sep 4, 2024
1 parent 995d428 commit 660cb51
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 354 deletions.
5 changes: 3 additions & 2 deletions specs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
"prepare": "rm -rf public && mkdir public && cp -r ../node_modules/instantsearch.css/themes public/themes"
},
"devDependencies": {
"@types/node": "18.11.13",
"@codesandbox/sandpack-react": "2.10.0",
"@types/node": "20.10.0",
"@codesandbox/sandpack-react": "2.19.1",
"@codesandbox/sandpack-themes": "2.0.21",
"dedent": "1.5.1",
"astro": "1.6.14",
"@astrojs/react": "1.2.2",
"instantsearch.css": "8.5.0",
"sass": "1.56.2"
}
Expand Down
52 changes: 30 additions & 22 deletions specs/src/components/Sandbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ const settings = {
}
</style>
<div id="custom"></div>
<hr />
<div id="searchbox"></div>
<div id="hits"></div>
`,
preamble: /* JS */ `
import 'instantsearch.css/themes/satellite-min.css';
import algoliasearch from 'algoliasearch/lite';
import { liteClient as algoliasearch } from 'algoliasearch/lite';
import instantsearch from 'instantsearch.js';
import { history } from 'instantsearch.js/es/lib/routers';
import { searchBox, hits } from 'instantsearch.js/es/widgets';
Expand All @@ -32,30 +33,30 @@ const settings = {
routing: {
router: history({
cleanUrlOnDispose: false,
})
}
}),
},
});
search.addWidgets([
...createWidgets(document.querySelector('#custom')),
...createWidgets(() =>
document.querySelector('#custom').appendChild(document.createElement('div'))
),
searchBox({
container: '#searchbox',
}),
hits({
container: '#hits',
templates: {
item: (hit, { components }) => components.Highlight({ attribute: 'name', hit }),
item: (hit, { components }) =>
components.Highlight({ attribute: 'name', hit }),
},
}),
]);
search.start();
`,
dependencies: {
// TODO: use current version somehow, both locally and in the built website
'instantsearch.js': 'latest',
'instantsearch.css': 'latest',
algoliasearch: 'latest',
algoliasearch: '5.1.1',
},
filename: '/widget.ts',
},
Expand All @@ -72,7 +73,7 @@ const settings = {
import 'instantsearch.css/themes/satellite-min.css';
import React from "react";
import { createRoot } from "react-dom/client";
import algoliasearch from "algoliasearch/lite";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { history } from "instantsearch.js/es/lib/routers";
import { InstantSearch, SearchBox, Hits, Highlight } from "react-instantsearch";
import { widgets } from "./widget.tsx";
Expand All @@ -91,6 +92,7 @@ const settings = {
}}
>
{widgets}
<hr />
<SearchBox />
<Hits hitComponent={Hit}/>
</InstantSearch>
Expand All @@ -101,11 +103,9 @@ const settings = {
}
`,
dependencies: {
react: 'latest',
'react-dom': 'latest',
algoliasearch: 'latest',
'instantsearch.css': 'latest',
'react-instantsearch': 'latest',
react: '18.2.0',
'react-dom': '18.2.0',
algoliasearch: '5.1.1',
},
filename: '/widget.tsx',
},
Expand All @@ -121,7 +121,7 @@ const settings = {
preamble: `
import "instantsearch.css/themes/satellite-min.css";
import Vue from "vue";
import algoliasearch from "algoliasearch/lite";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { history } from "instantsearch.js/es/lib/routers";
import { AisInstantSearch, AisHits, AisSearchBox } from "vue-instantsearch/vue2/es";
import Widget from "./Widget.vue";
Expand Down Expand Up @@ -149,15 +149,13 @@ const settings = {
}
},
},
[h(Widget), h(AisSearchBox), h(AisHits)]
[h(Widget), h('hr'), h(AisSearchBox), h(AisHits)]
),
}).$mount("#app");
`,
dependencies: {
vue: '2',
algoliasearch: 'latest',
'instantsearch.css': 'latest',
'vue-instantsearch': 'latest',
vue: '2.7.14',
algoliasearch: '5.1.1',
},
filename: '/Widget.vue',
},
Expand All @@ -166,9 +164,14 @@ const settings = {
export default function Sandbox({
code,
flavor,
modules,
}: {
code: string;
flavor: 'react' | 'js' | 'vue';
modules: {
files: Record<string, string>;
dependencies: Record<string, string>;
};
}) {
const { preamble, html, filename, dependencies } = settings[flavor];
return (
Expand All @@ -184,12 +187,17 @@ export default function Sandbox({
[filename]: {
code,
},
...modules.files,
}}
customSetup={{
dependencies,
dependencies: {
...dependencies,
...modules.dependencies,
},
entry: '/index.js',
}}
options={{
editorHeight: 500,
activeFile: filename,
showNavigator: true,
}}
Expand Down
42 changes: 26 additions & 16 deletions specs/src/components/WidgetContent.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { Code } from 'astro/components';
import type { WidgetFrontmatter } from '../types';
import ThemeSelector from './ThemeSelector.astro';
import Sandbox from './Sandbox.jsx';
import { getSandpackCssText } from "@codesandbox/sandpack-react";
import { getSandpackCssText } from '@codesandbox/sandpack-react';
import getFiles from '../getDependencyContent';
const modules = await getFiles();
type Props = {
frontmatter: WidgetFrontmatter;
Expand Down Expand Up @@ -114,21 +116,29 @@ const title = frontmatter.title;
)
}

{frontmatter.examples ? (
<>
<h3 id="example">Usage</h3>
<!-- TODO: theme is implied dark? -->
<style is:inline set:html={getSandpackCssText()}></style>
{frontmatter.examples.map(({ code, flavor, library }) => (
<div class="example">
<h4>{library}</h4>
<div class="code-output">
<Sandbox code={code} flavor={flavor} client:load />
</div>
</div>
))}
</>
) : null}
{
frontmatter.examples ? (
<>
<h3 id="example">Usage</h3>
<style id="sandpack" is:inline set:html={getSandpackCssText()} />
{frontmatter.examples.map(({ code, flavor, library }) => (
<details class="example">
<summary style="cursor: pointer">
<h4 style="display: inline-block; margin: 0;">{library}</h4>
</summary>
<div class="code-output">
<Sandbox
code={code}
flavor={flavor}
modules={modules[flavor]}
client:load
/>
</div>
</details>
))}
</>
) : null
}

<h3 id="css-classes">CSS classes</h3>
{
Expand Down
92 changes: 92 additions & 0 deletions specs/src/getDependencyContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { readdir, readFile } from 'fs/promises';
import { join } from 'path';

const cache = new Map();
async function getFilesFromDir(dir: string) {
if (cache.has(dir)) {
return cache.get(dir);
}
const output = (
await readdir(dir, {

Check warning on line 10 in specs/src/getDependencyContent.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

specs/src/getDependencyContent.ts#L10

Detected that function argument `dir` has entered the fs module.
withFileTypes: true,
recursive: true,
})
)
.filter((file) => file.isFile())
.map((file) => join(file.path.replace('../packages/', ''), file.name));

Check warning on line 16 in specs/src/getDependencyContent.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

specs/src/getDependencyContent.ts#L16

Detected possible user input going into a `path.join` or `path.resolve` function.
cache.set(dir, output);
return output;
}

async function getFiles(flavor: 'react' | 'js' | 'vue') {
const localDependencies = [
'instantsearch.css',
'instantsearch-ui-components',
'instantsearch.js',
flavor === 'react' && 'react-instantsearch',
flavor === 'react' && 'react-instantsearch-core',
flavor === 'vue' && 'vue-instantsearch',
].filter(Boolean);

return {
files: Object.fromEntries(
await Promise.all(
[
'instantsearch.css/package.json',
...(await getFilesFromDir('../packages/instantsearch.css/themes')),
'instantsearch-ui-components/package.json',
...(await getFilesFromDir(
'../packages/instantsearch-ui-components/dist'
)),
'instantsearch.js/package.json',
...(await getFilesFromDir('../packages/instantsearch.js/es')),
...(flavor === 'react'
? await getFilesFromDir('../packages/instantsearch.js/cjs')
: []),
flavor === 'react' && 'react-instantsearch/package.json',
...(flavor === 'react'
? await getFilesFromDir('../packages/react-instantsearch/dist')
: []),
flavor === 'react' && 'react-instantsearch-core/package.json',
...(flavor === 'react'
? await getFilesFromDir('../packages/react-instantsearch-core/dist')
: []),
flavor === 'vue' && 'vue-instantsearch/package.json',
...(flavor === 'vue'
? await getFilesFromDir('../packages/vue-instantsearch/vue2/es')
: []),
]
.filter(Boolean)
.map(async (file) => [
`/node_modules/${file}`,
{
code: await readFile(`../packages/${file}`, 'utf-8'),

Check warning on line 63 in specs/src/getDependencyContent.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

specs/src/getDependencyContent.ts#L63

Detected that function argument `file` has entered the fs module.
hidden: true,
},
])
)
),
dependencies: Object.assign(

Check warning on line 69 in specs/src/getDependencyContent.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

specs/src/getDependencyContent.ts#L69

Depending on the context, user control data in `Object.assign` can cause web response to include data that it should not have or can lead to a mass assignment vulnerability.
{},
...(await Promise.all(
localDependencies.map(async (pkg) =>
Object.fromEntries(
Object.entries(
JSON.parse(
await readFile(`../packages/${pkg}/package.json`, 'utf-8')

Check warning on line 76 in specs/src/getDependencyContent.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

specs/src/getDependencyContent.ts#L76

Detected that function argument `pkg` has entered the fs module.
).dependencies || {}
).filter(([key]) => !localDependencies.includes(key))
)
)
))
),
};
}

export default async function getDependencyContent() {
return {
react: await getFiles('react'),
js: await getFiles('js'),
vue: await getFiles('vue'),
};
}
Loading

0 comments on commit 660cb51

Please sign in to comment.