diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..3f96633e
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,41 @@
+name: "Goreleaser"
+
+on:
+ push:
+ tags:
+ - "v*"
+permissions:
+ contents: write
+
+jobs:
+ build-and-push:
+ runs-on: [self-hosted, linux]
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Set up Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+
+ - name: Node Build
+ run: make install-ui-packages ui
+
+ - name: Setup Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.19
+ - name: Run GoReleaser
+ uses: goreleaser/goreleaser-action@v4
+ with:
+ distribution: goreleaser
+ version: latest
+ args: release --rm-dist
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - uses: actions/upload-artifact@v3
+ with:
+ name: answer
+ path: ./dist/*
diff --git a/.github/workflows/build_dockerhub_img.yml b/.github/workflows/build_dockerhub_img.yml
index a176b322..07c5a0a9 100644
--- a/.github/workflows/build_dockerhub_img.yml
+++ b/.github/workflows/build_dockerhub_img.yml
@@ -12,7 +12,7 @@ on:
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: [self-hosted, linux]
steps:
- name: Checkout
uses: actions/checkout@v3
diff --git a/.github/workflows/build_github_img.yml b/.github/workflows/build_github_img.yml
index 358a296b..67fe28ea 100644
--- a/.github/workflows/build_github_img.yml
+++ b/.github/workflows/build_github_img.yml
@@ -17,7 +17,7 @@ env:
jobs:
build-and-push:
- runs-on: ubuntu-latest
+ runs-on: [self-hosted, linux]
permissions:
packages: write
diff --git a/.github/workflows/go_build_test.yml b/.github/workflows/go_build_test.yml
index ecd2f4f0..21045786 100644
--- a/.github/workflows/go_build_test.yml
+++ b/.github/workflows/go_build_test.yml
@@ -9,7 +9,7 @@ on:
jobs:
build-and-push:
- runs-on: ubuntu-latest
+ runs-on: [self-hosted, linux]
steps:
- name: Checkout
diff --git a/.github/workflows/node_build_test.yml b/.github/workflows/node_build_test.yml
index edf5b8cb..41c2c4c6 100644
--- a/.github/workflows/node_build_test.yml
+++ b/.github/workflows/node_build_test.yml
@@ -8,8 +8,7 @@ on:
jobs:
build-and-push:
- runs-on: ubuntu-latest
-
+ runs-on: [self-hosted, linux]
steps:
- name: Checkout
uses: actions/checkout@v3
diff --git a/.gitignore b/.gitignore
index 5776cd0c..c762475f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,8 +15,11 @@
/configs/config-dev.yaml
/go.work*
/logs
-/ui/build
/ui/node_modules
+/ui/build/*/*/*
+/ui/build/*.json
+/ui/build/*.html
+/ui/build/*.txt
/vendor
Thumbs*.db
tmp
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 18cbbd55..9feb6d72 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -2,7 +2,7 @@ env:
- GO11MODULE=on
- GO111MODULE=on
- GOPROXY=https://goproxy.io
- - CGO_ENABLED=1
+ - CGO_ENABLED=0
before:
hooks:
@@ -16,74 +16,48 @@ builds:
- linux
goarch:
- amd64
- # linux windows need cgomingw64-gcc
- id: build-windows
main: ./cmd/answer/.
binary: answer
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
- env:
- - CC=x86_64-w64-mingw32-gcc
- - CXX=x86_64-w64-mingw32-g++
goos:
- windows
goarch:
- amd64
- # linux arm64 need cgo arm64
- id: build-arm64
main: ./cmd/answer/.
binary: answer
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
- env:
- - CC=aarch64-linux-gnu-gcc
- - CXX=aarch64-linux-gnu-g++
goos:
- linux
goarch:
- - arm64
- - id: build-arm7
- main: ./cmd/answer/.
- binary: answer
- ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
- env:
- - CC=arm-linux-gnueabihf-gcc
- - CXX=arm-linux-gnueabihf-g++
- - AR=arm-linux-gnueabihf-ar
- goos:
- - linux
- goarch:
- - arm
- goarm:
- - 7
+ - arm64
- id: build-darwin-arm64
main: ./cmd/answer/.
binary: answer
- env:
- - CC=oa64-clang
- - CXX=oa64-clang++
goos:
- darwin
goarch:
- arm64
- ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
+ ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
flags: -v
- id: build-darwin-amd64
main: ./cmd/answer/.
binary: answer
- env:
- - CC=o64-clang
- - CXX=o64-clang++
goos:
- darwin
goarch:
- amd64
- ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
+ ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
flags: -v
archives:
- replacements:
- darwin: Darwin
+ darwin: macOS
amd64: x86_64
+ linux: Linux
+ windows: Windows
checksum:
name_template: 'checksums.txt'
snapshot:
@@ -95,10 +69,4 @@ changelog:
- '^docs:'
- '^test:'
-
-# sudo apt-get install build-essential
-# sudo apt-get install gcc-multilib g++-multilib
-# sudo apt-get install gcc-mingw-w64
-# sudo apt-get -y install gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf
-# sudo apt-get install clang llvm
-# goreleaser release --snapshot --rm-dist
\ No newline at end of file
+# goreleaser release --snapshot --rm-dist
diff --git a/Makefile b/Makefile
index d5c46a40..dd7c76d5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,30 +1,32 @@
.PHONY: build clean ui
-VERSION=1.0.3
+VERSION=1.0.4
BIN=answer
DIR_SRC=./cmd/answer
DOCKER_CMD=docker
-#GO_ENV=CGO_ENABLED=0
+GO_ENV=CGO_ENABLED=0 GO111MODULE=on
Revision=$(shell git rev-parse --short HEAD)
GO_FLAGS=-ldflags="-X main.Version=$(VERSION) -X 'main.Revision=$(Revision)' -X 'main.Time=`date`' -extldflags -static"
GO=$(GO_ENV) $(shell which go)
-build:
- @$(GO_ENV) $(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC)
+build: generate
+ @$(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC)
# https://dev.to/thewraven/universal-macos-binaries-with-go-1-16-3mm3
-universal:
+universal: generate
@GOOS=darwin GOARCH=amd64 $(GO_ENV) $(GO) build $(GO_FLAGS) -o ${BIN}_amd64 $(DIR_SRC)
@GOOS=darwin GOARCH=arm64 $(GO_ENV) $(GO) build $(GO_FLAGS) -o ${BIN}_arm64 $(DIR_SRC)
@lipo -create -output ${BIN} ${BIN}_amd64 ${BIN}_arm64
@rm -f ${BIN}_amd64 ${BIN}_arm64
generate:
- go get github.com/google/wire/cmd/wire@latest
- go install github.com/golang/mock/mockgen@v1.6.0
- go generate ./...
- go mod tidy
+ @$(GO) get github.com/google/wire/cmd/wire@v0.5.0
+ @$(GO) get github.com/golang/mock/mockgen@v1.6.0
+ @$(GO) install github.com/google/wire/cmd/wire@v0.5.0
+ @$(GO) install github.com/golang/mock/mockgen@v1.6.0
+ @$(GO) generate ./...
+ @$(GO) mod tidy
test:
@$(GO) test ./internal/repo/repo_test
@@ -39,6 +41,6 @@ install-ui-packages:
@corepack prepare pnpm@v7.12.2 --activate
ui:
- @cd ui && pnpm install && pnpm build && cd -
+ @cd ui && pnpm install && pnpm build && sed -i 's/%AnswerVersion%/'$(VERSION)'/g' ./build/index.html && cd -
all: clean build
diff --git a/docs/docs.go b/docs/docs.go
index cce01432..3adfd474 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -2911,6 +2911,45 @@ const docTemplate = `{
}
}
},
+ "/answer/api/v1/post/render": {
+ "post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "render post content",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Upload"
+ ],
+ "summary": "render post content",
+ "parameters": [
+ {
+ "description": "PostRenderReq",
+ "name": "data",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/schema.PostRenderReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/handler.RespBody"
+ }
+ }
+ }
+ }
+ },
"/answer/api/v1/question": {
"put": {
"security": [
@@ -5425,8 +5464,7 @@ const docTemplate = `{
"type": "object",
"required": [
"object_id",
- "original_text",
- "parsed_text"
+ "original_text"
],
"properties": {
"mention_username_list": {
@@ -5442,11 +5480,9 @@ const docTemplate = `{
},
"original_text": {
"description": "original comment content",
- "type": "string"
- },
- "parsed_text": {
- "description": "parsed comment content",
- "type": "string"
+ "type": "string",
+ "maxLength": 600,
+ "minLength": 2
},
"reply_comment_id": {
"description": "reply comment id",
@@ -5535,46 +5571,41 @@ const docTemplate = `{
},
"schema.AnswerAddReq": {
"type": "object",
+ "required": [
+ "content"
+ ],
"properties": {
"content": {
- "description": "content",
- "type": "string"
- },
- "html": {
- "description": "html",
- "type": "string"
+ "type": "string",
+ "maxLength": 65535,
+ "minLength": 6
},
"question_id": {
- "description": "question_id",
"type": "string"
}
}
},
"schema.AnswerUpdateReq": {
"type": "object",
+ "required": [
+ "content"
+ ],
"properties": {
"content": {
- "description": "content",
- "type": "string"
+ "type": "string",
+ "maxLength": 65535,
+ "minLength": 6
},
"edit_summary": {
- "description": "edit_summary",
- "type": "string"
- },
- "html": {
- "description": "html",
"type": "string"
},
"id": {
- "description": "id",
"type": "string"
},
"question_id": {
- "description": "question_id",
"type": "string"
},
"title": {
- "description": "title",
"type": "string"
}
}
@@ -6589,11 +6620,18 @@ const docTemplate = `{
}
}
},
+ "schema.PostRenderReq": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "string"
+ }
+ }
+ },
"schema.QuestionAdd": {
"type": "object",
"required": [
"content",
- "html",
"tags",
"title"
],
@@ -6604,12 +6642,6 @@ const docTemplate = `{
"maxLength": 65535,
"minLength": 6
},
- "html": {
- "description": "html",
- "type": "string",
- "maxLength": 65535,
- "minLength": 6
- },
"tags": {
"description": "tags",
"type": "array",
@@ -6669,6 +6701,9 @@ const docTemplate = `{
"collection_count": {
"type": "integer"
},
+ "created_at": {
+ "type": "integer"
+ },
"description": {
"type": "string"
},
@@ -6739,7 +6774,6 @@ const docTemplate = `{
"type": "object",
"required": [
"content",
- "html",
"id",
"tags",
"title"
@@ -6755,12 +6789,6 @@ const docTemplate = `{
"description": "edit summary",
"type": "string"
},
- "html": {
- "description": "html",
- "type": "string",
- "maxLength": 65535,
- "minLength": 6
- },
"id": {
"description": "question id",
"type": "string"
@@ -7326,10 +7354,6 @@ const docTemplate = `{
"description": "original text",
"type": "string"
},
- "parsed_text": {
- "description": "parsed text",
- "type": "string"
- },
"slug_name": {
"description": "slug_name",
"type": "string",
@@ -7416,7 +7440,8 @@ const docTemplate = `{
"schema.UpdateCommentReq": {
"type": "object",
"required": [
- "comment_id"
+ "comment_id",
+ "original_text"
],
"properties": {
"comment_id": {
@@ -7425,11 +7450,9 @@ const docTemplate = `{
},
"original_text": {
"description": "original comment content",
- "type": "string"
- },
- "parsed_text": {
- "description": "parsed comment content",
- "type": "string"
+ "type": "string",
+ "maxLength": 600,
+ "minLength": 2
}
}
},
@@ -7460,11 +7483,6 @@ const docTemplate = `{
"type": "string",
"maxLength": 4096
},
- "bio_html": {
- "description": "bio",
- "type": "string",
- "maxLength": 4096
- },
"display_name": {
"description": "display_name",
"type": "string",
@@ -7549,10 +7567,6 @@ const docTemplate = `{
"description": "original text",
"type": "string"
},
- "parsed_text": {
- "description": "parsed text",
- "type": "string"
- },
"slug_name": {
"description": "slug_name",
"type": "string",
diff --git a/docs/swagger.json b/docs/swagger.json
index 3503fce7..0282b612 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -2899,6 +2899,45 @@
}
}
},
+ "/answer/api/v1/post/render": {
+ "post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "render post content",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Upload"
+ ],
+ "summary": "render post content",
+ "parameters": [
+ {
+ "description": "PostRenderReq",
+ "name": "data",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/schema.PostRenderReq"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/handler.RespBody"
+ }
+ }
+ }
+ }
+ },
"/answer/api/v1/question": {
"put": {
"security": [
@@ -5413,8 +5452,7 @@
"type": "object",
"required": [
"object_id",
- "original_text",
- "parsed_text"
+ "original_text"
],
"properties": {
"mention_username_list": {
@@ -5430,11 +5468,9 @@
},
"original_text": {
"description": "original comment content",
- "type": "string"
- },
- "parsed_text": {
- "description": "parsed comment content",
- "type": "string"
+ "type": "string",
+ "maxLength": 600,
+ "minLength": 2
},
"reply_comment_id": {
"description": "reply comment id",
@@ -5523,46 +5559,41 @@
},
"schema.AnswerAddReq": {
"type": "object",
+ "required": [
+ "content"
+ ],
"properties": {
"content": {
- "description": "content",
- "type": "string"
- },
- "html": {
- "description": "html",
- "type": "string"
+ "type": "string",
+ "maxLength": 65535,
+ "minLength": 6
},
"question_id": {
- "description": "question_id",
"type": "string"
}
}
},
"schema.AnswerUpdateReq": {
"type": "object",
+ "required": [
+ "content"
+ ],
"properties": {
"content": {
- "description": "content",
- "type": "string"
+ "type": "string",
+ "maxLength": 65535,
+ "minLength": 6
},
"edit_summary": {
- "description": "edit_summary",
- "type": "string"
- },
- "html": {
- "description": "html",
"type": "string"
},
"id": {
- "description": "id",
"type": "string"
},
"question_id": {
- "description": "question_id",
"type": "string"
},
"title": {
- "description": "title",
"type": "string"
}
}
@@ -6577,11 +6608,18 @@
}
}
},
+ "schema.PostRenderReq": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "string"
+ }
+ }
+ },
"schema.QuestionAdd": {
"type": "object",
"required": [
"content",
- "html",
"tags",
"title"
],
@@ -6592,12 +6630,6 @@
"maxLength": 65535,
"minLength": 6
},
- "html": {
- "description": "html",
- "type": "string",
- "maxLength": 65535,
- "minLength": 6
- },
"tags": {
"description": "tags",
"type": "array",
@@ -6657,6 +6689,9 @@
"collection_count": {
"type": "integer"
},
+ "created_at": {
+ "type": "integer"
+ },
"description": {
"type": "string"
},
@@ -6727,7 +6762,6 @@
"type": "object",
"required": [
"content",
- "html",
"id",
"tags",
"title"
@@ -6743,12 +6777,6 @@
"description": "edit summary",
"type": "string"
},
- "html": {
- "description": "html",
- "type": "string",
- "maxLength": 65535,
- "minLength": 6
- },
"id": {
"description": "question id",
"type": "string"
@@ -7314,10 +7342,6 @@
"description": "original text",
"type": "string"
},
- "parsed_text": {
- "description": "parsed text",
- "type": "string"
- },
"slug_name": {
"description": "slug_name",
"type": "string",
@@ -7404,7 +7428,8 @@
"schema.UpdateCommentReq": {
"type": "object",
"required": [
- "comment_id"
+ "comment_id",
+ "original_text"
],
"properties": {
"comment_id": {
@@ -7413,11 +7438,9 @@
},
"original_text": {
"description": "original comment content",
- "type": "string"
- },
- "parsed_text": {
- "description": "parsed comment content",
- "type": "string"
+ "type": "string",
+ "maxLength": 600,
+ "minLength": 2
}
}
},
@@ -7448,11 +7471,6 @@
"type": "string",
"maxLength": 4096
},
- "bio_html": {
- "description": "bio",
- "type": "string",
- "maxLength": 4096
- },
"display_name": {
"description": "display_name",
"type": "string",
@@ -7537,10 +7555,6 @@
"description": "original text",
"type": "string"
},
- "parsed_text": {
- "description": "parsed text",
- "type": "string"
- },
"slug_name": {
"description": "slug_name",
"type": "string",
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index b02e9494..3fac2ae0 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -147,9 +147,8 @@ definitions:
type: string
original_text:
description: original comment content
- type: string
- parsed_text:
- description: parsed comment content
+ maxLength: 600
+ minLength: 2
type: string
reply_comment_id:
description: reply comment id
@@ -157,7 +156,6 @@ definitions:
required:
- object_id
- original_text
- - parsed_text
type: object
schema.AddReportReq:
properties:
@@ -217,35 +215,30 @@ definitions:
schema.AnswerAddReq:
properties:
content:
- description: content
- type: string
- html:
- description: html
+ maxLength: 65535
+ minLength: 6
type: string
question_id:
- description: question_id
type: string
+ required:
+ - content
type: object
schema.AnswerUpdateReq:
properties:
content:
- description: content
+ maxLength: 65535
+ minLength: 6
type: string
edit_summary:
- description: edit_summary
- type: string
- html:
- description: html
type: string
id:
- description: id
type: string
question_id:
- description: question_id
type: string
title:
- description: title
type: string
+ required:
+ - content
type: object
schema.AvatarInfo:
properties:
@@ -976,6 +969,11 @@ definitions:
type:
type: string
type: object
+ schema.PostRenderReq:
+ properties:
+ content:
+ type: string
+ type: object
schema.QuestionAdd:
properties:
content:
@@ -983,11 +981,6 @@ definitions:
maxLength: 65535
minLength: 6
type: string
- html:
- description: html
- maxLength: 65535
- minLength: 6
- type: string
tags:
description: tags
items:
@@ -1000,7 +993,6 @@ definitions:
type: string
required:
- content
- - html
- tags
- title
type: object
@@ -1036,6 +1028,8 @@ definitions:
type: integer
collection_count:
type: integer
+ created_at:
+ type: integer
description:
type: string
follow_count:
@@ -1090,11 +1084,6 @@ definitions:
edit_summary:
description: edit summary
type: string
- html:
- description: html
- maxLength: 65535
- minLength: 6
- type: string
id:
description: question id
type: string
@@ -1110,7 +1099,6 @@ definitions:
type: string
required:
- content
- - html
- id
- tags
- title
@@ -1490,9 +1478,6 @@ definitions:
original_text:
description: original text
type: string
- parsed_text:
- description: parsed text
- type: string
slug_name:
description: slug_name
maxLength: 35
@@ -1558,12 +1543,12 @@ definitions:
type: string
original_text:
description: original comment content
- type: string
- parsed_text:
- description: parsed comment content
+ maxLength: 600
+ minLength: 2
type: string
required:
- comment_id
+ - original_text
type: object
schema.UpdateFollowTagsReq:
properties:
@@ -1582,10 +1567,6 @@ definitions:
description: bio
maxLength: 4096
type: string
- bio_html:
- description: bio
- maxLength: 4096
- type: string
display_name:
description: display_name
maxLength: 30
@@ -1648,9 +1629,6 @@ definitions:
original_text:
description: original text
type: string
- parsed_text:
- description: parsed text
- type: string
slug_name:
description: slug_name
maxLength: 35
@@ -3684,6 +3662,30 @@ paths:
summary: user's votes
tags:
- Activity
+ /answer/api/v1/post/render:
+ post:
+ consumes:
+ - application/json
+ description: render post content
+ parameters:
+ - description: PostRenderReq
+ in: body
+ name: data
+ required: true
+ schema:
+ $ref: '#/definitions/schema.PostRenderReq'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/handler.RespBody'
+ security:
+ - ApiKeyAuth: []
+ summary: render post content
+ tags:
+ - Upload
/answer/api/v1/question:
delete:
consumes:
diff --git a/go.mod b/go.mod
index 33c4a499..1db48ddb 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.18
require (
github.com/Chain-Zhang/pinyin v0.1.3
github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267
+ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/bwmarrin/snowflake v0.3.0
github.com/davecgh/go-spew v1.1.1
github.com/disintegration/imaging v1.6.2
@@ -14,7 +15,7 @@ require (
github.com/go-playground/validator/v10 v10.11.1
github.com/go-sql-driver/mysql v1.6.0
github.com/goccy/go-json v0.9.11
- github.com/golang/mock v1.4.4
+ github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/google/wire v0.5.0
github.com/gosimple/slug v1.13.1
@@ -22,7 +23,6 @@ require (
github.com/jinzhu/copier v0.3.5
github.com/jinzhu/now v1.1.5
github.com/lib/pq v1.10.7
- github.com/mattn/go-sqlite3 v1.14.16
github.com/microcosm-cc/bluemonday v1.0.21
github.com/mojocn/base64Captcha v1.3.5
github.com/ory/dockertest/v3 v3.9.1
@@ -43,6 +43,7 @@ require (
golang.org/x/net v0.1.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/yaml.v3 v3.0.1
+ modernc.org/sqlite v1.14.2
xorm.io/builder v0.3.12
xorm.io/core v0.7.3
xorm.io/xorm v1.3.2
@@ -79,12 +80,14 @@ require (
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -97,6 +100,7 @@ require (
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
@@ -113,6 +117,7 @@ require (
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.23.0 // indirect
golang.org/x/image v0.1.0 // indirect
+ golang.org/x/mod v0.6.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.5.0 // indirect
golang.org/x/tools v0.2.0 // indirect
@@ -120,5 +125,14 @@ require (
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
+ lukechampine.com/uint128 v1.1.1 // indirect
+ modernc.org/cc/v3 v3.35.18 // indirect
+ modernc.org/ccgo/v3 v3.12.82 // indirect
+ modernc.org/libc v1.11.87 // indirect
+ modernc.org/mathutil v1.4.1 // indirect
+ modernc.org/memory v1.0.5 // indirect
+ modernc.org/opt v0.1.1 // indirect
+ modernc.org/strutil v1.1.1 // indirect
+ modernc.org/token v1.0.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
diff --git a/go.sum b/go.sum
index a808586a..a84e52f3 100644
--- a/go.sum
+++ b/go.sum
@@ -79,6 +79,8 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
+github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
@@ -142,6 +144,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
@@ -237,8 +240,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -696,6 +700,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -793,6 +798,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -832,6 +838,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -912,9 +919,11 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1009,6 +1018,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
@@ -1219,7 +1229,9 @@ modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
modernc.org/ccgo/v3 v3.12.82 h1:wudcnJyjLj1aQQCXF3IM9Gz2X6UNjw+afIghzdtn0v8=
modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
+modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
+modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
@@ -1271,9 +1283,11 @@ modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE=
modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
+modernc.org/tcl v1.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw=
modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/z v1.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao=
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index ac0b6254..9d1c1b20 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -52,6 +52,8 @@ backend:
other: "Comment are not allowed to edit."
not_found:
other: "Comment not found."
+ cannot_edit_after_deadline:
+ other: "The comment time has been too long to modify."
email:
duplicate:
other: "Email already exists."
@@ -508,6 +510,8 @@ ui:
label: Revision
answer:
label: Answer
+ feedback:
+ characters: content must be at least 6 characters in length.
edit_summary:
label: Edit Summary
placeholder: >-
@@ -638,7 +642,7 @@ ui:
msg:
empty: Email cannot be empty.
change_email:
- page_title: Welcome to Answer
+ page_title: Welcome to {{site_name}}
btn_cancel: Cancel
btn_update: Update email address
send_success: >-
@@ -772,6 +776,7 @@ ui:
Are you sure you want to add another answer?
You could use the
edit link to refine and improve your existing answer, instead.
empty: Answer cannot be empty.
+ characters: content must be at least 6 characters in length.
reopen:
title: Reopen this post
content: Are you sure you want to reopen?
@@ -838,7 +843,7 @@ ui:
modal_confirm:
title: Error...
account_result:
- page_title: Welcome to Answer
+ page_title: Welcome to {{site_name}}
success: Your new account is confirmed; you will be redirected to the home page.
link: Continue to homepage
invalid: >-
@@ -993,8 +998,12 @@ ui:
database tables first.
db_failed: Database connection failed
db_failed_desc: >-
- This either means that the database information in your <1>config.yaml1> file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down.
-
+ This either means that the database information in your <1>config.yaml1> file is incorrect or that contact with the database server could not be established. This could mean your host’s database server is down.
+ counts:
+ views: views
+ votes: votes
+ answers: answers
+ accepted: Accepted
page_404:
desc: "Unfortunately, this page doesn't exist."
back_home: Back to homepage
diff --git a/internal/base/constant/comment.go b/internal/base/constant/comment.go
new file mode 100644
index 00000000..6a0c7137
--- /dev/null
+++ b/internal/base/constant/comment.go
@@ -0,0 +1,7 @@
+package constant
+
+import "time"
+
+const (
+ CommentEditDeadline = time.Minute * 5
+)
diff --git a/internal/base/data/data.go b/internal/base/data/data.go
index 356c7157..0a16659e 100644
--- a/internal/base/data/data.go
+++ b/internal/base/data/data.go
@@ -7,10 +7,10 @@ import (
"github.com/answerdev/answer/pkg/dir"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
- _ "github.com/mattn/go-sqlite3"
"github.com/segmentfault/pacman/cache"
"github.com/segmentfault/pacman/contrib/cache/memory"
"github.com/segmentfault/pacman/log"
+ _ "modernc.org/sqlite"
"xorm.io/core"
"xorm.io/xorm"
ormlog "xorm.io/xorm/log"
@@ -38,11 +38,13 @@ func NewDB(debug bool, dataConf *Database) (*xorm.Engine, error) {
dataConf.Driver = string(schemas.MYSQL)
}
if dataConf.Driver == string(schemas.SQLITE) {
+ dataConf.Driver = "sqlite"
dbFileDir := filepath.Dir(dataConf.Connection)
log.Debugf("try to create database directory %s", dbFileDir)
if err := dir.CreateDirIfNotExist(dbFileDir); err != nil {
log.Errorf("create database dir failed: %s", err)
}
+ dataConf.MaxOpenConn = 1
}
engine, err := xorm.NewEngine(dataConf.Driver, dataConf.Connection)
if err != nil {
diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go
index 9d2880e0..af4b5b71 100644
--- a/internal/base/reason/reason.go
+++ b/internal/base/reason/reason.go
@@ -16,6 +16,7 @@ const (
const (
EmailOrPasswordWrong = "error.object.email_or_password_incorrect"
CommentNotFound = "error.comment.not_found"
+ CommentCannotEditAfterDeadline = "error.comment.cannot_edit_after_deadline"
QuestionNotFound = "error.question.not_found"
QuestionCannotDeleted = "error.question.cannot_deleted"
QuestionCannotClose = "error.question.cannot_close"
diff --git a/internal/base/validator/validator.go b/internal/base/validator/validator.go
index 8eae14e1..206e5808 100644
--- a/internal/base/validator/validator.go
+++ b/internal/base/validator/validator.go
@@ -97,8 +97,29 @@ func getTran(lo locales.Translator) ut.Translator {
return tran
}
+func NotBlank(fl validator.FieldLevel) (res bool) {
+ field := fl.Field()
+ switch field.Kind() {
+ case reflect.String:
+ trimSpace := strings.TrimSpace(field.String())
+ res := len(trimSpace) > 0
+ if !res {
+ field.SetString(trimSpace)
+ }
+ return true
+ case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array:
+ return field.Len() > 0
+ case reflect.Ptr, reflect.Interface, reflect.Func:
+ return !field.IsNil()
+ default:
+ return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
+ }
+}
+
func createDefaultValidator(la i18n.Language) *validator.Validate {
validate := validator.New()
+ // _ = validate.RegisterValidation("notblank", validators.NotBlank)
+ _ = validate.RegisterValidation("notblank", NotBlank)
validate.RegisterTagNameFunc(func(fld reflect.StructField) (res string) {
defer func() {
if len(res) > 0 {
diff --git a/internal/controller/comment_controller.go b/internal/controller/comment_controller.go
index eb025139..79ed9681 100644
--- a/internal/controller/comment_controller.go
+++ b/internal/controller/comment_controller.go
@@ -111,6 +111,7 @@ func (cc *CommentController) UpdateComment(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
+ req.IsAdmin = middleware.GetIsAdminFromContext(ctx)
can, err := cc.rankService.CheckOperationPermission(ctx, req.UserID, permission.CommentEdit, req.CommentID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go
index c97c81b4..894b4930 100644
--- a/internal/controller/template_controller.go
+++ b/internal/controller/template_controller.go
@@ -139,6 +139,9 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) {
}
siteInfo := tc.SiteInfo(ctx)
siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl)
+ if page > 1 {
+ siteInfo.Canonical = fmt.Sprintf("%s/questions?page=%d", siteInfo.General.SiteUrl, page)
+ }
UrlUseTitle := false
if siteInfo.SiteSeo.PermaLink == schema.PermaLinkQuestionIDAndTitle {
@@ -327,6 +330,9 @@ func (tc *TemplateController) TagList(ctx *gin.Context) {
siteInfo := tc.SiteInfo(ctx)
siteInfo.Canonical = fmt.Sprintf("%s/tags", siteInfo.General.SiteUrl)
+ if req.Page > 1 {
+ siteInfo.Canonical = fmt.Sprintf("%s/tags?page=%d", siteInfo.General.SiteUrl, req.Page)
+ }
siteInfo.Title = fmt.Sprintf("%s - %s", "Tags", siteInfo.General.Name)
tc.html(ctx, http.StatusOK, "tags.html", siteInfo, gin.H{
"page": page,
@@ -353,6 +359,9 @@ func (tc *TemplateController) TagInfo(ctx *gin.Context) {
siteInfo := tc.SiteInfo(ctx)
siteInfo.Canonical = fmt.Sprintf("%s/tags/%s", siteInfo.General.SiteUrl, tag)
+ if req.Page > 1 {
+ siteInfo.Canonical = fmt.Sprintf("%s/tags/%s?page=%d", siteInfo.General.SiteUrl, tag, req.Page)
+ }
siteInfo.Description = htmltext.FetchExcerpt(taginifo.ParsedText, "...", 240)
if len(taginifo.ParsedText) == 0 {
siteInfo.Description = "The tag has no description."
@@ -437,6 +446,7 @@ func (tc *TemplateController) html(ctx *gin.Context, code int, tpl string, siteI
data["HeadCode"] = siteInfo.CustomCssHtml.CustomHead
data["HeaderCode"] = siteInfo.CustomCssHtml.CustomHeader
data["FooterCode"] = siteInfo.CustomCssHtml.CustomFooter
+ data["Version"] = constant.Version
_, ok := data["path"]
if !ok {
data["path"] = ""
diff --git a/internal/controller/user_controller.go b/internal/controller/user_controller.go
index 909581cc..c2cf25bf 100644
--- a/internal/controller/user_controller.go
+++ b/internal/controller/user_controller.go
@@ -157,8 +157,8 @@ func (uc *UserController) RetrievePassWord(ctx *gin.Context) {
return
}
_, _ = uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeFindPass, ctx.ClientIP())
- code, err := uc.userService.RetrievePassWord(ctx, req)
- handler.HandleResponse(ctx, err, code)
+ _, err := uc.userService.RetrievePassWord(ctx, req)
+ handler.HandleResponse(ctx, err, nil)
}
// UseRePassWord godoc
diff --git a/internal/install/install_req.go b/internal/install/install_req.go
index ff544406..a465d6bd 100644
--- a/internal/install/install_req.go
+++ b/internal/install/install_req.go
@@ -5,6 +5,10 @@ import (
"net/url"
"strings"
+ "github.com/answerdev/answer/internal/base/reason"
+ "github.com/answerdev/answer/internal/base/validator"
+ "github.com/answerdev/answer/pkg/checker"
+ "github.com/segmentfault/pacman/errors"
"xorm.io/xorm/schemas"
)
@@ -82,6 +86,18 @@ type InitBaseInfoReq struct {
AdminEmail string `validate:"required,email,gt=0,lte=500" json:"email"`
}
+func (r *InitBaseInfoReq) Check() (errFields []*validator.FormErrorField, err error) {
+ if checker.IsInvalidUsername(r.AdminName) {
+ errField := &validator.FormErrorField{
+ ErrorField: "name",
+ ErrorMsg: reason.UsernameInvalid,
+ }
+ errFields = append(errFields, errField)
+ return errFields, errors.BadRequest(reason.UsernameInvalid)
+ }
+ return
+}
+
func (r *InitBaseInfoReq) FormatSiteUrl() {
parsedUrl, err := url.Parse(r.SiteURL)
if err != nil {
diff --git a/internal/repo/collection/collection_repo.go b/internal/repo/collection/collection_repo.go
index f73c74b7..396398c5 100644
--- a/internal/repo/collection/collection_repo.go
+++ b/internal/repo/collection/collection_repo.go
@@ -11,6 +11,7 @@ import (
collectioncommon "github.com/answerdev/answer/internal/service/collection_common"
"github.com/answerdev/answer/internal/service/unique"
"github.com/segmentfault/pacman/errors"
+ "xorm.io/xorm"
)
// collectionRepo collection repository
@@ -29,15 +30,28 @@ func NewCollectionRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) collec
// AddCollection add collection
func (cr *collectionRepo) AddCollection(ctx context.Context, collection *entity.Collection) (err error) {
- id, err := cr.uniqueIDRepo.GenUniqueIDStr(ctx, collection.TableName())
- if err == nil {
- collection.ID = id
- _, err = cr.data.DB.Insert(collection)
+ _, err = cr.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
+ var has bool
+ dbcollection := &entity.Collection{}
+ result = nil
+ has, err = session.Where("user_id = ? and object_id = ?", collection.UserID, collection.ObjectID).Get(dbcollection)
if err != nil {
- return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+ return
}
- }
- return nil
+ if has {
+ return
+ }
+ id, err := cr.uniqueIDRepo.GenUniqueIDStr(ctx, collection.TableName())
+ if err == nil {
+ collection.ID = id
+ _, err = session.Insert(collection)
+ if err != nil {
+ return result, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+ }
+ }
+ return
+ })
+ return err
}
// RemoveCollection delete collection
diff --git a/internal/repo/search_common/search_repo.go b/internal/repo/search_common/search_repo.go
index eac0620c..987fea5c 100644
--- a/internal/repo/search_common/search_repo.go
+++ b/internal/repo/search_common/search_repo.go
@@ -33,7 +33,7 @@ var (
"`user_id`",
"`vote_count`",
"`answer_count`",
- "0 as `accepted`",
+ "CASE WHEN `accepted_answer_id` > 0 THEN 2 ELSE 0 END as `accepted`",
"`question`.`status` as `status`",
"`post_update_time`",
}
diff --git a/internal/schema/answer_schema.go b/internal/schema/answer_schema.go
index 724d9af9..7fc6a12d 100644
--- a/internal/schema/answer_schema.go
+++ b/internal/schema/answer_schema.go
@@ -20,10 +20,10 @@ const (
)
type AnswerAddReq struct {
- QuestionID string `json:"question_id" ` // question_id
- Content string `json:"content" ` // content
- HTML string `json:"html" ` // html
- UserID string `json:"-" ` // user_id
+ QuestionID string `json:"question_id"`
+ Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
+ HTML string `json:"-"`
+ UserID string `json:"-"`
}
func (req *AnswerAddReq) Check() (errFields []*validator.FormErrorField, err error) {
@@ -32,13 +32,13 @@ func (req *AnswerAddReq) Check() (errFields []*validator.FormErrorField, err err
}
type AnswerUpdateReq struct {
- ID string `json:"id"` // id
- QuestionID string `json:"question_id" ` // question_id
- UserID string `json:"-" ` // user_id
- Title string `json:"title" ` // title
- Content string `json:"content"` // content
- HTML string `json:"html" ` // html
- EditSummary string `validate:"omitempty" json:"edit_summary"` // edit_summary
+ ID string `json:"id"`
+ QuestionID string `json:"question_id"`
+ Title string `json:"title"`
+ Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
+ EditSummary string `validate:"omitempty" json:"edit_summary"`
+ HTML string `json:"-"`
+ UserID string `json:"-"`
NoNeedReview bool `json:"-"`
// whether user can edit it
CanEdit bool `json:"-"`
diff --git a/internal/schema/comment_schema.go b/internal/schema/comment_schema.go
index 05b3e18a..dcc44bd5 100644
--- a/internal/schema/comment_schema.go
+++ b/internal/schema/comment_schema.go
@@ -14,9 +14,9 @@ type AddCommentReq struct {
// reply comment id
ReplyCommentID string `validate:"omitempty" json:"reply_comment_id"`
// original comment content
- OriginalText string `validate:"required" json:"original_text"`
+ OriginalText string `validate:"required,notblank,gte=2,lte=600" json:"original_text"`
// parsed comment content
- ParsedText string `validate:"required" json:"parsed_text"`
+ ParsedText string `json:"-"`
// @ user id list
MentionUsernameList []string `validate:"omitempty" json:"mention_username_list"`
// user id
@@ -47,11 +47,12 @@ type UpdateCommentReq struct {
// comment id
CommentID string `validate:"required" json:"comment_id"`
// original comment content
- OriginalText string `validate:"omitempty" json:"original_text"`
+ OriginalText string `validate:"required,notblank,gte=2,lte=600" json:"original_text"`
// parsed comment content
- ParsedText string `validate:"omitempty" json:"parsed_text"`
+ ParsedText string `json:"-"`
// user id
- UserID string `json:"-"`
+ UserID string `json:"-"`
+ IsAdmin bool `json:"-"`
}
func (req *UpdateCommentReq) Check() (errFields []*validator.FormErrorField, err error) {
diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go
index 4d4bda23..b656b834 100644
--- a/internal/schema/question_schema.go
+++ b/internal/schema/question_schema.go
@@ -41,11 +41,11 @@ type ReopenQuestionReq struct {
type QuestionAdd struct {
// question title
- Title string `validate:"required,gte=6,lte=150" json:"title"`
+ Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
// content
- Content string `validate:"required,gte=6,lte=65535" json:"content"`
+ Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
// html
- HTML string `validate:"required,gte=6,lte=65535" json:"html"`
+ HTML string `json:"-"`
// tags
Tags []*TagItem `validate:"required,dive" json:"tags"`
// user id
@@ -90,11 +90,11 @@ type QuestionUpdate struct {
// question id
ID string `validate:"required" json:"id"`
// question title
- Title string `validate:"required,gte=6,lte=150" json:"title"`
+ Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
// content
- Content string `validate:"required,gte=6,lte=65535" json:"content"`
+ Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
// html
- HTML string `validate:"required,gte=6,lte=65535" json:"html"`
+ HTML string `json:"-"`
// tags
Tags []*TagItem `validate:"required,dive" json:"tags"`
// edit summary
@@ -219,7 +219,7 @@ type UserQuestionInfo struct {
ViewCount int `json:"view_count"`
AnswerCount int `json:"answer_count"`
CollectionCount int `json:"collection_count"`
- CreateTime int `json:"create_time"`
+ CreatedAt int64 `json:"created_at"`
AcceptedAnswerID string `json:"accepted_answer_id"`
Status string `json:"status"`
}
@@ -253,6 +253,7 @@ const (
type QuestionPageResp struct {
ID string `json:"id" `
+ CreatedAt int64 `json:"created_at"`
Title string `json:"title"`
UrlTitle string `json:"url_title"`
Description string `json:"description"`
diff --git a/internal/schema/tag_schema.go b/internal/schema/tag_schema.go
index 3b7100a2..654e9178 100644
--- a/internal/schema/tag_schema.go
+++ b/internal/schema/tag_schema.go
@@ -144,7 +144,7 @@ type TagItem struct {
// original text
OriginalText string `validate:"omitempty" json:"original_text"`
// parsed text
- ParsedText string `validate:"omitempty" json:"parsed_text"`
+ ParsedText string `json:"-"`
}
// RemoveTagReq delete tag request
@@ -166,7 +166,7 @@ type UpdateTagReq struct {
// original text
OriginalText string `validate:"omitempty" json:"original_text"`
// parsed text
- ParsedText string `validate:"omitempty" json:"parsed_text"`
+ ParsedText string `json:"-"`
// edit summary
EditSummary string `validate:"omitempty" json:"edit_summary"`
// user id
diff --git a/internal/schema/user_schema.go b/internal/schema/user_schema.go
index 9b449b80..308568c8 100644
--- a/internal/schema/user_schema.go
+++ b/internal/schema/user_schema.go
@@ -2,12 +2,12 @@ package schema
import (
"encoding/json"
- "regexp"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/base/validator"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/pkg/checker"
+ "github.com/answerdev/answer/pkg/converter"
"github.com/jinzhu/copier"
"github.com/segmentfault/pacman/errors"
)
@@ -283,7 +283,7 @@ type UpdateInfoRequest struct {
// bio
Bio string `validate:"omitempty,gt=0,lte=4096" json:"bio"`
// bio
- BioHTML string `validate:"omitempty,gt=0,lte=4096" json:"bio_html"`
+ BioHTML string `json:"-"`
// website
Website string `validate:"omitempty,gt=0,lte=500" json:"website"`
// location
@@ -298,12 +298,9 @@ type AvatarInfo struct {
Custom string `validate:"omitempty,gt=0,lte=200" json:"custom"`
}
-func (u *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err error) {
- if len(u.Username) > 0 {
- errFields := make([]*validator.FormErrorField, 0)
- re := regexp.MustCompile(`^[a-z0-9._-]{4,30}$`)
- match := re.MatchString(u.Username)
- if !match {
+func (req *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err error) {
+ if len(req.Username) > 0 {
+ if checker.IsInvalidUsername(req.Username) {
errField := &validator.FormErrorField{
ErrorField: "username",
ErrorMsg: reason.UsernameInvalid,
@@ -312,6 +309,7 @@ func (u *UpdateInfoRequest) Check() (errFields []*validator.FormErrorField, err
return errFields, errors.BadRequest(reason.UsernameInvalid)
}
}
+ req.BioHTML = converter.Markdown2HTML(req.Bio)
return nil, nil
}
diff --git a/internal/service/comment/comment_service.go b/internal/service/comment/comment_service.go
index 92d9a194..18b755ab 100644
--- a/internal/service/comment/comment_service.go
+++ b/internal/service/comment/comment_service.go
@@ -121,33 +121,14 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
return nil, err
}
- if objInfo.ObjectType == constant.QuestionObjectType {
- cs.notificationQuestionComment(ctx, objInfo.ObjectCreatorUserID,
- objInfo.QuestionID, objInfo.Title, comment.ID, req.UserID, comment.OriginalText)
- } else if objInfo.ObjectType == constant.AnswerObjectType {
- cs.notificationAnswerComment(ctx, objInfo.QuestionID, objInfo.Title, objInfo.AnswerID,
- objInfo.ObjectCreatorUserID, comment.ID, req.UserID, comment.OriginalText)
- }
- if len(req.MentionUsernameList) > 0 {
- cs.notificationMention(ctx, req.MentionUsernameList, comment.ID, req.UserID)
- }
-
resp = &schema.GetCommentResp{}
resp.SetFromComment(comment)
- resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID, req.CanEdit, req.CanDelete)
+ resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID,
+ time.Now(), req.CanEdit, req.CanDelete)
- // get reply user info
- if len(resp.ReplyUserID) > 0 {
- replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
- if err != nil {
- return nil, err
- }
- if exist {
- resp.ReplyUsername = replyUser.Username
- resp.ReplyUserDisplayName = replyUser.DisplayName
- resp.ReplyUserStatus = replyUser.Status
- }
- cs.notificationCommentReply(ctx, replyUser.ID, objInfo.QuestionID, req.UserID)
+ commentResp, err := cs.addCommentNotification(ctx, req, resp, comment, objInfo)
+ if err != nil {
+ return commentResp, err
}
// get user info
@@ -178,6 +159,50 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment
return resp, nil
}
+func (cs *CommentService) addCommentNotification(
+ ctx context.Context, req *schema.AddCommentReq, resp *schema.GetCommentResp,
+ comment *entity.Comment, objInfo *schema.SimpleObjectInfo) (*schema.GetCommentResp, error) {
+ // The priority of the notification
+ // 1. reply to user
+ // 2. comment mention to user
+ // 3. answer or question was commented
+ alreadyNotifiedUserID := make(map[string]bool)
+
+ // get reply user info
+ if len(resp.ReplyUserID) > 0 && resp.ReplyUserID != req.UserID {
+ replyUser, exist, err := cs.userCommon.GetUserBasicInfoByID(ctx, resp.ReplyUserID)
+ if err != nil {
+ return nil, err
+ }
+ if exist {
+ resp.ReplyUsername = replyUser.Username
+ resp.ReplyUserDisplayName = replyUser.DisplayName
+ resp.ReplyUserStatus = replyUser.Status
+ }
+ cs.notificationCommentReply(ctx, replyUser.ID, comment.ID, req.UserID)
+ alreadyNotifiedUserID[replyUser.ID] = true
+ return nil, nil
+ }
+
+ if len(req.MentionUsernameList) > 0 {
+ alreadyNotifiedUserIDs := cs.notificationMention(
+ ctx, req.MentionUsernameList, comment.ID, req.UserID, alreadyNotifiedUserID)
+ for _, userID := range alreadyNotifiedUserIDs {
+ alreadyNotifiedUserID[userID] = true
+ }
+ return nil, nil
+ }
+
+ if objInfo.ObjectType == constant.QuestionObjectType && !alreadyNotifiedUserID[objInfo.ObjectCreatorUserID] {
+ cs.notificationQuestionComment(ctx, objInfo.ObjectCreatorUserID,
+ objInfo.QuestionID, objInfo.Title, comment.ID, req.UserID, comment.OriginalText)
+ } else if objInfo.ObjectType == constant.AnswerObjectType && !alreadyNotifiedUserID[objInfo.ObjectCreatorUserID] {
+ cs.notificationAnswerComment(ctx, objInfo.QuestionID, objInfo.Title, objInfo.AnswerID,
+ objInfo.ObjectCreatorUserID, comment.ID, req.UserID, comment.OriginalText)
+ }
+ return nil, nil
+}
+
// RemoveComment delete comment
func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveCommentReq) (err error) {
return cs.commentRepo.RemoveComment(ctx, req.CommentID)
@@ -185,6 +210,19 @@ func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveC
// UpdateComment update comment
func (cs *CommentService) UpdateComment(ctx context.Context, req *schema.UpdateCommentReq) (err error) {
+ old, exist, err := cs.commentCommonRepo.GetComment(ctx, req.CommentID)
+ if err != nil {
+ return
+ }
+ if !exist {
+ return errors.BadRequest(reason.CommentNotFound)
+ }
+
+ // user can edit the comment that was posted by himself before deadline.
+ if !req.IsAdmin && (time.Now().After(old.CreatedAt.Add(constant.CommentEditDeadline))) {
+ return errors.BadRequest(reason.CommentCannotEditAfterDeadline)
+ }
+
comment := &entity.Comment{}
_ = copier.Copy(comment, req)
comment.ID = req.CommentID
@@ -198,7 +236,7 @@ func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetComment
return
}
if !exist {
- return nil, errors.BadRequest(reason.UnknownError)
+ return nil, errors.BadRequest(reason.CommentNotFound)
}
resp = &schema.GetCommentResp{
@@ -243,7 +281,8 @@ func (cs *CommentService) GetComment(ctx context.Context, req *schema.GetComment
// check if current user vote this comment
resp.IsVote = cs.checkIsVote(ctx, req.UserID, resp.CommentID)
- resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID, req.CanEdit, req.CanDelete)
+ resp.MemberActions = permission.GetCommentPermission(ctx, req.UserID, resp.UserID,
+ comment.CreatedAt, req.CanEdit, req.CanDelete)
return resp, nil
}
@@ -339,7 +378,7 @@ func (cs *CommentService) convertCommentEntity2Resp(ctx context.Context, req *sc
commentResp.IsVote = cs.checkIsVote(ctx, req.UserID, commentResp.CommentID)
commentResp.MemberActions = permission.GetCommentPermission(ctx,
- req.UserID, commentResp.UserID, req.CanEdit, req.CanDelete)
+ req.UserID, commentResp.UserID, comment.CreatedAt, req.CanEdit, req.CanDelete)
return commentResp, nil
}
@@ -521,14 +560,16 @@ func (cs *CommentService) notificationCommentReply(ctx context.Context, replyUse
notice_queue.AddNotification(msg)
}
-func (cs *CommentService) notificationMention(ctx context.Context, mentionUsernameList []string, commentID, commentUserID string) {
+func (cs *CommentService) notificationMention(
+ ctx context.Context, mentionUsernameList []string, commentID, commentUserID string,
+ alreadyNotifiedUserID map[string]bool) (alreadyNotifiedUserIDs []string) {
for _, username := range mentionUsernameList {
userInfo, exist, err := cs.userCommon.GetUserBasicInfoByUserName(ctx, username)
if err != nil {
log.Error(err)
continue
}
- if exist {
+ if exist && !alreadyNotifiedUserID[userInfo.ID] {
msg := &schema.NotificationMsg{
ReceiverUserID: userInfo.ID,
TriggerUserID: commentUserID,
@@ -538,6 +579,8 @@ func (cs *CommentService) notificationMention(ctx context.Context, mentionUserna
msg.ObjectType = constant.CommentObjectType
msg.NotificationAction = constant.MentionYou
notice_queue.AddNotification(msg)
+ alreadyNotifiedUserIDs = append(alreadyNotifiedUserIDs, userInfo.ID)
}
}
+ return alreadyNotifiedUserIDs
}
diff --git a/internal/service/permission/comment_permission.go b/internal/service/permission/comment_permission.go
index 026b885a..7f8839ae 100644
--- a/internal/service/permission/comment_permission.go
+++ b/internal/service/permission/comment_permission.go
@@ -2,13 +2,15 @@ package permission
import (
"context"
+ "time"
+ "github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/schema"
)
// GetCommentPermission get comment permission
-func GetCommentPermission(ctx context.Context, userID string, creatorUserID string, canEdit, canDelete bool) (
- actions []*schema.PermissionMemberAction) {
+func GetCommentPermission(ctx context.Context, userID string, creatorUserID string,
+ createdAt time.Time, canEdit, canDelete bool) (actions []*schema.PermissionMemberAction) {
actions = make([]*schema.PermissionMemberAction, 0)
if len(userID) > 0 {
actions = append(actions, &schema.PermissionMemberAction{
@@ -17,7 +19,8 @@ func GetCommentPermission(ctx context.Context, userID string, creatorUserID stri
Type: "reason",
})
}
- if canEdit || userID == creatorUserID {
+ deadline := createdAt.Add(constant.CommentEditDeadline)
+ if canEdit || (userID == creatorUserID && time.Now().Before(deadline)) {
actions = append(actions, &schema.PermissionMemberAction{
Action: "edit",
Name: "Edit",
diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go
index deafa5b1..43be1b78 100644
--- a/internal/service/question_common/question.go
+++ b/internal/service/question_common/question.go
@@ -254,6 +254,7 @@ func (qs *QuestionCommon) FormatQuestionsPage(
for _, questionInfo := range questionList {
t := &schema.QuestionPageResp{
ID: questionInfo.ID,
+ CreatedAt: questionInfo.CreatedAt.Unix(),
Title: questionInfo.Title,
UrlTitle: htmltext.UrlTitle(questionInfo.Title),
Description: htmltext.FetchExcerpt(questionInfo.ParsedText, "...", 240),
diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go
index 946319d5..da66f4ce 100644
--- a/internal/service/user_common/user.go
+++ b/internal/service/user_common/user.go
@@ -4,7 +4,6 @@ import (
"context"
"encoding/hex"
"math/rand"
- "regexp"
"strings"
"github.com/Chain-Zhang/pinyin"
@@ -120,9 +119,7 @@ func (us *UserCommon) MakeUsername(ctx context.Context, displayName string) (use
username = strings.ToLower(username)
suffix := ""
- re := regexp.MustCompile(`^[a-z0-9._-]{4,30}$`)
- match := re.MatchString(username)
- if !match {
+ if checker.IsInvalidUsername(username) {
return "", errors.BadRequest(reason.UsernameInvalid)
}
diff --git a/pkg/checker/username.go b/pkg/checker/username.go
new file mode 100644
index 00000000..0225ec0b
--- /dev/null
+++ b/pkg/checker/username.go
@@ -0,0 +1,11 @@
+package checker
+
+import "regexp"
+
+var (
+ usernameReg = regexp.MustCompile(`^[a-z0-9._-]{4,30}$`)
+)
+
+func IsInvalidUsername(username string) bool {
+ return !usernameReg.MatchString(username)
+}
diff --git a/pkg/converter/markdown.go b/pkg/converter/markdown.go
index d302c1be..4f4a3c41 100644
--- a/pkg/converter/markdown.go
+++ b/pkg/converter/markdown.go
@@ -3,6 +3,7 @@ package converter
import (
"bytes"
+ "github.com/asaskevich/govalidator"
"github.com/microcosm-cc/bluemonday"
"github.com/segmentfault/pacman/log"
"github.com/yuin/goldmark"
@@ -10,6 +11,7 @@ import (
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
+ "github.com/yuin/goldmark/renderer/html"
goldmarkHTML "github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
)
@@ -54,6 +56,7 @@ type DangerousHTMLRenderer struct {
func (r *DangerousHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(ast.KindHTMLBlock, r.renderHTMLBlock)
reg.Register(ast.KindRawHTML, r.renderRawHTML)
+ reg.Register(ast.KindLink, r.renderLink)
}
func (r *DangerousHTMLRenderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
@@ -85,3 +88,30 @@ func (r *DangerousHTMLRenderer) renderHTMLBlock(w util.BufWriter, source []byte,
}
return ast.WalkContinue, nil
}
+
+func (r *DangerousHTMLRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
+ n := node.(*ast.Link)
+ if entering && r.renderLinkIsUrl(string(n.Destination)) {
+ _, _ = w.WriteString("')
+ } else {
+ _, _ = w.WriteString("")
+ }
+ return ast.WalkContinue, nil
+}
+
+func (r *DangerousHTMLRenderer) renderLinkIsUrl(verifyUrl string) bool {
+ return govalidator.IsURL(verifyUrl)
+}
diff --git a/ui/.gitignore b/ui/.gitignore
index fe3fdef0..f5128c7c 100644
--- a/ui/.gitignore
+++ b/ui/.gitignore
@@ -9,7 +9,11 @@
/coverage
# production
-/build
+
+/build/*/*/*
+/build/*.json
+/build/*.html
+/build/*.txt
# misc
.DS_Store
diff --git a/ui/build/favicon.ico b/ui/build/favicon.ico
new file mode 100644
index 00000000..6ab1fbda
Binary files /dev/null and b/ui/build/favicon.ico differ
diff --git a/ui/build/index.html b/ui/build/index.html
deleted file mode 100644
index f7ae498a..00000000
--- a/ui/build/index.html
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/ui/package.json b/ui/package.json
index dfd2c04d..5c23dc5d 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -22,7 +22,9 @@
"copy-to-clipboard": "^3.3.2",
"dayjs": "^1.11.5",
"diff": "^5.1.0",
+ "dompurify": "^2.4.3",
"emoji-regex": "^10.2.1",
+ "html-react-parser": "^3.0.8",
"i18next": "^21.9.0",
"katex": "^0.16.2",
"lodash": "^4.17.21",
@@ -51,6 +53,7 @@
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/color": "^3.0.3",
+ "@types/dompurify": "^2.4.0",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.184",
"@types/marked": "^4.0.6",
diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml
index d4e96662..8ec5b138 100644
--- a/ui/pnpm-lock.yaml
+++ b/ui/pnpm-lock.yaml
@@ -9,6 +9,7 @@ specifiers:
'@testing-library/react': ^13.3.0
'@testing-library/user-event': ^13.5.0
'@types/color': ^3.0.3
+ '@types/dompurify': ^2.4.0
'@types/jest': ^27.5.2
'@types/lodash': ^4.14.184
'@types/marked': ^4.0.6
@@ -28,6 +29,7 @@ specifiers:
customize-cra: ^1.0.0
dayjs: ^1.11.5
diff: ^5.1.0
+ dompurify: ^2.4.3
emoji-regex: ^10.2.1
eslint: ^8.0.1
eslint-config-airbnb: ^19.0.4
@@ -41,6 +43,7 @@ specifiers:
eslint-plugin-promise: ^6.0.0
eslint-plugin-react: ^7.30.1
eslint-plugin-react-hooks: ^4.6.0
+ html-react-parser: ^3.0.8
husky: ^8.0.1
i18next: ^21.9.0
katex: ^0.16.2
@@ -80,7 +83,9 @@ dependencies:
copy-to-clipboard: 3.3.2
dayjs: 1.11.5
diff: 5.1.0
+ dompurify: registry.npmjs.org/dompurify/2.4.3
emoji-regex: 10.2.1
+ html-react-parser: registry.npmjs.org/html-react-parser/3.0.8_react@18.2.0
i18next: 21.9.2
katex: 0.16.2
lodash: 4.17.21
@@ -109,6 +114,7 @@ devDependencies:
'@testing-library/react': 13.4.0_biqbaboplfbrettd7655fr4n2y
'@testing-library/user-event': 13.5.0_znccgeejomvff3jrsk3ljovfpu
'@types/color': registry.npmjs.org/@types/color/3.0.3
+ '@types/dompurify': registry.npmjs.org/@types/dompurify/2.4.0
'@types/jest': 27.5.2
'@types/lodash': 4.14.185
'@types/marked': 4.0.7
@@ -1894,7 +1900,7 @@ packages:
collect-v8-coverage: 1.0.1
exit: 0.1.2
glob: 7.2.3
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
istanbul-lib-coverage: 3.2.0
istanbul-lib-instrument: 5.2.0
istanbul-lib-report: 3.0.0
@@ -1923,7 +1929,7 @@ packages:
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dependencies:
callsites: 3.1.0
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
source-map: 0.6.1
/@jest/test-result/27.5.1:
@@ -1949,7 +1955,7 @@ packages:
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dependencies:
'@jest/test-result': 27.5.1
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jest-haste-map: 27.5.1
jest-runtime: 27.5.1
transitivePeerDependencies:
@@ -2630,9 +2636,6 @@ packages:
/@types/stack-utils/2.0.1:
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
- /@types/trusted-types/2.0.2:
- resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==}
-
/@types/warning/3.0.0:
resolution: {integrity: sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==}
dev: false
@@ -3437,7 +3440,7 @@ packages:
peerDependencies:
'@popperjs/core': ^2.11.6
dependencies:
- '@popperjs/core': 2.11.6
+ '@popperjs/core': registry.npmjs.org/@popperjs/core/2.11.6
dev: false
/brace-expansion/1.1.11:
@@ -3590,7 +3593,7 @@ packages:
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: registry.npmjs.org/fsevents/2.3.2
/chrome-trace-event/1.0.3:
resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
@@ -3989,7 +3992,7 @@ packages:
dependencies:
boolbase: 1.0.0
css-what: 3.4.2
- domutils: 1.7.0
+ domutils: registry.npmjs.org/domutils/1.7.0
nth-check: 1.0.2
/css-select/4.3.0:
@@ -3997,8 +4000,8 @@ packages:
dependencies:
boolbase: 1.0.0
css-what: 6.1.0
- domhandler: 4.3.1
- domutils: 2.8.0
+ domhandler: registry.npmjs.org/domhandler/4.3.1
+ domutils: registry.npmjs.org/domutils/2.8.0
nth-check: 2.1.1
/css-tree/1.0.0-alpha.37:
@@ -4830,54 +4833,12 @@ packages:
csstype: 3.1.1
dev: false
- /dom-serializer/0.2.2:
- resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
- dependencies:
- domelementtype: 2.3.0
- entities: 2.2.0
-
- /dom-serializer/1.4.1:
- resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
- dependencies:
- domelementtype: 2.3.0
- domhandler: 4.3.1
- entities: 2.2.0
-
- /domelementtype/1.3.1:
- resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
-
- /domelementtype/2.3.0:
- resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
-
/domexception/2.0.1:
resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==}
engines: {node: '>=8'}
dependencies:
webidl-conversions: 5.0.0
- /domhandler/4.3.1:
- resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
- engines: {node: '>= 4'}
- dependencies:
- domelementtype: 2.3.0
-
- /dompurify/2.4.0:
- resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==}
- dev: false
-
- /domutils/1.7.0:
- resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
- dependencies:
- dom-serializer: 0.2.2
- domelementtype: 1.3.1
-
- /domutils/2.8.0:
- resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
- dependencies:
- dom-serializer: 1.4.1
- domelementtype: 2.3.0
- domhandler: 4.3.1
-
/dot-case/3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
dependencies:
@@ -4948,12 +4909,9 @@ packages:
resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==}
engines: {node: '>=10.13.0'}
dependencies:
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
tapable: 2.2.1
- /entities/2.2.0:
- resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
-
/error-ex/1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
@@ -5040,7 +4998,7 @@ packages:
esutils: 2.0.3
optionator: 0.8.3
optionalDependencies:
- source-map: 0.6.1
+ source-map: registry.npmjs.org/source-map/0.6.1
/eslint-config-airbnb-base/15.0.0_hdzsmr7kawaomymueo2tso6fjq:
resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==}
@@ -5226,8 +5184,8 @@ packages:
'@babel/plugin-transform-react-jsx': ^7.14.9
eslint: ^8.1.0
dependencies:
- '@babel/plugin-syntax-flow': 7.18.6_@babel+core@7.19.1
- '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.19.1
+ '@babel/plugin-syntax-flow': registry.npmjs.org/@babel/plugin-syntax-flow/7.18.6_@babel+core@7.19.1
+ '@babel/plugin-transform-react-jsx': registry.npmjs.org/@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.19.1
eslint: 8.23.1
lodash: 4.17.21
string-natural-compare: 3.0.1
@@ -5828,7 +5786,7 @@ packages:
engines: {node: '>=10'}
dependencies:
at-least-node: 1.0.0
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jsonfile: 6.1.0
universalify: 2.0.0
@@ -5838,13 +5796,6 @@ packages:
/fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- /fsevents/2.3.2:
- resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
- requiresBuild: true
- optional: true
-
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
@@ -6104,14 +6055,6 @@ packages:
tapable: 2.2.1
webpack: 5.74.0
- /htmlparser2/6.1.0:
- resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
- dependencies:
- domelementtype: 2.3.0
- domhandler: 4.3.1
- domutils: 2.8.0
- entities: 2.2.0
-
/http-deceiver/1.2.7:
resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==}
@@ -6623,7 +6566,7 @@ packages:
ci-info: 3.4.0
deepmerge: 4.2.2
glob: 7.2.3
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jest-circus: 27.5.1
jest-environment-jsdom: 27.5.1
jest-environment-node: 27.5.1
@@ -6735,7 +6678,7 @@ packages:
micromatch: 4.0.5
walker: 1.0.8
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: registry.npmjs.org/fsevents/2.3.2
/jest-jasmine2/27.5.1:
resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==}
@@ -6795,7 +6738,7 @@ packages:
'@jest/types': 27.5.1
'@types/stack-utils': 2.0.1
chalk: 4.1.2
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
micromatch: 4.0.5
pretty-format: 27.5.1
slash: 3.0.0
@@ -6809,7 +6752,7 @@ packages:
'@jest/types': 28.1.3
'@types/stack-utils': 2.0.1
chalk: 4.1.2
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
micromatch: 4.0.5
pretty-format: 28.1.3
slash: 3.0.0
@@ -6878,7 +6821,7 @@ packages:
'@types/node': 16.11.59
chalk: 4.1.2
emittery: 0.8.1
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jest-docblock: 27.5.1
jest-environment-jsdom: 27.5.1
jest-environment-node: 27.5.1
@@ -6913,7 +6856,7 @@ packages:
collect-v8-coverage: 1.0.1
execa: 5.1.1
glob: 7.2.3
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jest-haste-map: 27.5.1
jest-message-util: 27.5.1
jest-mock: 27.5.1
@@ -6931,7 +6874,7 @@ packages:
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dependencies:
'@types/node': 16.11.59
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
/jest-snapshot/27.5.1:
resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==}
@@ -6949,7 +6892,7 @@ packages:
babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.1
chalk: 4.1.2
expect: 27.5.1
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
jest-diff: 27.5.1
jest-get-type: 27.5.1
jest-haste-map: 27.5.1
@@ -6981,7 +6924,7 @@ packages:
'@types/node': 16.11.59
chalk: 4.1.2
ci-info: 3.4.0
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
picomatch: 2.3.1
/jest-validate/27.5.1:
@@ -7179,7 +7122,7 @@ packages:
dependencies:
universalify: 2.0.0
optionalDependencies:
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
/jsonp/0.2.1:
resolution: {integrity: sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==}
@@ -7490,7 +7433,7 @@ packages:
d3: 7.6.1
dagre: 0.8.5
dagre-d3: 0.6.4
- dompurify: 2.4.0
+ dompurify: registry.npmjs.org/dompurify/2.4.0
graphlib: 2.1.8
khroma: 2.0.0
moment-mini: 2.24.0
@@ -8795,7 +8738,7 @@ packages:
webpack: '*'
dependencies:
purgecss: 4.1.3
- webpack: 5.74.0
+ webpack: registry.npmjs.org/webpack/5.74.0
webpack-sources: 3.2.3
dev: true
@@ -9105,7 +9048,7 @@ packages:
webpack-manifest-plugin: 4.1.1_webpack@5.74.0
workbox-webpack-plugin: 6.5.4_webpack@5.74.0
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: registry.npmjs.org/fsevents/2.3.2
transitivePeerDependencies:
- '@babel/plugin-syntax-flow'
- '@babel/plugin-transform-react-jsx'
@@ -9283,7 +9226,7 @@ packages:
dependencies:
css-select: 4.3.0
dom-converter: 0.2.0
- htmlparser2: 6.1.0
+ htmlparser2: registry.npmjs.org/htmlparser2/6.1.0
lodash: 4.17.21
strip-ansi: 6.0.1
@@ -9408,7 +9351,7 @@ packages:
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: registry.npmjs.org/fsevents/2.3.2
/run-parallel/1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -10513,7 +10456,7 @@ packages:
engines: {node: '>=10.13.0'}
dependencies:
glob-to-regexp: 0.4.1
- graceful-fs: 4.2.10
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
/wbuf/1.7.3:
resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==}
@@ -10864,7 +10807,7 @@ packages:
/workbox-window/6.5.4:
resolution: {integrity: sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==}
dependencies:
- '@types/trusted-types': 2.0.2
+ '@types/trusted-types': registry.npmjs.org/@types/trusted-types/2.0.2
workbox-core: 6.5.4
/wrap-ansi/6.2.0:
@@ -11012,6 +10955,343 @@ packages:
use-sync-external-store: 1.2.0_react@18.2.0
dev: false
+ registry.npmjs.org/@ampproject/remapping/2.2.0:
+ resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz}
+ name: '@ampproject/remapping'
+ version: 2.2.0
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/gen-mapping': registry.npmjs.org/@jridgewell/gen-mapping/0.1.1
+ '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping/0.3.15
+
+ registry.npmjs.org/@babel/code-frame/7.18.6:
+ resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz}
+ name: '@babel/code-frame'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/highlight': registry.npmjs.org/@babel/highlight/7.18.6
+
+ registry.npmjs.org/@babel/compat-data/7.19.1:
+ resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz}
+ name: '@babel/compat-data'
+ version: 7.19.1
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/core/7.19.1:
+ resolution: {integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz}
+ name: '@babel/core'
+ version: 7.19.1
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@ampproject/remapping': registry.npmjs.org/@ampproject/remapping/2.2.0
+ '@babel/code-frame': registry.npmjs.org/@babel/code-frame/7.18.6
+ '@babel/generator': registry.npmjs.org/@babel/generator/7.19.0
+ '@babel/helper-compilation-targets': registry.npmjs.org/@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1
+ '@babel/helper-module-transforms': registry.npmjs.org/@babel/helper-module-transforms/7.19.0
+ '@babel/helpers': registry.npmjs.org/@babel/helpers/7.19.0
+ '@babel/parser': registry.npmjs.org/@babel/parser/7.19.1
+ '@babel/template': registry.npmjs.org/@babel/template/7.18.10
+ '@babel/traverse': registry.npmjs.org/@babel/traverse/7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+ convert-source-map: registry.npmjs.org/convert-source-map/1.8.0
+ debug: registry.npmjs.org/debug/4.3.4
+ gensync: registry.npmjs.org/gensync/1.0.0-beta.2
+ json5: registry.npmjs.org/json5/2.2.1
+ semver: registry.npmjs.org/semver/6.3.0
+ transitivePeerDependencies:
+ - supports-color
+
+ registry.npmjs.org/@babel/generator/7.19.0:
+ resolution: {integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz}
+ name: '@babel/generator'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+ '@jridgewell/gen-mapping': registry.npmjs.org/@jridgewell/gen-mapping/0.3.2
+ jsesc: registry.npmjs.org/jsesc/2.5.2
+
+ registry.npmjs.org/@babel/helper-annotate-as-pure/7.18.6:
+ resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz}
+ name: '@babel/helper-annotate-as-pure'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1:
+ resolution: {integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz}
+ id: registry.npmjs.org/@babel/helper-compilation-targets/7.19.1
+ name: '@babel/helper-compilation-targets'
+ version: 7.19.1
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/compat-data': registry.npmjs.org/@babel/compat-data/7.19.1
+ '@babel/core': registry.npmjs.org/@babel/core/7.19.1
+ '@babel/helper-validator-option': registry.npmjs.org/@babel/helper-validator-option/7.18.6
+ browserslist: registry.npmjs.org/browserslist/4.21.4
+ semver: registry.npmjs.org/semver/6.3.0
+
+ registry.npmjs.org/@babel/helper-environment-visitor/7.18.9:
+ resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz}
+ name: '@babel/helper-environment-visitor'
+ version: 7.18.9
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/helper-function-name/7.19.0:
+ resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz}
+ name: '@babel/helper-function-name'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': registry.npmjs.org/@babel/template/7.18.10
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-hoist-variables/7.18.6:
+ resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz}
+ name: '@babel/helper-hoist-variables'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-module-imports/7.18.6:
+ resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz}
+ name: '@babel/helper-module-imports'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-module-transforms/7.19.0:
+ resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz}
+ name: '@babel/helper-module-transforms'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-environment-visitor': registry.npmjs.org/@babel/helper-environment-visitor/7.18.9
+ '@babel/helper-module-imports': registry.npmjs.org/@babel/helper-module-imports/7.18.6
+ '@babel/helper-simple-access': registry.npmjs.org/@babel/helper-simple-access/7.18.6
+ '@babel/helper-split-export-declaration': registry.npmjs.org/@babel/helper-split-export-declaration/7.18.6
+ '@babel/helper-validator-identifier': registry.npmjs.org/@babel/helper-validator-identifier/7.19.1
+ '@babel/template': registry.npmjs.org/@babel/template/7.18.10
+ '@babel/traverse': registry.npmjs.org/@babel/traverse/7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+ transitivePeerDependencies:
+ - supports-color
+
+ registry.npmjs.org/@babel/helper-plugin-utils/7.19.0:
+ resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz}
+ name: '@babel/helper-plugin-utils'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/helper-simple-access/7.18.6:
+ resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz}
+ name: '@babel/helper-simple-access'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-split-export-declaration/7.18.6:
+ resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz}
+ name: '@babel/helper-split-export-declaration'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/helper-string-parser/7.18.10:
+ resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz}
+ name: '@babel/helper-string-parser'
+ version: 7.18.10
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/helper-validator-identifier/7.19.1:
+ resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz}
+ name: '@babel/helper-validator-identifier'
+ version: 7.19.1
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/helper-validator-option/7.18.6:
+ resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz}
+ name: '@babel/helper-validator-option'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/@babel/helpers/7.19.0:
+ resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz}
+ name: '@babel/helpers'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': registry.npmjs.org/@babel/template/7.18.10
+ '@babel/traverse': registry.npmjs.org/@babel/traverse/7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+ transitivePeerDependencies:
+ - supports-color
+
+ registry.npmjs.org/@babel/highlight/7.18.6:
+ resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz}
+ name: '@babel/highlight'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': registry.npmjs.org/@babel/helper-validator-identifier/7.19.1
+ chalk: registry.npmjs.org/chalk/2.4.2
+ js-tokens: registry.npmjs.org/js-tokens/4.0.0
+
+ registry.npmjs.org/@babel/parser/7.19.1:
+ resolution: {integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz}
+ name: '@babel/parser'
+ version: 7.19.1
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/plugin-syntax-flow/7.18.6_@babel+core@7.19.1:
+ resolution: {integrity: sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz}
+ id: registry.npmjs.org/@babel/plugin-syntax-flow/7.18.6
+ name: '@babel/plugin-syntax-flow'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': registry.npmjs.org/@babel/core/7.19.1
+ '@babel/helper-plugin-utils': registry.npmjs.org/@babel/helper-plugin-utils/7.19.0
+
+ registry.npmjs.org/@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.19.1:
+ resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz}
+ id: registry.npmjs.org/@babel/plugin-syntax-jsx/7.18.6
+ name: '@babel/plugin-syntax-jsx'
+ version: 7.18.6
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': registry.npmjs.org/@babel/core/7.19.1
+ '@babel/helper-plugin-utils': registry.npmjs.org/@babel/helper-plugin-utils/7.19.0
+
+ registry.npmjs.org/@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.19.1:
+ resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz}
+ id: registry.npmjs.org/@babel/plugin-transform-react-jsx/7.19.0
+ name: '@babel/plugin-transform-react-jsx'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': registry.npmjs.org/@babel/core/7.19.1
+ '@babel/helper-annotate-as-pure': registry.npmjs.org/@babel/helper-annotate-as-pure/7.18.6
+ '@babel/helper-module-imports': registry.npmjs.org/@babel/helper-module-imports/7.18.6
+ '@babel/helper-plugin-utils': registry.npmjs.org/@babel/helper-plugin-utils/7.19.0
+ '@babel/plugin-syntax-jsx': registry.npmjs.org/@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/template/7.18.10:
+ resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz}
+ name: '@babel/template'
+ version: 7.18.10
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': registry.npmjs.org/@babel/code-frame/7.18.6
+ '@babel/parser': registry.npmjs.org/@babel/parser/7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+
+ registry.npmjs.org/@babel/traverse/7.19.1:
+ resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz}
+ name: '@babel/traverse'
+ version: 7.19.1
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': registry.npmjs.org/@babel/code-frame/7.18.6
+ '@babel/generator': registry.npmjs.org/@babel/generator/7.19.0
+ '@babel/helper-environment-visitor': registry.npmjs.org/@babel/helper-environment-visitor/7.18.9
+ '@babel/helper-function-name': registry.npmjs.org/@babel/helper-function-name/7.19.0
+ '@babel/helper-hoist-variables': registry.npmjs.org/@babel/helper-hoist-variables/7.18.6
+ '@babel/helper-split-export-declaration': registry.npmjs.org/@babel/helper-split-export-declaration/7.18.6
+ '@babel/parser': registry.npmjs.org/@babel/parser/7.19.1
+ '@babel/types': registry.npmjs.org/@babel/types/7.19.0
+ debug: registry.npmjs.org/debug/4.3.4
+ globals: registry.npmjs.org/globals/11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ registry.npmjs.org/@babel/types/7.19.0:
+ resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz}
+ name: '@babel/types'
+ version: 7.19.0
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': registry.npmjs.org/@babel/helper-string-parser/7.18.10
+ '@babel/helper-validator-identifier': registry.npmjs.org/@babel/helper-validator-identifier/7.19.1
+ to-fast-properties: registry.npmjs.org/to-fast-properties/2.0.0
+
+ registry.npmjs.org/@jridgewell/gen-mapping/0.1.1:
+ resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz}
+ name: '@jridgewell/gen-mapping'
+ version: 0.1.1
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': registry.npmjs.org/@jridgewell/set-array/1.1.2
+ '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec/1.4.14
+
+ registry.npmjs.org/@jridgewell/gen-mapping/0.3.2:
+ resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz}
+ name: '@jridgewell/gen-mapping'
+ version: 0.3.2
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': registry.npmjs.org/@jridgewell/set-array/1.1.2
+ '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec/1.4.14
+ '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping/0.3.15
+
+ registry.npmjs.org/@jridgewell/resolve-uri/3.1.0:
+ resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz}
+ name: '@jridgewell/resolve-uri'
+ version: 3.1.0
+ engines: {node: '>=6.0.0'}
+
+ registry.npmjs.org/@jridgewell/set-array/1.1.2:
+ resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz}
+ name: '@jridgewell/set-array'
+ version: 1.1.2
+ engines: {node: '>=6.0.0'}
+
+ registry.npmjs.org/@jridgewell/source-map/0.3.2:
+ resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz}
+ name: '@jridgewell/source-map'
+ version: 0.3.2
+ dependencies:
+ '@jridgewell/gen-mapping': registry.npmjs.org/@jridgewell/gen-mapping/0.3.2
+ '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping/0.3.15
+ dev: true
+
+ registry.npmjs.org/@jridgewell/sourcemap-codec/1.4.14:
+ resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz}
+ name: '@jridgewell/sourcemap-codec'
+ version: 1.4.14
+
+ registry.npmjs.org/@jridgewell/trace-mapping/0.3.15:
+ resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz}
+ name: '@jridgewell/trace-mapping'
+ version: 0.3.15
+ dependencies:
+ '@jridgewell/resolve-uri': registry.npmjs.org/@jridgewell/resolve-uri/3.1.0
+ '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec/1.4.14
+
+ registry.npmjs.org/@popperjs/core/2.11.6:
+ resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz}
+ name: '@popperjs/core'
+ version: 2.11.6
+ dev: false
+
registry.npmjs.org/@types/color-convert/2.0.0:
resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.0.tgz}
name: '@types/color-convert'
@@ -11033,3 +11313,949 @@ packages:
dependencies:
'@types/color-convert': registry.npmjs.org/@types/color-convert/2.0.0
dev: true
+
+ registry.npmjs.org/@types/dompurify/2.4.0:
+ resolution: {integrity: sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz}
+ name: '@types/dompurify'
+ version: 2.4.0
+ dependencies:
+ '@types/trusted-types': registry.npmjs.org/@types/trusted-types/2.0.2
+ dev: true
+
+ registry.npmjs.org/@types/eslint-scope/3.7.4:
+ resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz}
+ name: '@types/eslint-scope'
+ version: 3.7.4
+ dependencies:
+ '@types/eslint': registry.npmjs.org/@types/eslint/8.4.6
+ '@types/estree': registry.npmjs.org/@types/estree/1.0.0
+ dev: true
+
+ registry.npmjs.org/@types/eslint/8.4.6:
+ resolution: {integrity: sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz}
+ name: '@types/eslint'
+ version: 8.4.6
+ dependencies:
+ '@types/estree': registry.npmjs.org/@types/estree/1.0.0
+ '@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11
+ dev: true
+
+ registry.npmjs.org/@types/estree/0.0.51:
+ resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz}
+ name: '@types/estree'
+ version: 0.0.51
+ dev: true
+
+ registry.npmjs.org/@types/estree/1.0.0:
+ resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz}
+ name: '@types/estree'
+ version: 1.0.0
+ dev: true
+
+ registry.npmjs.org/@types/json-schema/7.0.11:
+ resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz}
+ name: '@types/json-schema'
+ version: 7.0.11
+ dev: true
+
+ registry.npmjs.org/@types/node/16.11.59:
+ resolution: {integrity: sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/node/-/node-16.11.59.tgz}
+ name: '@types/node'
+ version: 16.11.59
+ dev: true
+
+ registry.npmjs.org/@types/trusted-types/2.0.2:
+ resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz}
+ name: '@types/trusted-types'
+ version: 2.0.2
+
+ registry.npmjs.org/@webassemblyjs/ast/1.11.1:
+ resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz}
+ name: '@webassemblyjs/ast'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/helper-numbers': registry.npmjs.org/@webassemblyjs/helper-numbers/1.11.1
+ '@webassemblyjs/helper-wasm-bytecode': registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/1.11.1:
+ resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz}
+ name: '@webassemblyjs/floating-point-hex-parser'
+ version: 1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/helper-api-error/1.11.1:
+ resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz}
+ name: '@webassemblyjs/helper-api-error'
+ version: 1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/helper-buffer/1.11.1:
+ resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz}
+ name: '@webassemblyjs/helper-buffer'
+ version: 1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/helper-numbers/1.11.1:
+ resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz}
+ name: '@webassemblyjs/helper-numbers'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/floating-point-hex-parser': registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/1.11.1
+ '@webassemblyjs/helper-api-error': registry.npmjs.org/@webassemblyjs/helper-api-error/1.11.1
+ '@xtuc/long': registry.npmjs.org/@xtuc/long/4.2.2
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1:
+ resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz}
+ name: '@webassemblyjs/helper-wasm-bytecode'
+ version: 1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/helper-wasm-section/1.11.1:
+ resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz}
+ name: '@webassemblyjs/helper-wasm-section'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/helper-buffer': registry.npmjs.org/@webassemblyjs/helper-buffer/1.11.1
+ '@webassemblyjs/helper-wasm-bytecode': registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1
+ '@webassemblyjs/wasm-gen': registry.npmjs.org/@webassemblyjs/wasm-gen/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/ieee754/1.11.1:
+ resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz}
+ name: '@webassemblyjs/ieee754'
+ version: 1.11.1
+ dependencies:
+ '@xtuc/ieee754': registry.npmjs.org/@xtuc/ieee754/1.2.0
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/leb128/1.11.1:
+ resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz}
+ name: '@webassemblyjs/leb128'
+ version: 1.11.1
+ dependencies:
+ '@xtuc/long': registry.npmjs.org/@xtuc/long/4.2.2
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/utf8/1.11.1:
+ resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz}
+ name: '@webassemblyjs/utf8'
+ version: 1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/wasm-edit/1.11.1:
+ resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz}
+ name: '@webassemblyjs/wasm-edit'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/helper-buffer': registry.npmjs.org/@webassemblyjs/helper-buffer/1.11.1
+ '@webassemblyjs/helper-wasm-bytecode': registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1
+ '@webassemblyjs/helper-wasm-section': registry.npmjs.org/@webassemblyjs/helper-wasm-section/1.11.1
+ '@webassemblyjs/wasm-gen': registry.npmjs.org/@webassemblyjs/wasm-gen/1.11.1
+ '@webassemblyjs/wasm-opt': registry.npmjs.org/@webassemblyjs/wasm-opt/1.11.1
+ '@webassemblyjs/wasm-parser': registry.npmjs.org/@webassemblyjs/wasm-parser/1.11.1
+ '@webassemblyjs/wast-printer': registry.npmjs.org/@webassemblyjs/wast-printer/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/wasm-gen/1.11.1:
+ resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz}
+ name: '@webassemblyjs/wasm-gen'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/helper-wasm-bytecode': registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1
+ '@webassemblyjs/ieee754': registry.npmjs.org/@webassemblyjs/ieee754/1.11.1
+ '@webassemblyjs/leb128': registry.npmjs.org/@webassemblyjs/leb128/1.11.1
+ '@webassemblyjs/utf8': registry.npmjs.org/@webassemblyjs/utf8/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/wasm-opt/1.11.1:
+ resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz}
+ name: '@webassemblyjs/wasm-opt'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/helper-buffer': registry.npmjs.org/@webassemblyjs/helper-buffer/1.11.1
+ '@webassemblyjs/wasm-gen': registry.npmjs.org/@webassemblyjs/wasm-gen/1.11.1
+ '@webassemblyjs/wasm-parser': registry.npmjs.org/@webassemblyjs/wasm-parser/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/wasm-parser/1.11.1:
+ resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz}
+ name: '@webassemblyjs/wasm-parser'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/helper-api-error': registry.npmjs.org/@webassemblyjs/helper-api-error/1.11.1
+ '@webassemblyjs/helper-wasm-bytecode': registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/1.11.1
+ '@webassemblyjs/ieee754': registry.npmjs.org/@webassemblyjs/ieee754/1.11.1
+ '@webassemblyjs/leb128': registry.npmjs.org/@webassemblyjs/leb128/1.11.1
+ '@webassemblyjs/utf8': registry.npmjs.org/@webassemblyjs/utf8/1.11.1
+ dev: true
+
+ registry.npmjs.org/@webassemblyjs/wast-printer/1.11.1:
+ resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz}
+ name: '@webassemblyjs/wast-printer'
+ version: 1.11.1
+ dependencies:
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@xtuc/long': registry.npmjs.org/@xtuc/long/4.2.2
+ dev: true
+
+ registry.npmjs.org/@xtuc/ieee754/1.2.0:
+ resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz}
+ name: '@xtuc/ieee754'
+ version: 1.2.0
+ dev: true
+
+ registry.npmjs.org/@xtuc/long/4.2.2:
+ resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz}
+ name: '@xtuc/long'
+ version: 4.2.2
+ dev: true
+
+ registry.npmjs.org/acorn-import-assertions/1.8.0_acorn@8.8.0:
+ resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz}
+ id: registry.npmjs.org/acorn-import-assertions/1.8.0
+ name: acorn-import-assertions
+ version: 1.8.0
+ peerDependencies:
+ acorn: ^8
+ dependencies:
+ acorn: registry.npmjs.org/acorn/8.8.0
+ dev: true
+
+ registry.npmjs.org/acorn/8.8.0:
+ resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz}
+ name: acorn
+ version: 8.8.0
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ registry.npmjs.org/ajv-keywords/3.5.2_ajv@6.12.6:
+ resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz}
+ id: registry.npmjs.org/ajv-keywords/3.5.2
+ name: ajv-keywords
+ version: 3.5.2
+ peerDependencies:
+ ajv: ^6.9.1
+ dependencies:
+ ajv: registry.npmjs.org/ajv/6.12.6
+ dev: true
+
+ registry.npmjs.org/ajv/6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz}
+ name: ajv
+ version: 6.12.6
+ dependencies:
+ fast-deep-equal: registry.npmjs.org/fast-deep-equal/3.1.3
+ fast-json-stable-stringify: registry.npmjs.org/fast-json-stable-stringify/2.1.0
+ json-schema-traverse: registry.npmjs.org/json-schema-traverse/0.4.1
+ uri-js: registry.npmjs.org/uri-js/4.4.1
+ dev: true
+
+ registry.npmjs.org/ansi-styles/3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz}
+ name: ansi-styles
+ version: 3.2.1
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: registry.npmjs.org/color-convert/1.9.3
+
+ registry.npmjs.org/browserslist/4.21.4:
+ resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz}
+ name: browserslist
+ version: 4.21.4
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+ dependencies:
+ caniuse-lite: registry.npmjs.org/caniuse-lite/1.0.30001408
+ electron-to-chromium: registry.npmjs.org/electron-to-chromium/1.4.256
+ node-releases: registry.npmjs.org/node-releases/2.0.6
+ update-browserslist-db: registry.npmjs.org/update-browserslist-db/1.0.9_browserslist@4.21.4
+
+ registry.npmjs.org/buffer-from/1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz}
+ name: buffer-from
+ version: 1.1.2
+ dev: true
+
+ registry.npmjs.org/caniuse-lite/1.0.30001408:
+ resolution: {integrity: sha512-DdUCktgMSM+1ndk9EFMZcavsGszV7zxV9O7MtOHniTa/iyAIwJCF0dFVBdU9SijJbfh29hC9bCs07wu8pjnGJQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001408.tgz}
+ name: caniuse-lite
+ version: 1.0.30001408
+
+ registry.npmjs.org/chalk/2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz}
+ name: chalk
+ version: 2.4.2
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: registry.npmjs.org/ansi-styles/3.2.1
+ escape-string-regexp: registry.npmjs.org/escape-string-regexp/1.0.5
+ supports-color: registry.npmjs.org/supports-color/5.5.0
+
+ registry.npmjs.org/chrome-trace-event/1.0.3:
+ resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz}
+ name: chrome-trace-event
+ version: 1.0.3
+ engines: {node: '>=6.0'}
+ dev: true
+
+ registry.npmjs.org/color-convert/1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz}
+ name: color-convert
+ version: 1.9.3
+ dependencies:
+ color-name: registry.npmjs.org/color-name/1.1.3
+
+ registry.npmjs.org/color-name/1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz}
+ name: color-name
+ version: 1.1.3
+
+ registry.npmjs.org/commander/2.20.3:
+ resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/commander/-/commander-2.20.3.tgz}
+ name: commander
+ version: 2.20.3
+ dev: true
+
+ registry.npmjs.org/convert-source-map/1.8.0:
+ resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz}
+ name: convert-source-map
+ version: 1.8.0
+ dependencies:
+ safe-buffer: registry.npmjs.org/safe-buffer/5.1.2
+
+ registry.npmjs.org/debug/4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/debug/-/debug-4.3.4.tgz}
+ name: debug
+ version: 4.3.4
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: registry.npmjs.org/ms/2.1.2
+
+ registry.npmjs.org/dom-serializer/0.2.2:
+ resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz}
+ name: dom-serializer
+ version: 0.2.2
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ entities: registry.npmjs.org/entities/2.2.0
+
+ registry.npmjs.org/dom-serializer/1.4.1:
+ resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz}
+ name: dom-serializer
+ version: 1.4.1
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/4.3.1
+ entities: registry.npmjs.org/entities/2.2.0
+
+ registry.npmjs.org/dom-serializer/2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz}
+ name: dom-serializer
+ version: 2.0.0
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/5.0.3
+ entities: registry.npmjs.org/entities/4.4.0
+ dev: false
+
+ registry.npmjs.org/domelementtype/1.3.1:
+ resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz}
+ name: domelementtype
+ version: 1.3.1
+
+ registry.npmjs.org/domelementtype/2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz}
+ name: domelementtype
+ version: 2.3.0
+
+ registry.npmjs.org/domhandler/4.3.1:
+ resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz}
+ name: domhandler
+ version: 4.3.1
+ engines: {node: '>= 4'}
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+
+ registry.npmjs.org/domhandler/5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz}
+ name: domhandler
+ version: 5.0.3
+ engines: {node: '>= 4'}
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ dev: false
+
+ registry.npmjs.org/dompurify/2.4.0:
+ resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz}
+ name: dompurify
+ version: 2.4.0
+ dev: false
+
+ registry.npmjs.org/dompurify/2.4.3:
+ resolution: {integrity: sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz}
+ name: dompurify
+ version: 2.4.3
+ dev: false
+
+ registry.npmjs.org/domutils/1.7.0:
+ resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz}
+ name: domutils
+ version: 1.7.0
+ dependencies:
+ dom-serializer: registry.npmjs.org/dom-serializer/0.2.2
+ domelementtype: registry.npmjs.org/domelementtype/1.3.1
+
+ registry.npmjs.org/domutils/2.8.0:
+ resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz}
+ name: domutils
+ version: 2.8.0
+ dependencies:
+ dom-serializer: registry.npmjs.org/dom-serializer/1.4.1
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/4.3.1
+
+ registry.npmjs.org/domutils/3.0.1:
+ resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz}
+ name: domutils
+ version: 3.0.1
+ dependencies:
+ dom-serializer: registry.npmjs.org/dom-serializer/2.0.0
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/5.0.3
+ dev: false
+
+ registry.npmjs.org/electron-to-chromium/1.4.256:
+ resolution: {integrity: sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz}
+ name: electron-to-chromium
+ version: 1.4.256
+
+ registry.npmjs.org/enhanced-resolve/5.10.0:
+ resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz}
+ name: enhanced-resolve
+ version: 5.10.0
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
+ tapable: registry.npmjs.org/tapable/2.2.1
+ dev: true
+
+ registry.npmjs.org/entities/2.2.0:
+ resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/entities/-/entities-2.2.0.tgz}
+ name: entities
+ version: 2.2.0
+
+ registry.npmjs.org/entities/4.4.0:
+ resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/entities/-/entities-4.4.0.tgz}
+ name: entities
+ version: 4.4.0
+ engines: {node: '>=0.12'}
+ dev: false
+
+ registry.npmjs.org/es-module-lexer/0.9.3:
+ resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz}
+ name: es-module-lexer
+ version: 0.9.3
+ dev: true
+
+ registry.npmjs.org/escalade/3.1.1:
+ resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz}
+ name: escalade
+ version: 3.1.1
+ engines: {node: '>=6'}
+
+ registry.npmjs.org/escape-string-regexp/1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz}
+ name: escape-string-regexp
+ version: 1.0.5
+ engines: {node: '>=0.8.0'}
+
+ registry.npmjs.org/eslint-scope/5.1.1:
+ resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz}
+ name: eslint-scope
+ version: 5.1.1
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ esrecurse: registry.npmjs.org/esrecurse/4.3.0
+ estraverse: registry.npmjs.org/estraverse/4.3.0
+ dev: true
+
+ registry.npmjs.org/esrecurse/4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz}
+ name: esrecurse
+ version: 4.3.0
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: registry.npmjs.org/estraverse/5.3.0
+ dev: true
+
+ registry.npmjs.org/estraverse/4.3.0:
+ resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz}
+ name: estraverse
+ version: 4.3.0
+ engines: {node: '>=4.0'}
+ dev: true
+
+ registry.npmjs.org/estraverse/5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz}
+ name: estraverse
+ version: 5.3.0
+ engines: {node: '>=4.0'}
+ dev: true
+
+ registry.npmjs.org/events/3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/events/-/events-3.3.0.tgz}
+ name: events
+ version: 3.3.0
+ engines: {node: '>=0.8.x'}
+ dev: true
+
+ registry.npmjs.org/fast-deep-equal/3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz}
+ name: fast-deep-equal
+ version: 3.1.3
+ dev: true
+
+ registry.npmjs.org/fast-json-stable-stringify/2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz}
+ name: fast-json-stable-stringify
+ version: 2.1.0
+ dev: true
+
+ registry.npmjs.org/fsevents/2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz}
+ name: fsevents
+ version: 2.3.2
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ registry.npmjs.org/gensync/1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz}
+ name: gensync
+ version: 1.0.0-beta.2
+ engines: {node: '>=6.9.0'}
+
+ registry.npmjs.org/glob-to-regexp/0.4.1:
+ resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz}
+ name: glob-to-regexp
+ version: 0.4.1
+ dev: true
+
+ registry.npmjs.org/globals/11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/globals/-/globals-11.12.0.tgz}
+ name: globals
+ version: 11.12.0
+ engines: {node: '>=4'}
+
+ registry.npmjs.org/graceful-fs/4.2.10:
+ resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz}
+ name: graceful-fs
+ version: 4.2.10
+
+ registry.npmjs.org/has-flag/3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz}
+ name: has-flag
+ version: 3.0.0
+ engines: {node: '>=4'}
+
+ registry.npmjs.org/has-flag/4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz}
+ name: has-flag
+ version: 4.0.0
+ engines: {node: '>=8'}
+ dev: true
+
+ registry.npmjs.org/html-dom-parser/3.1.3:
+ resolution: {integrity: sha512-fI0yyNlIeSboxU+jnrA4v8qj4+M8SI9/q6AKYdwCY2qki22UtKCDTxvagHniECu7sa5/o2zFRdLleA67035lsA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-3.1.3.tgz}
+ name: html-dom-parser
+ version: 3.1.3
+ dependencies:
+ domhandler: registry.npmjs.org/domhandler/5.0.3
+ htmlparser2: registry.npmjs.org/htmlparser2/8.0.1
+ dev: false
+
+ registry.npmjs.org/html-react-parser/3.0.8_react@18.2.0:
+ resolution: {integrity: sha512-eIxPq/3Ja3+nZkx6X/BNpFy0lNuW+v3V4nzABzuL8KkRVdYY/2KyXO42epKonsEVVRSBxm2zsxWcOkT6fYL+iQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/html-react-parser/-/html-react-parser-3.0.8.tgz}
+ id: registry.npmjs.org/html-react-parser/3.0.8
+ name: html-react-parser
+ version: 3.0.8
+ peerDependencies:
+ react: 0.14 || 15 || 16 || 17 || 18
+ dependencies:
+ domhandler: registry.npmjs.org/domhandler/5.0.3
+ html-dom-parser: registry.npmjs.org/html-dom-parser/3.1.3
+ react: 18.2.0
+ react-property: registry.npmjs.org/react-property/2.0.0
+ style-to-js: registry.npmjs.org/style-to-js/1.1.3
+ dev: false
+
+ registry.npmjs.org/htmlparser2/6.1.0:
+ resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz}
+ name: htmlparser2
+ version: 6.1.0
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/4.3.1
+ domutils: registry.npmjs.org/domutils/2.8.0
+ entities: registry.npmjs.org/entities/2.2.0
+
+ registry.npmjs.org/htmlparser2/8.0.1:
+ resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz}
+ name: htmlparser2
+ version: 8.0.1
+ dependencies:
+ domelementtype: registry.npmjs.org/domelementtype/2.3.0
+ domhandler: registry.npmjs.org/domhandler/5.0.3
+ domutils: registry.npmjs.org/domutils/3.0.1
+ entities: registry.npmjs.org/entities/4.4.0
+ dev: false
+
+ registry.npmjs.org/inline-style-parser/0.1.1:
+ resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz}
+ name: inline-style-parser
+ version: 0.1.1
+ dev: false
+
+ registry.npmjs.org/jest-worker/27.5.1:
+ resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz}
+ name: jest-worker
+ version: 27.5.1
+ engines: {node: '>= 10.13.0'}
+ dependencies:
+ '@types/node': registry.npmjs.org/@types/node/16.11.59
+ merge-stream: registry.npmjs.org/merge-stream/2.0.0
+ supports-color: registry.npmjs.org/supports-color/8.1.1
+ dev: true
+
+ registry.npmjs.org/js-tokens/4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz}
+ name: js-tokens
+ version: 4.0.0
+
+ registry.npmjs.org/jsesc/2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz}
+ name: jsesc
+ version: 2.5.2
+ engines: {node: '>=4'}
+ hasBin: true
+
+ registry.npmjs.org/json-parse-even-better-errors/2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz}
+ name: json-parse-even-better-errors
+ version: 2.3.1
+ dev: true
+
+ registry.npmjs.org/json-schema-traverse/0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz}
+ name: json-schema-traverse
+ version: 0.4.1
+ dev: true
+
+ registry.npmjs.org/json5/2.2.1:
+ resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/json5/-/json5-2.2.1.tgz}
+ name: json5
+ version: 2.2.1
+ engines: {node: '>=6'}
+ hasBin: true
+
+ registry.npmjs.org/loader-runner/4.3.0:
+ resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz}
+ name: loader-runner
+ version: 4.3.0
+ engines: {node: '>=6.11.5'}
+ dev: true
+
+ registry.npmjs.org/merge-stream/2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz}
+ name: merge-stream
+ version: 2.0.0
+ dev: true
+
+ registry.npmjs.org/mime-db/1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz}
+ name: mime-db
+ version: 1.52.0
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ registry.npmjs.org/mime-types/2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz}
+ name: mime-types
+ version: 2.1.35
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: registry.npmjs.org/mime-db/1.52.0
+ dev: true
+
+ registry.npmjs.org/ms/2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/ms/-/ms-2.1.2.tgz}
+ name: ms
+ version: 2.1.2
+
+ registry.npmjs.org/neo-async/2.6.2:
+ resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz}
+ name: neo-async
+ version: 2.6.2
+ dev: true
+
+ registry.npmjs.org/node-releases/2.0.6:
+ resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz}
+ name: node-releases
+ version: 2.0.6
+
+ registry.npmjs.org/picocolors/1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz}
+ name: picocolors
+ version: 1.0.0
+
+ registry.npmjs.org/punycode/2.1.1:
+ resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz}
+ name: punycode
+ version: 2.1.1
+ engines: {node: '>=6'}
+ dev: true
+
+ registry.npmjs.org/randombytes/2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz}
+ name: randombytes
+ version: 2.1.0
+ dependencies:
+ safe-buffer: registry.npmjs.org/safe-buffer/5.2.1
+ dev: true
+
+ registry.npmjs.org/react-property/2.0.0:
+ resolution: {integrity: sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz}
+ name: react-property
+ version: 2.0.0
+ dev: false
+
+ registry.npmjs.org/safe-buffer/5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz}
+ name: safe-buffer
+ version: 5.1.2
+
+ registry.npmjs.org/safe-buffer/5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz}
+ name: safe-buffer
+ version: 5.2.1
+ dev: true
+
+ registry.npmjs.org/schema-utils/3.1.1:
+ resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz}
+ name: schema-utils
+ version: 3.1.1
+ engines: {node: '>= 10.13.0'}
+ dependencies:
+ '@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11
+ ajv: registry.npmjs.org/ajv/6.12.6
+ ajv-keywords: registry.npmjs.org/ajv-keywords/3.5.2_ajv@6.12.6
+ dev: true
+
+ registry.npmjs.org/semver/6.3.0:
+ resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/semver/-/semver-6.3.0.tgz}
+ name: semver
+ version: 6.3.0
+ hasBin: true
+
+ registry.npmjs.org/serialize-javascript/6.0.0:
+ resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz}
+ name: serialize-javascript
+ version: 6.0.0
+ dependencies:
+ randombytes: registry.npmjs.org/randombytes/2.1.0
+ dev: true
+
+ registry.npmjs.org/source-map-support/0.5.21:
+ resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz}
+ name: source-map-support
+ version: 0.5.21
+ dependencies:
+ buffer-from: registry.npmjs.org/buffer-from/1.1.2
+ source-map: registry.npmjs.org/source-map/0.6.1
+ dev: true
+
+ registry.npmjs.org/source-map/0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz}
+ name: source-map
+ version: 0.6.1
+ engines: {node: '>=0.10.0'}
+
+ registry.npmjs.org/style-to-js/1.1.3:
+ resolution: {integrity: sha512-zKI5gN/zb7LS/Vm0eUwjmjrXWw8IMtyA8aPBJZdYiQTXj4+wQ3IucOLIOnF7zCHxvW8UhIGh/uZh/t9zEHXNTQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.3.tgz}
+ name: style-to-js
+ version: 1.1.3
+ dependencies:
+ style-to-object: registry.npmjs.org/style-to-object/0.4.1
+ dev: false
+
+ registry.npmjs.org/style-to-object/0.4.1:
+ resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz}
+ name: style-to-object
+ version: 0.4.1
+ dependencies:
+ inline-style-parser: registry.npmjs.org/inline-style-parser/0.1.1
+ dev: false
+
+ registry.npmjs.org/supports-color/5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz}
+ name: supports-color
+ version: 5.5.0
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: registry.npmjs.org/has-flag/3.0.0
+
+ registry.npmjs.org/supports-color/8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz}
+ name: supports-color
+ version: 8.1.1
+ engines: {node: '>=10'}
+ dependencies:
+ has-flag: registry.npmjs.org/has-flag/4.0.0
+ dev: true
+
+ registry.npmjs.org/tapable/2.2.1:
+ resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz}
+ name: tapable
+ version: 2.2.1
+ engines: {node: '>=6'}
+ dev: true
+
+ registry.npmjs.org/terser-webpack-plugin/5.3.6_webpack@5.74.0:
+ resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz}
+ id: registry.npmjs.org/terser-webpack-plugin/5.3.6
+ name: terser-webpack-plugin
+ version: 5.3.6
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ '@swc/core': '*'
+ esbuild: '*'
+ uglify-js: '*'
+ webpack: ^5.1.0
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ esbuild:
+ optional: true
+ uglify-js:
+ optional: true
+ dependencies:
+ '@jridgewell/trace-mapping': registry.npmjs.org/@jridgewell/trace-mapping/0.3.15
+ jest-worker: registry.npmjs.org/jest-worker/27.5.1
+ schema-utils: registry.npmjs.org/schema-utils/3.1.1
+ serialize-javascript: registry.npmjs.org/serialize-javascript/6.0.0
+ terser: registry.npmjs.org/terser/5.15.0
+ webpack: registry.npmjs.org/webpack/5.74.0
+ dev: true
+
+ registry.npmjs.org/terser/5.15.0:
+ resolution: {integrity: sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/terser/-/terser-5.15.0.tgz}
+ name: terser
+ version: 5.15.0
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/source-map': registry.npmjs.org/@jridgewell/source-map/0.3.2
+ acorn: registry.npmjs.org/acorn/8.8.0
+ commander: registry.npmjs.org/commander/2.20.3
+ source-map-support: registry.npmjs.org/source-map-support/0.5.21
+ dev: true
+
+ registry.npmjs.org/to-fast-properties/2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz}
+ name: to-fast-properties
+ version: 2.0.0
+ engines: {node: '>=4'}
+
+ registry.npmjs.org/update-browserslist-db/1.0.9_browserslist@4.21.4:
+ resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz}
+ id: registry.npmjs.org/update-browserslist-db/1.0.9
+ name: update-browserslist-db
+ version: 1.0.9
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+ dependencies:
+ browserslist: registry.npmjs.org/browserslist/4.21.4
+ escalade: registry.npmjs.org/escalade/3.1.1
+ picocolors: registry.npmjs.org/picocolors/1.0.0
+
+ registry.npmjs.org/uri-js/4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz}
+ name: uri-js
+ version: 4.4.1
+ dependencies:
+ punycode: registry.npmjs.org/punycode/2.1.1
+ dev: true
+
+ registry.npmjs.org/watchpack/2.4.0:
+ resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz}
+ name: watchpack
+ version: 2.4.0
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ glob-to-regexp: registry.npmjs.org/glob-to-regexp/0.4.1
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
+ dev: true
+
+ registry.npmjs.org/webpack-sources/3.2.3:
+ resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz}
+ name: webpack-sources
+ version: 3.2.3
+ engines: {node: '>=10.13.0'}
+ dev: true
+
+ registry.npmjs.org/webpack/5.74.0:
+ resolution: {integrity: sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz}
+ name: webpack
+ version: 5.74.0
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ peerDependencies:
+ webpack-cli: '*'
+ peerDependenciesMeta:
+ webpack-cli:
+ optional: true
+ dependencies:
+ '@types/eslint-scope': registry.npmjs.org/@types/eslint-scope/3.7.4
+ '@types/estree': registry.npmjs.org/@types/estree/0.0.51
+ '@webassemblyjs/ast': registry.npmjs.org/@webassemblyjs/ast/1.11.1
+ '@webassemblyjs/wasm-edit': registry.npmjs.org/@webassemblyjs/wasm-edit/1.11.1
+ '@webassemblyjs/wasm-parser': registry.npmjs.org/@webassemblyjs/wasm-parser/1.11.1
+ acorn: registry.npmjs.org/acorn/8.8.0
+ acorn-import-assertions: registry.npmjs.org/acorn-import-assertions/1.8.0_acorn@8.8.0
+ browserslist: registry.npmjs.org/browserslist/4.21.4
+ chrome-trace-event: registry.npmjs.org/chrome-trace-event/1.0.3
+ enhanced-resolve: registry.npmjs.org/enhanced-resolve/5.10.0
+ es-module-lexer: registry.npmjs.org/es-module-lexer/0.9.3
+ eslint-scope: registry.npmjs.org/eslint-scope/5.1.1
+ events: registry.npmjs.org/events/3.3.0
+ glob-to-regexp: registry.npmjs.org/glob-to-regexp/0.4.1
+ graceful-fs: registry.npmjs.org/graceful-fs/4.2.10
+ json-parse-even-better-errors: registry.npmjs.org/json-parse-even-better-errors/2.3.1
+ loader-runner: registry.npmjs.org/loader-runner/4.3.0
+ mime-types: registry.npmjs.org/mime-types/2.1.35
+ neo-async: registry.npmjs.org/neo-async/2.6.2
+ schema-utils: registry.npmjs.org/schema-utils/3.1.1
+ tapable: registry.npmjs.org/tapable/2.2.1
+ terser-webpack-plugin: registry.npmjs.org/terser-webpack-plugin/5.3.6_webpack@5.74.0
+ watchpack: registry.npmjs.org/watchpack/2.4.0
+ webpack-sources: registry.npmjs.org/webpack-sources/3.2.3
+ transitivePeerDependencies:
+ - '@swc/core'
+ - esbuild
+ - uglify-js
+ dev: true
diff --git a/ui/public/index.html b/ui/public/index.html
index ac5f558f..0cbf8d29 100644
--- a/ui/public/index.html
+++ b/ui/public/index.html
@@ -4,6 +4,7 @@
+
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index 1febc724..76583a8d 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -56,7 +56,7 @@ export interface QuestionParams {
title: string;
url_title?: string;
content: string;
- html: string;
+ html?: string;
tags: Tag[];
}
@@ -207,7 +207,7 @@ export interface AnswerItem {
export interface PostAnswerReq {
content: string;
- html: string;
+ html?: string;
question_id: string;
}
diff --git a/ui/src/components/Comment/components/Form/index.tsx b/ui/src/components/Comment/components/Form/index.tsx
index 70c62fdd..bc93ddb4 100644
--- a/ui/src/components/Comment/components/Form/index.tsx
+++ b/ui/src/components/Comment/components/Form/index.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect, memo } from 'react';
-import { Button } from 'react-bootstrap';
+import { Button, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
@@ -7,7 +7,7 @@ import classNames from 'classnames';
import { TextArea, Mentions } from '@/components';
import { usePageUsers } from '@/hooks';
-const Form = ({
+const Index = ({
className = '',
value: initialValue = '',
onSendReply,
@@ -18,7 +18,7 @@ const Form = ({
const [value, setValue] = useState('');
const pageUsers = usePageUsers();
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
-
+ const [validationErrorMsg, setValidationErrorMsg] = useState('');
useEffect(() => {
if (!initialValue) {
return;
@@ -32,6 +32,13 @@ const Form = ({
const handleSelected = (val) => {
setValue(val);
};
+ const handleSendReply = () => {
+ onSendReply(value).catch((ex) => {
+ if (ex.isError) {
+ setValidationErrorMsg(ex.msg);
+ }
+ });
+ };
return (
-
-
-
-
{t(`tip_${mode}`)}
+
+
+
+
+
{t(`tip_${mode}`)}
+
+
+ {validationErrorMsg}
+
{type === 'edit' ? (
)}
@@ -72,4 +89,4 @@ const Form = ({
);
};
-export default memo(Form);
+export default memo(Index);
diff --git a/ui/src/components/Comment/components/Reply/index.tsx b/ui/src/components/Comment/components/Reply/index.tsx
index 01c9399c..3048c3a4 100644
--- a/ui/src/components/Comment/components/Reply/index.tsx
+++ b/ui/src/components/Comment/components/Reply/index.tsx
@@ -1,21 +1,30 @@
import { useState, memo } from 'react';
-import { Button } from 'react-bootstrap';
+import { Button, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
+import classNames from 'classnames';
+
import { TextArea, Mentions } from '@/components';
import { usePageUsers } from '@/hooks';
-const Form = ({ userName, onSendReply, onCancel, mode }) => {
+const Index = ({ userName, onSendReply, onCancel, mode }) => {
const [value, setValue] = useState('');
const pageUsers = usePageUsers();
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
-
+ const [validationErrorMsg, setValidationErrorMsg] = useState('');
const handleChange = (e) => {
setValue(e.target.value);
};
const handleSelected = (val) => {
setValue(val);
};
+ const handleSendReply = () => {
+ onSendReply(value).catch((ex) => {
+ if (ex.isError) {
+ setValidationErrorMsg(ex.msg);
+ }
+ });
+ };
return (
@@ -24,18 +33,26 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
-
-
-
-
{t(`tip_${mode}`)}
+
+
+
+
+
{t(`tip_${mode}`)}
+
+
+ {validationErrorMsg}
+
);
};
diff --git a/ui/src/components/Pagination/index.tsx b/ui/src/components/Pagination/index.tsx
index e8ac8883..40f220f1 100644
--- a/ui/src/components/Pagination/index.tsx
+++ b/ui/src/components/Pagination/index.tsx
@@ -3,6 +3,8 @@ import { Pagination } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useSearchParams, useNavigate, useLocation } from 'react-router-dom';
+import { scrollToDocTop } from '@/utils';
+
interface Props {
currentPage: number;
pageSize: number;
@@ -49,7 +51,7 @@ const PageItem = ({ page, currentPage, path }: PageItemProps) => {
e.preventDefault();
e.stopPropagation();
navigate(path);
- window.scrollTo(0, 0);
+ scrollToDocTop();
}}>
{page}
@@ -91,7 +93,7 @@ const Index: FC
= ({
onClick={(e) => {
e.preventDefault();
navigate(handleParams(currentPage - 1));
- window.scrollTo(0, 0);
+ scrollToDocTop();
}}>
{t('prev')}
@@ -186,7 +188,7 @@ const Index: FC = ({
onClick={(e) => {
e.preventDefault();
navigate(handleParams(currentPage + 1));
- window.scrollTo(0, 0);
+ scrollToDocTop();
}}>
{t('next')}
diff --git a/ui/src/components/QuestionList/index.tsx b/ui/src/components/QuestionList/index.tsx
index a78cef80..d0e216c3 100644
--- a/ui/src/components/QuestionList/index.tsx
+++ b/ui/src/components/QuestionList/index.tsx
@@ -6,7 +6,6 @@ import { useTranslation } from 'react-i18next';
import { pathFactory } from '@/router/pathFactory';
import type * as Type from '@/common/interface';
import {
- Icon,
Tag,
Pagination,
FormatTime,
@@ -14,6 +13,7 @@ import {
BaseUserCard,
QueryGroup,
QuestionListLoader,
+ Counts,
} from '@/components';
import { useQuestionList } from '@/services';
@@ -95,29 +95,15 @@ const QuestionList: FC = ({ source }) => {
preFix={t(li.operation_type)}
/>
-
-
-
- {li.vote_count}
-
- = 1 ? 'text-success' : ''
- }`}>
- = 1
- ? 'check-circle-fill'
- : 'chat-square-text-fill'
- }
- />
- {li.answer_count}
-
-
-
- {li.view_count}
-
-
+
= 1}
+ className="ms-0 ms-md-3 mt-2 mt-md-0"
+ />
{Array.isArray(li.tags)
@@ -139,7 +125,7 @@ const QuestionList: FC
= ({ source }) => {
currentPage={curPage}
totalSize={count}
pageSize={pageSize}
- pathname="/questions"
+ pathname={source === 'questions' ? '/questions' : ''}
/>
diff --git a/ui/src/components/TagSelector/index.tsx b/ui/src/components/TagSelector/index.tsx
index 4cb72a83..5a2279e5 100644
--- a/ui/src/components/TagSelector/index.tsx
+++ b/ui/src/components/TagSelector/index.tsx
@@ -155,6 +155,7 @@ const TagSelector: FC = ({
};
const handleKeyDown = (e) => {
e.stopPropagation();
+
if (!tags) {
return;
}
@@ -166,13 +167,20 @@ const TagSelector: FC = ({
if (keyCode === 40 && currentIndex < tags.length - 1) {
setCurrentIndex(currentIndex + 1);
}
- if (
- keyCode === 13 &&
- currentIndex > -1 &&
- currentIndex <= tags.length - 1
- ) {
+
+ if (keyCode === 13 && currentIndex > -1) {
e.preventDefault();
- handleClick(tags[currentIndex]);
+
+ if (tags.length === 0) {
+ tagModal.onShow(tag);
+ return;
+ }
+ if (currentIndex <= tags.length - 1) {
+ handleClick(tags[currentIndex]);
+ if (currentIndex === tags.length - 1 && currentIndex > 0) {
+ setCurrentIndex(currentIndex - 1);
+ }
+ }
}
};
return (
diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts
index 2a475e8b..49340cf7 100644
--- a/ui/src/components/index.ts
+++ b/ui/src/components/index.ts
@@ -32,6 +32,7 @@ import CustomizeTheme from './CustomizeTheme';
import PageTags from './PageTags';
import QuestionListLoader from './QuestionListLoader';
import TagsLoader from './TagsLoader';
+import Counts from './Counts';
export {
Avatar,
@@ -70,5 +71,6 @@ export {
PageTags,
QuestionListLoader,
TagsLoader,
+ Counts,
};
export type { EditorRef, JSONSchema, UISchema };
diff --git a/ui/src/pages/Questions/Ask/index.tsx b/ui/src/pages/Questions/Ask/index.tsx
index e4bc9cfd..b5cce8db 100644
--- a/ui/src/pages/Questions/Ask/index.tsx
+++ b/ui/src/pages/Questions/Ask/index.tsx
@@ -143,21 +143,7 @@ const Ask = () => {
const checkValidated = (): boolean => {
const bol = true;
const { title, content, tags, answer } = formData;
- if (!title.value) {
- // bol = false;
- // formData.title = {
- // value: '',
- // isInvalid: true,
- // errorMsg: t('form.fields.title.msg.empty'),
- // };
- } else if (Array.from(title.value).length > 150) {
- // bol = false;
- // formData.title = {
- // value: title.value,
- // isInvalid: true,
- // errorMsg: t('form.fields.title.msg.range'),
- // };
- } else {
+ if (title.value && Array.from(title.value).length <= 150) {
formData.title = {
value: title.value,
isInvalid: false,
@@ -165,14 +151,7 @@ const Ask = () => {
};
}
- if (!content.value) {
- // bol = false;
- // formData.content = {
- // value: '',
- // isInvalid: true,
- // errorMsg: t('form.fields.body.msg.empty'),
- // };
- } else {
+ if (content.value) {
formData.content = {
value: content.value,
isInvalid: false,
@@ -180,29 +159,16 @@ const Ask = () => {
};
}
- if (tags.value.length === 0) {
- // bol = false;
- // formData.tags = {
- // value: [],
- // isInvalid: true,
- // errorMsg: t('form.fields.tags.msg.empty'),
- // };
- } else {
+ if (Array.isArray(tags.value) && tags.value.length > 0) {
formData.tags = {
value: tags.value,
isInvalid: false,
errorMsg: '',
};
}
+
if (checked) {
- if (!answer.value) {
- // bol = false;
- // formData.answer = {
- // value: '',
- // isInvalid: true,
- // errorMsg: t('form.fields.answer.msg.empty'),
- // };
- } else {
+ if (answer.value) {
formData.answer = {
value: answer.value,
isInvalid: false,
@@ -227,7 +193,6 @@ const Ask = () => {
const params: Type.QuestionParams = {
title: formData.title.value,
content: formData.content.value,
- html: editorRef.current.getHtml(),
tags: formData.tags.value,
};
if (isEdit) {
@@ -261,7 +226,6 @@ const Ask = () => {
postAnswer({
question_id: id,
content: formData.answer.value,
- html: editorRef2.current.getHtml(),
})
.then(() => {
navigate(pathFactory.questionLanding(id, params.url_title));
diff --git a/ui/src/pages/Questions/Detail/components/Answer/index.tsx b/ui/src/pages/Questions/Detail/components/Answer/index.tsx
index 83824f12..1fb5f5d0 100644
--- a/ui/src/pages/Questions/Detail/components/Answer/index.tsx
+++ b/ui/src/pages/Questions/Detail/components/Answer/index.tsx
@@ -12,7 +12,7 @@ import {
FormatTime,
htmlRender,
} from '@/components';
-import { scrollTop, bgFadeOut } from '@/utils';
+import { scrollToElementTop, bgFadeOut } from '@/utils';
import { AnswerItem } from '@/common/interface';
import { acceptanceAnswer } from '@/services';
@@ -60,7 +60,7 @@ const Index: FC = ({
if (aid === data.id) {
setTimeout(() => {
const element = answerRef.current;
- scrollTop(element);
+ scrollToElementTop(element);
if (!searchParams.get('commentId')) {
bgFadeOut(answerRef.current);
}
diff --git a/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx b/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
index f1c7abbb..44cfa2cd 100644
--- a/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
+++ b/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
@@ -8,7 +8,7 @@ import classNames from 'classnames';
import { Editor, Modal, TextArea } from '@/components';
import { FormDataType } from '@/common/interface';
import { postAnswer } from '@/services';
-import { guard } from '@/utils';
+import { guard, handleFormError } from '@/utils';
interface Props {
visible?: boolean;
@@ -35,35 +35,60 @@ const Index: FC = ({ visible = false, data, callback }) => {
const [focusType, setFocusType] = useState('');
const [editorFocusState, setEditorFocusState] = useState(false);
+ const checkValidated = (): boolean => {
+ let bol = true;
+ const { content } = formData;
+
+ if (!content.value || Array.from(content.value.trim()).length < 6) {
+ bol = false;
+ formData.content = {
+ value: content.value,
+ isInvalid: true,
+ errorMsg: t('characters'),
+ };
+ } else {
+ formData.content = {
+ value: content.value,
+ isInvalid: false,
+ errorMsg: '',
+ };
+ }
+
+ setFormData({
+ ...formData,
+ });
+ return bol;
+ };
+
const handleSubmit = () => {
if (!guard.tryNormalLogged(true)) {
return;
}
- if (!formData.content.value) {
- setFormData({
- content: {
- value: '',
- isInvalid: true,
- errorMsg: t('empty'),
- },
- });
+ if (!checkValidated()) {
return;
}
postAnswer({
question_id: data?.qid,
content: formData.content.value,
html: marked.parse(formData.content.value),
- }).then((res) => {
- setShowEditor(false);
- setFormData({
- content: {
- value: '',
- isInvalid: false,
- errorMsg: '',
- },
+ })
+ .then((res) => {
+ setShowEditor(false);
+ setFormData({
+ content: {
+ value: '',
+ isInvalid: false,
+ errorMsg: '',
+ },
+ });
+ callback?.(res.info);
+ })
+ .catch((ex) => {
+ if (ex.isError) {
+ const stateData = handleFormError(ex, formData);
+ setFormData({ ...stateData });
+ }
});
- callback?.(res.info);
- });
};
const clickBtn = () => {
diff --git a/ui/src/pages/Questions/Detail/index.tsx b/ui/src/pages/Questions/Detail/index.tsx
index 0f3a5540..14f14bda 100644
--- a/ui/src/pages/Questions/Detail/index.tsx
+++ b/ui/src/pages/Questions/Detail/index.tsx
@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
import Pattern from '@/common/pattern';
import { Pagination } from '@/components';
import { loggedUserInfoStore, toastStore } from '@/stores';
-import { scrollTop } from '@/utils';
+import { scrollToElementTop } from '@/utils';
import { usePageTags, usePageUsers } from '@/hooks';
import type {
ListResult,
@@ -80,7 +80,7 @@ const Index = () => {
if (page > 0 || order) {
// scroll into view;
const element = document.getElementById('answerHeader');
- scrollTop(element);
+ scrollToElementTop(element);
}
res.list.forEach((item) => {
diff --git a/ui/src/pages/Questions/EditAnswer/index.tsx b/ui/src/pages/Questions/EditAnswer/index.tsx
index f5733851..411affbd 100644
--- a/ui/src/pages/Questions/EditAnswer/index.tsx
+++ b/ui/src/pages/Questions/EditAnswer/index.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useRef } from 'react';
+import React, { useState, useRef } from 'react';
import { Container, Row, Col, Form, Button, Card } from 'react-bootstrap';
import { useParams, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import classNames from 'classnames';
+import { handleFormError } from '@/utils';
import { usePageTags } from '@/hooks';
import { pathFactory } from '@/router/pathFactory';
import { Editor, EditorRef, Icon } from '@/components';
@@ -19,11 +20,11 @@ import {
import './index.scss';
interface FormDataItem {
- answer: Type.FormValue;
+ content: Type.FormValue;
description: Type.FormValue;
}
const initFormData = {
- answer: {
+ content: {
value: '',
isInvalid: false,
errorMsg: '',
@@ -35,7 +36,6 @@ const initFormData = {
},
};
const Index = () => {
- const [formData, setFormData] = useState(initFormData);
const { aid = '', qid = '' } = useParams();
const [focusType, setForceType] = useState('');
@@ -43,6 +43,10 @@ const Index = () => {
const navigate = useNavigate();
const { data } = useQueryAnswerInfo(aid);
+ const [formData, setFormData] = useState(initFormData);
+
+ initFormData.content.value = data?.info.content || '';
+
const { data: revisions = [] } = useQueryRevisions(aid);
const editorRef = useRef({
@@ -51,18 +55,10 @@ const Index = () => {
const questionContentRef = useRef(null);
- useEffect(() => {
- if (!data) {
- return;
- }
- formData.answer.value = data.info.content;
- setFormData({ ...formData });
- }, [data]);
-
const handleAnswerChange = (value: string) =>
setFormData({
...formData,
- answer: { ...formData.answer, value },
+ content: { ...formData.content, value },
});
const handleSummaryChange = (evt) => {
const v = evt.currentTarget.value;
@@ -74,18 +70,18 @@ const Index = () => {
const checkValidated = (): boolean => {
let bol = true;
- const { answer } = formData;
+ const { content } = formData;
- if (!answer.value) {
+ if (!content.value || Array.from(content.value.trim()).length < 6) {
bol = false;
- formData.answer = {
- value: '',
+ formData.content = {
+ value: content.value,
isInvalid: true,
- errorMsg: '标题不能为空',
+ errorMsg: t('form.fields.answer.feedback.characters'),
};
} else {
- formData.answer = {
- value: answer.value,
+ formData.content = {
+ value: content.value,
isInvalid: false,
errorMsg: '',
};
@@ -105,29 +101,36 @@ const Index = () => {
}
const params: Type.AnswerParams = {
- content: formData.answer.value,
+ content: formData.content.value,
html: editorRef.current.getHtml(),
question_id: qid,
id: aid,
edit_summary: formData.description.value,
};
- modifyAnswer(params).then((res) => {
- navigate(
- pathFactory.answerLanding({
- questionId: qid,
- slugTitle: data?.question?.url_title,
- answerId: aid,
- }),
- {
- state: { isReview: res?.wait_for_review },
- },
- );
- });
+ modifyAnswer(params)
+ .then((res) => {
+ navigate(
+ pathFactory.answerLanding({
+ questionId: qid,
+ slugTitle: data?.question?.url_title,
+ answerId: aid,
+ }),
+ {
+ state: { isReview: res?.wait_for_review },
+ },
+ );
+ })
+ .catch((ex) => {
+ if (ex.isError) {
+ const stateData = handleFormError(ex, formData);
+ setFormData({ ...stateData });
+ }
+ });
};
const handleSelectedRevision = (e) => {
const index = e.target.value;
const revision = revisions[index];
- formData.answer.value = revision.content.content;
+ formData.content.value = revision.content.content;
setFormData({ ...formData });
};
@@ -190,7 +193,7 @@ const Index = () => {
{t('form.fields.answer.label')}
{
ref={editorRef}
/>
- {formData.answer.errorMsg}
+ {formData.content.errorMsg}
diff --git a/ui/src/pages/Search/components/SearchItem/index.tsx b/ui/src/pages/Search/components/SearchItem/index.tsx
index dc63246c..1b4f786c 100644
--- a/ui/src/pages/Search/components/SearchItem/index.tsx
+++ b/ui/src/pages/Search/components/SearchItem/index.tsx
@@ -3,7 +3,7 @@ import { ListGroupItem } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { pathFactory } from '@/router/pathFactory';
-import { Icon, Tag, FormatTime, BaseUserCard } from '@/components';
+import { Tag, FormatTime, BaseUserCard, Counts } from '@/components';
import type { SearchResItem } from '@/common/interface';
import { escapeRemove } from '@/utils';
@@ -51,23 +51,17 @@ const Index: FC = ({ data }) => {
className="me-3"
preFix={data.object_type === 'question' ? 'asked' : 'answered'}
/>
-
-
-
- {data.object?.vote_count}
-
-
- {data.object?.accepted ? (
-
- ) : (
-
- )}
- {data.object?.answer_count}
-
-
+
+
{data.object?.excerpt && (
diff --git a/ui/src/pages/Users/ActivationResult/index.tsx b/ui/src/pages/Users/ActivationResult/index.tsx
index 77cdd52b..b62e2af4 100644
--- a/ui/src/pages/Users/ActivationResult/index.tsx
+++ b/ui/src/pages/Users/ActivationResult/index.tsx
@@ -3,10 +3,12 @@ import { Container, Row, Col } from 'react-bootstrap';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
+import { siteInfoStore } from '@/stores';
import { usePageTags } from '@/hooks';
const Index: FC = () => {
const { t } = useTranslation('translation', { keyPrefix: 'account_result' });
+ const siteName = siteInfoStore((state) => state.siteInfo.name);
const location = useLocation();
usePageTags({
title: t('account_activation', { keyPrefix: 'page_title' }),
@@ -15,7 +17,9 @@ const Index: FC = () => {
- {t('page_title')}
+
+ {t('page_title', { site_name: siteName })}
+
{location.pathname?.includes('success') && (
<>
{t('success')}
diff --git a/ui/src/pages/Users/ChangeEmail/index.tsx b/ui/src/pages/Users/ChangeEmail/index.tsx
index 33fcd8d3..225c7f6c 100644
--- a/ui/src/pages/Users/ChangeEmail/index.tsx
+++ b/ui/src/pages/Users/ChangeEmail/index.tsx
@@ -2,18 +2,22 @@ import { FC, memo } from 'react';
import { Container, Col } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
+import { siteInfoStore } from '@/stores';
import { usePageTags } from '@/hooks';
import SendEmail from './components/sendEmail';
const Index: FC = () => {
const { t } = useTranslation('translation', { keyPrefix: 'change_email' });
+ const siteName = siteInfoStore((state) => state.siteInfo.name);
usePageTags({
title: t('change_email', { keyPrefix: 'page_title' }),
});
return (
- {t('page_title')}
+
+ {t('page_title', { site_name: siteName })}
+
diff --git a/ui/src/pages/Users/ConfirmNewEmail/index.tsx b/ui/src/pages/Users/ConfirmNewEmail/index.tsx
index c30cd801..16d09c9c 100644
--- a/ui/src/pages/Users/ConfirmNewEmail/index.tsx
+++ b/ui/src/pages/Users/ConfirmNewEmail/index.tsx
@@ -4,7 +4,7 @@ import { Link, useSearchParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { usePageTags } from '@/hooks';
-import { loggedUserInfoStore } from '@/stores';
+import { loggedUserInfoStore, siteInfoStore } from '@/stores';
import { changeEmailVerify, getLoggedUserInfo } from '@/services';
const Index: FC = () => {
@@ -13,6 +13,7 @@ const Index: FC = () => {
const [step, setStep] = useState('loading');
const updateUser = loggedUserInfoStore((state) => state.update);
+ const siteName = siteInfoStore((state) => state.siteInfo.name);
useEffect(() => {
const code = searchParams.get('code');
@@ -38,7 +39,9 @@ const Index: FC = () => {
- {t('page_title')}
+
+ {t('page_title', { site_name: siteName })}
+
{step === 'success' && (
<>
{t('confirm_new_email')}
diff --git a/ui/src/pages/Users/Personal/components/Answers/index.tsx b/ui/src/pages/Users/Personal/components/Answers/index.tsx
index 383b09df..6f4685ec 100644
--- a/ui/src/pages/Users/Personal/components/Answers/index.tsx
+++ b/ui/src/pages/Users/Personal/components/Answers/index.tsx
@@ -2,7 +2,7 @@ import { FC, memo } from 'react';
import { ListGroup, ListGroupItem } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
-import { Icon, FormatTime, Tag } from '@/components';
+import { FormatTime, Tag, Counts } from '@/components';
import { pathFactory } from '@/router/pathFactory';
interface Props {
@@ -35,21 +35,16 @@ const Index: FC = ({ visible, data }) => {
-
-
- {item?.vote_count}
-
-
- {item.accepted === 2 && (
-
-
- {t('accepted')}
-
- )}
+
{item.question_info?.tags?.map((tag) => {
diff --git a/ui/src/pages/Users/Personal/components/DefaultList/index.tsx b/ui/src/pages/Users/Personal/components/DefaultList/index.tsx
index 5084f7ee..eeae2c9e 100644
--- a/ui/src/pages/Users/Personal/components/DefaultList/index.tsx
+++ b/ui/src/pages/Users/Personal/components/DefaultList/index.tsx
@@ -2,7 +2,7 @@ import { FC, memo } from 'react';
import { ListGroup, ListGroupItem } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
-import { Icon, FormatTime, Tag, BaseUserCard } from '@/components';
+import { FormatTime, Tag, BaseUserCard, Counts } from '@/components';
import { pathFactory } from '@/router/pathFactory';
interface Props {
@@ -44,35 +44,23 @@ const Index: FC
= ({ visible, tabName, data }) => {
>
)}
+
-
-
- {item.vote_count}
-
-
- {tabName !== 'answers' && (
- 0 ? 'text-success' : ''
- }`}>
- {Number(item.accepted_answer_id) > 0 ? (
-
- ) : (
-
- )}
- {item.answer_count}
-
- )}
-
-
-
- {item.view_count}
-
+ 0}
+ data={{
+ votes: item.vote_count,
+ answers: item.answer_count,
+ views: item.view_count,
+ }}
+ />
{item.tags?.map((tag) => {
diff --git a/ui/src/pages/Users/Personal/components/TopList/index.tsx b/ui/src/pages/Users/Personal/components/TopList/index.tsx
index 744a3f7b..43e5159d 100644
--- a/ui/src/pages/Users/Personal/components/TopList/index.tsx
+++ b/ui/src/pages/Users/Personal/components/TopList/index.tsx
@@ -32,9 +32,12 @@ const Index: FC
= ({ data, type }) => {
}>
{type === 'answer' ? item.question_info.title : item.title}
+
-
- {item.vote_count}
+
+
+ {item.vote_count} {t('votes', { keyPrefix: 'counts' })}
+
{type === 'question' && (
= ({ data, type }) => {
)}
- {item.answer_count}
+
+ {' '}
+ {item.answer_count} {t('answers', { keyPrefix: 'counts' })}
+
)}
diff --git a/ui/src/pages/Users/Settings/Profile/index.tsx b/ui/src/pages/Users/Settings/Profile/index.tsx
index 2d703b9e..698a49b2 100644
--- a/ui/src/pages/Users/Settings/Profile/index.tsx
+++ b/ui/src/pages/Users/Settings/Profile/index.tsx
@@ -2,7 +2,6 @@ import React, { FormEvent, useState, useEffect } from 'react';
import { Form, Button, Stack, ButtonGroup } from 'react-bootstrap';
import { Trans, useTranslation } from 'react-i18next';
-import { marked } from 'marked';
import MD5 from 'md5';
import type { FormDataType } from '@/common/interface';
@@ -205,7 +204,6 @@ const Index: React.FC = () => {
bio: formData.bio.value,
website: formData.website.value,
location: formData.location.value,
- bio_html: marked.parse(formData.bio.value),
};
modifyUserInfo(params)
diff --git a/ui/src/utils/common.ts b/ui/src/utils/common.ts
index e3e53652..c48c01bd 100644
--- a/ui/src/utils/common.ts
+++ b/ui/src/utils/common.ts
@@ -1,4 +1,6 @@
import i18next from 'i18next';
+import parse from 'html-react-parser';
+import * as DOMPurify from 'dompurify';
const Diff = require('diff');
@@ -21,7 +23,7 @@ function formatCount($num: number): string {
return res;
}
-function scrollTop(element) {
+function scrollToElementTop(element) {
if (!element) {
return;
}
@@ -36,6 +38,15 @@ function scrollTop(element) {
});
}
+const scrollToDocTop = () => {
+ setTimeout(() => {
+ window.scrollTo({
+ top: 0,
+ behavior: 'smooth',
+ });
+ });
+};
+
const bgFadeOut = (el) => {
if (el && !el.classList.contains('bg-fade-out')) {
el.classList.add('bg-fade-out');
@@ -160,14 +171,17 @@ function handleFormError(
) {
if (error.list?.length > 0) {
error.list.forEach((item) => {
- data[item.error_field].isInvalid = true;
- data[item.error_field].errorMsg = item.error_msg;
+ const errorFieldObject = data[item.error_field];
+ if (errorFieldObject) {
+ errorFieldObject.isInvalid = true;
+ errorFieldObject.errorMsg = item.error_msg;
+ }
});
}
return data;
}
-function diffText(newText: string, oldText: string): string {
+function diffText(newText: string, oldText?: string): string {
if (!newText) {
return '';
}
@@ -181,8 +195,6 @@ function diffText(newText: string, oldText: string): string {
?.replace(/ {
if (part.added) {
if (part.value.replace(/\n/g, '').length <= 0) {
@@ -214,10 +226,18 @@ function diffText(newText: string, oldText: string): string {
?.replace(/ {
};
export const shouldInitAppFetchData = () => {
- if (isIgnoredPath('/install')) {
+ if (isIgnoredPath('/install') && window.location.pathname === '/install') {
return false;
}
diff --git a/ui/src/utils/request.ts b/ui/src/utils/request.ts
index 4126c892..615cc8a3 100644
--- a/ui/src/utils/request.ts
+++ b/ui/src/utils/request.ts
@@ -48,7 +48,7 @@ class Request {
},
(error) => {
const { status, data: respData } = error.response || {};
- const { data = {}, msg = '' } = respData || {};
+ const { data = {}, msg = '', reason = '' } = respData || {};
if (status === 400) {
// show error message
if (data instanceof Object && data.err_type) {
@@ -79,7 +79,13 @@ class Request {
if (data instanceof Array && data.length > 0) {
// handle form error
- return Promise.reject({ isError: true, list: data });
+ return Promise.reject({
+ code: status,
+ msg,
+ reason,
+ isError: true,
+ list: data,
+ });
}
if (!data || Object.keys(data).length <= 0) {
diff --git a/ui/template/header.html b/ui/template/header.html
index 3a12a6a8..5b654c56 100644
--- a/ui/template/header.html
+++ b/ui/template/header.html
@@ -6,9 +6,9 @@
{{.title}}
- {{if .keywords }}
-
- {{end}}
+
+ {{if .keywords }}{{end}}
+