some small fixes & refactoring

This commit is contained in:
hsjobeki 2023-01-08 16:54:23 +01:00
parent 1a9dddb549
commit 4f268a851c
13 changed files with 142 additions and 2825 deletions

View File

@ -29,7 +29,7 @@ const getKey = (item: DocItem) => `${item.category}/${item.name}`;
export default function FunctionItem(props: FunctionItemProps) {
const { name, docItem, selected, handleClose } = props;
const { fn_type, category, description } = docItem;
const { fn_type, category, description, id } = docItem;
const { enqueueSnackbar } = useSnackbar();
const [favorites, setfavorites] = useLocalStorage<string[]>(
"personal-favorite",
@ -104,12 +104,7 @@ export default function FunctionItem(props: FunctionItemProps) {
<Box sx={{ float: "right", position: "absolute", right: 4 }}>
{isFavorit && <StarIcon />}
</Box>
<ListItemText
primary={`${
category.includes(".nix") ? "lib" : "builtins"
}.${name}`}
secondary={category}
/>
<ListItemText primary={`${id}`} secondary={category} />
<ListItemText secondary={descriptionPreview} />
<Typography
sx={{

View File

@ -23,6 +23,7 @@ import styles from "./preview.module.css";
import rehypeHighlight from "rehype-highlight";
import nix from "highlight.js/lib/languages/nix";
import Link from "next/link";
import { idText } from "typescript";
// import "highlight.js/styles/github-dark.css";
// import "highlight.js/styles/github.css";
@ -35,7 +36,7 @@ interface PreviewProps {
export const Preview = (props: PreviewProps) => {
const { docItem, handleClose, closeComponent = undefined } = props;
const { name, description, category, example, fn_type } = docItem;
const { name, description, category, example, fn_type, id } = docItem;
const theme = useTheme();
useEffect(() => {
@ -72,7 +73,9 @@ export const Preview = (props: PreviewProps) => {
<Typography
variant="h4"
sx={{ wordWrap: "normal", lineBreak: "anywhere" }}
>{`${prefix}.${name}`}</Typography>
>
{`${id}`}
</Typography>
{closeComponent || (
<Tooltip title="close details">
<IconButton
@ -89,13 +92,18 @@ export const Preview = (props: PreviewProps) => {
</Tooltip>
)}
</Box>
{
<Box sx={{ my: 1 }}>
<Typography variant="subtitle1">{`short form: lib.${name}`}</Typography>
</Box>
}
<List sx={{ width: "100%" }} disablePadding>
<ListItem sx={{ flexDirection: { xs: "column", sm: "row" }, px: 0 }}>
<ListItemIcon>
<Tooltip title={"read docs"}>
<MuiLink sx={{ m: "auto", color: "primary.light" }}>
<Link
href={prefix != "builtins" ? libDocsRef : builtinsDocsRef}
href={!id.includes("builtins") ? libDocsRef : builtinsDocsRef}
>
<LocalLibraryIcon sx={{ m: "auto" }} />
</Link>
@ -120,7 +128,7 @@ export const Preview = (props: PreviewProps) => {
component: "div",
}}
primary={
prefix !== "builtins" ? (
!id.includes("builtins") ? (
<Tooltip title={"browse source code"}>
<MuiLink>
<Link
@ -147,7 +155,7 @@ export const Preview = (props: PreviewProps) => {
}}
maxWidth="md"
>
{typeof description === "object"
{Array.isArray(description)
? description.map((d, idx) => (
<ReactMarkdown
key={idx}

View File

@ -263,11 +263,11 @@
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1670665290,
"narHash": "sha256-VkuPWVA+DF1AYx4hdw7JUxrJOdHP/cLhyL+t+xH9UsU=",
"lastModified": 1673188789,
"narHash": "sha256-Oj6blvGWqut923D3N+xb2iO/j6fl0ZJMbxAQ8FR3xv4=",
"owner": "hsjobeki",
"repo": "nixdoc",
"rev": "f9377fac1265f1e02329343aaff573dff68f9402",
"rev": "c8fd16629e40956b9839f7aa4df0d70dbb351f3f",
"type": "github"
},
"original": {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

143
package-lock.json generated
View File

@ -16,7 +16,6 @@
"@types/node": "18.11.9",
"@types/react": "^18.0.25",
"@types/react-dom": "18.0.8",
"beautiful-react-hooks": "^3.11.2",
"eslint": "8.27.0",
"eslint-config-next": "13.0.2",
"highlight.js": "^11.7.0",
@ -1264,15 +1263,6 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@remix-run/router": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.5.tgz",
"integrity": "sha512-my0Mycd+jruq/1lQuO5LBB6WTlL/e8DTCYWp44DfMTDcXz8DcTlgF0ISaLsGewt+ctHN+yA8xMq3q/N7uWJPug==",
"peer": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@rushstack/eslint-patch": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
@ -1668,21 +1658,6 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/beautiful-react-hooks": {
"version": "3.11.2",
"resolved": "https://registry.npmjs.org/beautiful-react-hooks/-/beautiful-react-hooks-3.11.2.tgz",
"integrity": "sha512-g3pIIZhYfvk1btovwojdMOZ/UjqHi5jqv0TPG0AbQ9B8N8qmGgfgMHPPShelwWevSy7b4VVTmWr1VUJ+QnDR+A==",
"dependencies": {
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1"
},
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0",
"react-router-dom": ">=5.0.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -3281,21 +3256,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -4361,38 +4326,6 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-router": {
"version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.5.tgz",
"integrity": "sha512-1RQJ8bM70YEumHIlNUYc6mFfUDoWa5EgPDenK/fq0bxD8DYpQUi/S6Zoft+9DBrh2xmtg92N5HMAJgGWDhKJ5Q==",
"peer": true,
"dependencies": {
"@remix-run/router": "1.0.5"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.5.tgz",
"integrity": "sha512-a7HsgikBR0wNfroBHcZUCd9+mLRqZS8R5U1Z1mzLWxFXEkUT3vR1XXmSIVoVpxVX8Bar0nQYYYc9Yipq8dWwAA==",
"peer": true,
"dependencies": {
"@remix-run/router": "1.0.5",
"react-router": "6.4.5"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@ -4554,21 +4487,6 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/rxjs": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
"integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/rxjs/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
"peer": true
},
"node_modules/sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
@ -6004,12 +5922,6 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
},
"@remix-run/router": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.5.tgz",
"integrity": "sha512-my0Mycd+jruq/1lQuO5LBB6WTlL/e8DTCYWp44DfMTDcXz8DcTlgF0ISaLsGewt+ctHN+yA8xMq3q/N7uWJPug==",
"peer": true
},
"@rushstack/eslint-patch": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
@ -6303,15 +6215,6 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"beautiful-react-hooks": {
"version": "3.11.2",
"resolved": "https://registry.npmjs.org/beautiful-react-hooks/-/beautiful-react-hooks-3.11.2.tgz",
"integrity": "sha512-g3pIIZhYfvk1btovwojdMOZ/UjqHi5jqv0TPG0AbQ9B8N8qmGgfgMHPPShelwWevSy7b4VVTmWr1VUJ+QnDR+A==",
"requires": {
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -7451,21 +7354,11 @@
"p-locate": "^5.0.0"
}
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -8104,25 +7997,6 @@
}
}
},
"react-router": {
"version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.5.tgz",
"integrity": "sha512-1RQJ8bM70YEumHIlNUYc6mFfUDoWa5EgPDenK/fq0bxD8DYpQUi/S6Zoft+9DBrh2xmtg92N5HMAJgGWDhKJ5Q==",
"peer": true,
"requires": {
"@remix-run/router": "1.0.5"
}
},
"react-router-dom": {
"version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.5.tgz",
"integrity": "sha512-a7HsgikBR0wNfroBHcZUCd9+mLRqZS8R5U1Z1mzLWxFXEkUT3vR1XXmSIVoVpxVX8Bar0nQYYYc9Yipq8dWwAA==",
"peer": true,
"requires": {
"@remix-run/router": "1.0.5",
"react-router": "6.4.5"
}
},
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@ -8223,23 +8097,6 @@
"queue-microtask": "^1.2.2"
}
},
"rxjs": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
"integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
"peer": true,
"requires": {
"tslib": "^2.1.0"
},
"dependencies": {
"tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
"peer": true
}
}
},
"sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",

View File

@ -4,96 +4,7 @@ import { Box } from "@mui/material";
import FunctionItem from "../components/functionItem/functionItem";
import { NixType, nixTypes, MetaData, DocItem } from "../types/nix";
import { data } from "../models/data";
import { useRouter } from "next/router";
function pipe<T>(...fns: ((arr: T) => T)[]) {
return (x: T) => fns.reduce((v, f) => f(v), x);
}
const search =
(term: string) =>
(data: MetaData): MetaData => {
return data.filter((item) => {
return Object.values(item).some((value) => {
if (value) {
if (typeof value === "object" && value.length > 0) {
return value.join("\n").toLowerCase().includes(term.toLowerCase());
}
const valueAsString = value.toString();
return valueAsString.toLowerCase().includes(term.toLowerCase());
}
return false;
});
});
};
function getTypes(
fnName: string,
fnType: string | undefined
): { args: NixType[]; types: NixType[] } {
if (fnType) {
let cleanType = fnType.replace(/ /g, "").replace(`${fnName}::`, "");
const tokens = cleanType
.split(/(::|->|\[|\]|\{|\}|\(|\))/gm)
.filter(Boolean);
const lastArrowIdx = tokens.lastIndexOf("->");
if (lastArrowIdx) {
// Function has at least on return value
const interpretToken = (token: string) => {
if (token === "(" || token === ")") {
return "function" as NixType;
} else if (token === "[" || token === "]") {
return "list" as NixType;
} else if (token === "{" || token === "}") {
return "attrset" as NixType;
} else if (nixTypes.includes(token.toLowerCase() as NixType)) {
return token.toLowerCase() as NixType;
} else if (
token.length === 1 &&
["a", "b", "c", "d", "e"].includes(token)
) {
return "any" as NixType;
} else {
return undefined;
}
};
const returnValueTokens = tokens.slice(lastArrowIdx + 1);
const types = returnValueTokens
.map(interpretToken)
.filter(Boolean)
.filter((e, i, s) => s.indexOf(e) === i);
const args = tokens
.slice(0, lastArrowIdx)
.map(interpretToken)
.filter(Boolean)
.filter((e, i, s) => s.indexOf(e) === i);
return { args, types } as { args: NixType[]; types: NixType[] };
}
}
return { args: ["any"], types: ["any"] };
}
const filterByType =
({ to, from }: { to: NixType; from: NixType }) =>
(data: MetaData): MetaData => {
if (to === "any" && from === "any") {
return data;
} else {
return data.filter(
// TODO: Implement proper type matching
({ name, fn_type }) => {
if (fn_type) {
const parsedType = getTypes(name, fn_type);
return (
parsedType.args.includes(from) && parsedType.types.includes(to)
);
} else {
return to === "any" && from === "any";
}
}
);
}
};
import { byQuery, byType, pipe } from "../queries";
export default function FunctionsPage() {
const [selected, setSelected] = useState<string | null>(null);
@ -102,7 +13,6 @@ export default function FunctionsPage() {
to: "any",
from: "any",
});
const router = useRouter();
const handleSelect = (key: string) => {
console.log({ key });
@ -116,7 +26,7 @@ export default function FunctionsPage() {
};
const filteredData = useMemo(
() => pipe(filterByType(filter), search(term))(data),
() => pipe(byType(filter), byQuery(term))(data),
[filter, term]
);

39
queries/byQuery.ts Normal file
View File

@ -0,0 +1,39 @@
import { DocItem, MetaData } from "../types/nix";
export const byQuery =
(rawTerm: string) =>
(data: MetaData): MetaData => {
const term = rawTerm.toLowerCase();
return data.reduce((results: (DocItem & {relevance: number})[], docItem: DocItem)=>{
const matchesOn = Object.keys(docItem).filter(key=>{
const rawValue = docItem[key as keyof DocItem];
if(rawValue === null || rawValue === undefined){
return false;
}
const value = Array.isArray(rawValue) ? rawValue.join("\n").toLowerCase() : rawValue.toLowerCase()
if(value.includes(term)){
return true;
}
return false;
})
if(matchesOn?.length){
results.push({...docItem, relevance: getRelevance(matchesOn as (keyof DocItem)[]) })
}
return results;
},[]).sort((a,b)=> b.relevance - a.relevance)
};
const getRelevance = (matchesOn: (keyof DocItem)[]): number => {
const relevanceMap = {
id: 10,
name: 5,
fn_type: 4,
category: 3,
example: 2,
description: 1,
}
return matchesOn.reduce((count,key)=>{
return count + relevanceMap[key]
},0);
}

24
queries/byType.ts Normal file
View File

@ -0,0 +1,24 @@
import { MetaData, NixType } from "../types/nix";
import { getTypes } from "./lib";
export const byType =
({ to, from }: { to: NixType; from: NixType }) =>
(data: MetaData): MetaData => {
if (to === "any" && from === "any") {
return data;
} else {
return data.filter(
// TODO: Implement proper type matching
({ name, fn_type }) => {
if (fn_type) {
const parsedType = getTypes(name, fn_type);
return (
parsedType.args.includes(from) && parsedType.types.includes(to)
);
} else {
return to === "any" && from === "any";
}
}
);
}
};

3
queries/index.ts Normal file
View File

@ -0,0 +1,3 @@
export {byQuery} from "./byQuery";
export {byType} from "./byType";
export {pipe} from "./lib"

52
queries/lib.ts Normal file
View File

@ -0,0 +1,52 @@
import { NixType, nixTypes } from "../types/nix";
export function pipe<T>(...fns: ((arr: T) => T)[]) {
return (x: T) => fns.reduce((v, f) => f(v), x);
}
export function getTypes(
fnName: string,
fnType: string | undefined
): { args: NixType[]; types: NixType[] } {
if (fnType) {
let cleanType = fnType.replace(/ /g, "").replace(`${fnName}::`, "");
const tokens = cleanType
.split(/(::|->|\[|\]|\{|\}|\(|\))/gm)
.filter(Boolean);
const lastArrowIdx = tokens.lastIndexOf("->");
if (lastArrowIdx) {
// Function has at least on return value
const interpretToken = (token: string) => {
if (token === "(" || token === ")") {
return "function" as NixType;
} else if (token === "[" || token === "]") {
return "list" as NixType;
} else if (token === "{" || token === "}") {
return "attrset" as NixType;
} else if (nixTypes.includes(token.toLowerCase() as NixType)) {
return token.toLowerCase() as NixType;
} else if (
token.length === 1 &&
["a", "b", "c", "d", "e"].includes(token)
) {
return "any" as NixType;
} else {
return undefined;
}
};
const returnValueTokens = tokens.slice(lastArrowIdx + 1);
const types = returnValueTokens
.map(interpretToken)
.filter(Boolean)
.filter((e, i, s) => s.indexOf(e) === i);
const args = tokens
.slice(0, lastArrowIdx)
.map(interpretToken)
.filter(Boolean)
.filter((e, i, s) => s.indexOf(e) === i);
return { args, types } as { args: NixType[]; types: NixType[] };
}
}
return { args: ["any"], types: ["any"] };
}

View File

@ -5,6 +5,7 @@ const info = Object.entries(builtins).map(([name, meta]) => {
const fn_type = types[name]?.fn_type || null;
const { args, arity, doc } = meta;
return {
id: `builtins.${name}`,
category: "builtins",
fn_type,
name,

View File

@ -9,6 +9,7 @@ export const nixTypes: NixType[] = [
];
export type DocItem = {
id: string;
category: string;
name: string;
fn_type?: string;