aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/.vitepress/components/api-docs/format.ts14
-rw-r--r--docs/.vitepress/components/api-docs/method.ts1
-rw-r--r--docs/.vitepress/components/api-docs/method.vue120
-rw-r--r--docs/.vitepress/components/api-docs/refresh-button.vue69
-rw-r--r--docs/.vitepress/components/api-docs/refresh.svg1
-rw-r--r--docs/.vitepress/config.ts1
-rw-r--r--docs/api/.gitignore10
7 files changed, 204 insertions, 12 deletions
diff --git a/docs/.vitepress/components/api-docs/format.ts b/docs/.vitepress/components/api-docs/format.ts
new file mode 100644
index 00000000..34de1e0c
--- /dev/null
+++ b/docs/.vitepress/components/api-docs/format.ts
@@ -0,0 +1,14 @@
+export function formatResult(result: unknown): string {
+ return result === undefined
+ ? 'undefined'
+ : typeof result === 'bigint'
+ ? `${result}n`
+ : JSON.stringify(result, undefined, 2)
+ .replaceAll('\\r', '')
+ .replaceAll('<', '&lt;')
+ .replaceAll(
+ /(^ *|: )"([^'\n]*?)"(?=,?$|: )/gm,
+ (_, p1, p2) => `${p1}'${p2.replace(/\\"/g, '"')}'`
+ )
+ .replaceAll(/\n */g, ' ');
+}
diff --git a/docs/.vitepress/components/api-docs/method.ts b/docs/.vitepress/components/api-docs/method.ts
index 4da480b8..91f99d4e 100644
--- a/docs/.vitepress/components/api-docs/method.ts
+++ b/docs/.vitepress/components/api-docs/method.ts
@@ -8,6 +8,7 @@ export interface ApiDocsMethod {
readonly throws: string | undefined; // HTML
readonly signature: string; // HTML
readonly examples: string; // HTML
+ readonly refresh: (() => Promise<unknown[]>) | undefined;
readonly seeAlsos: string[];
readonly sourcePath: string; // URL-Suffix
}
diff --git a/docs/.vitepress/components/api-docs/method.vue b/docs/.vitepress/components/api-docs/method.vue
index 83a4100c..37b44748 100644
--- a/docs/.vitepress/components/api-docs/method.vue
+++ b/docs/.vitepress/components/api-docs/method.vue
@@ -1,8 +1,11 @@
<script setup lang="ts">
+import { computed, ref, useTemplateRef } from 'vue';
import { sourceBaseUrl } from '../../../api/source-base-url';
import { slugify } from '../../shared/utils/slugify';
+import { formatResult } from './format';
import type { ApiDocsMethod } from './method';
import MethodParameters from './method-parameters.vue';
+import RefreshButton from './refresh-button.vue';
const { method } = defineProps<{ method: ApiDocsMethod }>();
const {
@@ -14,10 +17,113 @@ const {
throws,
signature,
examples,
+ refresh,
seeAlsos,
sourcePath,
} = method;
+const code = useTemplateRef('code');
+const codeBlock = computed(() => code.value?.querySelector('div pre code'));
+const codeLines = ref<Element[]>();
+
+function initRefresh(): Element[] {
+ if (codeBlock.value == null) {
+ return [];
+ }
+ const domLines = codeBlock.value.querySelectorAll('.line');
+ let lineIndex = 0;
+ const result: Element[] = [];
+ while (lineIndex < domLines.length) {
+ // Skip empty and preparatory lines (no '^faker.' invocation)
+ if (
+ domLines[lineIndex]?.children.length === 0 ||
+ !/^\w*faker\w*\./i.test(domLines[lineIndex]?.textContent ?? '')
+ ) {
+ lineIndex++;
+ continue;
+ }
+
+ // Skip to end of the invocation (if multiline)
+ while (
+ domLines[lineIndex] != null &&
+ !/^([^ ].*)?\)(\.\w+)?;? ?(\/\/|$)/.test(
+ domLines[lineIndex]?.textContent ?? ''
+ )
+ ) {
+ lineIndex++;
+ }
+
+ if (lineIndex >= domLines.length) {
+ break;
+ }
+
+ const domLine = domLines[lineIndex];
+ result.push(domLine);
+ lineIndex++;
+
+ // Purge old results
+ if (domLine.lastElementChild?.textContent?.startsWith('//')) {
+ // Inline comments
+ domLine.lastElementChild.remove();
+ } else {
+ // Multiline comments
+ while (domLines[lineIndex]?.children[0]?.textContent?.startsWith('//')) {
+ domLines[lineIndex].previousSibling?.remove(); // newline
+ domLines[lineIndex].remove(); // comment
+ lineIndex++;
+ }
+ }
+
+ // Add space between invocation and comment (if missing)
+ const lastElementChild = domLine.lastElementChild;
+ if (
+ lastElementChild != null &&
+ !lastElementChild.textContent?.endsWith(' ')
+ ) {
+ lastElementChild.textContent += ' ';
+ }
+ }
+
+ return result;
+}
+
+async function onRefresh(): Promise<void> {
+ if (refresh != null && codeBlock.value != null) {
+ codeLines.value ??= initRefresh();
+
+ const results = await refresh();
+
+ // Remove old comments
+ codeBlock.value
+ .querySelectorAll('.comment-delete-marker')
+ .forEach((el) => el.remove());
+
+ // Insert new comments
+ for (let i = 0; i < results.length; i++) {
+ const result = results[i];
+ const domLine = codeLines.value[i];
+ const prettyResult = formatResult(result);
+ const resultLines = prettyResult.split('\\n');
+
+ if (resultLines.length === 1) {
+ domLine.insertAdjacentHTML('beforeend', newCommentSpan(resultLines[0]));
+ } else {
+ for (const line of resultLines.reverse()) {
+ domLine.insertAdjacentHTML('afterend', newCommentLine(line));
+ }
+ }
+ }
+ }
+}
+
+function newCommentLine(content: string): string {
+ return `<span class="line comment-delete-marker">\n${newCommentSpan(content)}</span>`;
+}
+
+function newCommentSpan(content: string): string {
+ return `<span class="comment-delete-marker" style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// ${content}</span>`;
+}
+
function seeAlsoToUrl(see: string): string {
const [, module, methodName] = see.replace(/\(.*/, '').split('\.');
@@ -51,8 +157,14 @@ function seeAlsoToUrl(see: string): string {
<div v-html="signature" />
- <h3>Examples</h3>
- <div v-html="examples" />
+ <h3 class="inline">Examples</h3>
+ <RefreshButton
+ class="refresh"
+ v-if="refresh != null"
+ style="margin-left: 0.5em"
+ :refresh="onRefresh"
+ />
+ <div ref="code" v-html="examples" />
<div v-if="seeAlsos.length > 0">
<h3>See Also</h3>
@@ -107,4 +219,8 @@ svg.source-link-icon {
display: inline;
margin-left: 0.3em;
}
+
+h3.inline {
+ display: inline-block;
+}
</style>
diff --git a/docs/.vitepress/components/api-docs/refresh-button.vue b/docs/.vitepress/components/api-docs/refresh-button.vue
new file mode 100644
index 00000000..c2210eab
--- /dev/null
+++ b/docs/.vitepress/components/api-docs/refresh-button.vue
@@ -0,0 +1,69 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+// This should probably use emit instead, but emit cannot be awaited
+const { refresh } = defineProps<{ refresh: () => Promise<void> }>();
+
+const spinning = ref(false);
+
+async function onRefresh() {
+ spinning.value = true;
+ await Promise.all([refresh(), delay(100)]);
+ spinning.value = false;
+}
+
+// Extra delay to make the spinning effect more visible
+// Some examples barely/don't change, so the spinning is the only visible effect
+function delay(ms: number) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+</script>
+
+<template>
+ <button
+ class="refresh"
+ title="Refresh Examples"
+ :disabled="spinning"
+ @click="onRefresh"
+ >
+ <div :class="{ spinning: spinning }" />
+ </button>
+</template>
+
+<style scoped>
+button.refresh {
+ border: 1px solid var(--vp-code-copy-code-border-color);
+ border-radius: 4px;
+ width: 40px;
+ height: 40px;
+ font-size: 25px;
+ vertical-align: middle;
+}
+
+button.refresh div {
+ background-image: url('refresh.svg');
+ background-position: 50%;
+ background-size: 20px;
+ background-repeat: no-repeat;
+ width: 100%;
+ height: 100%;
+}
+
+button.refresh:hover {
+ background-color: var(--vp-code-copy-code-bg);
+ opacity: 1;
+}
+
+div.spinning {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+</style>
diff --git a/docs/.vitepress/components/api-docs/refresh.svg b/docs/.vitepress/components/api-docs/refresh.svg
new file mode 100644
index 00000000..8320a2b2
--- /dev/null
+++ b/docs/.vitepress/components/api-docs/refresh.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M20 12a8 8 0 0 1-6.44 7.85 8 8 0 0 1-8.95-4.79 8 8 0 0 1 2.94-9.71 8 8 0 0 1 10.1 1" style="fill:none;stroke:rgba(128,128,128,1);stroke-width:2"/><path d="m19.65 4.25-4.04 4.03 5.5 1.47z" style="fill:rgba(128,128,128,1)"/></svg> \ No newline at end of file
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 746803ad..4fcc469e 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -133,6 +133,7 @@ async function enableFaker() {
e.g. 'faker.food.description()' or 'fakerZH_CN.person.firstName()'
For other languages please refer to https://fakerjs.dev/guide/localization.html#available-locales
For a full list of all methods please refer to https://fakerjs.dev/api/\`, logStyle);
+ enableFaker = () => imported; // Init only once
return imported;
}
`,
diff --git a/docs/api/.gitignore b/docs/api/.gitignore
deleted file mode 100644
index 47b11a83..00000000
--- a/docs/api/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-# Markdown
-*.md
-!index.md
-
-# TypeScript
-*.ts
-!api-types.ts
-
-# JSON
-*.json