mirror of
https://github.com/tauri-apps/tauri-search.git
synced 2026-02-04 02:41:20 +01:00
chore: improvements to interactive playground
This commit is contained in:
21
README.md
21
README.md
@@ -4,12 +4,27 @@
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
# install npm dependencies (in all repos)
|
||||
# 1. installs deps for both CLI and Docs
|
||||
# 2. starts Docs server (in dev mode with HMR), opens in browser
|
||||
# 3. starts Meilisearch server in Docker
|
||||
pnpm run start
|
||||
```
|
||||
|
||||
If you've already installed all the deps and want more granular control you can try any of the following script targets:
|
||||
|
||||
```bash
|
||||
# start Docker services (you must have Docker installed)
|
||||
docker compose up
|
||||
# bring up documentation / playground site
|
||||
pnpm run dev
|
||||
# or
|
||||
pnpm run up
|
||||
|
||||
# stop Docker services
|
||||
docker compose down
|
||||
# or
|
||||
pnpm run down
|
||||
|
||||
# turn on watcher mode for both CLI and Docs
|
||||
pnpm run watch
|
||||
```
|
||||
|
||||
A browser window should now have opened up pointing to `http://localhost:3333`. See you over there.
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
services:
|
||||
scraper:
|
||||
image: getmeili/docs-scraper:latest
|
||||
container_name: scraper
|
||||
command: pipenv run ./docs_scraper config.json -d
|
||||
depends_on:
|
||||
- search
|
||||
environment:
|
||||
- MEILISEARCH_HOST_URL=localhost:7700
|
||||
- MEILISEARCH_API_KEY=""
|
||||
volumes:
|
||||
- ./scraper:/data.ms
|
||||
# We are not using the scraper for anything currently but keeping it here
|
||||
# for now in case we decide to
|
||||
|
||||
# scraper:
|
||||
# image: getmeili/docs-scraper:latest
|
||||
# container_name: scraper
|
||||
# command: pipenv run ./docs_scraper config.json -d
|
||||
# depends_on:
|
||||
# - search
|
||||
# environment:
|
||||
# - MEILISEARCH_HOST_URL=localhost:7700
|
||||
# - MEILISEARCH_API_KEY=""
|
||||
# volumes:
|
||||
# - ./scraper:/data.ms
|
||||
|
||||
search:
|
||||
image: getmeili/meilisearch:latest
|
||||
|
||||
@@ -1,3 +1,83 @@
|
||||
{
|
||||
"extends": "@antfu"
|
||||
"extends": ["plugin:vue/vue3-recommended", "prettier"],
|
||||
"plugins": ["cypress", "@typescript-eslint"],
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"settings": {
|
||||
// https://github.com/meteorlxy/eslint-plugin-prettier-vue#eslint-config
|
||||
"SFCBlocks": {}
|
||||
},
|
||||
"rules": {
|
||||
// "prettier-vue/prettier": [
|
||||
// "error",
|
||||
// {
|
||||
// "printWidth": 120,
|
||||
// "singleQuote": false,
|
||||
// "semi": true
|
||||
// }
|
||||
// ],
|
||||
"vue/no-lone-template": "off",
|
||||
"vue/no-multiple-template-root": "off",
|
||||
"vue/no-vmodel-argument": "off",
|
||||
/**
|
||||
* turn this back on once the false warning for using string literals goes away;
|
||||
* for now, so long as we express an "emits" clause then TS should keep us honest
|
||||
* here rather than relying on lint rules.
|
||||
*/
|
||||
"vue/require-explicit-emits": "off",
|
||||
"no-trailing-spaces": ["warn", { "skipBlankLines": true, "ignoreComments": true }],
|
||||
"no-console": "warn",
|
||||
"prefer-const": "error",
|
||||
|
||||
"semi": "off",
|
||||
"quotes": ["warn", "double", { "avoidEscape": true, "allowTemplateLiterals": true }],
|
||||
"no-unused-vars": "off",
|
||||
"curly": ["warn", "multi-line"],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
||||
// our use of `-spec` files for testing prevents us using this
|
||||
"unicorn/filename-case": "off",
|
||||
// reduce has been getting a bad rap lately; its true that often
|
||||
// a filter or map would be clearer and equally as effective but
|
||||
// there are still some legit cases to use reduce
|
||||
"unicorn/no-array-reduce": "off",
|
||||
"unicorn/prevent-abbreviations": "off",
|
||||
"unicorn/no-null": "off",
|
||||
"no-nested-ternary": "off",
|
||||
// doesn't play well with prettier
|
||||
"unicorn/no-nested-ternary": "off",
|
||||
// this is kind of nice sometimes
|
||||
"unicorn/no-array-callback-reference": "off",
|
||||
|
||||
// we need exceptions to be only "warn" because
|
||||
// there are valid use cases for generic variables being
|
||||
// used before being defined
|
||||
"no-use-before-define": ["warn"],
|
||||
"@typescript-eslint/semi": ["error"],
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/member-delimiter-style": [
|
||||
"error",
|
||||
{
|
||||
"multiline": {
|
||||
"delimiter": "semi",
|
||||
"requireLast": true
|
||||
},
|
||||
"singleline": {
|
||||
"delimiter": "semi",
|
||||
"requireLast": false
|
||||
}
|
||||
}
|
||||
],
|
||||
// "cases" allows for graceful use of that variable
|
||||
// name in Typescript test cases
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"varsIgnorePattern": "cases|^_",
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "pnpm install",
|
||||
"build": "vite-ssg build",
|
||||
"dev": "vite --port 3333 --open",
|
||||
"lint": "eslint \"**/*.{vue,ts,js}\"",
|
||||
@@ -18,6 +19,7 @@
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.9",
|
||||
"prism-theme-vars": "^0.2.2",
|
||||
"tauri-search": "link:../",
|
||||
"ts-morph": "^13.0.3",
|
||||
"vue": "^3.2.28",
|
||||
"vue-demi": "^0.12.1",
|
||||
@@ -26,14 +28,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.16.0",
|
||||
"@iconify-json/ant-design": "^1.0.2",
|
||||
"@iconify-json/bx": "^1.0.3",
|
||||
"@iconify-json/carbon": "^1.0.14",
|
||||
"@iconify-json/cib": "^1.0.1",
|
||||
"@iconify-json/fluent": "^1.0.15",
|
||||
"@iconify-json/ic": "^1.0.8",
|
||||
"@iconify-json/mdi": "^1.0.12",
|
||||
"@iconify-json/ph": "^1.0.4",
|
||||
"@iconify-json/tabler": "^1.0.12",
|
||||
"@iconify-json/teenyicons": "^1.0.1",
|
||||
"@iconify-json/vscode-icons": "^1.0.3",
|
||||
"@intlify/vite-plugin-vue-i18n": "^3.2.1",
|
||||
"@types/markdown-it-link-attributes": "^3.0.1",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
|
||||
26
docs/pnpm-lock.yaml
generated
26
docs/pnpm-lock.yaml
generated
@@ -2,14 +2,17 @@ lockfileVersion: 5.3
|
||||
|
||||
specifiers:
|
||||
'@antfu/eslint-config': ^0.16.0
|
||||
'@iconify-json/ant-design': ^1.0.2
|
||||
'@iconify-json/bx': ^1.0.3
|
||||
'@iconify-json/carbon': ^1.0.14
|
||||
'@iconify-json/cib': ^1.0.1
|
||||
'@iconify-json/fluent': ^1.0.15
|
||||
'@iconify-json/ic': ^1.0.8
|
||||
'@iconify-json/mdi': ^1.0.12
|
||||
'@iconify-json/ph': ^1.0.4
|
||||
'@iconify-json/tabler': ^1.0.12
|
||||
'@iconify-json/teenyicons': ^1.0.1
|
||||
'@iconify-json/vscode-icons': ^1.0.3
|
||||
'@intlify/vite-plugin-vue-i18n': ^3.2.1
|
||||
'@types/markdown-it-link-attributes': ^3.0.1
|
||||
'@types/nprogress': ^0.2.0
|
||||
@@ -32,6 +35,7 @@ specifiers:
|
||||
nprogress: ^0.2.0
|
||||
pinia: ^2.0.9
|
||||
prism-theme-vars: ^0.2.2
|
||||
tauri-search: link:../
|
||||
ts-morph: ^13.0.3
|
||||
typescript: ^4.5.5
|
||||
unplugin-auto-import: ^0.5.11
|
||||
@@ -60,6 +64,7 @@ dependencies:
|
||||
nprogress: 0.2.0
|
||||
pinia: 2.0.9_typescript@4.5.5+vue@3.2.28
|
||||
prism-theme-vars: 0.2.2
|
||||
tauri-search: link:..
|
||||
ts-morph: 13.0.3
|
||||
vue: 3.2.28
|
||||
vue-demi: 0.12.1_vue@3.2.28
|
||||
@@ -68,14 +73,17 @@ dependencies:
|
||||
|
||||
devDependencies:
|
||||
'@antfu/eslint-config': 0.16.0_eslint@8.7.0+typescript@4.5.5
|
||||
'@iconify-json/ant-design': 1.0.2
|
||||
'@iconify-json/bx': 1.0.3
|
||||
'@iconify-json/carbon': 1.0.14
|
||||
'@iconify-json/cib': 1.0.1
|
||||
'@iconify-json/fluent': 1.0.15
|
||||
'@iconify-json/ic': 1.0.8
|
||||
'@iconify-json/mdi': 1.0.12
|
||||
'@iconify-json/ph': 1.0.4
|
||||
'@iconify-json/tabler': 1.0.12
|
||||
'@iconify-json/teenyicons': 1.0.1
|
||||
'@iconify-json/vscode-icons': 1.0.3
|
||||
'@intlify/vite-plugin-vue-i18n': 3.2.1_vite@2.7.13+vue-i18n@9.1.9
|
||||
'@types/markdown-it-link-attributes': 3.0.1
|
||||
'@types/nprogress': 0.2.0
|
||||
@@ -1584,6 +1592,12 @@ packages:
|
||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||
dev: true
|
||||
|
||||
/@iconify-json/ant-design/1.0.2:
|
||||
resolution: {integrity: sha512-pyD1RM5gB61vgP1g3F9yMfmZkxCHW6zbHsJJJaBQG1YkJBUmN/9i3pJjyprwCmlOcw16E8DMUWKMCWG00edDCw==}
|
||||
dependencies:
|
||||
'@iconify/types': 1.0.12
|
||||
dev: true
|
||||
|
||||
/@iconify-json/bx/1.0.3:
|
||||
resolution: {integrity: sha512-nwUxwOwocTp5u+KcBUraqEXiC7VG6niL6RQIdbLsRjZwouxayyVXPIkBPwMEmxpcTk1SA8Jh52MI+Scex1wJSA==}
|
||||
dependencies:
|
||||
@@ -1620,6 +1634,12 @@ packages:
|
||||
'@iconify/types': 1.0.12
|
||||
dev: true
|
||||
|
||||
/@iconify-json/ph/1.0.4:
|
||||
resolution: {integrity: sha512-hcxC2k25/Lh/bgXgbwAD4WvnC8BeunSqafFwIOyL1dCu3QGBgKmPFIBUv4W2kBm+rbrv7F3WHPFBAJDVrjpunA==}
|
||||
dependencies:
|
||||
'@iconify/types': 1.0.12
|
||||
dev: true
|
||||
|
||||
/@iconify-json/tabler/1.0.12:
|
||||
resolution: {integrity: sha512-ZUXFwecBxSrJhtMiJgLwd+ol2etNRl5T/yMfRFRq5ZGIDSmkk+W0ZbkMroSlglo2Eu3UZ4gNYLNg3x3efGzDlg==}
|
||||
dependencies:
|
||||
@@ -1632,6 +1652,12 @@ packages:
|
||||
'@iconify/types': 1.0.12
|
||||
dev: true
|
||||
|
||||
/@iconify-json/vscode-icons/1.0.3:
|
||||
resolution: {integrity: sha512-3GW+zXEqQxqYCUcglAITagE945qCJUOihCC7yJwE7yPKkYOEsEb+w6GKNkqJ8RMM0vJFA4uNqSJTtqaFS9QF+A==}
|
||||
dependencies:
|
||||
'@iconify/types': 1.0.12
|
||||
dev: true
|
||||
|
||||
/@iconify/types/1.0.12:
|
||||
resolution: {integrity: sha512-6er6wSGF3hgc1JEZqiGpg21CTCjHBYOUwqLmb2Idzkjiw6ogalGP0ZMLVutCzah+0WB4yP+Zd2oVPN8jvJ+Ftg==}
|
||||
dev: true
|
||||
|
||||
15
docs/src/components.d.ts
vendored
15
docs/src/components.d.ts
vendored
@@ -4,22 +4,33 @@
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
'AntDesign:fileMarkdownOutlined': typeof import('~icons/ant-design/file-markdown-outlined')['default']
|
||||
'Bx:bxSearchAlt': typeof import('~icons/bx/bx-search-alt')['default']
|
||||
'Carbon:document': typeof import('~icons/carbon/document')['default']
|
||||
'Carbon:errorFilled': typeof import('~icons/carbon/error-filled')['default']
|
||||
'Carbon:listDropdown': typeof import('~icons/carbon/list-dropdown')['default']
|
||||
'Carbon:nextFilled': typeof import('~icons/carbon/next-filled')['default']
|
||||
CarbonLanguage: typeof import('~icons/carbon/language')['default']
|
||||
CarbonMoon: typeof import('~icons/carbon/moon')['default']
|
||||
CarbonSun: typeof import('~icons/carbon/sun')['default']
|
||||
CarbonWarning: typeof import('~icons/carbon/warning')['default']
|
||||
Counter: typeof import('./components/Counter.vue')['default']
|
||||
'Fluent:databaseSearch24Regular': typeof import('~icons/fluent/database-search24-regular')['default']
|
||||
Footer: typeof import('./components/Footer.vue')['default']
|
||||
'Ic:roundScreenSearchDesktop': typeof import('~icons/ic/round-screen-search-desktop')['default']
|
||||
'Mdi:folderHome': typeof import('~icons/mdi/folder-home')['default']
|
||||
'Mdi:github': typeof import('~icons/mdi/github')['default']
|
||||
'Mdi:languageRust': typeof import('~icons/mdi/language-rust')['default']
|
||||
'Mdi:languageTypescript': typeof import('~icons/mdi/language-typescript')['default']
|
||||
'Ph:linkLight': typeof import('~icons/ph/link-light')['default']
|
||||
README: typeof import('./components/README.md')['default']
|
||||
SearchActions: typeof import('./components/SearchActions.vue')['default']
|
||||
SearchHit: typeof import('./components/SearchHit.vue')['default']
|
||||
SearchResults: typeof import('./components/SearchResults.vue')['default']
|
||||
SearchStats: typeof import('./components/SearchStats.vue')['default']
|
||||
SimpleCard: typeof import('./components/SimpleCard.vue')['default']
|
||||
'Tabler:databaseImport': typeof import('~icons/tabler/database-import')['default']
|
||||
'Teenyicons:dockerOutline': typeof import('~icons/teenyicons/docker-outline')['default']
|
||||
'VscodeIcons:fileTypeRust': typeof import('~icons/vscode-icons/file-type-rust')['default']
|
||||
'VscodeIcons:fileTypeTypescriptOfficial': typeof import('~icons/vscode-icons/file-type-typescript-official')['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +1,111 @@
|
||||
<script setup lang="ts">
|
||||
import { isDark, toggleDark } from '~/composables'
|
||||
import { isDark, toggleDark } from "~/composables";
|
||||
|
||||
const { t, availableLocales, locale } = useI18n()
|
||||
const { t, availableLocales, locale } = useI18n();
|
||||
|
||||
const toggleLocales = () => {
|
||||
// change to some real logic
|
||||
const locales = availableLocales
|
||||
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length]
|
||||
}
|
||||
const locales = availableLocales;
|
||||
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length];
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="text-xl my-2 flex flex-row items-center justify-center space-x-2">
|
||||
<router-link class=" icon-btn " to="/" :title="t('button.home')">
|
||||
<mdi:folder-home />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/" :title="t('button.home')">
|
||||
<mdi:folder-home />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Docs Home
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<router-link class=" icon-btn " to="/search" :title="t('button.home')">
|
||||
<bx:bx-search-alt />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/search" :title="t('button.home')">
|
||||
<bx:bx-search-alt />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Interactive Playground
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<div class="px-4 text-gray-200/50 dark:text-gray-300/50 text-light ">
|
||||
|
|
||||
</div>
|
||||
|
||||
<router-link class=" icon-btn " to="/meilisearch" :title="t('nav.indexing')">
|
||||
<fluent:database-search-24-regular />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/meilisearch" :title="t('nav.indexing')">
|
||||
<fluent:database-search-24-regular />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
MeiliSearch Info
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<router-link class=" icon-btn " to="/scraper" :title="t('nav.indexing')">
|
||||
<tabler:database-import />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/scraper" :title="t('nav.indexing')">
|
||||
<tabler:database-import />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Scraper
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<router-link class=" icon-btn " to="/docs-searchbar" :title="t('nav.indexing')">
|
||||
<ic:round-screen-search-desktop />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/docs-searchbar" :title="t('nav.indexing')">
|
||||
<carbon:list-dropdown />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Search Bar
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<router-link class=" icon-btn " to="/docker" :title="t('button.about')">
|
||||
<teenyicons:docker-outline />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class=" icon-btn " to="/docker" :title="t('button.about')">
|
||||
<teenyicons:docker-outline />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
local Docker search server
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<div class="px-4 text-gray-200/50 dark:text-gray-300/50 text-light ">
|
||||
|
|
||||
</div>
|
||||
|
||||
<router-link class="icon-btn " to="/ts-docs">
|
||||
<mdi:language-typescript />
|
||||
</router-link>
|
||||
<router-link class="icon-btn " to="/rust-docs">
|
||||
<mdi:language-rust />
|
||||
</router-link>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class="icon-btn " to="/ts-docs">
|
||||
<mdi:language-typescript />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Typescript API Documentation
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class="icon-btn " to="/rust-docs">
|
||||
<mdi:language-rust />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Rust API Documentation
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<router-link class="icon-btn " to="/rust-docs">
|
||||
<carbon:document />
|
||||
</router-link>
|
||||
<template #popper>
|
||||
Markdown API Documentation
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<div class="px-4 text-gray-200/50 dark:text-gray-300/50 text-light ">
|
||||
|
|
||||
</div>
|
||||
|
||||
<v-tooltip>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<button class=" icon-btn !outline-none" :title="t('nav.toggle_dark')" @click="toggleDark()">
|
||||
<carbon-moon v-if="isDark" />
|
||||
<carbon-sun v-else />
|
||||
@@ -65,9 +115,14 @@ const toggleLocales = () => {
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<a class=" icon-btn mx-2" :title="t('nav.toggle_langs')" @click="toggleLocales">
|
||||
<carbon-language />
|
||||
</a>
|
||||
<v-tooltip :delay="{ show: 500, hide: 100 }">
|
||||
<a class=" icon-btn mx-2" :title="t('nav.toggle_langs')" @click="toggleLocales">
|
||||
<carbon-language />
|
||||
</a>
|
||||
<template #popper>
|
||||
Switch Language for Heading Content
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
|
||||
38
docs/src/components/SearchActions.vue
Normal file
38
docs/src/components/SearchActions.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import { useSearch } from "~/modules/search";
|
||||
const s = useSearch();
|
||||
const indexPossibilites = ["repo", "prose", "TS API", "RS API"];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col rounded-md bg-gray-100/25 dark:bg-gray-900/25">
|
||||
<div class="flex flex-col space-y-2 rounded-t-md overflow-hidden">
|
||||
|
||||
<div class="font-bold text-lg px-4 py-3 bg-gray-900/10 dark:bg-gray-100/10">
|
||||
ACTIONS
|
||||
</div>
|
||||
|
||||
<div class="p-4 flex flex-col space-y-2">
|
||||
|
||||
<div v-for="idx in indexPossibilites" :key="idx" class=" rounded cursor-pointer p-1 flex">
|
||||
<div class="actions flex flex-row space-x-1 items-center text-gray-100 dark:text-gray-700 transition-colors duration-200">
|
||||
<carbon:next-filled class="flex hover:text-green-500" />
|
||||
<carbon:error-filled class="flex hover:text-orange-500" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row ml-2">
|
||||
<span class="font-medium">{{idx}} </span>
|
||||
<span class="font-light">pipeline</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.btn {
|
||||
@apply text-xs ;
|
||||
}
|
||||
</style>
|
||||
66
docs/src/components/SearchHit.vue
Normal file
66
docs/src/components/SearchHit.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import { PropType } from "vue";
|
||||
import { GenericDoc } from "~/types/meilisearch";
|
||||
|
||||
const props = defineProps({
|
||||
document: {
|
||||
type: Object as PropType<GenericDoc>, required: true}
|
||||
});
|
||||
|
||||
const doc = computed(() => props.document);
|
||||
const showDetails = ref(false);
|
||||
|
||||
const apiKind = computed(() => {
|
||||
if(doc.value._idx !== "api") {
|
||||
return "";
|
||||
}
|
||||
switch(doc.value.kind) {
|
||||
case "Function":
|
||||
return "fn";
|
||||
case "Namespace":
|
||||
return "module";
|
||||
case "Interface":
|
||||
return "interface";
|
||||
default:
|
||||
return doc.value?.kind ? String(doc.value?.kind).toLowerCase() : "";
|
||||
}
|
||||
});
|
||||
|
||||
const details = () => {
|
||||
showDetails.value = !showDetails.value;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col border-1 rounded px-2 py-1 border-gray-500 hover:bg-gray-100 dark:hover:bg-gray-700 ">
|
||||
<div class="flex flex-row space-x-1 items-center place-content-center cursor-pointer" @click="details">
|
||||
<mdi:github v-if="doc._idx === 'repo'" class="flex flex-shrink-0" />
|
||||
<vscode-icons:file-type-typescript-official v-if="doc._idx === 'api' && doc.language === 'typescript'" class="flex flex-shrink-0" />
|
||||
<vscode-icons:file-type-rust v-if="doc._idx === 'api' && doc.language === 'rust'" class="flex" />
|
||||
<ant-design:file-markdown-outlined v-if="doc._idx === 'prose'" class="flex" />
|
||||
<div class="flex flex-shrink-0">{{doc.name}}</div>
|
||||
|
||||
<div class="flex flex-grow ml-1 font-light text-xs italic truncate">
|
||||
{{doc.description}}
|
||||
</div>
|
||||
|
||||
<div v-if="doc._idx === 'api'" class="flex text-xs font-medium px-1 py-0.5 bg-blue-500 dark:bg-blue-600 text-gray-50 rounded">
|
||||
{{apiKind}}
|
||||
</div>
|
||||
<div class="flex px-1 hover:text-green-600 hover:font-bold ">
|
||||
<a :href="doc.url" target="_new">
|
||||
<ph:link-light class="flex" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-if="showDetails" class="items-start">
|
||||
<div v-for="key in Object.keys(doc)" :key="key" class="flex flex-row">
|
||||
<span class="flex font-bold">{{key}}:</span>
|
||||
<span class="flex ml-1">{{doc[key]}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
30
docs/src/components/SearchResults.vue
Normal file
30
docs/src/components/SearchResults.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
query: {type: String, default: ""}
|
||||
});
|
||||
import { useSearch } from "~/modules/search";
|
||||
const s = useSearch();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search-stats flex flex-col rounded-md h-full">
|
||||
|
||||
<div class="rounded-t-md overflow-hidden">
|
||||
<div class="font-bold text-lg rounded-t-md bg-gray-900/10 dark:bg-gray-100/10 py-3 px-4">
|
||||
Results
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="s.searchResults.length >0 && s.searchStatus ==='ready'" class="p-4 mb-2 space-y-2">
|
||||
<search-hit v-for="hit in s.searchResults" :key="hit.id" :document="hit" />
|
||||
</div>
|
||||
<div v-else class="flex flex-col flex-grow justify-center italic">
|
||||
<div v-if="query.length > 0" >
|
||||
no results
|
||||
</div>
|
||||
<div v-else>
|
||||
add a search query above
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
42
docs/src/components/SearchStats.vue
Normal file
42
docs/src/components/SearchStats.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { useSearch } from "~/modules/search";
|
||||
const s = useSearch();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search-stats flex flex-col rounded-md bg-gray-100/25 dark:bg-gray-800/25">
|
||||
|
||||
<div class="rounded-t-md overflow-hidden">
|
||||
<div class="font-bold text-lg rounded-t-md bg-gray-900/10 dark:bg-gray-100/10 py-3 px-4">
|
||||
INDEXES
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="s.$state.health" class="text-xs mt-2" >
|
||||
<div class="text-green-500">MeiliSearch Service Healthy!</div>
|
||||
<div class="db-size">db size: {{s.dbSize}}</div>
|
||||
</div>
|
||||
<span v-else class="text-red-500 ">
|
||||
Meilisearch is not available locally!
|
||||
</span>
|
||||
<div class="p-4">
|
||||
<div
|
||||
v-for="idx in s.$state.indexes"
|
||||
:key="idx.uid"
|
||||
class="index flex flex-row w-full py-2 border-1 rounded border-gray-500 p-4 mt-4"
|
||||
>
|
||||
<span class="index-name flex flex-grow font-medium">{{idx.name}}</span>
|
||||
<v-tooltip >
|
||||
<span class="index-name font-light cursor-pointer">
|
||||
{{s.indexInfo(idx.name)?.numberOfDocuments}}
|
||||
</span>
|
||||
<template #popper>
|
||||
<span class="dark:text-gray-300">
|
||||
# of Docs
|
||||
</span>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
|
||||
title: { type: String, required: true },
|
||||
kind: { type: String, required: true },
|
||||
/** the link URL */
|
||||
url: { type: String, required: true },
|
||||
/** prose description */
|
||||
description: { type: String, required: false },
|
||||
/** any other properties that don't fit above */
|
||||
rest: { type: Object, required: false },
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
178
docs/src/modules/search.ts
Normal file
178
docs/src/modules/search.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { acceptHMRUpdate, defineStore } from "pinia";
|
||||
import type { UserModule } from "~/types";
|
||||
import { MeiliSearchHealth, MeiliSearchIndex, MeiliSearchInterface, MeiliSearchResponse, MeiliSearchStats } from "~/types/meilisearch";
|
||||
|
||||
//#region STORE
|
||||
export interface SearchState {
|
||||
/** is the HTTP server of MeiliSearch reachable */
|
||||
health: boolean | "initializing";
|
||||
|
||||
/** the indexes which are defined on MeiliSearch */
|
||||
indexes: MeiliSearchInterface[];
|
||||
|
||||
/** database stats for MeiliSearch */
|
||||
stats?: MeiliSearchStats;
|
||||
|
||||
searchStatus: "ready" | "searching" | "error" | "not-ready";
|
||||
|
||||
searchResults: {id: string; _idx: string; [key: string]: unknown}[];
|
||||
}
|
||||
|
||||
export const useSearch = defineStore("search", ({
|
||||
state: () => ({
|
||||
health: "initializing",
|
||||
indexes: [],
|
||||
stats: undefined,
|
||||
searchStatus: "not-ready",
|
||||
searchResults: [],
|
||||
}) as SearchState,
|
||||
actions: {
|
||||
async search(text: string, indexes?: string[]) {
|
||||
if(text.trim()==="") {
|
||||
this.$state.searchResults = [];
|
||||
return;
|
||||
}
|
||||
if(!indexes) {
|
||||
indexes = this.$state.indexes.map(i => i.uid);
|
||||
}
|
||||
console.group(`searching for: "${text}"`);
|
||||
console.info(`search on ${indexes.length} indexes`, indexes);
|
||||
console.time("search");
|
||||
this.$state.searchStatus = "searching";
|
||||
|
||||
const waitFor: Promise<any>[] = [];
|
||||
for (const idx of indexes) {
|
||||
const addIndex =
|
||||
(result: MeiliSearchResponse): MeiliSearchResponse => ({
|
||||
...result,
|
||||
hits: result.hits.map(i =>
|
||||
({...i, _idx: idx})
|
||||
)
|
||||
});
|
||||
|
||||
waitFor.push(
|
||||
get<
|
||||
MeiliSearchResponse,
|
||||
MeiliSearchResponse
|
||||
>
|
||||
(api().search(idx,text), addIndex)
|
||||
);
|
||||
}
|
||||
const results = await Promise.all(waitFor);
|
||||
this.$state.searchStatus = "ready";
|
||||
console.timeEnd("search");
|
||||
|
||||
const hits = results.flatMap(i => i.hits);
|
||||
console.info(`found ${hits.length} documents`);
|
||||
console.groupEnd();
|
||||
this.$state.searchResults = hits;
|
||||
|
||||
return results;
|
||||
},
|
||||
statsUpdate(s: MeiliSearchStats) {
|
||||
this.$state.stats = s;
|
||||
},
|
||||
healthUpdate(h: boolean) {
|
||||
this.$state.health = h;
|
||||
},
|
||||
indexUpdate(idx: MeiliSearchInterface[]) {
|
||||
this.$state.indexes = idx;
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
dbSize: (state) => state.stats?.databaseSize || 0,
|
||||
indexInfo: (state) => (idx: string): MeiliSearchIndex | undefined => state.stats?.indexes[idx]
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(
|
||||
acceptHMRUpdate(
|
||||
useSearch,
|
||||
import.meta.hot)
|
||||
);
|
||||
}
|
||||
//#endregion STORE
|
||||
|
||||
//#region SERVICE
|
||||
/**
|
||||
* Sets up a useful API surface and background
|
||||
* checks for certain meta-data which is available
|
||||
* as a Pinia store.
|
||||
*/
|
||||
export const install: UserModule = ({ isClient }) => {
|
||||
if (isClient) {
|
||||
const s = useSearch();
|
||||
|
||||
const { pause, resume, isActive } = useIntervalFn(async() => {
|
||||
s.indexUpdate(await indexes());
|
||||
s.statsUpdate(await stats());
|
||||
}, 2000, {immediate: true});
|
||||
|
||||
// check health of MeiliSearch
|
||||
useIntervalFn(async() => {
|
||||
const h = await health();
|
||||
s.healthUpdate(h);
|
||||
s.$state.searchStatus = !h ? "not-ready": "ready";
|
||||
|
||||
if(h === true && !isActive) resume();
|
||||
if(h === false && isActive) pause();
|
||||
}, 1000, {immediate: true});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
async function get<T extends {}, U extends {} = never>(
|
||||
url: string,
|
||||
cb?: ((r: T) => U)
|
||||
) {
|
||||
const res = await fetch(url);
|
||||
if(res.ok) {
|
||||
const result = res.json();
|
||||
|
||||
return (
|
||||
cb
|
||||
? result.then(r => cb(r)) as Promise<U>
|
||||
: result as Promise<T>
|
||||
) as never extends U ? Promise<T> : Promise<U>;
|
||||
|
||||
} else {
|
||||
console.groupCollapsed(`Error with API`);
|
||||
console.info(`Request: GET ${url}`);
|
||||
console.warn(`Error [${res.status}]: ${res.statusText}`);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
function api(base: string = "http://localhost:7700") {
|
||||
return {
|
||||
search: (idx: string, text: string) => `${base}/indexes/${idx}/search?q=${text}`,
|
||||
stats: `${base}/stats`,
|
||||
health: `${base}/health`,
|
||||
indexes: `${base}/indexes`
|
||||
};
|
||||
}
|
||||
|
||||
async function health(): Promise<boolean> {
|
||||
const response = await (
|
||||
await fetch(api().health)
|
||||
).json() as MeiliSearchHealth;
|
||||
return response.status === "available";
|
||||
}
|
||||
|
||||
async function indexes() {
|
||||
return await (
|
||||
await fetch(api().indexes)
|
||||
).json() as MeiliSearchInterface[];
|
||||
}
|
||||
|
||||
async function stats() {
|
||||
return await (
|
||||
await fetch(api().stats)
|
||||
).json() as MeiliSearchStats;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -2,16 +2,24 @@
|
||||
|
||||
+++ Install Dependencies and Start Docs Site (_looks like you already did_)
|
||||
```bash
|
||||
# install npm dependencies (in all repos)
|
||||
# 1. installs deps for both CLI and Docs
|
||||
# 2. starts Docs server (in dev mode with HMR), opens in browser
|
||||
# 3. starts Meilisearch server in Docker
|
||||
pnpm run start
|
||||
# start Docker services (you must have Docker installed)
|
||||
docker compose up
|
||||
# bring up documentation / playground site
|
||||
pnpm run dev
|
||||
```
|
||||
A browser window should now have openned up pointing to `http://localhost:3333`.
|
||||
|
||||
You are now up and running with the documentation site and assuming your Docker services also started up -- the [search server](./meilisearch) and [scraper utility](./scraper) -- then you will be able to start trying out searches immediately.
|
||||
> A browser window should now have opened to [`http://localhost:3333`](http://localhost:3333).
|
||||
|
||||
You are now up and running with the documentation site -- and assuming you have Docker installed -- a local [search server](./meilisearch) which you can interact with.
|
||||
|
||||
### Already installed Deps?
|
||||
|
||||
If you've already installed all the deps and want more granular control you can choose from the various script targets or just choose _watch_ to look at docs with active editing capability:
|
||||
|
||||
```bash
|
||||
# turn on watcher mode for both CLI and Docs
|
||||
pnpm run watch
|
||||
```
|
||||
+++
|
||||
|
||||
|
||||
|
||||
@@ -1,37 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { onStartTyping, useIntervalFn } from '@vueuse/core'
|
||||
const el = ref()
|
||||
const searchText = ref('')
|
||||
import { onStartTyping } from "@vueuse/core";
|
||||
import { useSearch } from "~/modules/search";
|
||||
const el = ref();
|
||||
const searchText = ref("");
|
||||
const s = useSearch();
|
||||
const { t } = useI18n();
|
||||
|
||||
|
||||
debouncedWatch(
|
||||
searchText,
|
||||
async() => {
|
||||
await s.search(searchText.value);
|
||||
},
|
||||
{ debounce: 500 }
|
||||
);
|
||||
|
||||
onStartTyping(() => {
|
||||
if (!el.value.active)
|
||||
el.value.focus()
|
||||
})
|
||||
if (!el.value.active) {el.value.focus();};
|
||||
});
|
||||
|
||||
const searchAvailable = ref(false)
|
||||
|
||||
useIntervalFn(async() => {
|
||||
const response = await (await fetch('http://localhost:7700/health')).json() as { status: string }
|
||||
searchAvailable.value = response.status === 'available'
|
||||
}, 5000)
|
||||
|
||||
const router = useRouter()
|
||||
const search = async() => {
|
||||
const response = await (await fetch(`http://localhost:7700/indexes/repo/search?q=${searchText.value}`)).json()
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="py-8 w-full flex flex-col space-y-4">
|
||||
<div class="text-xl">
|
||||
Use the local Meilisearch here.
|
||||
</div>
|
||||
<div class="text-xs" :class="searchAvailable ? 'text-green-500' : 'text-red-500'">
|
||||
<span v-if="searchAvailable">Meilisearch Found Locally!</span>
|
||||
<span v-else>Meilisearch is not available locally!</span>
|
||||
</div>
|
||||
<div class="py-3 w-full h-full">
|
||||
<h1 class="text-xl mb-4">
|
||||
Meilisearch Playground
|
||||
</h1>
|
||||
|
||||
<input
|
||||
id="input"
|
||||
ref="el"
|
||||
@@ -40,25 +35,22 @@ const { t } = useI18n()
|
||||
:aria-label="t('home.ask-for-search')"
|
||||
type="text"
|
||||
autocomplete="false"
|
||||
class="px-auto px-4 py-2 w-250px text-center bg-transparent self-center"
|
||||
spellcheck="false"
|
||||
class="px-auto px-4 py-3 w-350px text-center bg-transparent self-center"
|
||||
border="~ rounded gray-200 dark:gray-700"
|
||||
outline="none active:none"
|
||||
@keydown.enter="search"
|
||||
>
|
||||
<label class="hidden" for="input">{{ t('home.ask-for-search') }}</label>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="m-3 text-sm btn"
|
||||
:disabled="!searchText"
|
||||
@click="search"
|
||||
>
|
||||
{{ t('button.go') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="results-area grid grid-cols-3 gap-4 h-full mt-8 mx-4">
|
||||
<div class="flex flex-col col-span-1 space-y-4">
|
||||
<search-actions />
|
||||
<search-stats class="mt-4" />
|
||||
</div>
|
||||
|
||||
<div class="results-area flex flex-col flex-grow">
|
||||
results
|
||||
<div class="col-span-2 rounded-md bg-gray-100/25 dark:bg-gray-900/25">
|
||||
<search-results :query="searchText" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
59
docs/src/types/meilisearch.ts
Normal file
59
docs/src/types/meilisearch.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
export interface MeiliSearchHealth {
|
||||
/** the current health status; is "available" when healthy */
|
||||
status: string;
|
||||
}
|
||||
|
||||
export type datetime = string;
|
||||
|
||||
export interface MeiliSearchInterface {
|
||||
uid: string;
|
||||
name: string;
|
||||
/** datetime string (aka., 2022-01-23T22:47:42.745395044Z) */
|
||||
createdAt: datetime;
|
||||
/** datetime string (aka., 2022-01-23T22:47:42.745395044Z) */
|
||||
updatedAt: datetime;
|
||||
/**
|
||||
* the property serving as the primary key for the index,
|
||||
* use `id` unless there's a good reason not to
|
||||
*/
|
||||
primaryKey: string;
|
||||
}
|
||||
|
||||
export interface MeiliSearchIndex {
|
||||
numberOfDocuments: number;
|
||||
isIndexing: false;
|
||||
fieldDistribution: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global MeiliSearch Stats
|
||||
*/
|
||||
export interface MeiliSearchStats {
|
||||
databaseSize: number;
|
||||
lastUpdate: datetime;
|
||||
indexes: Record<string, MeiliSearchIndex>;
|
||||
}
|
||||
|
||||
export type GenericDoc = {id: string; _idx?: string; [key:string]: unknown};
|
||||
|
||||
|
||||
export interface MeiliSearchResponse<T extends {} = GenericDoc> {
|
||||
hits: T[];
|
||||
limit: number;
|
||||
nbHits: number;
|
||||
offset: number;
|
||||
processingTimeMs: number;
|
||||
query: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The search results but _with_ the index used inserted on
|
||||
* each "hit"
|
||||
*/
|
||||
export type WithIndex<T extends MeiliSearchResponse> =
|
||||
Omit<T, "hits"> & { hits:
|
||||
{
|
||||
[K in keyof T["hits"]]: T["hits"][K] & Record<K, {_idx: string}>
|
||||
}[number];
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"vite-plugin-vue-layouts/client"
|
||||
],
|
||||
"paths": {
|
||||
"~/*": ["src/*"]
|
||||
"~/*": ["src/*"],
|
||||
}
|
||||
},
|
||||
"include": ["src", "test", "vite.config.ts"],
|
||||
|
||||
@@ -8,11 +8,11 @@ const config: Config.InitialOptions = {
|
||||
transform: {
|
||||
"^.+\\.ts$": "ts-jest",
|
||||
},
|
||||
testPathIgnorePatterns: ["/node_modules/"],
|
||||
testPathIgnorePatterns: ["/node_modules/", "/docs/"],
|
||||
moduleNameMapper: {
|
||||
"^[/]{0,1}~/(.*)$": resolve(process.cwd(), "src", "$1"),
|
||||
},
|
||||
testMatch: ["test/**/?(*[-.])+(spec|test).ts"],
|
||||
testMatch: ["**/?(*[-.])+(spec|test).ts"],
|
||||
setupFilesAfterEnv: ["jest-extended"],
|
||||
testEnvironment: "node",
|
||||
};
|
||||
|
||||
37
package.json
37
package.json
@@ -7,10 +7,12 @@
|
||||
"ts-ast": "./bin/ts-ast.cjs"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "run-p start:*",
|
||||
"start:seach": "pnpm install",
|
||||
"start:docs": "pnpm -C ./docs/ pnpm install",
|
||||
"up": "docker compose up",
|
||||
"start": "run-s prep watch",
|
||||
"prep": "run-p start:*",
|
||||
"start:cli": "pnpm install",
|
||||
"start:docs": "pnpm -C docs start",
|
||||
"start:docker": "run-s up",
|
||||
"up": "docker compose up -d",
|
||||
"down": "docker compose down",
|
||||
"restart": "docker compose restart",
|
||||
"vol:inspect": "run-s vol:inspect:*",
|
||||
@@ -23,25 +25,29 @@
|
||||
"into:scraper": "docker exec -it scraper bash",
|
||||
"ping": "http GET localhost:7700/health",
|
||||
"prune": "docker system prune",
|
||||
"mountpoint": "bash scripts/mountpoint.bash",
|
||||
"dev": "pnpm -C demo pnpm run dev",
|
||||
"dev": "pnpm -C docs dev",
|
||||
"lint": "eslint src --ext ts,js,tsx,jsx --fix --no-error-on-unmatched-pattern",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"ts-ast-overview": "node ./bin/ts-ast-overview.js",
|
||||
"ts-ast": "node ./bin/ts-ast.js",
|
||||
"watch": "run-p watch:*",
|
||||
"watch:docs": "pnpm -C docs/ run dev",
|
||||
"watch:cli": "tsup src/cli/*.ts --format=esm,cjs --clean --sourcemap -d bin --watch"
|
||||
"watch:docs": "pnpm -C docs dev",
|
||||
"watch:cli": "tsup src/cli/*.ts --format=esm,cjs --clean --sourcemap -d bin --watch",
|
||||
"watch:types": "tsup src/models/index.ts src/type/index.ts --dts"
|
||||
},
|
||||
"author": "Ken Snyder<ken@ken.net>",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"pnpm": ">=3"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"gray-matter": "^4.0.3",
|
||||
"inferred-types": "^0.18.4",
|
||||
"native-dash": "^1.21.5",
|
||||
"node-fetch": "^3.1.1",
|
||||
"ts-morph": "^13.0.2",
|
||||
"node-fetch": "^3.2.0",
|
||||
"ts-morph": "^13.0.3",
|
||||
"xxhash-wasm": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -49,17 +55,18 @@
|
||||
"@octokit/types": "^6.34.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/node": "14",
|
||||
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||
"@typescript-eslint/parser": "^5.9.1",
|
||||
"@types/node": "^14.18.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"eslint": "^8.7.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^25.3.4",
|
||||
"eslint-plugin-jest": "^25.7.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"fx": "^20.0.2",
|
||||
"husky": "^7.0.4",
|
||||
"jest": "^27.4.7",
|
||||
"jest-extended": "^1.2.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
@@ -73,6 +80,6 @@
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-node": "^10.4.0",
|
||||
"tsup": "^5.11.11",
|
||||
"typescript": "^4.6.0-dev.20220117"
|
||||
"typescript": "^4.6.0-dev.20220124"
|
||||
}
|
||||
}
|
||||
|
||||
460
pnpm-lock.yaml
generated
460
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { RepoModel } from "~/models/RepoModel";
|
||||
import { IRepoModel } from "~/models/RepoModel";
|
||||
import { url } from "~/types/aliases";
|
||||
import { createMapper } from "~/utils/createMapper";
|
||||
import { GithubRepoResp } from "~/utils/github/getRepo";
|
||||
@@ -6,7 +6,7 @@ import { GithubRepoResp } from "~/utils/github/getRepo";
|
||||
/**
|
||||
* Maps a **Typescript Module** to the Meilisearch documents for that module.
|
||||
*/
|
||||
export const githubMapper = createMapper<GithubRepoResp["data"], RepoModel>(
|
||||
export const githubMapper = createMapper<GithubRepoResp["data"], IRepoModel>(
|
||||
"githubMapper",
|
||||
(i) => ({
|
||||
id: `github_${i.full_name.replace("/", "_")}`,
|
||||
|
||||
@@ -24,6 +24,6 @@ export const tsFunction = createMapper<TsAstFunction, ApiModel>("tsFunction", (i
|
||||
type: s.type.name,
|
||||
comment: s.comment?.text || s.comment?.shortText,
|
||||
})),
|
||||
declaration: `function ${i.name}(${i.signature.map((s) => `s.name`).join(", ")})`,
|
||||
declaration: `function ${i.name}(${i.signature.map((s) => `${s.name}`).join(", ")})`,
|
||||
url: `${TAURI_JS_DOCS_URL}/modules/${i.module}#${i.name}`,
|
||||
}));
|
||||
|
||||
@@ -2,7 +2,7 @@ import { TypescriptKind } from "~/enums";
|
||||
import { en } from "~/stop-words";
|
||||
import { createModel } from "~/utils/createModel";
|
||||
|
||||
export interface ApiModel {
|
||||
export interface IApiModel {
|
||||
id: string;
|
||||
language: "rust" | "typescript";
|
||||
/**
|
||||
@@ -29,10 +29,9 @@ export interface ApiModel {
|
||||
parameters?: { name: string; type?: string; comment?: string; kind: TypescriptKind }[];
|
||||
}
|
||||
|
||||
const model = createModel<ApiModel>("api", (c) =>
|
||||
export const ApiModel = createModel<IApiModel>("api", (c) =>
|
||||
c //
|
||||
.stopWords(en)
|
||||
.filterable("language", "kind", "module", "tags")
|
||||
);
|
||||
|
||||
export default model;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { datetime, url } from "~/types/aliases";
|
||||
import { createModel } from "~/utils/createModel";
|
||||
|
||||
export interface RepoModel {
|
||||
export interface IRepoModel {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
@@ -28,4 +28,4 @@ export interface RepoModel {
|
||||
url: url;
|
||||
}
|
||||
|
||||
export const RepoModel = createModel<RepoModel>("repo");
|
||||
export const RepoModel = createModel<IRepoModel>("repo");
|
||||
|
||||
2
src/models/index.ts
Normal file
2
src/models/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./RepoModel";
|
||||
export * from "./ApiModel";
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "~/models/api";
|
||||
import {ApiModel} from "~/models";
|
||||
import {
|
||||
tsClass,
|
||||
tsFunction,
|
||||
@@ -20,7 +20,7 @@ import { tsEnumeration } from "~/mappers/tsEnumeration";
|
||||
export async function typescriptPipeline() {
|
||||
// get AST from output of TSDoc's JSON option
|
||||
const ast = await parseTypescriptAst();
|
||||
const model = await api;
|
||||
const model = await ApiModel;
|
||||
|
||||
const waitFor: Promise<MsAddOrReplace>[] = [];
|
||||
|
||||
|
||||
@@ -147,22 +147,6 @@ export type PropCharacteristicsApi<E extends string> = Omit<
|
||||
E
|
||||
>;
|
||||
|
||||
// name: p => p.string().searchable().
|
||||
const prose: ModelDefnApi = {
|
||||
document: {
|
||||
foo: (m) => m.string("foo", "bar").displayed().searchable(),
|
||||
bar: (m) => m.boolean().searchable(),
|
||||
baz: (m) => m.number(),
|
||||
},
|
||||
index: {
|
||||
rankingRules: (r) => r.words().attribute().exactness(),
|
||||
stopWords: [],
|
||||
synonyms: {
|
||||
ts: ["typescript"],
|
||||
typescript: ["ts"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export type SearchModel<N extends string, T extends any> = {
|
||||
/** the name of the model */
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
MsSettingsResponse,
|
||||
RankingRule,
|
||||
RankingRulesApi,
|
||||
StopWords,
|
||||
} from "~/types";
|
||||
import xxhash from "xxhash-wasm";
|
||||
import fetch from "node-fetch";
|
||||
@@ -122,7 +121,7 @@ export type SearchModel<T extends {}> = {
|
||||
filterable?: (keyof T)[];
|
||||
distinct?: (keyof T)[];
|
||||
sortable?: (keyof T)[];
|
||||
stopWords?: StopWords;
|
||||
stopWords?: string[];
|
||||
synonyms?: IndexSynonyms;
|
||||
};
|
||||
query: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { parseFunction } from "./parseFunction";
|
||||
import { parseInterface } from "./parseInterface";
|
||||
import { parseReference } from "./parseReference";
|
||||
import { parseTypeAlias } from "./parseTypeAlias";
|
||||
import { parseVariable } from "./parseVariable";
|
||||
|
||||
export function parseModule(mod: TypescriptBlock) {
|
||||
const modDefn: TsAstModule = {
|
||||
@@ -25,7 +26,7 @@ export function parseModule(mod: TypescriptBlock) {
|
||||
for (const i of mod.children || []) {
|
||||
switch (i.kindString) {
|
||||
case TypescriptKind.Enumeration:
|
||||
modDefn.enums.push(parseEnumeration(mod, i));
|
||||
modDefn.enums.push(parseEnumeration(mod.name, i));
|
||||
break;
|
||||
case TypescriptKind.Function:
|
||||
modDefn.functions.push(parseFunction(mod.name, i));
|
||||
@@ -37,7 +38,7 @@ export function parseModule(mod: TypescriptBlock) {
|
||||
modDefn.classes.push(parseClass(mod.name, i));
|
||||
break;
|
||||
case TypescriptKind.Variable:
|
||||
modDefn.variables.push(i);
|
||||
modDefn.variables.push(parseVariable(mod.name, i));
|
||||
break;
|
||||
case TypescriptKind.TypeAlias:
|
||||
modDefn.typeAliases.push(parseTypeAlias(mod.name, i));
|
||||
|
||||
12
test/frontmatter.test.ts
Normal file
12
test/frontmatter.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { readFileSync } from "fs";
|
||||
import matter from "gray-matter";
|
||||
|
||||
describe("frontmatter tests", () => {
|
||||
|
||||
it("faq", () => {
|
||||
const content = readFileSync("test/fixtures/prose/faq.md", "utf-8");
|
||||
const output = matter(content);
|
||||
console.log(output)
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,23 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "es2016",
|
||||
"target": "es2019",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"incremental": false,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
"noUnusedLocals": true,
|
||||
"strictNullChecks": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"types": [
|
||||
"cypress",
|
||||
"vite/client",
|
||||
"vite-plugin-pages/client",
|
||||
"vite-plugin-vue-layouts/client"
|
||||
],
|
||||
"types": [],
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
|
||||
Reference in New Issue
Block a user