docstra 1.7.3 → 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -129
- package/cli/index.js +25 -0
- package/dist/client/index.d.mts +2 -8
- package/dist/client/index.d.ts +2 -8
- package/dist/client/index.js +22 -41
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +22 -38
- package/dist/client/index.mjs.map +1 -1
- package/dist/server/docstra-loader.js +39 -1
- package/dist/server/docstra-loader.js.map +1 -1
- package/dist/server/docstra-loader.mjs +39 -1
- package/dist/server/docstra-loader.mjs.map +1 -1
- package/dist/server/index.d.mts +2 -3
- package/dist/server/index.d.ts +2 -3
- package/dist/server/index.js +84 -35
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +84 -35
- package/dist/server/index.mjs.map +1 -1
- package/dist/{types-BTnHEZBE.d.mts → types-CvrHe34X.d.mts} +1 -3
- package/dist/{types-BTnHEZBE.d.ts → types-CvrHe34X.d.ts} +1 -3
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -2,136 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
**The Modern Documentation Framework for Next.js**
|
|
4
4
|
|
|
5
|
-
Docstra is a powerful
|
|
5
|
+
Docstra is a powerful and easy-to-use documentation framework built for Next.js App Router. It provides a beautiful default theme, MDX support and flexible components to build your documentation site in minutes.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
See Our [Website](https://docstra.sudhucodes.com) for more documentation.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Install `docstra` and its peer dependencies:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install docstra
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### 2. Configuration
|
|
20
|
-
|
|
21
|
-
Create `docstra.config.ts` in your project root:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
import { DocstraConfig } from "docstra/config";
|
|
25
|
-
|
|
26
|
-
const config: DocstraConfig = {
|
|
27
|
-
title: "My Docs",
|
|
28
|
-
description: "Documentation for my project",
|
|
29
|
-
github: {
|
|
30
|
-
user: "myuser",
|
|
31
|
-
repo: "myrepo",
|
|
32
|
-
},
|
|
33
|
-
sidebar: {
|
|
34
|
-
// ... sidebar entries
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default config;
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 3. Source Setup
|
|
42
|
-
|
|
43
|
-
Create `src/lib/source.ts` (or `lib/source.ts`) to manage your content:
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
import { createSource } from "docstra/server";
|
|
47
|
-
import { docs } from "../.docstra"; // Generated at build time
|
|
48
|
-
|
|
49
|
-
export const source = createSource(docs);
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### 4. Component Mapping (Important!)
|
|
53
|
-
|
|
54
|
-
Create `mdx-components.tsx` in your project root. This is critical for getting the default components (like code blocks) working correctly.
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
import { defaultMdxComponents } from "docstra/server";
|
|
58
|
-
import { DocstraCodeBlock } from "docstra";
|
|
59
|
-
|
|
60
|
-
export function useMDXComponents() {
|
|
61
|
-
return {
|
|
62
|
-
...defaultMdxComponents(),
|
|
63
|
-
pre: DocstraCodeBlock, // Manually map to avoid server/client bundle conflicts
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 5. Create the Page
|
|
69
|
-
|
|
70
|
-
Create your catch-all route at `app/docs/[[...slug]]/page.tsx`:
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
import { source } from "@/lib/source";
|
|
74
|
-
import { notFound } from "next/navigation";
|
|
75
|
-
import { DocstraProvider, DocstraPage, DocstraBody, DocstraHeader } from "docstra";
|
|
76
|
-
import { useMDXComponents } from "@/mdx-components";
|
|
77
|
-
import config from "@/docstra.config";
|
|
78
|
-
|
|
79
|
-
export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
80
|
-
const { slug } = await params;
|
|
81
|
-
|
|
82
|
-
// 1. Get page data
|
|
83
|
-
const page = source.getPage(slug);
|
|
84
|
-
if (!page) return notFound();
|
|
85
|
-
|
|
86
|
-
// 2. Destructure info (safe JSON) and body (MDX Component)
|
|
87
|
-
const { info, body: MDX } = page;
|
|
88
|
-
|
|
89
|
-
// 3. Render
|
|
90
|
-
return (
|
|
91
|
-
<DocstraProvider docstraConfig={config} docs={source.files} pageData={info}>
|
|
92
|
-
<DocstraHeader />
|
|
93
|
-
<DocstraPage>
|
|
94
|
-
<DocstraBody>
|
|
95
|
-
<MDX components={useMDXComponents()} />
|
|
96
|
-
</DocstraBody>
|
|
97
|
-
</DocstraPage>
|
|
98
|
-
</DocstraProvider>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Generate static params for SSG
|
|
103
|
-
export function generateStaticParams() {
|
|
104
|
-
return source.generateStaticParams();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Generate metadata
|
|
108
|
-
export async function generateMetadata({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
109
|
-
const { slug } = await params;
|
|
110
|
-
const page = source.getPage(slug);
|
|
111
|
-
if (!page) return notFound();
|
|
112
|
-
return {
|
|
113
|
-
title: page.info.data.metadata.title,
|
|
114
|
-
description: page.info.data.metadata.description,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### 6. Build
|
|
120
|
-
|
|
121
|
-
Update your `next.config.ts` or `with-docstra` setup (if applicable) and run:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
npm run build
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Docstra will generate the `.docstra/index.ts` file manifest, and your docs will be live!
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 🛠 Features
|
|
132
|
-
|
|
133
|
-
- **MDX Support**: Write documentation in Markdown/MDX.
|
|
134
|
-
- **Auto Sidebar/TOC**: `DocstraPage` automatically handles layouts.
|
|
135
|
-
- **Search**: Built-in search (requires configuration).
|
|
136
|
-
- **Code Highlighting**: Powered by Prism with copy support.
|
|
137
|
-
- **Type Safe**: Full TypeScript support.
|
|
11
|
+
Thanks for using Docstra! Happy Documentation :)
|
package/cli/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const package = require("../package.json");
|
|
4
|
+
const command = process.argv[2];
|
|
5
|
+
|
|
6
|
+
if (command === "init") {
|
|
7
|
+
console.log(`
|
|
8
|
+
Docstra CLI ${package.version}
|
|
9
|
+
${package.description}
|
|
10
|
+
|
|
11
|
+
Thank you for trying the Docstra CLI.
|
|
12
|
+
We are actively working on the \`init\` command and it will be
|
|
13
|
+
available in an upcoming release.
|
|
14
|
+
|
|
15
|
+
Stay tuned!
|
|
16
|
+
`);
|
|
17
|
+
} else {
|
|
18
|
+
console.log(`
|
|
19
|
+
Usage:
|
|
20
|
+
docstra init
|
|
21
|
+
|
|
22
|
+
Description:
|
|
23
|
+
Initializes Docstra in your project (coming soon).
|
|
24
|
+
`);
|
|
25
|
+
}
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1 from 'react';
|
|
3
|
-
import { D as DocstraConfig, p as pageDataContent, a as DocstraContextType } from '../types-
|
|
3
|
+
import { D as DocstraConfig, p as pageDataContent, a as DocstraContextType } from '../types-CvrHe34X.mjs';
|
|
4
4
|
|
|
5
5
|
declare function DocstraProvider({ children, docstraConfig, docs, pageData: initialPageData, slug }: {
|
|
6
6
|
children: React$1.ReactNode;
|
|
@@ -13,8 +13,6 @@ declare function useDocstra(): DocstraContextType;
|
|
|
13
13
|
|
|
14
14
|
declare function DocstraHeader(): react_jsx_runtime.JSX.Element;
|
|
15
15
|
|
|
16
|
-
declare function DocstraSidebar(): react_jsx_runtime.JSX.Element;
|
|
17
|
-
|
|
18
16
|
interface DocstraPageProps {
|
|
19
17
|
children: React.ReactNode;
|
|
20
18
|
toc?: boolean;
|
|
@@ -27,10 +25,6 @@ interface Props {
|
|
|
27
25
|
}
|
|
28
26
|
declare function DocstraBody({ children }: Props): react_jsx_runtime.JSX.Element;
|
|
29
27
|
|
|
30
|
-
declare function DocstraTOC(): react_jsx_runtime.JSX.Element;
|
|
31
|
-
|
|
32
28
|
declare function DocstraCodeBlock(props: any): react_jsx_runtime.JSX.Element;
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export { DocstraBody, DocstraCodeBlock, DocstraHeader, DocstraPage, DocstraProvider, DocstraSearchBox, DocstraSidebar, DocstraTOC, useDocstra };
|
|
30
|
+
export { DocstraBody, DocstraCodeBlock, DocstraHeader, DocstraPage, DocstraProvider, useDocstra };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1 from 'react';
|
|
3
|
-
import { D as DocstraConfig, p as pageDataContent, a as DocstraContextType } from '../types-
|
|
3
|
+
import { D as DocstraConfig, p as pageDataContent, a as DocstraContextType } from '../types-CvrHe34X.js';
|
|
4
4
|
|
|
5
5
|
declare function DocstraProvider({ children, docstraConfig, docs, pageData: initialPageData, slug }: {
|
|
6
6
|
children: React$1.ReactNode;
|
|
@@ -13,8 +13,6 @@ declare function useDocstra(): DocstraContextType;
|
|
|
13
13
|
|
|
14
14
|
declare function DocstraHeader(): react_jsx_runtime.JSX.Element;
|
|
15
15
|
|
|
16
|
-
declare function DocstraSidebar(): react_jsx_runtime.JSX.Element;
|
|
17
|
-
|
|
18
16
|
interface DocstraPageProps {
|
|
19
17
|
children: React.ReactNode;
|
|
20
18
|
toc?: boolean;
|
|
@@ -27,10 +25,6 @@ interface Props {
|
|
|
27
25
|
}
|
|
28
26
|
declare function DocstraBody({ children }: Props): react_jsx_runtime.JSX.Element;
|
|
29
27
|
|
|
30
|
-
declare function DocstraTOC(): react_jsx_runtime.JSX.Element;
|
|
31
|
-
|
|
32
28
|
declare function DocstraCodeBlock(props: any): react_jsx_runtime.JSX.Element;
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export { DocstraBody, DocstraCodeBlock, DocstraHeader, DocstraPage, DocstraProvider, DocstraSearchBox, DocstraSidebar, DocstraTOC, useDocstra };
|
|
30
|
+
export { DocstraBody, DocstraCodeBlock, DocstraHeader, DocstraPage, DocstraProvider, useDocstra };
|
package/dist/client/index.js
CHANGED
|
@@ -36,9 +36,6 @@ __export(client_exports, {
|
|
|
36
36
|
DocstraHeader: () => DocstraHeader,
|
|
37
37
|
DocstraPage: () => DocstraPage,
|
|
38
38
|
DocstraProvider: () => DocstraProvider,
|
|
39
|
-
DocstraSearchBox: () => DocstraSearchBox,
|
|
40
|
-
DocstraSidebar: () => DocstraSidebar,
|
|
41
|
-
DocstraTOC: () => DocstraTOC,
|
|
42
39
|
useDocstra: () => useDocstra
|
|
43
40
|
});
|
|
44
41
|
module.exports = __toCommonJS(client_exports);
|
|
@@ -238,6 +235,7 @@ var import_link2 = __toESM(require("next/link"));
|
|
|
238
235
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
239
236
|
function DocstraHeader() {
|
|
240
237
|
const { openSidebar, setOpenSidebar, docstraConfig } = useDocstra();
|
|
238
|
+
const githubRepo = "https://github.com/" + docstraConfig?.editOnGithub?.owner + "/" + docstraConfig?.editOnGithub?.repo;
|
|
241
239
|
(0, import_react3.useEffect)(() => {
|
|
242
240
|
if (openSidebar) {
|
|
243
241
|
document.body.classList.add("max-md:overflow-hidden");
|
|
@@ -255,8 +253,8 @@ function DocstraHeader() {
|
|
|
255
253
|
}
|
|
256
254
|
) }),
|
|
257
255
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "hidden divide-x divide-gray-200 md:flex items-center", children: [
|
|
258
|
-
docstraConfig.navbar?.links?.map((link) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link2.default, { href: link.href, className: "px-6 hover:text-gray-
|
|
259
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link2.default, { href:
|
|
256
|
+
docstraConfig.navbar?.links?.map((link) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link2.default, { href: link.href, className: "px-6 hover:text-gray-600", children: link.name }, link.name)),
|
|
257
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link2.default, { href: githubRepo || "https://github.com/sudhucodes/docstra", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "size-6 mx-6", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3" }) }) })
|
|
260
258
|
] }),
|
|
261
259
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
262
260
|
"button",
|
|
@@ -366,8 +364,8 @@ function DocstraTOC() {
|
|
|
366
364
|
const lastScrollY = (0, import_react4.useRef)(0);
|
|
367
365
|
const observerRef = (0, import_react4.useRef)(null);
|
|
368
366
|
const pathname = (0, import_navigation3.usePathname)();
|
|
369
|
-
const
|
|
370
|
-
const
|
|
367
|
+
const baseUrlOfGithub = "https://github.com/" + docstraConfig?.editOnGithub?.owner + "/" + docstraConfig?.editOnGithub?.repo;
|
|
368
|
+
const githubLink = `${baseUrlOfGithub}/edit/main/${docstraConfig?.editOnGithub?.path}/${mdxFilePath}`;
|
|
371
369
|
(0, import_react4.useEffect)(() => {
|
|
372
370
|
const onScroll = () => {
|
|
373
371
|
const currentY = window.scrollY;
|
|
@@ -449,7 +447,7 @@ function DocstraTOC() {
|
|
|
449
447
|
docstraConfig.editOnGithub && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
450
448
|
"a",
|
|
451
449
|
{
|
|
452
|
-
href:
|
|
450
|
+
href: githubLink,
|
|
453
451
|
rel: "noopener noreferrer",
|
|
454
452
|
className: "flex items-center gap-2 text-gray-400 hover:text-gray-700 transition",
|
|
455
453
|
children: [
|
|
@@ -758,7 +756,7 @@ function DocstraPagination() {
|
|
|
758
756
|
const currentIndex = flatLinks.findIndex((item) => item.href === pathname);
|
|
759
757
|
const prev = currentIndex > 0 ? flatLinks[currentIndex - 1] : null;
|
|
760
758
|
const next = currentIndex < flatLinks.length - 1 ? flatLinks[currentIndex + 1] : null;
|
|
761
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col
|
|
759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col lg:flex-row gap-2 justify-between py-10 mt-10", children: [
|
|
762
760
|
prev ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
763
761
|
import_link5.default,
|
|
764
762
|
{
|
|
@@ -804,43 +802,29 @@ function DocstraBody({ children }) {
|
|
|
804
802
|
}
|
|
805
803
|
|
|
806
804
|
// src/client/components/code-block.tsx
|
|
807
|
-
var import_react7 = require("react");
|
|
808
|
-
var import_prism_react_renderer = require("prism-react-renderer");
|
|
809
805
|
var import_lucide_react10 = require("lucide-react");
|
|
810
|
-
var
|
|
806
|
+
var import_react7 = require("react");
|
|
811
807
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
812
808
|
function DocstraCodeBlock(props) {
|
|
813
|
-
const {
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const
|
|
819
|
-
const
|
|
809
|
+
const { filename, children, className, rawText } = props;
|
|
810
|
+
const isInline = !className?.includes("language-");
|
|
811
|
+
if (isInline) {
|
|
812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { className: "px-1 py-0.5 rounded border border-gray-200 text-gray-800 text-sm", children: typeof children === "string" ? children : children.props.children });
|
|
813
|
+
}
|
|
814
|
+
const [isCopied, setIsCopied] = (0, import_react7.useState)(false);
|
|
815
|
+
const match = className.match(/language-([\w-]+)/);
|
|
816
|
+
const language = match?.[1];
|
|
820
817
|
const handleCopy = () => {
|
|
821
|
-
navigator.clipboard.writeText(
|
|
822
|
-
|
|
823
|
-
|
|
818
|
+
navigator.clipboard.writeText(rawText);
|
|
819
|
+
setIsCopied(true);
|
|
820
|
+
setTimeout(() => setIsCopied(false), 2e3);
|
|
824
821
|
};
|
|
825
|
-
(0, import_react7.useEffect)(() => {
|
|
826
|
-
if (copied) {
|
|
827
|
-
const timeout = setTimeout(() => setCopied(false), 2e3);
|
|
828
|
-
return () => clearTimeout(timeout);
|
|
829
|
-
}
|
|
830
|
-
}, [copied]);
|
|
831
822
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "max-w-2xl overflow-hidden rounded-lg text-sm text-gray-800 border border-gray-200/80 mt-4", children: [
|
|
832
823
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center bg-gray-50 justify-between border-b border-gray-200/80", children: [
|
|
833
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs text-gray-400 p-4", children:
|
|
834
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
835
|
-
"button",
|
|
836
|
-
{
|
|
837
|
-
onClick: handleCopy,
|
|
838
|
-
className: "rounded cursor-pointer aspect-square p-2 m-2 text-xs hover:bg-gray-200 transition",
|
|
839
|
-
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react10.CheckIcon, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react10.CopyIcon, { className: "size-4" })
|
|
840
|
-
}
|
|
841
|
-
)
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs text-gray-400 p-4", children: filename || language }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: handleCopy, className: "rounded cursor-pointer aspect-square p-2 m-2 text-xs hover:bg-gray-200 transition", children: isCopied ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react10.CheckIcon, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react10.CopyIcon, { className: "size-4" }) })
|
|
842
826
|
] }),
|
|
843
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { className: "p-4 font-mono whitespace-pre scrollbar-x overflow-x-auto", children })
|
|
844
828
|
] });
|
|
845
829
|
}
|
|
846
830
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -850,9 +834,6 @@ function DocstraCodeBlock(props) {
|
|
|
850
834
|
DocstraHeader,
|
|
851
835
|
DocstraPage,
|
|
852
836
|
DocstraProvider,
|
|
853
|
-
DocstraSearchBox,
|
|
854
|
-
DocstraSidebar,
|
|
855
|
-
DocstraTOC,
|
|
856
837
|
useDocstra
|
|
857
838
|
});
|
|
858
839
|
//# sourceMappingURL=index.js.map
|