├── .github
└── workflows
│ └── pages.yaml
├── .gitignore
├── .node-version
├── Dockerfile
├── README.md
├── Taskfile.yaml
├── assets
└── demo.png
├── cmd
├── goggle
│ └── main.go
├── indexer
│ └── main.go
├── mirror
│ └── main.go
└── repl
│ └── main.go
├── frontend
├── index.html
├── package.json
├── src
│ ├── App.tsx
│ ├── Bar.tsx
│ ├── Search.tsx
│ ├── goggle.ts
│ ├── index.css
│ ├── main.tsx
│ ├── syntaxck.d.ts
│ ├── theme.ts
│ ├── vite-env.d.ts
│ └── wasm.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── go.mod
├── go.sum
├── pkg
├── core
│ ├── lib.go
│ ├── marshal.go
│ ├── signature.go
│ ├── sim.go
│ └── types.go
├── eval
│ └── lib.go
├── goggle
│ └── lib.go
├── index
│ ├── README.md
│ ├── indexer.go
│ ├── lib.go
│ ├── marshal.go
│ ├── mirror.go
│ ├── mirror_test.go
│ └── types.go
└── query
│ └── query.go
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── wasm
└── syntaxck
└── main.go
/.github/workflows/pages.yaml:
--------------------------------------------------------------------------------
1 | name: Deploy frontend
2 | on:
3 | push:
4 | branches:
5 | - main
6 | workflow_dispatch:
7 | concurrency:
8 | group: pages
9 | cancel-in-progress: true
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v4
16 | - name: Install Task
17 | uses: arduino/setup-task@v1
18 | - name: Setup pnpm
19 | uses: pnpm/action-setup@v2.4.0
20 | with:
21 | version: 8.10.2
22 | - name: Setup Node.js environment
23 | uses: actions/setup-node@v4.0.0
24 | with:
25 | node-version-file: .node-version
26 | cache: pnpm
27 | - name: Setup Go environment
28 | uses: actions/setup-go@v5.0.0
29 | with:
30 | go-version-file: go.mod
31 | - name: Setup Binaryen
32 | uses: Aandreba/setup-binaryen@v1.0.0
33 | with:
34 | token: ${{ secrets.GITHUB_TOKEN }}
35 | - name: Install dependencies
36 | run: pnpm install
37 | - name: Compile WASM
38 | run: task wasm-exec syntaxck
39 | - name: Build frontend
40 | run: pnpm build
41 | working-directory: frontend
42 | env:
43 | NODE_ENV: production
44 | VITE_EXTERN_ENDPOINT: ${{ vars.EXTERN_ENDPOINT }}
45 | - name: Setup Pages
46 | uses: actions/configure-pages@v3
47 | - name: Upload artifact
48 | uses: actions/upload-pages-artifact@v2
49 | with:
50 | path: ./frontend/dist
51 | deploy:
52 | needs: build
53 | permissions:
54 | contents: read
55 | pages: write
56 | id-token: write
57 | environment:
58 | name: GitHub Pages
59 | url: ${{ steps.deployment.outputs.page_url }}
60 | runs-on: ubuntu-latest
61 | steps:
62 | - name: Deploy to GitHub Pages
63 | id: deployment
64 | uses: actions/deploy-pages@v3.0.1
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | dist-ssr
4 | *.local
5 |
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 | pnpm-debug.log*
13 | lerna-debug.log*
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | /goggle
27 | /ignored
28 | /index.json
29 | /index.gob
30 | *.task
31 | *.br
32 | *.wasm
33 | /frontend/src/wasm_exec.js
34 | /mirror.json
35 |
36 | *.env
37 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | v20.10.0
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # syntax=docker/dockerfile:1
2 |
3 | FROM golang:1.21.5-alpine3.18 as indexer
4 |
5 | WORKDIR /app
6 |
7 | COPY go.mod go.sum ./
8 |
9 | RUN ["go", "mod", "download"]
10 |
11 | COPY ./pkg ./pkg
12 | COPY ./cmd ./cmd
13 |
14 | RUN ["go", "run", "./cmd/indexer"]
15 |
16 | RUN ["go", "build", "./cmd/goggle"]
17 |
18 | FROM alpine:3.18 as runner
19 |
20 | WORKDIR /app
21 |
22 | COPY --from=indexer /app/index.gob /app/goggle ./
23 |
24 | EXPOSE 6099
25 |
26 | CMD ["./goggle"]
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Goggle 🥽
2 | Search your api through types, with speed
3 |
4 | ## Overview
5 |
6 | Goggle is a type-directed search engine like [hoogle](https://github.com/ndmitchell/hoogle) but for [Go](https://go.dev/)
7 |
8 | ## :tada: Try Goggle now!
9 |
10 | Try Goggle for yourself! You can now visit [here](https://abiriadev.github.io/goggle/) to see Goggle in action.
11 |
12 | ## :camera: Demo
13 |
14 | 
15 |
16 | ## :mag: Query
17 |
18 | You can type query to search and filter results.
19 |
20 | The most simplest form is just Go's standard function definition.
21 |
22 | ```go
23 | func length(s string) int
24 | ```
25 |
26 | But we can omit a function name, to retrieve results whose name does not match with `length`.
27 |
28 | ```go
29 | func (s string) int
30 | ```
31 |
32 | We can omit a `func` keyword too.
33 |
34 | ```go
35 | (s string) int
36 | ```
37 |
38 | Finally, we can omit argument names.
39 |
40 | ```go
41 | (string) int
42 | ```
43 |
44 | ### Query syntax definition
45 |
46 | ```ebnf
47 | Type = Primitives | SliceType | PointerType | identifier .
48 | Primitives = "bool" | Int | UInt | "float32" | "float64" | "complex64" | "complex128" .
49 | Int = "int" | "int8" | "int16" | "int32" | "int64" .
50 | UInt = "uint" | "uint8" | "uint16" | "uint32" | "uint64" | "uintptr" .
51 |
52 | SliceType = "[" "]" Type .
53 |
54 | Parameters = "(" [ Type { "," Type } ] ")" .
55 | Query = [ "func" ] [ identifier ] Parameters [ Type ] .
56 | ```
57 |
58 | ## Build Manually
59 |
60 | ```sh
61 | $ git clone https://github.com/abiriadev/goggle && cd goggle
62 | ```
63 |
64 | ### Build indexer from source and index custom packages
65 |
66 | ```sh
67 | $ go run ./cmd/indexer
68 | # or
69 | $ go run ./cmd/indexer
70 | ```
71 |
72 | See help page for more information:
73 |
74 | ```sh
75 | Usage of indexer:
76 | -f string
77 | index format (default "gob")
78 | -o string
79 | path to save index file
80 | ```
81 |
82 | ### Build and run REPL
83 |
84 | ```sh
85 | $ go run ./cmd/repl
86 | # or optionally pass a path to index file to use
87 | $ go run ./cmd/repl
88 | ```
89 |
90 | It will then show you a prompt starting with `λ`.
91 |
92 | Type any query(like `() bool`) and enter to see the results.
93 |
94 | ```go
95 | λ () bool
96 | func utf8.FullRune() bool // FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
97 | func nettest.TestableAddress() bool // TestableAddress reports whether address of network is testable on the current platform configuration.
98 | func nettest.SupportsRawSocket() bool // SupportsRawSocket reports whether the current session is available to use raw sockets.
99 | func nettest.SupportsIPv6() bool // SupportsIPv6 reports whether the platform supports IPv6 networking functionality.
100 | func nettest.SupportsIPv4() bool // SupportsIPv4 reports whether the platform supports IPv4 networking functionality.
101 | func signal.Ignored() bool // Ignored reports whether sig is currently ignored.
102 | func slices.Equal() bool // Equal reports whether two slices are equal: the same length and all elements equal.
103 | func testenv.OptimizationOff() bool // OptimizationOff reports whether optimization is disabled.
104 | func testenv.HasSymlink() bool // HasSymlink reports whether the current system can use os.Symlink.
105 | func testenv.HasSrc() bool // HasSrc reports whether the entire source tree is available under GOROOT.
106 | ```
107 |
108 | ### Build and run Goggle server
109 |
110 | ```sh
111 | $ go run ./cmd/goggle
112 | ```
113 |
114 | The default port number is `6099`(L33T or `Gogg`). You can pass `-port` option to change it.
115 |
116 | ```sh
117 | Usage of goggle:
118 | -port int
119 | port number to bind (default 6099)
120 | ```
121 |
122 | Try requesting from terminal:
123 |
124 | ```sh
125 | $ http :6099/search q='() bool' -v
126 |
127 | POST /search HTTP/1.1
128 | Accept: application/json, */*;q=0.5
129 | Accept-Encoding: gzip, deflate, br
130 | Connection: keep-alive
131 | Content-Length: 15
132 | Content-Type: application/json
133 | Host: localhost:6099
134 | User-Agent: HTTPie/3.2.1
135 |
136 | {
137 | "q": "() bool"
138 | }
139 |
140 | HTTP/1.1 200 OK
141 | Access-Control-Allow-Origin: *
142 | Content-Length: 1970
143 | Content-Type: text/plain; charset=utf-8
144 | Date: Tue, 12 Dec 2023 04:12:01 GMT
145 |
146 | {
147 | "items": [
148 | {
149 | "sim": 0,
150 | "sig": "func utf8.FullRune() bool",
151 | "summary": "FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.",
152 | "link": "https://pkg.go.dev/unicode/utf8#FullRune"
153 | },
154 | {
155 | "sim": 0,
156 | "sig": "func nettest.TestableAddress() bool",
157 | "summary": "TestableAddress reports whether address of network is testable on the current platform configuration.",
158 | "link": "https://pkg.go.dev/golang.org/x/net/nettest#TestableAddress"
159 | },
160 | ...
161 | ]
162 | }
163 | ```
164 |
165 | ### Build and run frontend
166 |
167 | Ensure that you have [Go](https://go.dev), [Task](https://github.com/go-task/task), [Node.js](https://nodejs.org), and [Binaryen](https://github.com/WebAssembly/binaryen) installed.
168 |
169 | Then, execuate the following commands:
170 |
171 | ```sh
172 | $ task wasm-exec syntaxck
173 | $ corepack enable
174 | $ pnpm install --frozen-lockfile
175 | $ cd frontend
176 | ```
177 |
178 | If you don't want to have local Goggle proxy, you can specify your already-deployed endpoint by setting `VITE_EXTERN_ENDPOINT` variable.
179 |
180 | ```sh
181 | $ echo 'VITE_EXTERN_ENDPOINT=' > .env.production
182 | ```
183 |
184 | Then, run!
185 |
186 | ```sh
187 | $ pnpm dev
188 | # Or, to use an external endpoint:
189 | $ pnpm dev --mode production
190 | ```
191 |
192 | For building the frontend for deployment or serving:
193 |
194 | ```sh
195 | $ pnpm build
196 | ```
197 |
198 | ## :memo: TODO
199 |
200 | - [ ] Index
201 | - [x] Portable index file
202 | - [ ] Index popular packages
203 | - [ ] Incremental search
204 | - [ ] Frontend
205 | - [ ] Standalone result view
206 | - [x] Link to pkg.go.dev
207 | - [x] Brief description
208 | - [ ] Syntax hightlighting for search result
209 | - [ ] Use dedicated search bar component
210 | - [ ] Query
211 | - [ ] Compound types
212 | - [ ] Array
213 | - [ ] Slice
214 | - [ ] Pointer type
215 | - [ ] Inline struct type
216 | - [ ] Interface resolution
217 | - [ ] Method
218 | - [ ] Multiple return
219 | - [ ] Parameter collaping
220 | - [ ] Spread syntax
221 | - [ ] Generics
222 | - [ ] Constraints
223 | - [x] Levenshtein distance
224 | - [ ] Argument-level similarity comparison
225 | - [ ] Hoogle-like structured edit distance
226 | - [ ] Subtype polymorphic edit distance
227 | - [x] GHA CD automation
228 | - [ ] External tools
229 | - [x] REPL
230 | - [ ] vscode extension
231 | - [ ] neovim LSP support?
232 |
233 | ## :grinning: This is really awwwesome!! How can I help?
234 |
235 | There are many ways to support and contribute to the ongoing maintenance and improvement of Goggle. Any support is greatly appreciated!
236 |
237 | - **Spread the world.** Share Goggle with your co-workers, students, and community so that they can find it useful as well!
238 | - **Report bugs.** If you encounter any unexpected behavior or runtime panics, please open an issue to report and document them.
239 | - **Make your document cleaner.** Although Goggle can find items without documentation, it doesn't have a power to generate intuitive identifiers and descriptive summaries. So it's a good idea to document you package thoroughly to enhance developer experience.
240 | - **Suggest better idea.** Currently, Goggle's approximate search doesn't support structural edit-distance, and there are still a lot of missing features. Your suggestions for more accurate and efficient implementations are always welcome.
241 | - **Build creative tools on top of Goggle.** Goggle currently supports web search and REPL, but the possibilities for its application are limitless. Ideas like a vscode extension, LSP autocompletion, etc., could significantly expand its ecosystem.
242 |
--------------------------------------------------------------------------------
/Taskfile.yaml:
--------------------------------------------------------------------------------
1 | version: 3
2 |
3 | tasks:
4 | dist:
5 | cmds:
6 | - mkdir -p ./dist
7 | wasm-exec:
8 | cmds:
9 | - cp $(go env GOROOT)/misc/wasm/wasm_exec.js ./frontend/src/wasm_exec.js
10 | generates:
11 | - ./frontend/src/wasm_exec.js
12 | syntaxck:
13 | env:
14 | GOARCH: wasm
15 | GOOS: js
16 | cmds:
17 | - go build -o ./dist/syntaxck.wasm ./wasm/syntaxck
18 | - wasm-opt ./dist/syntaxck.wasm --enable-bulk-memory -Oz -o ./dist/syntaxck.pack.wasm
19 | - mkdir -p ./frontend/src/assets/
20 | - cp ./dist/syntaxck.pack.wasm ./frontend/src/assets/syntaxck.pack.wasm
21 | sources:
22 | - ./wasm/syntaxck/*.go
23 | generates:
24 | - ./dist/syntaxck.wasm
25 | - ./dist/syntaxck.pack.wasm
26 | - ./frontend/src/assets/syntaxck.pack.wasm
27 |
--------------------------------------------------------------------------------
/assets/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abiriadev/goggle/5a5a6d55b6a5a1b2df9e5e8d59f4a94e701d502e/assets/demo.png
--------------------------------------------------------------------------------
/cmd/goggle/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "flag"
6 | "fmt"
7 | "log"
8 | "log/slog"
9 | "net/http"
10 | "strconv"
11 |
12 | "github.com/abiriadev/goggle/pkg/goggle"
13 | )
14 |
15 | func pathArg() string {
16 | flag.Parse()
17 | f := flag.Arg(0)
18 |
19 | if f == "" {
20 | return "index.gob"
21 | }
22 |
23 | return f
24 | }
25 |
26 | type QueryRequest struct {
27 | Q string `json:"q"`
28 | }
29 |
30 | type QueryHandler struct {
31 | Goggle goggle.Goggle
32 | }
33 |
34 | func (qh *QueryHandler) Query(query string) (goggle.ResultSet, error) {
35 | return qh.Goggle.Query(query)
36 | }
37 |
38 | func (qh *QueryHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
39 | slog.Info("Request", "method", r.Method, "path", r.URL)
40 |
41 | rw.Header().Set("Access-Control-Allow-Origin", "*")
42 |
43 | var req QueryRequest
44 | err := json.NewDecoder(r.Body).Decode(&req)
45 | if err != nil {
46 | rw.WriteHeader(400)
47 | rw.Write([]byte(err.Error()))
48 | return
49 | }
50 |
51 | slog.Info("Query", "q", req.Q)
52 |
53 | rs, err := qh.Query(req.Q)
54 | if err != nil {
55 | rw.WriteHeader(400)
56 | rw.Write([]byte(err.Error()))
57 | }
58 |
59 | slog.Info("ResultSet", "items found", len(rs.Results))
60 |
61 | err = rs.MarshalJsonTo(rw)
62 | if err != nil {
63 | rw.WriteHeader(500)
64 | rw.Write([]byte(err.Error()))
65 | }
66 | }
67 |
68 | func main() {
69 | port := flag.Int("port", 6099, "port number to bind")
70 | f := pathArg()
71 |
72 | goggle, err := goggle.NewGoggle(goggle.Config{Limit: 10})
73 | if err != nil {
74 | panic(err)
75 | }
76 |
77 | err = goggle.Load(f)
78 | if err != nil {
79 | panic(err)
80 | }
81 |
82 | qh := QueryHandler{Goggle: goggle}
83 |
84 | http.Handle("/search", &qh)
85 |
86 | slog.Info("server is listening on", "port", strconv.Itoa(*port))
87 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
88 | }
89 |
--------------------------------------------------------------------------------
/cmd/indexer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 |
6 | "github.com/abiriadev/goggle/pkg/index"
7 | )
8 |
9 | func main() {
10 | indexDestFileName := flag.String("o", "", "path to save index file")
11 | format := flag.String("f", "gob", "index format")
12 |
13 | if *format != "json" && *format != "gob" {
14 | panic("invalid format: only `json` and `gob` are supported")
15 | }
16 |
17 | flag.Parse()
18 |
19 | target := flag.Args()
20 | if len(target) == 0 {
21 | target = append(target, "std")
22 | }
23 |
24 | index, err := index.NewIndexer().IndexPackages(target)
25 | if err != nil {
26 | panic(err)
27 | }
28 |
29 | if *format == "json" {
30 | if *indexDestFileName == "" {
31 | *indexDestFileName = "index.json"
32 | }
33 |
34 | err = index.SaveJson(*indexDestFileName)
35 | } else {
36 | if *indexDestFileName == "" {
37 | *indexDestFileName = "index.gob"
38 | }
39 |
40 | err = index.Save(*indexDestFileName)
41 | }
42 |
43 | if err != nil {
44 | panic(err)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/cmd/mirror/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 |
7 | "github.com/abiriadev/goggle/pkg/index"
8 | )
9 |
10 | func main() {
11 | m, err := index.ResolveFullIndex()
12 | if err != nil {
13 | panic(err)
14 | }
15 |
16 | f, err := os.Create("mirror.json")
17 | if err != nil {
18 | panic(err)
19 | }
20 |
21 | err = json.NewEncoder(f).Encode(m)
22 | if err != nil {
23 | panic(err)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/repl/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 |
7 | "github.com/abiriadev/goggle/pkg/goggle"
8 | "github.com/chzyer/readline"
9 | )
10 |
11 | func pathArg() string {
12 | flag.Parse()
13 | f := flag.Arg(0)
14 |
15 | if f == "" {
16 | return "index.gob"
17 | }
18 |
19 | return f
20 | }
21 |
22 | func main() {
23 | f := pathArg()
24 |
25 | goggle, err := goggle.NewGoggle(goggle.Config{Limit: 10})
26 | if err != nil {
27 | panic(err)
28 | }
29 |
30 | err = goggle.Load(f)
31 | if err != nil {
32 | panic(err)
33 | }
34 |
35 | rl, err := readline.New("λ ")
36 | if err != nil {
37 | panic(err)
38 | }
39 | defer rl.Close()
40 |
41 | for {
42 | line, err := rl.Readline()
43 | if err != nil {
44 | break
45 | }
46 |
47 | rs, err := goggle.Query(line)
48 | if err != nil {
49 | fmt.Println(err)
50 | }
51 |
52 | for _, ri := range rs.Results {
53 | fmt.Println(ri.SigWithComment())
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 | Goggle
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@emotion/react": "^11.11.1",
13 | "@emotion/styled": "^11.11.0",
14 | "@mui/icons-material": "^5.14.19",
15 | "@mui/material": "^5.14.20",
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0"
18 | },
19 | "devDependencies": {
20 | "@types/react": "^18.2.37",
21 | "@types/react-dom": "^18.2.15",
22 | "@vitejs/plugin-react-swc": "^3.5.0",
23 | "typescript": "^5.2.2",
24 | "vite": "^5.0.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Typography } from '@mui/material'
2 | import { Bar } from './Bar.tsx'
3 | import { Search } from './Search.tsx'
4 |
5 | function App() {
6 | return (
7 | <>
8 |
9 |
15 |
22 | Goggle
23 |
24 |
25 |
26 | >
27 | )
28 | }
29 |
30 | export default App
31 |
--------------------------------------------------------------------------------
/frontend/src/Bar.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | AppBar,
3 | Link,
4 | Toolbar,
5 | Typography,
6 | } from '@mui/material'
7 | import GitHubIcon from '@mui/icons-material/GitHub'
8 |
9 | export const Bar = () => (
10 |
15 |
16 |
21 | Goggle
22 |
23 |
28 |
29 |
30 |
31 |
32 | )
33 |
--------------------------------------------------------------------------------
/frontend/src/Search.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { loadWasm } from './wasm'
3 | import {
4 | Autocomplete,
5 | Link,
6 | TextField,
7 | Typography,
8 | useTheme,
9 | } from '@mui/material'
10 | import './syntaxck.d.ts'
11 | import { ResultItem, query } from './goggle.ts'
12 |
13 | export const Search = () => {
14 | const theme = useTheme()
15 | const [wasmLoad, setWasmLoad] = useState(false)
16 | const [resultSet, setResultSet] = useState<
17 | Array
18 | >([])
19 | const [inp, setInp] = useState('')
20 |
21 | useEffect(() => {
22 | ;(async () => {
23 | await loadWasm()
24 | setWasmLoad(true)
25 | })()
26 | }, [])
27 |
28 | useEffect(() => {
29 | if (!(wasmLoad && window.syntaxck(inp))) return
30 | ;(async () => {
31 | try {
32 | const rs = await query(inp)
33 |
34 | setResultSet(rs.items)
35 | } catch (e) {
36 | console.error(e)
37 | }
38 | })()
39 | }, [inp])
40 |
41 | return (
42 | _}
50 | getOptionLabel={o =>
51 | typeof o === 'string' ? o : o.sig
52 | }
53 | componentsProps={{
54 | popper: {
55 | modifiers: [
56 | { name: 'flip', enabled: false },
57 | {
58 | name: 'preventOverflow',
59 | enabled: false,
60 | },
61 | ],
62 | },
63 | }}
64 | onInputChange={(_, i) => setInp(i)}
65 | onChange={(_, o, r) => {
66 | if (r === 'selectOption') {
67 | window.open(
68 | typeof o === 'string' ? o : o?.link,
69 | '_blank',
70 | )
71 | }
72 | }}
73 | renderInput={p => (
74 | fieldset': {
78 | borderColor:
79 | theme.palette.primary
80 | .main,
81 | },
82 | },
83 | '& .MuiOutlinedInput-root:hover': {
84 | '& > fieldset': {
85 | borderColor:
86 | theme.palette.primary
87 | .main,
88 | },
89 | },
90 | }}
91 | {...p}
92 | />
93 | )}
94 | renderOption={(p, o) => (
95 |
96 |
101 |
102 | {o.sig}
103 |
104 |
113 | {o.summary}
114 |
115 |
116 |
117 | )}
118 | />
119 | )
120 | }
121 |
--------------------------------------------------------------------------------
/frontend/src/goggle.ts:
--------------------------------------------------------------------------------
1 | export interface ResultSet {
2 | items: Array
3 | }
4 |
5 | export interface ResultItem {
6 | sim: number
7 | sig: string
8 | summary: string
9 | link: string
10 | }
11 |
12 | const host =
13 | import.meta.env.MODE === 'production'
14 | ? import.meta.env.VITE_EXTERN_ENDPOINT
15 | : '/api'
16 |
17 | console.log('host', host)
18 | console.log('mode', import.meta.env)
19 |
20 | export const query = async (
21 | query: string,
22 | ): Promise => {
23 | const raw = await fetch(`${host}/search`, {
24 | method: 'POST',
25 | body: JSON.stringify({ q: query }),
26 | })
27 |
28 | console.table(raw)
29 |
30 | if (!raw.ok) {
31 | throw new Error('response was not successful')
32 | }
33 |
34 | return await raw.json()
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | color-scheme: light dark;
3 | background-color: #202224;
4 | }
5 |
6 | body {
7 | margin: 0;
8 | }
9 |
10 | #root {
11 | width: 100vw;
12 | height: 100vh;
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.tsx'
4 | import './index.css'
5 | import { ThemeProvider } from '@mui/material/styles'
6 | import { theme } from './theme.ts'
7 |
8 | ReactDOM.createRoot(
9 | document.getElementById('root')!,
10 | ).render(
11 |
12 |
13 |
14 |
15 | ,
16 | )
17 |
--------------------------------------------------------------------------------
/frontend/src/syntaxck.d.ts:
--------------------------------------------------------------------------------
1 | declare global {
2 | export interface Window {
3 | Go: any
4 | syntaxck: (query: string) => bool
5 | }
6 | }
7 |
8 | export {}
9 |
--------------------------------------------------------------------------------
/frontend/src/theme.ts:
--------------------------------------------------------------------------------
1 | import { createTheme } from '@mui/material/styles'
2 |
3 | export const theme = createTheme({
4 | palette: {
5 | mode: 'dark',
6 | primary: {
7 | main: '#007d9c',
8 | light: '#50b7e0',
9 | },
10 | },
11 | })
12 |
--------------------------------------------------------------------------------
/frontend/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.wasm'
4 |
--------------------------------------------------------------------------------
/frontend/src/wasm.ts:
--------------------------------------------------------------------------------
1 | import './wasm_exec.js'
2 | import syntaxckPath from './assets/syntaxck.pack.wasm'
3 |
4 | export const loadWasm = async (): Promise => {
5 | const goWasm = new window.Go()
6 | const result = await WebAssembly.instantiateStreaming(
7 | fetch(syntaxckPath),
8 | goWasm.importObject,
9 | )
10 | goWasm.run(result.instance)
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noFallthroughCasesInSwitch": true
20 | },
21 | "include": ["src"],
22 | "references": [{ "path": "./tsconfig.node.json" }]
23 | }
24 |
--------------------------------------------------------------------------------
/frontend/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig(({ mode }) => ({
6 | plugins: [react()],
7 |
8 | base: mode === 'development' ? '/' : '/goggle',
9 |
10 | server: {
11 | proxy: {
12 | '/api': {
13 | target: 'http://localhost:6099',
14 | changeOrigin: true,
15 | rewrite: p => p.replace(/^\/api/, ''),
16 | },
17 | },
18 | },
19 |
20 | assetsInclude: ['**/*.wasm'],
21 | }))
22 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/abiriadev/goggle
2 |
3 | go 1.21.4
4 |
5 | require (
6 | github.com/alecthomas/participle/v2 v2.1.1
7 | github.com/chzyer/readline v1.5.1
8 | )
9 |
10 | require (
11 | github.com/hbollon/go-edlib v1.6.0 // indirect
12 | github.com/kr/pretty v0.3.1 // indirect
13 | github.com/kr/text v0.2.0 // indirect
14 | github.com/repeale/fp-go v0.11.1 // indirect
15 | github.com/rogpeppe/go-internal v1.9.0 // indirect
16 | github.com/samber/mo v1.11.0 // indirect
17 | golang.org/x/mod v0.14.0 // indirect
18 | golang.org/x/sys v0.1.0 // indirect
19 | golang.org/x/tools v0.16.0 // indirect
20 | )
21 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0=
2 | github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
3 | github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8=
4 | github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c=
5 | github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
6 | github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
7 | github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
8 | github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
9 | github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
10 | github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
11 | github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
12 | github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
13 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
14 | github.com/hbollon/go-edlib v1.6.0 h1:ga7AwwVIvP8mHm9GsPueC0d71cfRU/52hmPJ7Tprv4E=
15 | github.com/hbollon/go-edlib v1.6.0/go.mod h1:wnt6o6EIVEzUfgbUZY7BerzQ2uvzp354qmS2xaLkrhM=
16 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
17 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
18 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
19 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
20 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
21 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
22 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
23 | github.com/repeale/fp-go v0.11.1 h1:Q/e+gNyyHaxKAyfdbBqvip3DxhVWH453R+kthvSr9Mk=
24 | github.com/repeale/fp-go v0.11.1/go.mod h1:4KrwQJB1VRY+06CA+jTc4baZetr6o2PeuqnKr5ybQUc=
25 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
26 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
27 | github.com/samber/mo v1.11.0 h1:ZOiSkrGGpNhVv/1dxP02risztdMTIwE8KSW9OG4k5bY=
28 | github.com/samber/mo v1.11.0/go.mod h1:BfkrCPuYzVG3ZljnZB783WIJIGk1mcZr9c9CPf8tAxs=
29 | golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
30 | golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
31 | golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
32 | golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
33 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34 | golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
35 | golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
36 |
--------------------------------------------------------------------------------
/pkg/core/lib.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "github.com/samber/mo"
5 | )
6 |
7 | type Arg struct {
8 | Name string `json:"name"`
9 | Type string `json:"type"`
10 | }
11 |
12 | type FuncDef struct {
13 | Package string `json:"pkg"`
14 | PackageMame string `json:"pkg_name"`
15 | Name string `json:"name"`
16 | Args []Arg `json:"args"`
17 | Return string `json:"ret"`
18 | Summary string `json:"sum"`
19 | Link string `json:"link"`
20 | }
21 |
22 | type MethodDef struct {
23 | Package string `json:"pkg"`
24 | PackageMame string `json:"pkg_name"`
25 | Name string `json:"name"`
26 | Receiver string `json:"recv"`
27 | Args []Arg `json:"args"`
28 | Return string `json:"ret"`
29 | Summary string `json:"sum"`
30 | Link string `json:"link"`
31 | }
32 |
33 | func (this *FuncDef) ToResult(sim Similarity) ResultItem {
34 | return ResultItem{
35 | Similarity: sim,
36 | Sig: this.Signature(),
37 | Summary: this.Summary,
38 | Link: this.Link,
39 | }
40 | }
41 |
42 | type Item = mo.Either[FuncDef, MethodDef]
43 |
44 | type ResultItem struct {
45 | Similarity Similarity `json:"sim"`
46 | Sig string `json:"sig"`
47 | Summary string `json:"summary"`
48 | Link string `json:"link"`
49 | }
50 |
51 | type ResultSet struct {
52 | Results []ResultItem `json:"items"`
53 | }
54 |
55 | func NewResultSet() ResultSet {
56 | return ResultSet{make([]ResultItem, 0)}
57 | }
58 |
--------------------------------------------------------------------------------
/pkg/core/marshal.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "encoding/json"
5 | "io"
6 | )
7 |
8 | func (rs *ResultSet) MarshalJson() ([]byte, error) {
9 | return json.Marshal(rs)
10 | }
11 |
12 | func (rs *ResultSet) MarshalJsonTo(w io.Writer) error {
13 | return json.NewEncoder(w).Encode(rs)
14 | }
15 |
--------------------------------------------------------------------------------
/pkg/core/signature.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/repeale/fp-go"
8 | )
9 |
10 | type ToSignature interface {
11 | Signature() string
12 | }
13 |
14 | func args(args []Arg) string {
15 | return fmt.Sprintf("(%s)", strings.Join(fp.Map(func(arg Arg) string {
16 | return fmt.Sprintf("%s %s", arg.Name, arg.Type)
17 | })(args), ", "))
18 | }
19 |
20 | func (f *FuncDef) Signature() string {
21 | return fmt.Sprintf("func %s.%s%s %s", f.PackageMame, f.Name, args(f.Args), f.Return)
22 | }
23 |
24 | func (ri *ResultItem) Signature() string {
25 | return ri.Sig
26 | }
27 |
28 | func (ri *ResultItem) SigWithComment() string {
29 | return fmt.Sprintf("%s\t// %s", ri.Sig, ri.Summary)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/core/sim.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | type Similarity float64
4 |
5 | const (
6 | Equivalent Similarity = 0
7 | Subequal = 0.25
8 | Different = 1
9 | )
10 |
--------------------------------------------------------------------------------
/pkg/core/types.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | type Type interface {
4 | }
5 |
6 | type Array[T any] struct {
7 | t T
8 | }
9 |
--------------------------------------------------------------------------------
/pkg/eval/lib.go:
--------------------------------------------------------------------------------
1 | package eval
2 |
3 | import (
4 | "cmp"
5 | "slices"
6 |
7 | "github.com/abiriadev/goggle/pkg/core"
8 | "github.com/abiriadev/goggle/pkg/index"
9 | "github.com/abiriadev/goggle/pkg/query"
10 | "github.com/hbollon/go-edlib"
11 | )
12 |
13 | func Lev(a, b string) core.Similarity {
14 | s, err := edlib.StringsSimilarity(a, b, edlib.Levenshtein)
15 | if err != nil {
16 | // unreachable error
17 | panic(err)
18 | }
19 |
20 | return core.Similarity(1 - s)
21 | }
22 |
23 | func AccSim(sims []core.Similarity) core.Similarity {
24 | acc := core.Equivalent
25 |
26 | for _, sim := range sims {
27 | acc += sim
28 | }
29 |
30 | return acc / core.Similarity(len(sims))
31 | }
32 |
33 | func CombSim(a, b core.Similarity) core.Similarity {
34 | return (a + b) / 2
35 | }
36 |
37 | func EvaluateName(ident string, query string) core.Similarity {
38 | if query == "" {
39 | return core.Equivalent
40 | } else {
41 | return Lev(query, ident)
42 | }
43 | }
44 |
45 | func EvaluateArgs(args []core.Arg, query query.Query) core.Similarity {
46 | if len(query.Args) != len(args) {
47 | return core.Different
48 | }
49 |
50 | for i, arg := range query.Args {
51 | if args[i].Type != arg {
52 | return core.Different
53 | }
54 | }
55 |
56 | // TODO: qp does not support argument names yet
57 | return core.Equivalent
58 |
59 | // sarr := make([]core.Similarity, len(args))
60 | //
61 | // for i, arg := range query.Args {
62 | // if args[i].Type != arg {
63 | // return core.Different
64 | // }
65 | // e := EvaluateName(arg, args[i].Name)
66 | // sarr = append(
67 | // sarr,
68 | // e,
69 | // )
70 | // }
71 | //
72 | // return AccSim(sarr)
73 | }
74 |
75 | func EvaluateFunc(item *core.FuncDef, query query.Query) core.Similarity {
76 | if query.Ret == item.Return {
77 | argsSim := EvaluateArgs(item.Args, query)
78 |
79 | if argsSim == core.Different {
80 | return core.Different
81 | }
82 |
83 | namesSim := EvaluateName(item.Name, query.Name)
84 |
85 | return namesSim
86 | // return namesSim
87 | }
88 | return core.Different
89 | }
90 |
91 | // TODO: complete this function later
92 | func EvaluateMethod(item *core.MethodDef, query query.Query) core.Similarity {
93 | return core.Different
94 | }
95 |
96 | func limitSlice[T any](slice []T, limit int) []T {
97 | if len(slice) < limit {
98 | return slice
99 | } else {
100 | return slice[:limit]
101 | }
102 | }
103 |
104 | func Query(index *index.Index, query query.Query, limit int) core.ResultSet {
105 | rs := core.NewResultSet()
106 |
107 | for _, item := range index.FuncItems {
108 | sim := EvaluateFunc(&item, query)
109 |
110 | rs.Results = append(rs.Results, item.ToResult(sim))
111 | }
112 |
113 | slices.SortFunc(rs.Results, func(a, b core.ResultItem) int {
114 | return cmp.Compare(a.Similarity, b.Similarity)
115 | })
116 |
117 | rs.Results = limitSlice(rs.Results, limit)
118 |
119 | return rs
120 | }
121 |
--------------------------------------------------------------------------------
/pkg/goggle/lib.go:
--------------------------------------------------------------------------------
1 | package goggle
2 |
3 | import (
4 | "github.com/abiriadev/goggle/pkg/core"
5 | "github.com/abiriadev/goggle/pkg/eval"
6 | "github.com/abiriadev/goggle/pkg/index"
7 | "github.com/abiriadev/goggle/pkg/query"
8 | "github.com/alecthomas/participle/v2"
9 | )
10 |
11 | // reexports:
12 |
13 | // ResultSet represents a query result ordered by accuracy
14 | type ResultSet = core.ResultSet
15 |
16 | // ResultItem represents a single item that matches to the query
17 | type ResultItem = core.ResultItem
18 |
19 | // Similarity represents how the results are accurate
20 | type Similarity = core.Similarity
21 |
22 | // Configuration for Goggle
23 | type Config struct {
24 | Limit int
25 | }
26 |
27 | // The main entry to the Goggle search engine
28 | type Goggle struct {
29 | index index.Index
30 | qp participle.Parser[query.Query]
31 | cfg Config
32 | }
33 |
34 | func NewGoggle(cfg Config) (Goggle, error) {
35 | qp, err := query.QueryParser()
36 | if err != nil {
37 | return Goggle{}, err
38 | }
39 |
40 | return Goggle{index.NewIndex(), *qp, cfg}, nil
41 | }
42 |
43 | // Initialize new Goggle search engine by loading index from the path
44 | func (g *Goggle) Load(indexFile string) error {
45 | index, err := index.Load(indexFile)
46 | if err != nil {
47 | return err
48 | }
49 |
50 | g.index = index
51 | return nil
52 | }
53 |
54 | // Query Goggle with a given query
55 | func (g *Goggle) Query(query string) (core.ResultSet, error) {
56 | q, err := g.qp.ParseString("", query)
57 | if err != nil {
58 | return core.ResultSet{}, err
59 | }
60 |
61 | return eval.Query(&g.index, *q, g.cfg.Limit), nil
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/index/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 인덱스 커엽다!!
4 |
--------------------------------------------------------------------------------
/pkg/index/indexer.go:
--------------------------------------------------------------------------------
1 | package index
2 |
3 | import (
4 | "fmt"
5 | "go/ast"
6 | "go/doc"
7 | "strings"
8 |
9 | "github.com/abiriadev/goggle/pkg/core"
10 | "github.com/repeale/fp-go"
11 | "golang.org/x/tools/go/packages"
12 | )
13 |
14 | type Indexer struct{}
15 |
16 | func NewIndexer() Indexer {
17 | return Indexer{}
18 | }
19 |
20 | func (indexer Indexer) IndexPackages(pkgsToIndex []string) (Index, error) {
21 | pkgs, err := packages.Load(
22 | &packages.Config{
23 | Mode: packages.NeedName |
24 | packages.NeedTypes |
25 | packages.NeedSyntax,
26 | },
27 | pkgsToIndex...,
28 | )
29 | if err != nil {
30 | return Index{}, nil
31 | }
32 |
33 | index := NewIndex()
34 |
35 | for _, pkg := range pkgs {
36 | d, err := doc.NewFromFiles(pkg.Fset, pkg.Syntax, pkg.PkgPath)
37 | if err != nil {
38 | continue
39 | }
40 |
41 | for _, f := range d.Funcs {
42 | r := f.Decl.Type.Results
43 | if r == nil || r.NumFields() != 1 {
44 | continue
45 | }
46 |
47 | v, b := r.List[0].Type.(*ast.Ident)
48 | if !b {
49 | continue
50 | }
51 |
52 | args := make([]core.Arg, 0)
53 |
54 | // analyzeFuncDecl(f.Decl)
55 |
56 | pl := f.Decl.Type.Params.List
57 | for _, arg := range pl {
58 | if arg != nil {
59 | a := arg.Names
60 | if len(a) != 1 {
61 | continue
62 | }
63 |
64 | a1 := a[0]
65 |
66 | t, isIdent := arg.Type.(*ast.Ident)
67 | if !isIdent {
68 | continue
69 | }
70 |
71 | args = append(args, core.Arg{
72 | Name: a1.Name,
73 | Type: t.Name,
74 | })
75 | }
76 | }
77 |
78 | var docLinkRoute string
79 | if docLinkRoute = d.ImportPath; isVendored(d.ImportPath) {
80 | docLinkRoute = strings.TrimPrefix(d.ImportPath, "vendor/")
81 | }
82 |
83 | index.FuncItems = append(index.FuncItems, core.FuncDef{
84 | Package: d.ImportPath,
85 | PackageMame: pkg.Name,
86 | Name: f.Name,
87 | Args: args,
88 | Return: v.Name,
89 | Summary: d.Synopsis(f.Doc),
90 | Link: fmt.Sprintf("https://pkg.go.dev/%s#%s", docLinkRoute, f.Name),
91 | })
92 | }
93 | }
94 |
95 | return index, nil
96 | }
97 |
98 | func analyzeFuncDecl(f *ast.FuncDecl) {
99 | // WARN: nilable
100 | // name := f.Name.Name
101 |
102 | // WARN: nilable
103 | ft := f.Type
104 |
105 | for _, field := range fp.Filter(func(n *ast.Field) bool {
106 | return n != nil
107 | })(ft.Params.List) {
108 | fty := field.Type
109 |
110 | fmt.Printf("fty: %T\n", fty)
111 | }
112 | }
113 |
114 | func isVendored(importPath string) bool {
115 | return strings.HasPrefix(importPath, "vendor/")
116 | // || strings.Contains(importPath, "/vendor/")
117 | }
118 |
--------------------------------------------------------------------------------
/pkg/index/lib.go:
--------------------------------------------------------------------------------
1 | package index
2 |
--------------------------------------------------------------------------------
/pkg/index/marshal.go:
--------------------------------------------------------------------------------
1 | package index
2 |
3 | import (
4 | "encoding/gob"
5 | "encoding/json"
6 | "io"
7 | "os"
8 | )
9 |
10 | func (index *Index) MarshalJson() ([]byte, error) {
11 | return json.Marshal(index)
12 | }
13 |
14 | func (index *Index) MarshalJsonTo(w io.Writer) error {
15 | return json.NewEncoder(w).Encode(index)
16 | }
17 |
18 | func (index *Index) SaveJson(filename string) error {
19 | w, e := os.Create(filename)
20 | if e != nil {
21 | return e
22 | }
23 |
24 | return index.MarshalJsonTo(w)
25 | }
26 |
27 | func UnmarshalJson(data []byte) (Index, error) {
28 | var idx Index
29 | return idx, json.Unmarshal(data, &idx)
30 | }
31 |
32 | func UnmarshalJsonFrom(r io.Reader) (Index, error) {
33 | var idx Index
34 | return idx, json.NewDecoder(r).Decode(&idx)
35 | }
36 |
37 | func LoadJson(filename string) (Index, error) {
38 | r, e := os.Open(filename)
39 | if e != nil {
40 | return Index{}, e
41 | }
42 |
43 | return UnmarshalJsonFrom(r)
44 | }
45 |
46 | func (index *Index) Save(filename string) error {
47 | w, err := os.Create(filename)
48 | if err != nil {
49 | return err
50 | }
51 |
52 | gob.Register(Index{})
53 |
54 | enc := gob.NewEncoder(w)
55 |
56 | return enc.Encode(index)
57 | }
58 |
59 | func Load(filename string) (Index, error) {
60 | r, err := os.Open(filename)
61 | if err != nil {
62 | return Index{}, err
63 | }
64 |
65 | gob.Register(Index{})
66 |
67 | dec := gob.NewDecoder(r)
68 |
69 | var index Index
70 | err = dec.Decode(&index)
71 |
72 | return index, err
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/index/mirror.go:
--------------------------------------------------------------------------------
1 | package index
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "net/http"
8 | "strconv"
9 | "time"
10 | )
11 |
12 | // maximum index server limit
13 | const LIMIT = 2000
14 | const INDEX_MAXIMUM_TAIL = 5
15 |
16 | func ResolveFullIndex() ([]ModuleIndex, error) {
17 | midxes := make([]ModuleIndex, 0)
18 | var inc *time.Time
19 |
20 | for {
21 | r, err := FetchModuleIndex(inc, LIMIT)
22 | if err != nil {
23 | return nil, err
24 | }
25 |
26 | m, err := ParseModuleIndex(r)
27 | if err != nil {
28 | return nil, err
29 | }
30 |
31 | midxes = append(midxes, m...)
32 |
33 | if len(m) >= INDEX_MAXIMUM_TAIL {
34 | t := IncTimeStamp(m[len(m)-1])
35 | inc = &t
36 |
37 | fmt.Println(*inc)
38 | } else {
39 | break
40 | }
41 | }
42 |
43 | return midxes, nil
44 | }
45 |
46 | func IncTimeStamp(midxes ModuleIndex) time.Time {
47 | return midxes.Timestamp.Add(time.Nanosecond)
48 | }
49 |
50 | func FetchModuleIndex(since *time.Time, limit int) (io.Reader, error) {
51 | req, err := http.NewRequest("GET", "https://index.golang.org/index", nil)
52 | if err != nil {
53 | return nil, err
54 | }
55 |
56 | q := req.URL.Query()
57 | if since != nil {
58 | q.Add("since", since.Format(time.RFC3339))
59 | }
60 | q.Add("limit", strconv.Itoa(limit))
61 | req.URL.RawQuery = q.Encode()
62 |
63 | if err != nil {
64 | return nil, err
65 | }
66 |
67 | client := &http.Client{}
68 |
69 | res, err := client.Do(req)
70 | if err != nil {
71 | return nil, err
72 | }
73 |
74 | return res.Body, nil
75 | }
76 |
77 | type ModuleIndex struct {
78 | Path string
79 | Version string
80 | Timestamp time.Time
81 | }
82 |
83 | func ParseModuleIndex(r io.Reader) ([]ModuleIndex, error) {
84 | dec := json.NewDecoder(r)
85 |
86 | midxes := make([]ModuleIndex, 0)
87 |
88 | for {
89 | var v ModuleIndex
90 | err := dec.Decode(&v)
91 | if err != nil {
92 | if err == io.EOF {
93 | break
94 | }
95 |
96 | return nil, nil
97 | }
98 |
99 | midxes = append(midxes, v)
100 | }
101 |
102 | return midxes, nil
103 | }
104 |
--------------------------------------------------------------------------------
/pkg/index/mirror_test.go:
--------------------------------------------------------------------------------
1 | package index
2 |
3 | import (
4 | "strings"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func TestModuleIndexParser(t *testing.T) {
10 | raw := "{}\n{}\n{\"Timestamp\":\"2019-04-10T19:08:52.997264Z\"}"
11 |
12 | v, err := ParseModuleIndex(strings.NewReader(raw))
13 |
14 | if err != nil {
15 | t.Fatal(err)
16 | }
17 |
18 | if len(v) != 3 {
19 | t.Fail()
20 | }
21 |
22 | if v[2].Timestamp != time.Date(2019, 04, 10, 19, 8, 52, 997264000, time.UTC) {
23 | t.Fatal(v[2].Timestamp)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/index/types.go:
--------------------------------------------------------------------------------
1 | package index
2 |
3 | import (
4 | "github.com/abiriadev/goggle/pkg/core"
5 | "github.com/repeale/fp-go"
6 | )
7 |
8 | // The central struct for all kind of indexing and searching
9 | type Index struct {
10 | FuncItems []core.FuncDef `json:"func"`
11 | MethodItems []core.MethodDef `json:"met"`
12 | }
13 |
14 | // Create an empty index
15 | func NewIndex() Index {
16 | return Index{make([]core.FuncDef, 0), make([]core.MethodDef, 0)}
17 | }
18 |
19 | func ConcatSliceTo[T any](slices [][]T, dest []T) []T {
20 | for _, sl := range slices {
21 | dest = append(dest, sl...)
22 | }
23 |
24 | return dest
25 | }
26 |
27 | func ConcatSlice[T any](slices [][]T) []T {
28 | r := make([]T, 0)
29 |
30 | for _, sl := range slices {
31 | r = append(r, sl...)
32 | }
33 |
34 | return r
35 | }
36 |
37 | func MergeIndex(idxes []Index) Index {
38 | return Index{
39 | FuncItems: ConcatSlice(
40 | fp.Map(func(idx Index) []core.FuncDef {
41 | return idx.FuncItems
42 | })(idxes),
43 | ),
44 | MethodItems: ConcatSlice(
45 | fp.Map(func(idx Index) []core.MethodDef {
46 | return idx.MethodItems
47 | })(idxes),
48 | ),
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/query/query.go:
--------------------------------------------------------------------------------
1 | package query
2 |
3 | import "github.com/alecthomas/participle/v2"
4 |
5 | type Query struct {
6 | Name string `"func"? @Ident?`
7 | Args []string `"(" ( @Ident ( "," @Ident )* )? ")"`
8 | Ret string `@Ident?`
9 | }
10 |
11 | func QueryParser() (*participle.Parser[Query], error) {
12 | p, err := participle.Build[Query]()
13 | return p, err
14 | }
15 |
16 | func QueryParserUnsafe() *participle.Parser[Query] {
17 | return participle.MustBuild[Query]()
18 | }
19 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | frontend:
10 | dependencies:
11 | '@emotion/react':
12 | specifier: ^11.11.1
13 | version: 11.11.1(@types/react@18.2.42)(react@18.2.0)
14 | '@emotion/styled':
15 | specifier: ^11.11.0
16 | version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.42)(react@18.2.0)
17 | '@mui/icons-material':
18 | specifier: ^5.14.19
19 | version: 5.14.19(@mui/material@5.14.20)(@types/react@18.2.42)(react@18.2.0)
20 | '@mui/material':
21 | specifier: ^5.14.20
22 | version: 5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)
23 | react:
24 | specifier: ^18.2.0
25 | version: 18.2.0
26 | react-dom:
27 | specifier: ^18.2.0
28 | version: 18.2.0(react@18.2.0)
29 | devDependencies:
30 | '@types/react':
31 | specifier: ^18.2.37
32 | version: 18.2.42
33 | '@types/react-dom':
34 | specifier: ^18.2.15
35 | version: 18.2.17
36 | '@vitejs/plugin-react-swc':
37 | specifier: ^3.5.0
38 | version: 3.5.0(vite@5.0.5)
39 | typescript:
40 | specifier: ^5.2.2
41 | version: 5.3.2
42 | vite:
43 | specifier: ^5.0.0
44 | version: 5.0.5
45 |
46 | packages:
47 |
48 | /@babel/code-frame@7.23.5:
49 | resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
50 | engines: {node: '>=6.9.0'}
51 | dependencies:
52 | '@babel/highlight': 7.23.4
53 | chalk: 2.4.2
54 | dev: false
55 |
56 | /@babel/helper-module-imports@7.22.15:
57 | resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
58 | engines: {node: '>=6.9.0'}
59 | dependencies:
60 | '@babel/types': 7.23.5
61 | dev: false
62 |
63 | /@babel/helper-string-parser@7.23.4:
64 | resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
65 | engines: {node: '>=6.9.0'}
66 | dev: false
67 |
68 | /@babel/helper-validator-identifier@7.22.20:
69 | resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
70 | engines: {node: '>=6.9.0'}
71 | dev: false
72 |
73 | /@babel/highlight@7.23.4:
74 | resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
75 | engines: {node: '>=6.9.0'}
76 | dependencies:
77 | '@babel/helper-validator-identifier': 7.22.20
78 | chalk: 2.4.2
79 | js-tokens: 4.0.0
80 | dev: false
81 |
82 | /@babel/runtime@7.23.5:
83 | resolution: {integrity: sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==}
84 | engines: {node: '>=6.9.0'}
85 | dependencies:
86 | regenerator-runtime: 0.14.0
87 | dev: false
88 |
89 | /@babel/types@7.23.5:
90 | resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==}
91 | engines: {node: '>=6.9.0'}
92 | dependencies:
93 | '@babel/helper-string-parser': 7.23.4
94 | '@babel/helper-validator-identifier': 7.22.20
95 | to-fast-properties: 2.0.0
96 | dev: false
97 |
98 | /@emotion/babel-plugin@11.11.0:
99 | resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
100 | dependencies:
101 | '@babel/helper-module-imports': 7.22.15
102 | '@babel/runtime': 7.23.5
103 | '@emotion/hash': 0.9.1
104 | '@emotion/memoize': 0.8.1
105 | '@emotion/serialize': 1.1.2
106 | babel-plugin-macros: 3.1.0
107 | convert-source-map: 1.9.0
108 | escape-string-regexp: 4.0.0
109 | find-root: 1.1.0
110 | source-map: 0.5.7
111 | stylis: 4.2.0
112 | dev: false
113 |
114 | /@emotion/cache@11.11.0:
115 | resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==}
116 | dependencies:
117 | '@emotion/memoize': 0.8.1
118 | '@emotion/sheet': 1.2.2
119 | '@emotion/utils': 1.2.1
120 | '@emotion/weak-memoize': 0.3.1
121 | stylis: 4.2.0
122 | dev: false
123 |
124 | /@emotion/hash@0.9.1:
125 | resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==}
126 | dev: false
127 |
128 | /@emotion/is-prop-valid@1.2.1:
129 | resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==}
130 | dependencies:
131 | '@emotion/memoize': 0.8.1
132 | dev: false
133 |
134 | /@emotion/memoize@0.8.1:
135 | resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==}
136 | dev: false
137 |
138 | /@emotion/react@11.11.1(@types/react@18.2.42)(react@18.2.0):
139 | resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==}
140 | peerDependencies:
141 | '@types/react': '*'
142 | react: '>=16.8.0'
143 | peerDependenciesMeta:
144 | '@types/react':
145 | optional: true
146 | dependencies:
147 | '@babel/runtime': 7.23.5
148 | '@emotion/babel-plugin': 11.11.0
149 | '@emotion/cache': 11.11.0
150 | '@emotion/serialize': 1.1.2
151 | '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0)
152 | '@emotion/utils': 1.2.1
153 | '@emotion/weak-memoize': 0.3.1
154 | '@types/react': 18.2.42
155 | hoist-non-react-statics: 3.3.2
156 | react: 18.2.0
157 | dev: false
158 |
159 | /@emotion/serialize@1.1.2:
160 | resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==}
161 | dependencies:
162 | '@emotion/hash': 0.9.1
163 | '@emotion/memoize': 0.8.1
164 | '@emotion/unitless': 0.8.1
165 | '@emotion/utils': 1.2.1
166 | csstype: 3.1.2
167 | dev: false
168 |
169 | /@emotion/sheet@1.2.2:
170 | resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==}
171 | dev: false
172 |
173 | /@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.2.42)(react@18.2.0):
174 | resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==}
175 | peerDependencies:
176 | '@emotion/react': ^11.0.0-rc.0
177 | '@types/react': '*'
178 | react: '>=16.8.0'
179 | peerDependenciesMeta:
180 | '@types/react':
181 | optional: true
182 | dependencies:
183 | '@babel/runtime': 7.23.5
184 | '@emotion/babel-plugin': 11.11.0
185 | '@emotion/is-prop-valid': 1.2.1
186 | '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0)
187 | '@emotion/serialize': 1.1.2
188 | '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0)
189 | '@emotion/utils': 1.2.1
190 | '@types/react': 18.2.42
191 | react: 18.2.0
192 | dev: false
193 |
194 | /@emotion/unitless@0.8.1:
195 | resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
196 | dev: false
197 |
198 | /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0):
199 | resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
200 | peerDependencies:
201 | react: '>=16.8.0'
202 | dependencies:
203 | react: 18.2.0
204 | dev: false
205 |
206 | /@emotion/utils@1.2.1:
207 | resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==}
208 | dev: false
209 |
210 | /@emotion/weak-memoize@0.3.1:
211 | resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==}
212 | dev: false
213 |
214 | /@esbuild/android-arm64@0.19.8:
215 | resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==}
216 | engines: {node: '>=12'}
217 | cpu: [arm64]
218 | os: [android]
219 | requiresBuild: true
220 | dev: true
221 | optional: true
222 |
223 | /@esbuild/android-arm@0.19.8:
224 | resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==}
225 | engines: {node: '>=12'}
226 | cpu: [arm]
227 | os: [android]
228 | requiresBuild: true
229 | dev: true
230 | optional: true
231 |
232 | /@esbuild/android-x64@0.19.8:
233 | resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==}
234 | engines: {node: '>=12'}
235 | cpu: [x64]
236 | os: [android]
237 | requiresBuild: true
238 | dev: true
239 | optional: true
240 |
241 | /@esbuild/darwin-arm64@0.19.8:
242 | resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==}
243 | engines: {node: '>=12'}
244 | cpu: [arm64]
245 | os: [darwin]
246 | requiresBuild: true
247 | dev: true
248 | optional: true
249 |
250 | /@esbuild/darwin-x64@0.19.8:
251 | resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==}
252 | engines: {node: '>=12'}
253 | cpu: [x64]
254 | os: [darwin]
255 | requiresBuild: true
256 | dev: true
257 | optional: true
258 |
259 | /@esbuild/freebsd-arm64@0.19.8:
260 | resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==}
261 | engines: {node: '>=12'}
262 | cpu: [arm64]
263 | os: [freebsd]
264 | requiresBuild: true
265 | dev: true
266 | optional: true
267 |
268 | /@esbuild/freebsd-x64@0.19.8:
269 | resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==}
270 | engines: {node: '>=12'}
271 | cpu: [x64]
272 | os: [freebsd]
273 | requiresBuild: true
274 | dev: true
275 | optional: true
276 |
277 | /@esbuild/linux-arm64@0.19.8:
278 | resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==}
279 | engines: {node: '>=12'}
280 | cpu: [arm64]
281 | os: [linux]
282 | requiresBuild: true
283 | dev: true
284 | optional: true
285 |
286 | /@esbuild/linux-arm@0.19.8:
287 | resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==}
288 | engines: {node: '>=12'}
289 | cpu: [arm]
290 | os: [linux]
291 | requiresBuild: true
292 | dev: true
293 | optional: true
294 |
295 | /@esbuild/linux-ia32@0.19.8:
296 | resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==}
297 | engines: {node: '>=12'}
298 | cpu: [ia32]
299 | os: [linux]
300 | requiresBuild: true
301 | dev: true
302 | optional: true
303 |
304 | /@esbuild/linux-loong64@0.19.8:
305 | resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==}
306 | engines: {node: '>=12'}
307 | cpu: [loong64]
308 | os: [linux]
309 | requiresBuild: true
310 | dev: true
311 | optional: true
312 |
313 | /@esbuild/linux-mips64el@0.19.8:
314 | resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==}
315 | engines: {node: '>=12'}
316 | cpu: [mips64el]
317 | os: [linux]
318 | requiresBuild: true
319 | dev: true
320 | optional: true
321 |
322 | /@esbuild/linux-ppc64@0.19.8:
323 | resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==}
324 | engines: {node: '>=12'}
325 | cpu: [ppc64]
326 | os: [linux]
327 | requiresBuild: true
328 | dev: true
329 | optional: true
330 |
331 | /@esbuild/linux-riscv64@0.19.8:
332 | resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==}
333 | engines: {node: '>=12'}
334 | cpu: [riscv64]
335 | os: [linux]
336 | requiresBuild: true
337 | dev: true
338 | optional: true
339 |
340 | /@esbuild/linux-s390x@0.19.8:
341 | resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==}
342 | engines: {node: '>=12'}
343 | cpu: [s390x]
344 | os: [linux]
345 | requiresBuild: true
346 | dev: true
347 | optional: true
348 |
349 | /@esbuild/linux-x64@0.19.8:
350 | resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==}
351 | engines: {node: '>=12'}
352 | cpu: [x64]
353 | os: [linux]
354 | requiresBuild: true
355 | dev: true
356 | optional: true
357 |
358 | /@esbuild/netbsd-x64@0.19.8:
359 | resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==}
360 | engines: {node: '>=12'}
361 | cpu: [x64]
362 | os: [netbsd]
363 | requiresBuild: true
364 | dev: true
365 | optional: true
366 |
367 | /@esbuild/openbsd-x64@0.19.8:
368 | resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==}
369 | engines: {node: '>=12'}
370 | cpu: [x64]
371 | os: [openbsd]
372 | requiresBuild: true
373 | dev: true
374 | optional: true
375 |
376 | /@esbuild/sunos-x64@0.19.8:
377 | resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==}
378 | engines: {node: '>=12'}
379 | cpu: [x64]
380 | os: [sunos]
381 | requiresBuild: true
382 | dev: true
383 | optional: true
384 |
385 | /@esbuild/win32-arm64@0.19.8:
386 | resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==}
387 | engines: {node: '>=12'}
388 | cpu: [arm64]
389 | os: [win32]
390 | requiresBuild: true
391 | dev: true
392 | optional: true
393 |
394 | /@esbuild/win32-ia32@0.19.8:
395 | resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==}
396 | engines: {node: '>=12'}
397 | cpu: [ia32]
398 | os: [win32]
399 | requiresBuild: true
400 | dev: true
401 | optional: true
402 |
403 | /@esbuild/win32-x64@0.19.8:
404 | resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==}
405 | engines: {node: '>=12'}
406 | cpu: [x64]
407 | os: [win32]
408 | requiresBuild: true
409 | dev: true
410 | optional: true
411 |
412 | /@floating-ui/core@1.5.2:
413 | resolution: {integrity: sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==}
414 | dependencies:
415 | '@floating-ui/utils': 0.1.6
416 | dev: false
417 |
418 | /@floating-ui/dom@1.5.3:
419 | resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==}
420 | dependencies:
421 | '@floating-ui/core': 1.5.2
422 | '@floating-ui/utils': 0.1.6
423 | dev: false
424 |
425 | /@floating-ui/react-dom@2.0.4(react-dom@18.2.0)(react@18.2.0):
426 | resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==}
427 | peerDependencies:
428 | react: '>=16.8.0'
429 | react-dom: '>=16.8.0'
430 | dependencies:
431 | '@floating-ui/dom': 1.5.3
432 | react: 18.2.0
433 | react-dom: 18.2.0(react@18.2.0)
434 | dev: false
435 |
436 | /@floating-ui/utils@0.1.6:
437 | resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
438 | dev: false
439 |
440 | /@mui/base@5.0.0-beta.26(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0):
441 | resolution: {integrity: sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==}
442 | engines: {node: '>=12.0.0'}
443 | peerDependencies:
444 | '@types/react': ^17.0.0 || ^18.0.0
445 | react: ^17.0.0 || ^18.0.0
446 | react-dom: ^17.0.0 || ^18.0.0
447 | peerDependenciesMeta:
448 | '@types/react':
449 | optional: true
450 | dependencies:
451 | '@babel/runtime': 7.23.5
452 | '@floating-ui/react-dom': 2.0.4(react-dom@18.2.0)(react@18.2.0)
453 | '@mui/types': 7.2.10(@types/react@18.2.42)
454 | '@mui/utils': 5.14.20(@types/react@18.2.42)(react@18.2.0)
455 | '@popperjs/core': 2.11.8
456 | '@types/react': 18.2.42
457 | clsx: 2.0.0
458 | prop-types: 15.8.1
459 | react: 18.2.0
460 | react-dom: 18.2.0(react@18.2.0)
461 | dev: false
462 |
463 | /@mui/core-downloads-tracker@5.14.20:
464 | resolution: {integrity: sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==}
465 | dev: false
466 |
467 | /@mui/icons-material@5.14.19(@mui/material@5.14.20)(@types/react@18.2.42)(react@18.2.0):
468 | resolution: {integrity: sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==}
469 | engines: {node: '>=12.0.0'}
470 | peerDependencies:
471 | '@mui/material': ^5.0.0
472 | '@types/react': ^17.0.0 || ^18.0.0
473 | react: ^17.0.0 || ^18.0.0
474 | peerDependenciesMeta:
475 | '@types/react':
476 | optional: true
477 | dependencies:
478 | '@babel/runtime': 7.23.5
479 | '@mui/material': 5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)
480 | '@types/react': 18.2.42
481 | react: 18.2.0
482 | dev: false
483 |
484 | /@mui/material@5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0):
485 | resolution: {integrity: sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==}
486 | engines: {node: '>=12.0.0'}
487 | peerDependencies:
488 | '@emotion/react': ^11.5.0
489 | '@emotion/styled': ^11.3.0
490 | '@types/react': ^17.0.0 || ^18.0.0
491 | react: ^17.0.0 || ^18.0.0
492 | react-dom: ^17.0.0 || ^18.0.0
493 | peerDependenciesMeta:
494 | '@emotion/react':
495 | optional: true
496 | '@emotion/styled':
497 | optional: true
498 | '@types/react':
499 | optional: true
500 | dependencies:
501 | '@babel/runtime': 7.23.5
502 | '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0)
503 | '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.42)(react@18.2.0)
504 | '@mui/base': 5.0.0-beta.26(@types/react@18.2.42)(react-dom@18.2.0)(react@18.2.0)
505 | '@mui/core-downloads-tracker': 5.14.20
506 | '@mui/system': 5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(react@18.2.0)
507 | '@mui/types': 7.2.10(@types/react@18.2.42)
508 | '@mui/utils': 5.14.20(@types/react@18.2.42)(react@18.2.0)
509 | '@types/react': 18.2.42
510 | '@types/react-transition-group': 4.4.10
511 | clsx: 2.0.0
512 | csstype: 3.1.2
513 | prop-types: 15.8.1
514 | react: 18.2.0
515 | react-dom: 18.2.0(react@18.2.0)
516 | react-is: 18.2.0
517 | react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0)
518 | dev: false
519 |
520 | /@mui/private-theming@5.14.20(@types/react@18.2.42)(react@18.2.0):
521 | resolution: {integrity: sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==}
522 | engines: {node: '>=12.0.0'}
523 | peerDependencies:
524 | '@types/react': ^17.0.0 || ^18.0.0
525 | react: ^17.0.0 || ^18.0.0
526 | peerDependenciesMeta:
527 | '@types/react':
528 | optional: true
529 | dependencies:
530 | '@babel/runtime': 7.23.5
531 | '@mui/utils': 5.14.20(@types/react@18.2.42)(react@18.2.0)
532 | '@types/react': 18.2.42
533 | prop-types: 15.8.1
534 | react: 18.2.0
535 | dev: false
536 |
537 | /@mui/styled-engine@5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0):
538 | resolution: {integrity: sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==}
539 | engines: {node: '>=12.0.0'}
540 | peerDependencies:
541 | '@emotion/react': ^11.4.1
542 | '@emotion/styled': ^11.3.0
543 | react: ^17.0.0 || ^18.0.0
544 | peerDependenciesMeta:
545 | '@emotion/react':
546 | optional: true
547 | '@emotion/styled':
548 | optional: true
549 | dependencies:
550 | '@babel/runtime': 7.23.5
551 | '@emotion/cache': 11.11.0
552 | '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0)
553 | '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.42)(react@18.2.0)
554 | csstype: 3.1.2
555 | prop-types: 15.8.1
556 | react: 18.2.0
557 | dev: false
558 |
559 | /@mui/system@5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.42)(react@18.2.0):
560 | resolution: {integrity: sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==}
561 | engines: {node: '>=12.0.0'}
562 | peerDependencies:
563 | '@emotion/react': ^11.5.0
564 | '@emotion/styled': ^11.3.0
565 | '@types/react': ^17.0.0 || ^18.0.0
566 | react: ^17.0.0 || ^18.0.0
567 | peerDependenciesMeta:
568 | '@emotion/react':
569 | optional: true
570 | '@emotion/styled':
571 | optional: true
572 | '@types/react':
573 | optional: true
574 | dependencies:
575 | '@babel/runtime': 7.23.5
576 | '@emotion/react': 11.11.1(@types/react@18.2.42)(react@18.2.0)
577 | '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.42)(react@18.2.0)
578 | '@mui/private-theming': 5.14.20(@types/react@18.2.42)(react@18.2.0)
579 | '@mui/styled-engine': 5.14.20(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
580 | '@mui/types': 7.2.10(@types/react@18.2.42)
581 | '@mui/utils': 5.14.20(@types/react@18.2.42)(react@18.2.0)
582 | '@types/react': 18.2.42
583 | clsx: 2.0.0
584 | csstype: 3.1.2
585 | prop-types: 15.8.1
586 | react: 18.2.0
587 | dev: false
588 |
589 | /@mui/types@7.2.10(@types/react@18.2.42):
590 | resolution: {integrity: sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==}
591 | peerDependencies:
592 | '@types/react': ^17.0.0 || ^18.0.0
593 | peerDependenciesMeta:
594 | '@types/react':
595 | optional: true
596 | dependencies:
597 | '@types/react': 18.2.42
598 | dev: false
599 |
600 | /@mui/utils@5.14.20(@types/react@18.2.42)(react@18.2.0):
601 | resolution: {integrity: sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==}
602 | engines: {node: '>=12.0.0'}
603 | peerDependencies:
604 | '@types/react': ^17.0.0 || ^18.0.0
605 | react: ^17.0.0 || ^18.0.0
606 | peerDependenciesMeta:
607 | '@types/react':
608 | optional: true
609 | dependencies:
610 | '@babel/runtime': 7.23.5
611 | '@types/prop-types': 15.7.11
612 | '@types/react': 18.2.42
613 | prop-types: 15.8.1
614 | react: 18.2.0
615 | react-is: 18.2.0
616 | dev: false
617 |
618 | /@popperjs/core@2.11.8:
619 | resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
620 | dev: false
621 |
622 | /@rollup/rollup-android-arm-eabi@4.6.1:
623 | resolution: {integrity: sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==}
624 | cpu: [arm]
625 | os: [android]
626 | requiresBuild: true
627 | dev: true
628 | optional: true
629 |
630 | /@rollup/rollup-android-arm64@4.6.1:
631 | resolution: {integrity: sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==}
632 | cpu: [arm64]
633 | os: [android]
634 | requiresBuild: true
635 | dev: true
636 | optional: true
637 |
638 | /@rollup/rollup-darwin-arm64@4.6.1:
639 | resolution: {integrity: sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==}
640 | cpu: [arm64]
641 | os: [darwin]
642 | requiresBuild: true
643 | dev: true
644 | optional: true
645 |
646 | /@rollup/rollup-darwin-x64@4.6.1:
647 | resolution: {integrity: sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==}
648 | cpu: [x64]
649 | os: [darwin]
650 | requiresBuild: true
651 | dev: true
652 | optional: true
653 |
654 | /@rollup/rollup-linux-arm-gnueabihf@4.6.1:
655 | resolution: {integrity: sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==}
656 | cpu: [arm]
657 | os: [linux]
658 | requiresBuild: true
659 | dev: true
660 | optional: true
661 |
662 | /@rollup/rollup-linux-arm64-gnu@4.6.1:
663 | resolution: {integrity: sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==}
664 | cpu: [arm64]
665 | os: [linux]
666 | requiresBuild: true
667 | dev: true
668 | optional: true
669 |
670 | /@rollup/rollup-linux-arm64-musl@4.6.1:
671 | resolution: {integrity: sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==}
672 | cpu: [arm64]
673 | os: [linux]
674 | requiresBuild: true
675 | dev: true
676 | optional: true
677 |
678 | /@rollup/rollup-linux-x64-gnu@4.6.1:
679 | resolution: {integrity: sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==}
680 | cpu: [x64]
681 | os: [linux]
682 | requiresBuild: true
683 | dev: true
684 | optional: true
685 |
686 | /@rollup/rollup-linux-x64-musl@4.6.1:
687 | resolution: {integrity: sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==}
688 | cpu: [x64]
689 | os: [linux]
690 | requiresBuild: true
691 | dev: true
692 | optional: true
693 |
694 | /@rollup/rollup-win32-arm64-msvc@4.6.1:
695 | resolution: {integrity: sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==}
696 | cpu: [arm64]
697 | os: [win32]
698 | requiresBuild: true
699 | dev: true
700 | optional: true
701 |
702 | /@rollup/rollup-win32-ia32-msvc@4.6.1:
703 | resolution: {integrity: sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==}
704 | cpu: [ia32]
705 | os: [win32]
706 | requiresBuild: true
707 | dev: true
708 | optional: true
709 |
710 | /@rollup/rollup-win32-x64-msvc@4.6.1:
711 | resolution: {integrity: sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==}
712 | cpu: [x64]
713 | os: [win32]
714 | requiresBuild: true
715 | dev: true
716 | optional: true
717 |
718 | /@swc/core-darwin-arm64@1.3.100:
719 | resolution: {integrity: sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==}
720 | engines: {node: '>=10'}
721 | cpu: [arm64]
722 | os: [darwin]
723 | requiresBuild: true
724 | dev: true
725 | optional: true
726 |
727 | /@swc/core-darwin-x64@1.3.100:
728 | resolution: {integrity: sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==}
729 | engines: {node: '>=10'}
730 | cpu: [x64]
731 | os: [darwin]
732 | requiresBuild: true
733 | dev: true
734 | optional: true
735 |
736 | /@swc/core-linux-arm64-gnu@1.3.100:
737 | resolution: {integrity: sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==}
738 | engines: {node: '>=10'}
739 | cpu: [arm64]
740 | os: [linux]
741 | requiresBuild: true
742 | dev: true
743 | optional: true
744 |
745 | /@swc/core-linux-arm64-musl@1.3.100:
746 | resolution: {integrity: sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==}
747 | engines: {node: '>=10'}
748 | cpu: [arm64]
749 | os: [linux]
750 | requiresBuild: true
751 | dev: true
752 | optional: true
753 |
754 | /@swc/core-linux-x64-gnu@1.3.100:
755 | resolution: {integrity: sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==}
756 | engines: {node: '>=10'}
757 | cpu: [x64]
758 | os: [linux]
759 | requiresBuild: true
760 | dev: true
761 | optional: true
762 |
763 | /@swc/core-linux-x64-musl@1.3.100:
764 | resolution: {integrity: sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==}
765 | engines: {node: '>=10'}
766 | cpu: [x64]
767 | os: [linux]
768 | requiresBuild: true
769 | dev: true
770 | optional: true
771 |
772 | /@swc/core-win32-arm64-msvc@1.3.100:
773 | resolution: {integrity: sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==}
774 | engines: {node: '>=10'}
775 | cpu: [arm64]
776 | os: [win32]
777 | requiresBuild: true
778 | dev: true
779 | optional: true
780 |
781 | /@swc/core-win32-ia32-msvc@1.3.100:
782 | resolution: {integrity: sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==}
783 | engines: {node: '>=10'}
784 | cpu: [ia32]
785 | os: [win32]
786 | requiresBuild: true
787 | dev: true
788 | optional: true
789 |
790 | /@swc/core-win32-x64-msvc@1.3.100:
791 | resolution: {integrity: sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==}
792 | engines: {node: '>=10'}
793 | cpu: [x64]
794 | os: [win32]
795 | requiresBuild: true
796 | dev: true
797 | optional: true
798 |
799 | /@swc/core@1.3.100:
800 | resolution: {integrity: sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==}
801 | engines: {node: '>=10'}
802 | requiresBuild: true
803 | peerDependencies:
804 | '@swc/helpers': ^0.5.0
805 | peerDependenciesMeta:
806 | '@swc/helpers':
807 | optional: true
808 | dependencies:
809 | '@swc/counter': 0.1.2
810 | '@swc/types': 0.1.5
811 | optionalDependencies:
812 | '@swc/core-darwin-arm64': 1.3.100
813 | '@swc/core-darwin-x64': 1.3.100
814 | '@swc/core-linux-arm64-gnu': 1.3.100
815 | '@swc/core-linux-arm64-musl': 1.3.100
816 | '@swc/core-linux-x64-gnu': 1.3.100
817 | '@swc/core-linux-x64-musl': 1.3.100
818 | '@swc/core-win32-arm64-msvc': 1.3.100
819 | '@swc/core-win32-ia32-msvc': 1.3.100
820 | '@swc/core-win32-x64-msvc': 1.3.100
821 | dev: true
822 |
823 | /@swc/counter@0.1.2:
824 | resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==}
825 | dev: true
826 |
827 | /@swc/types@0.1.5:
828 | resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
829 | dev: true
830 |
831 | /@types/parse-json@4.0.2:
832 | resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
833 | dev: false
834 |
835 | /@types/prop-types@15.7.11:
836 | resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
837 |
838 | /@types/react-dom@18.2.17:
839 | resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==}
840 | dependencies:
841 | '@types/react': 18.2.42
842 | dev: true
843 |
844 | /@types/react-transition-group@4.4.10:
845 | resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==}
846 | dependencies:
847 | '@types/react': 18.2.42
848 | dev: false
849 |
850 | /@types/react@18.2.42:
851 | resolution: {integrity: sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==}
852 | dependencies:
853 | '@types/prop-types': 15.7.11
854 | '@types/scheduler': 0.16.8
855 | csstype: 3.1.2
856 |
857 | /@types/scheduler@0.16.8:
858 | resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
859 |
860 | /@vitejs/plugin-react-swc@3.5.0(vite@5.0.5):
861 | resolution: {integrity: sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==}
862 | peerDependencies:
863 | vite: ^4 || ^5
864 | dependencies:
865 | '@swc/core': 1.3.100
866 | vite: 5.0.5
867 | transitivePeerDependencies:
868 | - '@swc/helpers'
869 | dev: true
870 |
871 | /ansi-styles@3.2.1:
872 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
873 | engines: {node: '>=4'}
874 | dependencies:
875 | color-convert: 1.9.3
876 | dev: false
877 |
878 | /babel-plugin-macros@3.1.0:
879 | resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
880 | engines: {node: '>=10', npm: '>=6'}
881 | dependencies:
882 | '@babel/runtime': 7.23.5
883 | cosmiconfig: 7.1.0
884 | resolve: 1.22.8
885 | dev: false
886 |
887 | /callsites@3.1.0:
888 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
889 | engines: {node: '>=6'}
890 | dev: false
891 |
892 | /chalk@2.4.2:
893 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
894 | engines: {node: '>=4'}
895 | dependencies:
896 | ansi-styles: 3.2.1
897 | escape-string-regexp: 1.0.5
898 | supports-color: 5.5.0
899 | dev: false
900 |
901 | /clsx@2.0.0:
902 | resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
903 | engines: {node: '>=6'}
904 | dev: false
905 |
906 | /color-convert@1.9.3:
907 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
908 | dependencies:
909 | color-name: 1.1.3
910 | dev: false
911 |
912 | /color-name@1.1.3:
913 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
914 | dev: false
915 |
916 | /convert-source-map@1.9.0:
917 | resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
918 | dev: false
919 |
920 | /cosmiconfig@7.1.0:
921 | resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
922 | engines: {node: '>=10'}
923 | dependencies:
924 | '@types/parse-json': 4.0.2
925 | import-fresh: 3.3.0
926 | parse-json: 5.2.0
927 | path-type: 4.0.0
928 | yaml: 1.10.2
929 | dev: false
930 |
931 | /csstype@3.1.2:
932 | resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
933 |
934 | /dom-helpers@5.2.1:
935 | resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
936 | dependencies:
937 | '@babel/runtime': 7.23.5
938 | csstype: 3.1.2
939 | dev: false
940 |
941 | /error-ex@1.3.2:
942 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
943 | dependencies:
944 | is-arrayish: 0.2.1
945 | dev: false
946 |
947 | /esbuild@0.19.8:
948 | resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==}
949 | engines: {node: '>=12'}
950 | hasBin: true
951 | requiresBuild: true
952 | optionalDependencies:
953 | '@esbuild/android-arm': 0.19.8
954 | '@esbuild/android-arm64': 0.19.8
955 | '@esbuild/android-x64': 0.19.8
956 | '@esbuild/darwin-arm64': 0.19.8
957 | '@esbuild/darwin-x64': 0.19.8
958 | '@esbuild/freebsd-arm64': 0.19.8
959 | '@esbuild/freebsd-x64': 0.19.8
960 | '@esbuild/linux-arm': 0.19.8
961 | '@esbuild/linux-arm64': 0.19.8
962 | '@esbuild/linux-ia32': 0.19.8
963 | '@esbuild/linux-loong64': 0.19.8
964 | '@esbuild/linux-mips64el': 0.19.8
965 | '@esbuild/linux-ppc64': 0.19.8
966 | '@esbuild/linux-riscv64': 0.19.8
967 | '@esbuild/linux-s390x': 0.19.8
968 | '@esbuild/linux-x64': 0.19.8
969 | '@esbuild/netbsd-x64': 0.19.8
970 | '@esbuild/openbsd-x64': 0.19.8
971 | '@esbuild/sunos-x64': 0.19.8
972 | '@esbuild/win32-arm64': 0.19.8
973 | '@esbuild/win32-ia32': 0.19.8
974 | '@esbuild/win32-x64': 0.19.8
975 | dev: true
976 |
977 | /escape-string-regexp@1.0.5:
978 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
979 | engines: {node: '>=0.8.0'}
980 | dev: false
981 |
982 | /escape-string-regexp@4.0.0:
983 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
984 | engines: {node: '>=10'}
985 | dev: false
986 |
987 | /find-root@1.1.0:
988 | resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
989 | dev: false
990 |
991 | /fsevents@2.3.3:
992 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
993 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
994 | os: [darwin]
995 | requiresBuild: true
996 | dev: true
997 | optional: true
998 |
999 | /function-bind@1.1.2:
1000 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
1001 | dev: false
1002 |
1003 | /has-flag@3.0.0:
1004 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
1005 | engines: {node: '>=4'}
1006 | dev: false
1007 |
1008 | /hasown@2.0.0:
1009 | resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
1010 | engines: {node: '>= 0.4'}
1011 | dependencies:
1012 | function-bind: 1.1.2
1013 | dev: false
1014 |
1015 | /hoist-non-react-statics@3.3.2:
1016 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
1017 | dependencies:
1018 | react-is: 16.13.1
1019 | dev: false
1020 |
1021 | /import-fresh@3.3.0:
1022 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
1023 | engines: {node: '>=6'}
1024 | dependencies:
1025 | parent-module: 1.0.1
1026 | resolve-from: 4.0.0
1027 | dev: false
1028 |
1029 | /is-arrayish@0.2.1:
1030 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
1031 | dev: false
1032 |
1033 | /is-core-module@2.13.1:
1034 | resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
1035 | dependencies:
1036 | hasown: 2.0.0
1037 | dev: false
1038 |
1039 | /js-tokens@4.0.0:
1040 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
1041 | dev: false
1042 |
1043 | /json-parse-even-better-errors@2.3.1:
1044 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
1045 | dev: false
1046 |
1047 | /lines-and-columns@1.2.4:
1048 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
1049 | dev: false
1050 |
1051 | /loose-envify@1.4.0:
1052 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
1053 | hasBin: true
1054 | dependencies:
1055 | js-tokens: 4.0.0
1056 | dev: false
1057 |
1058 | /nanoid@3.3.7:
1059 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
1060 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1061 | hasBin: true
1062 | dev: true
1063 |
1064 | /object-assign@4.1.1:
1065 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
1066 | engines: {node: '>=0.10.0'}
1067 | dev: false
1068 |
1069 | /parent-module@1.0.1:
1070 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
1071 | engines: {node: '>=6'}
1072 | dependencies:
1073 | callsites: 3.1.0
1074 | dev: false
1075 |
1076 | /parse-json@5.2.0:
1077 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
1078 | engines: {node: '>=8'}
1079 | dependencies:
1080 | '@babel/code-frame': 7.23.5
1081 | error-ex: 1.3.2
1082 | json-parse-even-better-errors: 2.3.1
1083 | lines-and-columns: 1.2.4
1084 | dev: false
1085 |
1086 | /path-parse@1.0.7:
1087 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
1088 | dev: false
1089 |
1090 | /path-type@4.0.0:
1091 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
1092 | engines: {node: '>=8'}
1093 | dev: false
1094 |
1095 | /picocolors@1.0.0:
1096 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
1097 | dev: true
1098 |
1099 | /postcss@8.4.32:
1100 | resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==}
1101 | engines: {node: ^10 || ^12 || >=14}
1102 | dependencies:
1103 | nanoid: 3.3.7
1104 | picocolors: 1.0.0
1105 | source-map-js: 1.0.2
1106 | dev: true
1107 |
1108 | /prop-types@15.8.1:
1109 | resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
1110 | dependencies:
1111 | loose-envify: 1.4.0
1112 | object-assign: 4.1.1
1113 | react-is: 16.13.1
1114 | dev: false
1115 |
1116 | /react-dom@18.2.0(react@18.2.0):
1117 | resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
1118 | peerDependencies:
1119 | react: ^18.2.0
1120 | dependencies:
1121 | loose-envify: 1.4.0
1122 | react: 18.2.0
1123 | scheduler: 0.23.0
1124 | dev: false
1125 |
1126 | /react-is@16.13.1:
1127 | resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
1128 | dev: false
1129 |
1130 | /react-is@18.2.0:
1131 | resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
1132 | dev: false
1133 |
1134 | /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0):
1135 | resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
1136 | peerDependencies:
1137 | react: '>=16.6.0'
1138 | react-dom: '>=16.6.0'
1139 | dependencies:
1140 | '@babel/runtime': 7.23.5
1141 | dom-helpers: 5.2.1
1142 | loose-envify: 1.4.0
1143 | prop-types: 15.8.1
1144 | react: 18.2.0
1145 | react-dom: 18.2.0(react@18.2.0)
1146 | dev: false
1147 |
1148 | /react@18.2.0:
1149 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
1150 | engines: {node: '>=0.10.0'}
1151 | dependencies:
1152 | loose-envify: 1.4.0
1153 | dev: false
1154 |
1155 | /regenerator-runtime@0.14.0:
1156 | resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
1157 | dev: false
1158 |
1159 | /resolve-from@4.0.0:
1160 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
1161 | engines: {node: '>=4'}
1162 | dev: false
1163 |
1164 | /resolve@1.22.8:
1165 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
1166 | hasBin: true
1167 | dependencies:
1168 | is-core-module: 2.13.1
1169 | path-parse: 1.0.7
1170 | supports-preserve-symlinks-flag: 1.0.0
1171 | dev: false
1172 |
1173 | /rollup@4.6.1:
1174 | resolution: {integrity: sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==}
1175 | engines: {node: '>=18.0.0', npm: '>=8.0.0'}
1176 | hasBin: true
1177 | optionalDependencies:
1178 | '@rollup/rollup-android-arm-eabi': 4.6.1
1179 | '@rollup/rollup-android-arm64': 4.6.1
1180 | '@rollup/rollup-darwin-arm64': 4.6.1
1181 | '@rollup/rollup-darwin-x64': 4.6.1
1182 | '@rollup/rollup-linux-arm-gnueabihf': 4.6.1
1183 | '@rollup/rollup-linux-arm64-gnu': 4.6.1
1184 | '@rollup/rollup-linux-arm64-musl': 4.6.1
1185 | '@rollup/rollup-linux-x64-gnu': 4.6.1
1186 | '@rollup/rollup-linux-x64-musl': 4.6.1
1187 | '@rollup/rollup-win32-arm64-msvc': 4.6.1
1188 | '@rollup/rollup-win32-ia32-msvc': 4.6.1
1189 | '@rollup/rollup-win32-x64-msvc': 4.6.1
1190 | fsevents: 2.3.3
1191 | dev: true
1192 |
1193 | /scheduler@0.23.0:
1194 | resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
1195 | dependencies:
1196 | loose-envify: 1.4.0
1197 | dev: false
1198 |
1199 | /source-map-js@1.0.2:
1200 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
1201 | engines: {node: '>=0.10.0'}
1202 | dev: true
1203 |
1204 | /source-map@0.5.7:
1205 | resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
1206 | engines: {node: '>=0.10.0'}
1207 | dev: false
1208 |
1209 | /stylis@4.2.0:
1210 | resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
1211 | dev: false
1212 |
1213 | /supports-color@5.5.0:
1214 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
1215 | engines: {node: '>=4'}
1216 | dependencies:
1217 | has-flag: 3.0.0
1218 | dev: false
1219 |
1220 | /supports-preserve-symlinks-flag@1.0.0:
1221 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1222 | engines: {node: '>= 0.4'}
1223 | dev: false
1224 |
1225 | /to-fast-properties@2.0.0:
1226 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
1227 | engines: {node: '>=4'}
1228 | dev: false
1229 |
1230 | /typescript@5.3.2:
1231 | resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
1232 | engines: {node: '>=14.17'}
1233 | hasBin: true
1234 | dev: true
1235 |
1236 | /vite@5.0.5:
1237 | resolution: {integrity: sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==}
1238 | engines: {node: ^18.0.0 || >=20.0.0}
1239 | hasBin: true
1240 | peerDependencies:
1241 | '@types/node': ^18.0.0 || >=20.0.0
1242 | less: '*'
1243 | lightningcss: ^1.21.0
1244 | sass: '*'
1245 | stylus: '*'
1246 | sugarss: '*'
1247 | terser: ^5.4.0
1248 | peerDependenciesMeta:
1249 | '@types/node':
1250 | optional: true
1251 | less:
1252 | optional: true
1253 | lightningcss:
1254 | optional: true
1255 | sass:
1256 | optional: true
1257 | stylus:
1258 | optional: true
1259 | sugarss:
1260 | optional: true
1261 | terser:
1262 | optional: true
1263 | dependencies:
1264 | esbuild: 0.19.8
1265 | postcss: 8.4.32
1266 | rollup: 4.6.1
1267 | optionalDependencies:
1268 | fsevents: 2.3.3
1269 | dev: true
1270 |
1271 | /yaml@1.10.2:
1272 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
1273 | engines: {node: '>= 6'}
1274 | dev: false
1275 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - frontend
3 |
--------------------------------------------------------------------------------
/wasm/syntaxck/main.go:
--------------------------------------------------------------------------------
1 | //go:build wasm
2 |
3 | package main
4 |
5 | import (
6 | "syscall/js"
7 |
8 | "github.com/abiriadev/goggle/pkg/query"
9 | )
10 |
11 | // global-lifetime query parser
12 | // TODO: use closure later?
13 | var qp = query.QueryParserUnsafe()
14 |
15 | func main() {
16 | js.Global().Set("syntaxck", js.FuncOf(syntaxckSys))
17 |
18 | <-make(chan struct{}, 0)
19 | }
20 |
21 | // string -> bool
22 | func syntaxckSys(_ js.Value, args []js.Value) any {
23 | // SAFETY: check array boundaries
24 | if len(args) != 1 {
25 | return "only one argument needed"
26 | }
27 |
28 | return syntaxck(args[0].String())
29 | }
30 |
31 | func syntaxck(query string) bool {
32 | _, err := qp.ParseString("", query)
33 | return err == nil
34 | }
35 |
--------------------------------------------------------------------------------