提交 9c6d7531 作者: 方治民

feat: springboot v3 + openapi v3 等相关适配完成

上级 ccb648b8
......@@ -30,11 +30,11 @@ dependencies {
// Optional: Doc
implementation project(":basic-common:doc")
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// Optional: Auth
implementation project(":basic-auth")
implementation "cn.dev33:sa-token-spring-boot-starter:${saTokenVersion}"
implementation "cn.dev33:sa-token-spring-boot3-starter:${saTokenVersion}"
// Optional: WebSocket && STOMP 依赖 Auth + Redis 模块
implementation project(":basic-websocket")
......@@ -59,6 +59,6 @@ dependencies {
implementation "cn.hutool:hutool-core:${hutoolVersion}"
implementation "cn.hutool:hutool-extra:${hutoolVersion}"
// https://github.com/vladmihalcea/hibernate-types
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.app.config;
import cn.dev33.satoken.exception.*;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.exception.FailStatusException;
import javax.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.aspectj.bridge.AbortException;
import org.hibernate.validator.internal.engine.ConstraintViolationImpl;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局错误处理
......@@ -33,130 +19,14 @@ import org.springframework.web.bind.annotation.ResponseStatus;
* 2017年11月30日 上午11:36:31
*/
@Slf4j
@ControllerAdvice
@ResponseBody
@Order
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {
final I18n i18n;
/**
* 参数校验异常
*
* @param e 异常信息
* @return 统一的校验失败信息 {@link Status#EXPECTATION_FAILED
*/
@ExceptionHandler(
{ BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class }
)
public Result<String> validFailHandler(Exception e) {
String details = null;
if (e instanceof ConstraintViolationException) {
details = ((ConstraintViolationException) e).getConstraintViolations().iterator().next().getMessage();
} else {
BindingResult result = null;
if (e instanceof MethodArgumentNotValidException) {
result = ((MethodArgumentNotValidException) e).getBindingResult();
} else if (e instanceof BindException) {
result = ((BindException) e).getBindingResult();
}
if (result != null) {
ObjectError error = result.getAllErrors().iterator().next();
if (error instanceof FieldError fieldError) {
// TODO: 可以优化成提取 @ApiModelProperty value 中文描述
// 构建明确的字段错误提示, 例如: id 不能为 null, 如果自己填写了 message 则不追加 field 字段前缀
ConstraintViolationImpl<?> violation = error.unwrap(ConstraintViolationImpl.class);
String template = violation.getMessageTemplate();
String prefix = "";
// 如果是模板字符串, 则在消息前添加字段提示
if (template.contains("{") && template.contains("}")) {
prefix = fieldError.getField() + " ";
}
details = prefix + i18n.get(fieldError);
} else {
details = i18n.get(error);
}
}
}
return Result.no(Status.EXPECTATION_FAILED, details);
}
/**
* 不支持的HttpMethod异常
*
* @param e 异常信息
* @return 异常信息反馈 {@link Status#METHOD_NOT_ALLOWED
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result<String> httpRequestMethodNotSupportedErrorHandler(Exception e) {
return Result.no(Status.METHOD_NOT_ALLOWED, e.getMessage());
}
/**
* 未登录异常(鉴权失败)
*
* @return 异常信息反馈 {@link Status#UNAUTHORIZED
*/
@ExceptionHandler(NotLoginException.class)
public Result<String> unauthorizedErrorHandler() {
return Result.no(Status.UNAUTHORIZED);
}
/**
* 1. 二级认证失败异常
* 2. 角色条件不满足
* 3. 权限条件不满足
* 4. HTTP Basic 验证不通过
* 5. 用户被禁止访问该服务
* 6. API 被禁用
*
* @return 异常信息反馈 {@link Status#FORBIDDEN
*/
@ExceptionHandler(
{
// https://sa-token.dev33.cn/doc.html#/up/safe-auth
NotSafeException.class,
// https://sa-token.dev33.cn/doc.html#/use/at-check
NotRoleException.class,
NotPermissionException.class,
// https://sa-token.dev33.cn/doc.html#/up/basic-auth
NotBasicAuthException.class,
// https://sa-token.dev33.cn/doc.html#/up/disable
DisableServiceException.class,
ApiDisabledException.class,
}
)
public Result<String> forbiddenHandler() {
return Result.no(Status.FORBIDDEN);
}
/**
* 自定义业务异常
*/
@ExceptionHandler(BusinessException.class)
public Result<String> businessExceptionHandler(BusinessException e) {
return Result.no(Status.BAD_REQUEST, e.getCode(), e.getMessage(), null);
}
/**
* 失败状态异常
*/
@ExceptionHandler(FailStatusException.class)
public Result<String> failStatusExceptionHandler(FailStatusException e) {
return Result.no(e.getStatus(), e.getMessage());
}
/**
* 取消请求异常(忽略)
*/
@ExceptionHandler({ ClientAbortException.class, AbortException.class, HttpMessageNotWritableException.class })
public void ignoreExceptionHandler() {}
/**
* 其他异常
*
* @param e 异常信息
......
......@@ -3,12 +3,12 @@ package com.yiring.app.domain.user;
import com.yiring.auth.domain.user.User;
import com.yiring.common.domain.BasicEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.io.Serial;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
......
......@@ -2,11 +2,13 @@
package com.yiring.app.vo.user;
import com.yiring.common.jackson.MappingSerialize;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
/**
......@@ -15,9 +17,8 @@ import lombok.experimental.FieldDefaults;
* 2022/7/13 11:36
*/
@ApiModel("UserExtensionVo")
@Schema(name = "UserExtensionVo", description = "用户扩展信息")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
......@@ -26,10 +27,13 @@ public class UserExtensionVo implements Serializable {
@Serial
private static final long serialVersionUID = -2251567849918281906L;
@ApiModelProperty(value = "性别", example = "男")
@Schema(description = "性别", example = "男", allowableValues = { "男", "女" }, type = "string")
@MappingSerialize(mapping = "0:女,1:男")
Integer gender;
@ApiModelProperty(value = "年龄", example = "18")
@Schema(description = "年龄", example = "18")
Integer age;
@Schema(description = "简介", example = "Hi")
String introduction;
}
......@@ -10,6 +10,7 @@ import com.yiring.app.domain.user.UserExtensionRepository;
import com.yiring.app.vo.user.UserExtensionVo;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
import com.yiring.common.annotation.DownloadResponse;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
......@@ -19,16 +20,17 @@ import com.yiring.common.util.Commons;
import com.yiring.common.util.FileUtils;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Example;
import org.springframework.http.MediaType;
......@@ -43,9 +45,8 @@ import org.springframework.web.bind.annotation.*;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = 0)
@Api(tags = "示例", description = "Example")
@Tag(name = "示例", description = "Example")
@RequestMapping("/example/")
@RestController
@RequiredArgsConstructor
......@@ -55,7 +56,7 @@ public class ExampleController {
final Auths auths;
final UserExtensionRepository userExtensionRepository;
@ApiOperation("Hello World")
@Operation(summary = "Hello World")
@GetMapping
public Result<String> hello() {
return Result.ok("example.hello");
......@@ -64,16 +65,16 @@ public class ExampleController {
/**
* 测试失败自定义状态信息输出
*/
@ApiOperation("测试失败")
@Operation(summary = "测试失败")
@GetMapping("fail")
public Result<String> fail() {
throw BusinessException.i18n("Code.1");
}
@SaCheckLogin
@ApiOperation("分页条件查询")
@Operation(summary = "分页条件查询")
@GetMapping("page")
public Result<PageVo<String>> page(@Validated PageParam param) {
public Result<PageVo<String>> page(@ParameterObject @Validated PageParam param) {
log.debug("PageParam: {}", param);
String text = i18n.get("example.hello");
......@@ -82,7 +83,7 @@ public class ExampleController {
return Result.ok(vo);
}
@ApiOperation(value = "JSON 传参")
@Operation(summary = "JSON 传参")
@PostMapping("json")
public Result<PageVo<String>> json(
@RequestBody(required = false) @Validated(Group.Optional.class) PageParam param
......@@ -91,9 +92,10 @@ public class ExampleController {
}
@SaIgnore
@DownloadResponse
@SneakyThrows(IOException.class)
@ApiOperation(value = "文件下载", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@GetMapping("download")
@Operation(summary = "文件下载")
@GetMapping(value = "download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {
ClassPathResource resource = new ClassPathResource("static/cat.jpg");
FileUtils.download(response, resource.getFile());
......@@ -101,7 +103,7 @@ public class ExampleController {
@SaCheckSafe
@SaCheckLogin
@ApiOperation("查询用户属性")
@Operation(summary = "查询用户属性")
@GetMapping("findUserExtensionInfo")
public Result<UserExtensionVo> findUserExtensionInfo() {
User user = auths.getLoginUser();
......
......@@ -19,3 +19,5 @@ logging:
springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator: WARN
# 关闭接口扫描 ApiListingReferenceScanner 日志
springfox.documentation.spring.web.scanners.ApiListingReferenceScanner: WARN
# https://github.com/spring-projects/spring-framework/issues/29612
org.springframework.core.LocalVariableTableParameterNameDiscoverer: ERROR
......@@ -12,19 +12,34 @@ spring:
username: ${env.extra.username}
password: ${env.extra.password}
jpa:
database-platform: org.hibernate.dialect.PostgreSQL10Dialect
database-platform: org.hibernate.dialect.PostgreSQLDialect
open-in-view: true
hibernate:
ddl-auto: update
show-sql: true
show-sql: false
properties:
hibernate:
format_sql: true
redis:
database: 5
host: ${env.host}
port: 6379
password: ${env.extra.password}
# https://github.com/spring-projects/spring-data-jpa/issues/2717
# https://hibernate.atlassian.net/browse/HHH-15827
jakarta:
persistence:
sharedCache:
mode: UNSPECIFIED
data:
redis:
database: 5
port: 6379
host: ${env.host}
password: ${env.extra.password}
springdoc:
default-consumes-media-type: "application/x-www-form-urlencoded"
default-produces-media-type: "application/json"
default-flat-param-object: true
override-with-generic-response: false
api-docs:
resolve-schema-properties: true
# knife4j
knife4j:
......
......@@ -3,3 +3,16 @@
example.hello=\uD83D\uDE0E Hello World
# \u4E1A\u52A1\u72B6\u6001\u7801\u9519\u8BEF\u6D88\u606F
Code.1=\u5931\u8D25
Code.1000=\u7528\u6237\u4E0D\u5B58\u5728
Code.1001=\u6743\u9650\u6807\u8BC6\u91CD\u590D
Code.1002=\u89D2\u8272\u6807\u8BC6\u91CD\u590D
Code.10000=\u4E8C\u7EA7\u8BA4\u8BC1\u6821\u9A8C\u5931\u8D25
Code.10001=\u89D2\u8272\u6743\u9650\u4E0D\u8DB3
Code.10002=\u6743\u9650\u4E0D\u8DB3
Code.10003=\u672A\u6388\u6743
Code.100000=\u7528\u6237\u540D\u5DF2\u5B58\u5728
Code.100001=\u624B\u673A\u53F7\u5DF2\u5B58\u5728
Code.100002=\u90AE\u7BB1\u5DF2\u5B58\u5728
Code.100003=\u8D26\u53F7\u5BC6\u7801\u9519\u8BEF
Code.100004=\u7528\u6237\u88AB\u7981\u7528, \u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
Code.100005=\u7528\u6237\u88AB\u7981\u6B62\u767B\u5F55, \u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
......@@ -3,3 +3,16 @@
example.hello=\uD83D\uDE0E Hello World
# \u4E1A\u52A1\u72B6\u6001\u7801\u9519\u8BEF\u6D88\u606F
Code.1=\u5931\u8D25
Code.1000=\u7528\u6237\u4E0D\u5B58\u5728
Code.1001=\u6743\u9650\u6807\u8BC6\u91CD\u590D
Code.1002=\u89D2\u8272\u6807\u8BC6\u91CD\u590D
Code.10000=\u4E8C\u7EA7\u8BA4\u8BC1\u6821\u9A8C\u5931\u8D25
Code.10001=\u89D2\u8272\u6743\u9650\u4E0D\u8DB3
Code.10002=\u6743\u9650\u4E0D\u8DB3
Code.10003=\u672A\u6388\u6743
Code.100000=\u7528\u6237\u540D\u5DF2\u5B58\u5728
Code.100001=\u624B\u673A\u53F7\u5DF2\u5B58\u5728
Code.100002=\u90AE\u7BB1\u5DF2\u5B58\u5728
Code.100003=\u8D26\u53F7\u5BC6\u7801\u9519\u8BEF
Code.100004=\u7528\u6237\u88AB\u7981\u7528, \u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
Code.100005=\u7528\u6237\u88AB\u7981\u6B62\u767B\u5F55, \u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
javax.validation.constraints.AssertFalse.message=\u53EA\u80FD\u4E3A false
javax.validation.constraints.AssertTrue.message=\u53EA\u80FD\u4E3A true
javax.validation.constraints.DecimalMax.message=\u5FC5\u987B\u5C0F\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
javax.validation.constraints.DecimalMin.message=\u5FC5\u987B\u5927\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
javax.validation.constraints.Digits.message=\u6570\u5B57\u7684\u503C\u8D85\u51FA\u4E86\u5141\u8BB8\u8303\u56F4(\u53EA\u5141\u8BB8\u5728{integer}\u4F4D\u6574\u6570\u548C{fraction}\u4F4D\u5C0F\u6570\u8303\u56F4\u5185)
javax.validation.constraints.Email.message=\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
javax.validation.constraints.Future.message=\u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4
javax.validation.constraints.FutureOrPresent.message=\u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u6216\u73B0\u5728\u7684\u65F6\u95F4
javax.validation.constraints.Max.message=\u6700\u5927\u4E0D\u80FD\u8D85\u8FC7{value}
javax.validation.constraints.Min.message=\u6700\u5C0F\u4E0D\u80FD\u5C0F\u4E8E{value}
javax.validation.constraints.Negative.message=\u5FC5\u987B\u662F\u8D1F\u6570
javax.validation.constraints.NegativeOrZero.message=\u5FC5\u987B\u662F\u8D1F\u6570\u6216\u96F6
javax.validation.constraints.NotBlank.message=\u4E0D\u80FD\u4E3A\u7A7A
javax.validation.constraints.NotEmpty.message=\u4E0D\u80FD\u4E3A\u7A7A
javax.validation.constraints.NotNull.message=\u4E0D\u80FD\u4E3A null
javax.validation.constraints.Null.message=\u5FC5\u987B\u4E3A null
javax.validation.constraints.Past.message=\u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u7684\u65F6\u95F4
javax.validation.constraints.PastOrPresent.message=\u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u6216\u73B0\u5728\u7684\u65F6\u95F4
javax.validation.constraints.Pattern.message=\u9700\u8981\u5339\u914D\u6B63\u5219\u8868\u8FBE\u5F0F"{regexp}"
javax.validation.constraints.Positive.message=\u5FC5\u987B\u662F\u6B63\u6570
javax.validation.constraints.PositiveOrZero.message=\u5FC5\u987B\u662F\u6B63\u6570\u6216\u96F6
javax.validation.constraints.Size.message=\u4E2A\u6570\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
jakarta.validation.constraints.AssertFalse.message=\u53EA\u80FD\u4E3Afalse
jakarta.validation.constraints.AssertTrue.message=\u53EA\u80FD\u4E3Atrue
jakarta.validation.constraints.DecimalMax.message=\u5FC5\u987B\u5C0F\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
jakarta.validation.constraints.DecimalMin.message=\u5FC5\u987B\u5927\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
jakarta.validation.constraints.Digits.message=\u6570\u5B57\u7684\u503C\u8D85\u51FA\u4E86\u5141\u8BB8\u8303\u56F4(\u53EA\u5141\u8BB8\u5728{integer}\u4F4D\u6574\u6570\u548C{fraction}\u4F4D\u5C0F\u6570\u8303\u56F4\u5185)
jakarta.validation.constraints.Email.message=\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
jakarta.validation.constraints.Future.message=\u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4
jakarta.validation.constraints.FutureOrPresent.message=\u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u6216\u73B0\u5728\u7684\u65F6\u95F4
jakarta.validation.constraints.Max.message=\u6700\u5927\u4E0D\u80FD\u8D85\u8FC7{value}
jakarta.validation.constraints.Min.message=\u6700\u5C0F\u4E0D\u80FD\u5C0F\u4E8E{value}
jakarta.validation.constraints.Negative.message=\u5FC5\u987B\u662F\u8D1F\u6570
jakarta.validation.constraints.NegativeOrZero.message=\u5FC5\u987B\u662F\u8D1F\u6570\u6216\u96F6
jakarta.validation.constraints.NotBlank.message=\u4E0D\u80FD\u4E3A\u7A7A
jakarta.validation.constraints.NotEmpty.message=\u4E0D\u80FD\u4E3A\u7A7A
jakarta.validation.constraints.NotNull.message=\u4E0D\u80FD\u4E3Anull
jakarta.validation.constraints.Null.message=\u5FC5\u987B\u4E3Anull
jakarta.validation.constraints.Past.message=\u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u7684\u65F6\u95F4
jakarta.validation.constraints.PastOrPresent.message=\u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u6216\u73B0\u5728\u7684\u65F6\u95F4
jakarta.validation.constraints.Pattern.message=\u9700\u8981\u5339\u914D\u6B63\u5219\u8868\u8FBE\u5F0F"{regexp}"
jakarta.validation.constraints.Positive.message=\u5FC5\u987B\u662F\u6B63\u6570
jakarta.validation.constraints.PositiveOrZero.message=\u5FC5\u987B\u662F\u6B63\u6570\u6216\u96F6
jakarta.validation.constraints.Size.message=\u4E2A\u6570\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
org.hibernate.validator.constraints.CreditCardNumber.message=\u4E0D\u5408\u6CD5\u7684\u4FE1\u7528\u5361\u53F7\u7801
org.hibernate.validator.constraints.Currency.message=\u4E0D\u5408\u6CD5\u7684\u8D27\u5E01 (\u5FC5\u987B\u662F{value}\u5176\u4E2D\u4E4B\u4E00)
org.hibernate.validator.constraints.EAN.message=\u4E0D\u5408\u6CD5\u7684{type}\u6761\u5F62\u7801
......
......@@ -9,11 +9,13 @@ dependencies {
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// sa-token
implementation "cn.dev33:sa-token-spring-boot-starter:${saTokenVersion}"
implementation "cn.dev33:sa-token-spring-boot3-starter:${saTokenVersion}"
implementation "cn.dev33:sa-token-dao-redis-jackson:${saTokenVersion}"
// Sa-Token 整合 Redis (使用 jackson 序列化方式)
implementation 'org.apache.commons:commons-pool2'
// fastjson
implementation "com.alibaba.fastjson2:fastjson2:${fastJsonVersion}"
......@@ -21,8 +23,11 @@ dependencies {
// hutool-core
implementation "cn.hutool:hutool-core:${hutoolVersion}"
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
// hypersistence-utils-hibernate-60
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
// https://mvnrepository.com/artifact/org.jetbrains/annotations
implementation "org.jetbrains:annotations:${jetbrainsAnnotationsVersion}"
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.annotation;
import cn.dev33.satoken.annotation.SaIgnore;
import java.lang.annotation.*;
/**
* 忽略登录校验
* 与 @SaCheckLogin 相对
*
* @author Jim
* @version 0.1
* 2022/4/7 15:21
* @deprecated 已过期,请使用 @SaIgnore
*/
@SuppressWarnings({ "unused" })
@Deprecated
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SaIgnore
public @interface AuthIgnore {
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.config;
import cn.dev33.satoken.exception.*;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 授权异常拦截处理
*
* @author Jim
* @version 0.1
* 2023/1/12 14:06
*/
@Slf4j
@Order(0)
@RestControllerAdvice
@RequiredArgsConstructor
public class AuthExceptionHandler {
/**
* 未登录异常(鉴权失败)
*
* @return 异常信息反馈 {@link Status#UNAUTHORIZED
*/
@ExceptionHandler(NotLoginException.class)
public Result<String> unauthorizedErrorHandler() {
return Result.no(Status.UNAUTHORIZED);
}
/**
* 1. 二级认证失败异常
* 2. 角色条件不满足
* 3. 权限条件不满足
* 4. HTTP Basic 验证不通过
* 5. 用户被禁止访问该服务
* 6. API 被禁用
*
* @return 异常信息反馈 {@link Status#FORBIDDEN
*/
@ExceptionHandler(
{
// https://sa-token.dev33.cn/doc.html#/up/safe-auth
NotSafeException.class,
// https://sa-token.dev33.cn/doc.html#/use/at-check
NotRoleException.class,
NotPermissionException.class,
// https://sa-token.dev33.cn/doc.html#/up/basic-auth
NotBasicAuthException.class,
// https://sa-token.dev33.cn/doc.html#/up/disable
DisableServiceException.class,
ApiDisabledException.class,
}
)
public Result<String> forbiddenHandler(Exception e) {
if (e instanceof NotSafeException) {
return Result.no(Status.FORBIDDEN, "Code.10000");
}
if (e instanceof NotRoleException) {
return Result.no(Status.FORBIDDEN, "Code.10001");
}
if (e instanceof NotPermissionException) {
return Result.no(Status.FORBIDDEN, "Code.10002");
}
if (e instanceof NotBasicAuthException) {
return Result.no(Status.FORBIDDEN, "Code.10003");
}
log.warn(e.getMessage(), e);
return Result.no(Status.FORBIDDEN);
}
}
......@@ -12,7 +12,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
......@@ -24,10 +24,10 @@ import org.springframework.stereotype.Component;
*/
@Component
@RequiredArgsConstructor
public class StpInterfaceImpl implements StpInterface {
@Resource
UserRepository userRepository;
final UserRepository userRepository;
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
......@@ -50,6 +50,7 @@ public class StpInterfaceImpl implements StpInterface {
/**
* 根据 id 获取用户信息
*
* @param loginId 登录 ID
* @return 用户信息
*/
......@@ -57,7 +58,7 @@ public class StpInterfaceImpl implements StpInterface {
String id = Objects.toString(loginId);
Optional<User> optional = userRepository.findById(id);
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception("用户不存在");
throw Status.NOT_FOUND.exception("Code.1000");
}
return optional.get();
......
......@@ -6,9 +6,10 @@ import static com.yiring.auth.domain.permission.Permission.TABLE_NAME;
import com.alibaba.fastjson2.JSONObject;
import com.yiring.common.domain.BasicEntity;
import io.hypersistence.utils.hibernate.type.json.JsonType;
import jakarta.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
......@@ -99,7 +100,7 @@ public class Permission extends BasicEntity implements Serializable {
* 可用于扩展一些前端可能用到的路由参数
*/
@Comment("扩展元数据信息")
@org.hibernate.annotations.Type(type = "json")
@org.hibernate.annotations.Type(JsonType.class)
@Column(columnDefinition = "json")
JSONObject meta;
......@@ -123,6 +124,7 @@ public class Permission extends BasicEntity implements Serializable {
/**
* 获取权限的元数据信息,通常是根据前端所需来输出,可自定义调整
*
* @return JSON 格式 Meta 元数据
*/
public JSONObject getMetaJson() {
......
......@@ -8,11 +8,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.user.User;
import com.yiring.common.domain.BasicEntity;
import jakarta.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
......
......@@ -4,12 +4,12 @@ package com.yiring.auth.domain.user;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yiring.auth.domain.role.Role;
import com.yiring.common.domain.BasicEntity;
import jakarta.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.param.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("LoginParam")
@Schema(name = "LoginParam")
@Data
@Builder
@NoArgsConstructor
......@@ -27,11 +27,11 @@ public class LoginParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456895L;
@ApiModelProperty(value = "账号(支持用户名/手机号/邮箱)", example = "admin", required = true)
@Parameter(description = "账号(支持用户名/手机号/邮箱)", example = "admin")
@NotEmpty(message = "账号不能为空")
String account;
@ApiModelProperty(value = "密码", example = "123456", required = true)
@Parameter(description = "密码", example = "123456")
@NotEmpty(message = "密码不能为空")
String password;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.param.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -17,7 +17,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("RegisterParam")
@Schema(name = "RegisterParam")
@Data
@Builder
@NoArgsConstructor
......@@ -28,32 +28,32 @@ public class RegisterParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456895L;
@ApiModelProperty(value = "用户名", example = "admin", required = true)
@Parameter(description = "用户名", example = "admin")
@NotEmpty(message = "用户名不能为空")
String username;
@ApiModelProperty(value = "密码", example = "123456", required = true)
@Parameter(description = "密码", example = "123456")
@NotEmpty(message = "密码不能为空")
String password;
@ApiModelProperty(value = "真实姓名", example = "管理员", required = true)
@Parameter(description = "真实姓名", example = "管理员")
@NotEmpty(message = "真实姓名不能为空")
String realName;
@ApiModelProperty(value = "手机号", example = "13012345678", required = true)
@Parameter(description = "手机号", example = "13012345678")
@NotEmpty(message = "手机号不能为空")
@Pattern(regexp = "^1\\d{10}$", message = "手机号码格式不正确")
String mobile;
@ApiModelProperty(value = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
@Parameter(description = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
String avatar;
@ApiModelProperty(value = "邮箱", example = "developer@yiring.com")
@Parameter(description = "邮箱", example = "developer@yiring.com")
String email;
@ApiModelProperty(value = "简介", example = "平台管理员")
@Parameter(description = "简介", example = "平台管理员")
String introduction;
@ApiModelProperty(value = "是否启用", example = "true")
@Parameter(description = "是否启用", example = "true")
Boolean enable;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.param.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("SafeParam")
@Schema(name = "SafeParam")
@Data
@Builder
@NoArgsConstructor
......@@ -27,7 +27,7 @@ public class SafeParam implements Serializable {
@Serial
private static final long serialVersionUID = 9106494470582579138L;
@ApiModelProperty(value = "密码", example = "123456", required = true)
@Parameter(description = "密码", example = "123456")
@NotEmpty(message = "密码不能为空")
String password;
}
......@@ -4,13 +4,13 @@ package com.yiring.auth.param.permission;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.common.validation.group.Group;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -23,7 +23,7 @@ import lombok.experimental.FieldDefaults;
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel("PermissionParam")
@Schema(name = "PermissionParam")
@Data
@Builder
@NoArgsConstructor
......@@ -34,47 +34,47 @@ public class PermissionParam implements Serializable {
@Serial
private static final long serialVersionUID = -6781934969837655538L;
@ApiModelProperty(value = "id", example = "1")
@Parameter(description = "id", example = "1")
@NotBlank(groups = { Group.Edit.class })
String id;
@ApiModelProperty(value = "权限类型", example = "MENU", required = true)
@Parameter(description = "权限类型", example = "MENU")
@NotNull(message = "权限类型不能为空")
Permission.Type type;
@ApiModelProperty(value = "序号", example = "1")
@Parameter(description = "序号", example = "1")
Integer serial;
@ApiModelProperty(value = "标识", example = "Dashboard", required = true)
@Parameter(description = "标识", example = "Dashboard")
@NotEmpty(message = "权限标识不能为空")
String uid;
@ApiModelProperty(value = "名称", example = "Dashboard", required = true)
@Parameter(description = "名称", example = "Dashboard")
@NotEmpty(message = "权限名称不能为空")
String name;
@ApiModelProperty(value = "路径", example = "/dashboard")
@Parameter(description = "路径", example = "/dashboard")
String path;
@ApiModelProperty(value = "重定向", example = "/dashboard/workbench")
@Parameter(description = "重定向", example = "/dashboard/workbench")
String redirect;
@ApiModelProperty(value = "组件", example = "LAYOUT")
@Parameter(description = "组件", example = "LAYOUT")
String component;
@ApiModelProperty(value = "图标", example = "ion:grid-outline")
@Parameter(description = "图标", example = "ion:grid-outline")
String icon;
@ApiModelProperty(value = "是否隐藏", example = "false")
@Parameter(description = "是否隐藏", example = "false")
Boolean hidden;
@ApiModelProperty(value = "是否启用", example = "true")
@Parameter(description = "是否启用", example = "true")
Boolean enable;
@ApiModelProperty(value = "父级ID", example = "0")
@Parameter(description = "父级ID", example = "0")
@Builder.Default
String pid = "0";
@ApiModelProperty(value = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
@Parameter(description = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
String meta;
}
......@@ -2,12 +2,12 @@
package com.yiring.auth.param.role;
import com.yiring.common.validation.group.Group;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -19,7 +19,7 @@ import lombok.experimental.FieldDefaults;
* 2022/3/25 17:09
*/
@ApiModel("RoleParam")
@Schema(name = "RoleParam")
@Data
@Builder
@NoArgsConstructor
......@@ -30,15 +30,15 @@ public class RoleParam implements Serializable {
@Serial
private static final long serialVersionUID = 6572751635422870217L;
@ApiModelProperty(value = "id", example = "1")
@Parameter(description = "id", example = "1")
@NotBlank(groups = { Group.Edit.class })
String id;
@ApiModelProperty(value = "标识", example = "admin", required = true)
@Parameter(description = "标识", example = "admin")
@NotEmpty(message = "角色标识不能为空")
String uid;
@ApiModelProperty(value = "名称", example = "管理员", required = true)
@Parameter(description = "名称", example = "管理员")
@NotEmpty(message = "角色名称不能为空")
String name;
}
......@@ -9,8 +9,8 @@ import com.yiring.common.core.Status;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Resource;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
......@@ -23,10 +23,10 @@ import org.springframework.stereotype.Component;
@SuppressWarnings("unused")
@Component
@RequiredArgsConstructor
public class Auths {
@Resource
UserRepository userRepository;
final UserRepository userRepository;
/**
* 管理员角色标识
......@@ -36,6 +36,7 @@ public class Auths {
/**
* 根据 Token 获取用户信息
* 如果用户未登录或校验失败会抛出 NotLoginException {@link Status#UNAUTHORIZED}
*
* @param token token
* @return 用户信息
*/
......@@ -70,6 +71,7 @@ public class Auths {
/**
* 踢出这个用户 id 所有登录状态(可能有多人重复登录了一个账号的情况)
*
* @param userId 用户 id
*/
public void logoutAll(String userId) {
......@@ -81,6 +83,7 @@ public class Auths {
/**
* 判断用户是否为超级管理员
*
* @param userId 用户 ID
* @return 是否为管理员
*/
......@@ -91,6 +94,7 @@ public class Auths {
/**
* 检查用户是否为管理员(检查用户是否拥有包含 admin 字符的角色)
*
* @param user 用户
* @return 是否为管理员
*/
......@@ -104,6 +108,7 @@ public class Auths {
/**
* 检查当前登录用户是否为管理员
* {@link this.isAdmin}
*
* @return 是否为管理员
*/
public boolean checkLoginUserIsAdmin() {
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.util;
import com.sun.istack.Nullable;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.role.Role;
import com.yiring.auth.vo.permission.MenuVo;
import com.yiring.auth.vo.permission.PermissionVo;
import com.yiring.auth.vo.role.RoleVo;
import com.yiring.common.util.Commons;
import jakarta.annotation.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
......@@ -28,6 +28,7 @@ public class Permissions {
/**
* 将角色集合转换成 Vo 集合
*
* @param roles 角色集合
* @return vos
*/
......@@ -40,6 +41,7 @@ public class Permissions {
/**
* 将权限集合转换成菜单树
*
* @param permissions 权限集合
* @return 菜单树
*/
......@@ -75,6 +77,7 @@ public class Permissions {
/**
* 菜单树递归排序
*
* @param menus 菜单集合
* @return 排序后的菜单集合
*/
......@@ -88,7 +91,7 @@ public class Permissions {
)
)
.peek(item -> {
if (!Commons.isNullOrEmpty(item.getChildren())) {
if (Commons.notEmpty(item.getChildren())) {
item.setChildren(sortMenuTreeVo(item.getChildren()));
}
})
......@@ -97,6 +100,7 @@ public class Permissions {
/**
* 将权限集合转换成 Vo 集合
*
* @param permissions 权限集合
* @return vos
*/
......@@ -114,6 +118,7 @@ public class Permissions {
/**
* 提取角色集合含有的权限去重结果
*
* @param roles 角色集合
* @return 权限集合
*/
......@@ -130,8 +135,9 @@ public class Permissions {
/**
* 根据 pid 构建树状权限集合
*
* @param permissions 权限集合
* @param pid 权限父级 ID
* @param pid 权限父级 ID
* @return 树状权限集合
*/
public List<PermissionVo> toTree(List<Permission> permissions, @NonNull String pid) {
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.vo.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import lombok.*;
......@@ -16,7 +15,7 @@ import lombok.experimental.FieldDefaults;
* 2019/5/28 22:11
*/
@ApiModel("LoginVo")
@Schema(name = "LoginVo")
@Data
@Builder
@NoArgsConstructor
......@@ -27,9 +26,9 @@ public class LoginVo implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456896L;
@ApiModelProperty(value = "用户 ID", example = "1")
@Schema(description = "用户 ID", example = "1")
String userId;
@ApiModelProperty(value = "token", example = "c68ca9c8c04b4a59afeafd2fb7c04741")
@Schema(description = "token", example = "c68ca9c8c04b4a59afeafd2fb7c04741")
String token;
}
......@@ -4,8 +4,7 @@ package com.yiring.auth.vo.permission;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
......@@ -21,7 +20,7 @@ import lombok.experimental.FieldDefaults;
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel("MenuVo")
@Schema(name = "MenuVo")
@Data
@Builder
@NoArgsConstructor
......@@ -38,24 +37,24 @@ public class MenuVo implements Serializable {
@JsonIgnore
String pid;
@ApiModelProperty(value = "唯一标识", example = "Dashboard")
@Schema(description = "唯一标识", example = "Dashboard")
String uid;
@ApiModelProperty(value = "名称", example = "Dashboard")
@Schema(description = "名称", example = "Dashboard")
String name;
@ApiModelProperty(value = "路径", example = "/dashboard")
@Schema(description = "路径", example = "/dashboard")
String path;
@ApiModelProperty(value = "重定向", example = "/dashboard/workbench")
@Schema(description = "重定向", example = "/dashboard/workbench")
String redirect;
@ApiModelProperty(value = "组件", example = "LAYOUT")
@Schema(description = "组件", example = "LAYOUT")
String component;
@ApiModelProperty(value = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
@Schema(description = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
JSONObject meta;
@ApiModelProperty(value = "子权限")
@Schema(description = "子权限")
List<MenuVo> children;
}
......@@ -4,8 +4,8 @@ package com.yiring.auth.vo.permission;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.yiring.auth.domain.permission.Permission;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
......@@ -14,13 +14,14 @@ import lombok.experimental.FieldDefaults;
/**
* 权限输出类
*
* @author Jim
* @version 0.1
* 2022/3/25 17:09
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel("PermissionVo")
@Schema(name = "PermissionVo")
@Data
@Builder
@NoArgsConstructor
......@@ -31,42 +32,42 @@ public class PermissionVo implements Serializable {
@Serial
private static final long serialVersionUID = -9139328772148985141L;
@ApiModelProperty(value = "主键", example = "1")
@Parameter(description = "主键", example = "1")
String id;
@ApiModelProperty(value = "权限类型", example = "MENU")
@Parameter(description = "权限类型", example = "MENU")
Permission.Type type;
@ApiModelProperty(value = "序号", example = "1")
@Parameter(description = "序号", example = "1")
Integer serial;
@ApiModelProperty(value = "标识", example = "home")
@Parameter(description = "标识", example = "home")
String uid;
@ApiModelProperty(value = "名称", example = "主页")
@Parameter(description = "名称", example = "主页")
String name;
@ApiModelProperty(value = "路径", example = "/")
@Parameter(description = "路径", example = "/")
String path;
@ApiModelProperty(value = "组件", example = "/home")
@Parameter(description = "组件", example = "/home")
String component;
@ApiModelProperty(value = "图标", example = "menu")
@Parameter(description = "图标", example = "menu")
String icon;
@ApiModelProperty(value = "是否隐藏", example = "false")
@Parameter(description = "是否隐藏", example = "false")
Boolean hidden;
@ApiModelProperty(value = "是否启用", example = "true")
@Parameter(description = "是否启用", example = "true")
Boolean enable;
@ApiModelProperty(value = "父级ID", example = "0")
@Parameter(description = "父级ID", example = "0")
String pid;
@ApiModelProperty(value = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
@Parameter(description = "元数据", example = "{\"title\": \"routes.dashboard.dashboard\"}")
JSONObject meta;
@ApiModelProperty(value = "子权限")
@Parameter(description = "子权限")
List<PermissionVo> children;
}
......@@ -2,8 +2,7 @@
package com.yiring.auth.vo.role;
import com.yiring.auth.vo.permission.PermissionVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
......@@ -12,12 +11,13 @@ import lombok.experimental.FieldDefaults;
/**
* 角色响应类
*
* @author Jim
* @version 0.1
* 2022/3/25 17:09
*/
@ApiModel("RoleVo")
@Schema(name = "RoleVo")
@Data
@Builder
@NoArgsConstructor
......@@ -28,15 +28,15 @@ public class RoleVo implements Serializable {
@Serial
private static final long serialVersionUID = -9154497137563970840L;
@ApiModelProperty(value = "主键", example = "1")
@Schema(description = "主键", example = "1")
String id;
@ApiModelProperty(value = "标识", example = "admin")
@Schema(description = "标识", example = "admin")
String uid;
@ApiModelProperty(value = "名称", example = "系统管理员")
@Schema(description = "名称", example = "系统管理员")
String name;
@ApiModelProperty("权限")
@Schema(description = "权限")
List<PermissionVo> permissions;
}
......@@ -2,8 +2,7 @@
package com.yiring.auth.vo.user;
import com.yiring.auth.vo.role.RoleVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
......@@ -13,11 +12,12 @@ import lombok.experimental.FieldDefaults;
/**
* 用户信息
*
* @author ifzm
* 2022/03/03 10:35
**/
@ApiModel("UserInfo")
@Schema(name = "UserInfo")
@Data
@Builder
@NoArgsConstructor
......@@ -28,28 +28,28 @@ public class UserInfoVo implements Serializable {
@Serial
private static final long serialVersionUID = -5319037883240327088L;
@ApiModelProperty(value = "主键", example = "1")
@Schema(description = "主键", example = "1")
String userId;
@ApiModelProperty(value = "手机号", example = "15616260195")
@Schema(description = "手机号", example = "15616260195")
String mobile;
@ApiModelProperty(value = "真实姓名", example = "超级用户")
@Schema(description = "真实姓名", example = "超级用户")
String realName;
@ApiModelProperty(value = "用户名", example = "admin")
@Schema(description = "用户名", example = "admin")
String username;
@ApiModelProperty(value = "介绍", example = "系统管理员")
@Schema(description = "介绍", example = "系统管理员")
String desc;
@ApiModelProperty(value = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
@Schema(description = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
String avatar;
@ApiModelProperty("角色")
@Schema(description = "角色")
@Builder.Default
List<RoleVo> roles = new ArrayList<>(0);
@ApiModelProperty(value = "用户主页", example = "/dashboard/workbench")
@Schema(description = "用户主页", example = "/dashboard/workbench")
String homePath;
}
......@@ -2,8 +2,7 @@
package com.yiring.auth.vo.user;
import com.yiring.auth.vo.role.RoleVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
......@@ -13,11 +12,12 @@ import lombok.experimental.FieldDefaults;
/**
* 用户信息
*
* @author ifzm
* 2022/03/03 10:35
**/
@ApiModel("UserInfo")
@Schema(name = "UserInfo")
@Data
@Builder
@NoArgsConstructor
......@@ -28,25 +28,25 @@ public class UserMenuListVo implements Serializable {
@Serial
private static final long serialVersionUID = -5319037883240327088L;
@ApiModelProperty(value = "主键", example = "1")
@Schema(description = "主键", example = "1")
String userId;
@ApiModelProperty(value = "真实姓名", example = "超级用户")
@Schema(description = "真实姓名", example = "超级用户")
String realName;
@ApiModelProperty(value = "用户名", example = "admin")
@Schema(description = "用户名", example = "admin")
String username;
@ApiModelProperty(value = "介绍", example = "系统管理员")
@Schema(description = "介绍", example = "系统管理员")
String desc;
@ApiModelProperty(value = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
@Schema(description = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
String avatar;
@ApiModelProperty("角色")
@Schema(description = "角色")
@Builder.Default
List<RoleVo> roles = new ArrayList<>(0);
@ApiModelProperty(value = "用户主页", example = "/dashboard/workbench")
@Schema(description = "用户主页", example = "/dashboard/workbench")
String homePath;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
......@@ -11,11 +10,12 @@ import lombok.experimental.FieldDefaults;
/**
* 用户信息
*
* @author ifzm
* 2022/03/03 10:35
**/
@ApiModel("UserVo")
@Schema(name = "UserVo")
@Data
@Builder
@NoArgsConstructor
......@@ -26,39 +26,39 @@ public class UserVo implements Serializable {
@Serial
private static final long serialVersionUID = -2184378273450466835L;
@ApiModelProperty(value = "主键", example = "1")
@Schema(description = "主键", example = "1")
String id;
@ApiModelProperty(value = "真实姓名", example = "超级用户")
@Schema(description = "真实姓名", example = "超级用户")
String realName;
@ApiModelProperty(value = "用户名", example = "admin")
@Schema(description = "用户名", example = "admin")
String username;
@ApiModelProperty(value = "手机号", example = "13012345678")
@Schema(description = "手机号", example = "13012345678")
String mobile;
@ApiModelProperty(value = "邮箱", example = "developer@yiring.com")
@Schema(description = "邮箱", example = "developer@yiring.com")
String email;
@ApiModelProperty(value = "职称", example = "系统管理员")
@Schema(description = "职称", example = "系统管理员")
String title;
@ApiModelProperty(value = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
@Schema(description = "头像", example = "https://s1.ax1x.com/2022/03/30/qggJH0.jpg")
String avatar;
@ApiModelProperty(value = "是否启用", example = "true")
@Schema(description = "是否启用", example = "true")
Boolean enabled;
@ApiModelProperty(value = "是否删除", example = "false")
@Schema(description = "是否删除", example = "false")
Boolean deleted;
@ApiModelProperty(value = "最后登录IP地址", example = "127.0.0.1")
@Schema(description = "最后登录IP地址", example = "127.0.0.1")
String lastLoginIp;
@ApiModelProperty(value = "最后登录时间", example = "2022-10-24 10:24:00")
@Schema(description = "最后登录时间", example = "2022-10-24 10:24:00")
LocalDateTime lastLoginTime;
@ApiModelProperty(value = "最后登录时间", example = "2022-01-01 00:00:00")
@Schema(description = "最后登录时间", example = "2022-01-01 00:00:00")
LocalDateTime createTime;
}
......@@ -5,7 +5,6 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.auth.param.auth.LoginParam;
......@@ -16,12 +15,15 @@ import com.yiring.auth.vo.auth.LoginVo;
import com.yiring.common.core.Result;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.util.Commons;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import javax.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Example;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -39,9 +41,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@SuppressWarnings({ "all" })
@ApiSupport(order = -99)
@Api(tags = "身份认证", description = "Auth")
@Tag(
name = "Auth",
description = "身份认证",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-9999") }) }
)
@RestController
@RequestMapping("/auth/")
@RequiredArgsConstructor
......@@ -50,9 +54,9 @@ public class AuthController {
final Auths auths;
final UserRepository userRepository;
@ApiOperation(value = "注册")
@PostMapping("register")
public Result<String> register(@Validated RegisterParam param) {
@Operation(summary = "注册")
@PostMapping(value = "register")
public Result<String> register(@ParameterObject @Validated RegisterParam param) {
// 检查用户名是否存在
long count = userRepository.count(Example.of(User.builder().username(param.getUsername()).build()));
if (count > 0) {
......@@ -88,9 +92,9 @@ public class AuthController {
return Result.ok();
}
@ApiOperation(value = "登录")
@Operation(summary = "登录")
@PostMapping("login")
public Result<LoginVo> login(@Validated LoginParam param, HttpServletRequest request) {
public Result<LoginVo> login(@ParameterObject @Validated LoginParam param, HttpServletRequest request) {
// 查询用户信息是否匹配
User user = userRepository.findByAccount(param.getAccount());
if (user == null) {
......@@ -126,13 +130,13 @@ public class AuthController {
return Result.ok(vo);
}
@ApiOperation(value = "检查登录")
@Operation(summary = "检查登录")
@GetMapping("valid")
public Result<Boolean> valid() {
return Result.ok(StpUtil.isLogin());
}
@ApiOperation(value = "登出")
@Operation(summary = "登出")
@GetMapping("logout")
public Result<String> logout() {
StpUtil.logout();
......@@ -144,13 +148,12 @@ public class AuthController {
* 默认安全时间: 120s
*
* @param param 用户密码
* @return
* @link { https://sa-token.dev33.cn/doc.html#/up/safe-auth }
* @link { <a href="https://sa-token.dev33.cn/doc.html#/up/safe-auth">...</a> }
*/
@SaCheckLogin
@ApiOperation(value = "安全校验")
@Operation(summary = "安全验证")
@GetMapping("safe")
public Result<String> safe(@Validated SafeParam param) {
public Result<String> safe(@ParameterObject @Validated SafeParam param) {
User user = auths.getLoginUser();
if (SaSecureUtil.sha256(param.getPassword()).equals(user.getPassword())) {
StpUtil.openSafe(120);
......
......@@ -4,7 +4,6 @@ package com.yiring.auth.web.sys.permission;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONValidator;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.permission.PermissionRepository;
import com.yiring.auth.param.permission.PermissionParam;
......@@ -18,13 +17,16 @@ import com.yiring.common.param.PageParam;
import com.yiring.common.param.PidParam;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
......@@ -44,9 +46,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = -97)
@Api(tags = "权限管理", description = "Permission")
@Tag(
name = "权限管理",
description = "Permission",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-99") }) }
)
@RestController
@RequestMapping("/sys/permission/")
@RequiredArgsConstructor
......@@ -54,9 +58,9 @@ public class PermissionController {
final PermissionRepository permissionRepository;
@ApiOperation(value = "新增")
@Operation(summary = "新增")
@PostMapping("add")
public Result<String> add(@Validated({ Group.Add.class }) PermissionParam param) {
public Result<String> add(@ParameterObject @Validated({ Group.Add.class }) PermissionParam param) {
if (has(param.getUid())) {
throw BusinessException.i18n("Code.1001");
}
......@@ -66,9 +70,9 @@ public class PermissionController {
return Result.ok();
}
@ApiOperation(value = "修改")
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@Validated({ Group.Edit.class }) PermissionParam param) {
public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) PermissionParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -86,9 +90,9 @@ public class PermissionController {
return Result.ok();
}
@ApiOperation(value = "删除")
@Operation(summary = "删除")
@PostMapping("deleted")
public Result<String> deleted(@Validated IdParam param) {
public Result<String> deleted(@ParameterObject @Validated IdParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -99,9 +103,9 @@ public class PermissionController {
return Result.ok();
}
@ApiOperation(value = "查询")
@Operation(summary = "查询")
@GetMapping("find")
public Result<PermissionVo> find(@Validated IdParam param) {
public Result<PermissionVo> find(@ParameterObject @Validated IdParam param) {
Optional<Permission> optional = permissionRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -114,18 +118,18 @@ public class PermissionController {
return Result.ok(vo);
}
@ApiOperation(value = "分页查询")
@Operation(summary = "分页查询")
@GetMapping("page")
public Result<PageVo<PermissionVo>> page(@Validated PageParam param) {
public Result<PageVo<PermissionVo>> page(@ParameterObject @Validated PageParam param) {
Page<Permission> page = permissionRepository.findAll(PageParam.toPageable(param));
List<PermissionVo> data = Permissions.toPermissionVos(page.toList());
PageVo<PermissionVo> vo = PageVo.build(data, page.getTotalElements());
return Result.ok(vo);
}
@ApiOperation(value = "树结构查询")
@Operation(summary = "树结构查询")
@GetMapping(value = "tree")
public Result<ArrayList<PermissionVo>> tree(@Validated(Group.Optional.class) PidParam param) {
public Result<ArrayList<PermissionVo>> tree(@ParameterObject @Validated(Group.Optional.class) PidParam param) {
List<Permission> permissions = permissionRepository.findAll();
List<PermissionVo> vos = Permissions.toTree(
permissions,
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.web.sys.role;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.permission.PermissionRepository;
import com.yiring.auth.domain.role.Role;
......@@ -17,12 +16,15 @@ import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.io.Serializable;
import java.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
......@@ -42,9 +44,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = -96)
@Api(tags = "角色管理", description = "Role")
@Tag(
name = "角色管理",
description = "Role",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-98") }) }
)
@RestController
@RequestMapping("/sys/role/")
@RequiredArgsConstructor
......@@ -53,9 +57,9 @@ public class RoleController {
final RoleRepository roleRepository;
final PermissionRepository permissionRepository;
@ApiOperation(value = "新增")
@Operation(summary = "新增")
@PostMapping("add")
public Result<String> add(@Validated({ Group.Add.class }) RoleParam param) {
public Result<String> add(@ParameterObject @Validated({ Group.Add.class }) RoleParam param) {
if (has(param.getUid())) {
throw BusinessException.i18n("Code.1002");
}
......@@ -66,9 +70,9 @@ public class RoleController {
return Result.ok();
}
@ApiOperation(value = "修改")
@Operation(summary = "修改")
@PostMapping("modify")
public Result<String> modify(@Validated({ Group.Edit.class }) RoleParam param) {
public Result<String> modify(@ParameterObject @Validated({ Group.Edit.class }) RoleParam param) {
Optional<Role> optional = roleRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -87,9 +91,12 @@ public class RoleController {
return Result.ok();
}
@ApiOperation(value = "分配权限")
@Operation(summary = "分配权限")
@PostMapping("assign")
public Result<String> assign(@Validated IdParam idParam, @Validated IdsParam idsParam) {
public Result<String> assign(
@ParameterObject @Validated IdParam idParam,
@ParameterObject @Validated IdsParam idsParam
) {
Optional<Role> optional = roleRepository.findById(idParam.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -105,17 +112,17 @@ public class RoleController {
return Result.ok();
}
@ApiOperation(value = "删除")
@Operation(summary = "删除")
@PostMapping("deleted")
public Result<String> deleted(@Validated IdsParam param) {
public Result<String> deleted(@ParameterObject @Validated IdsParam param) {
List<Role> roles = roleRepository.findAllById(param.toIds());
roleRepository.deleteAll(roles);
return Result.ok();
}
@ApiOperation(value = "查询")
@Operation(summary = "查询")
@GetMapping("find")
public Result<RoleVo> find(@Validated IdParam param) {
public Result<RoleVo> find(@ParameterObject @Validated IdParam param) {
Optional<Role> optional = roleRepository.findById(param.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -128,16 +135,16 @@ public class RoleController {
return Result.ok(vo);
}
@ApiOperation(value = "分页查询")
@Operation(summary = "分页查询")
@GetMapping("page")
public Result<PageVo<RoleVo>> page(@Validated PageParam param) {
public Result<PageVo<RoleVo>> page(@ParameterObject @Validated PageParam param) {
Page<Role> page = roleRepository.findAll(PageParam.toPageable(param));
List<RoleVo> data = new ArrayList<>(Permissions.toRoleVos(page.toSet()));
PageVo<RoleVo> vo = PageVo.build(data, page.getTotalElements());
return Result.ok(vo);
}
@ApiOperation(value = "选项查询")
@Operation(summary = "选项查询")
@GetMapping("selector")
public Result<ArrayList<RoleVo>> selector() {
List<Role> roles = roleRepository.findAll();
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.web.sys.user;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.role.Role;
import com.yiring.auth.domain.role.RoleRepository;
import com.yiring.auth.domain.user.User;
......@@ -14,13 +13,16 @@ import com.yiring.common.param.IdsParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.util.Commons;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Page;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -38,9 +40,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = -95)
@Api(tags = "用户管理", description = "User")
@Tag(
name = "用户管理",
description = "User",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-97") }) }
)
@RestController
@RequestMapping("/sys/user/")
@RequiredArgsConstructor
......@@ -49,9 +53,12 @@ public class UserController {
final UserRepository userRepository;
final RoleRepository roleRepository;
@ApiOperation(value = "分配角色")
@Operation(summary = "分配角色")
@PostMapping("assign")
public Result<String> assign(@Validated IdParam idParam, @Validated IdsParam idsParam) {
public Result<String> assign(
@ParameterObject @Validated IdParam idParam,
@ParameterObject @Validated IdsParam idsParam
) {
Optional<User> optional = userRepository.findById(idParam.getId());
if (optional.isEmpty()) {
throw Status.NOT_FOUND.exception();
......@@ -67,9 +74,9 @@ public class UserController {
return Result.ok();
}
@ApiOperation(value = "分页查询")
@Operation(summary = "分页查询")
@GetMapping("page")
public Result<PageVo<UserVo>> page(@Validated PageParam param) {
public Result<PageVo<UserVo>> page(@ParameterObject @Validated PageParam param) {
Page<User> page = userRepository.findAll(PageParam.toPageable(param));
List<UserVo> data = page.get().map(user -> Commons.transform(user, UserVo.class)).collect(Collectors.toList());
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.web.user;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.auth.domain.permission.Permission;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
......@@ -9,8 +8,10 @@ import com.yiring.auth.util.Permissions;
import com.yiring.auth.vo.permission.MenuVo;
import com.yiring.auth.vo.user.UserInfoVo;
import com.yiring.common.core.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
......@@ -31,9 +32,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = -95)
@Api(tags = "用户信息", description = "UserView")
@Tag(
name = "用户信息",
description = "UserView",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-9998") }) }
)
@RestController
@RequestMapping("/user/")
@RequiredArgsConstructor
......@@ -41,7 +44,7 @@ public class UserViewController {
final Auths auths;
@ApiOperation(value = "获取登录用户信息")
@Operation(summary = "获取登录用户信息")
@GetMapping("getUserInfo")
public Result<UserInfoVo> getUserInfo() {
User user = auths.getLoginUser();
......@@ -57,7 +60,7 @@ public class UserViewController {
return Result.ok(userInfoVo);
}
@ApiOperation(value = "获取用户菜单")
@Operation(summary = "获取用户菜单")
@GetMapping("getMenuList")
public Result<ArrayList<MenuVo>> getMenuList() {
User user = auths.getLoginUser();
......@@ -70,7 +73,7 @@ public class UserViewController {
return Result.ok((ArrayList<MenuVo>) vos);
}
@ApiOperation(value = "获取用户权限")
@Operation(summary = "获取用户权限")
@GetMapping("getPermCode")
public Result<ArrayList<String>> getPermCode() {
User user = auths.getLoginUser();
......
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
token-name: App-Token
# token有效期,单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
......
Code.1000=\u7528\u6237\u4E0D\u5B58\u5728
Code.1001=\u6743\u9650\u6807\u8BC6\u91CD\u590D
Code.1002=\u89D2\u8272\u6807\u8BC6\u91CD\u590D
Code.10000=\u4E8C\u7EA7\u8BA4\u8BC1\u6821\u9A8C\u5931\u8D25
Code.10001=\u89D2\u8272\u6743\u9650\u4E0D\u8DB3
Code.10002=\u6743\u9650\u4E0D\u8DB3
Code.10003=\u672A\u6388\u6743
Code.100000=\u7528\u6237\u540D\u5DF2\u5B58\u5728
Code.100001=\u624B\u673A\u53F7\u5DF2\u5B58\u5728
Code.100002=\u90AE\u7BB1\u5DF2\u5B58\u5728
......
Code.1000=\u7528\u6237\u4E0D\u5B58\u5728
Code.1001=\u6743\u9650\u6807\u8BC6\u91CD\u590D
Code.1002=\u89D2\u8272\u6807\u8BC6\u91CD\u590D
Code.10000=\u4E8C\u7EA7\u8BA4\u8BC1\u6821\u9A8C\u5931\u8D25
Code.10001=\u89D2\u8272\u6743\u9650\u4E0D\u8DB3
Code.10002=\u6743\u9650\u4E0D\u8DB3
Code.10003=\u672A\u6388\u6743
Code.100000=\u7528\u6237\u540D\u5DF2\u5B58\u5728
Code.100001=\u624B\u673A\u53F7\u5DF2\u5B58\u5728
Code.100002=\u90AE\u7BB1\u5DF2\u5B58\u5728
......
Status.OK=OK
Status.OK=\u6210\u529F
Status.NON_AUTHORITATIVE_INFORMATION=\u8BA4\u8BC1\u5931\u8D25
Status.BAD_REQUEST=\u8BF7\u6C42\u5931\u8D25
Status.UNAUTHORIZED=\u51ED\u8BC1\u8FC7\u671F
......
......@@ -11,7 +11,7 @@ dependencies {
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// hutool-extra
implementation "cn.hutool:hutool-extra:${hutoolVersion}"
......@@ -22,9 +22,9 @@ dependencies {
// JTS 几何对象操作库
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
// https://github.com/vladmihalcea/hypersistence-utils
// hypersistence-utils-hibernate-60
implementation "io.hypersistence:hypersistence-utils-hibernate-60:${hibernateTypesVersion}"
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
implementation("org.n52.jackson:jackson-datatype-jts:1.2.10") {
......
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.annotation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.lang.annotation.*;
import org.springframework.core.annotation.AliasFor;
import org.springframework.http.MediaType;
/**
* 下载响应注解
*
* @author Jim
* @version 0.1
* 2023/1/12 11:22
*/
@SuppressWarnings({ "unused" })
@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ApiResponse
public @interface DownloadResponse {
@AliasFor(annotation = ApiResponse.class)
String responseCode() default "200";
@AliasFor(annotation = ApiResponse.class)
String description() default "OK";
@AliasFor(annotation = ApiResponse.class)
Content content() default @Content(
schema = @Schema(type = "string", format = "binary"),
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE
);
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.aspect;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.yiring.common.constant.DateFormatter;
import com.yiring.common.core.Result;
import com.yiring.common.util.Commons;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
......@@ -36,9 +36,9 @@ public class RequestAspect {
Boolean debug;
/**
* 白名单
* 白名单(忽略)
*/
List<String> WHITE_LIST = List.of("/swagger-resources", "/error");
List<String> IGNORE_LIST = List.of("/swagger-resources", "/error", "/v3/api-docs");
@Pointcut(
"@annotation(org.springframework.web.bind.annotation.RequestMapping) || @annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping) || @annotation(org.springframework.web.bind.annotation.PatchMapping) || @annotation(org.springframework.web.bind.annotation.ExceptionHandler)"
......@@ -49,8 +49,10 @@ public class RequestAspect {
public Object around(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = getRequest();
// 放行白名单
if (WHITE_LIST.contains(request.getServletPath())) {
return point.proceed();
for (String path : IGNORE_LIST) {
if (request.getServletPath().startsWith(path)) {
return point.proceed();
}
}
// 计算接口执行耗时
......@@ -66,10 +68,13 @@ public class RequestAspect {
String extra = "";
if (Boolean.TRUE.equals(debug)) {
String headers = JSONObject.toJSONString(
ServletUtil.getHeaderMap(request),
JakartaServletUtil.getHeaderMap(request),
JSONWriter.Feature.PrettyFormat
);
String params = JSONObject.toJSONString(
JakartaServletUtil.getParamMap(request),
JSONWriter.Feature.PrettyFormat
);
String params = JSONObject.toJSONString(ServletUtil.getParamMap(request), JSONWriter.Feature.PrettyFormat);
extra += String.format("\nHeaders: %s", headers);
extra += String.format("\nParams: %s", params);
if (result instanceof Result) {
......
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.config;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.exception.BusinessException;
import com.yiring.common.exception.FailStatusException;
import jakarta.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.aspectj.bridge.AbortException;
import org.hibernate.validator.internal.engine.ConstraintViolationImpl;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 核心异常拦截处理
*
* @author Jim
* @version 0.1
* 2023/1/12 14:06
*/
@Slf4j
@Order(0)
@RestControllerAdvice
@RequiredArgsConstructor
public class CoreExceptionHandler {
final I18n i18n;
/**
* 参数校验异常
*
* @param e 异常信息
* @return 统一的校验失败信息 {@link Status#EXPECTATION_FAILED
*/
@ExceptionHandler(
{ BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class }
)
public Result<String> validFailHandler(Exception e) {
String details = null;
if (e instanceof ConstraintViolationException) {
details = ((ConstraintViolationException) e).getConstraintViolations().iterator().next().getMessage();
} else {
BindingResult result = null;
if (e instanceof MethodArgumentNotValidException) {
result = ((MethodArgumentNotValidException) e).getBindingResult();
} else if (e instanceof BindException) {
result = ((BindException) e).getBindingResult();
}
if (result != null) {
ObjectError error = result.getAllErrors().iterator().next();
if (error instanceof FieldError fieldError) {
// 构建明确的字段错误提示, 例如: id 不能为 null, 如果自己填写了 message 则不追加 field 字段前缀
ConstraintViolationImpl<?> violation = error.unwrap(ConstraintViolationImpl.class);
String template = violation.getMessageTemplate();
String prefix = "";
// 如果是模板字符串, 则在消息前添加字段提示
if (template.contains("{") && template.contains("}")) {
prefix = "参数" + fieldError.getField();
}
details = prefix + i18n.get(fieldError);
} else {
details = i18n.get(error);
}
}
}
return Result.no(Status.EXPECTATION_FAILED, details);
}
/**
* 参数读取解析失败异常
* eg: 例如参数使用 RequestBody 接收,但是传了个空字符串,导致解析失败
*
* @param e 异常
* @return 校验失败信息 {@link Status#EXPECTATION_FAILED
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result<String> httpMessageNotReadableExceptionHandler(Exception e) {
log.warn(e.getMessage(), e);
return Result.no(Status.EXPECTATION_FAILED);
}
/**
* 不支持的HttpMethod异常
*
* @param e 异常信息
* @return 异常信息反馈 {@link Status#METHOD_NOT_ALLOWED
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result<String> httpRequestMethodNotSupportedErrorHandler(Exception e) {
return Result.no(Status.METHOD_NOT_ALLOWED, e.getMessage());
}
/**
* 自定义业务异常
*/
@ExceptionHandler(BusinessException.class)
public Result<String> businessExceptionHandler(BusinessException e) {
return Result.no(e.getStatus(), e.getMessage());
}
/**
* 失败状态异常
*/
@ExceptionHandler(FailStatusException.class)
public Result<String> failStatusExceptionHandler(FailStatusException e) {
return Result.no(e.getStatus(), e.getMessage());
}
/**
* 取消请求异常(忽略)
*/
@ExceptionHandler({ ClientAbortException.class, AbortException.class, HttpMessageNotWritableException.class })
public void ignoreExceptionHandler() {}
}
......@@ -4,7 +4,7 @@ package com.yiring.common.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.n52.jackson.datatype.jts.JtsModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -18,10 +18,10 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@RequiredArgsConstructor
public class JacksonConfig {
@Resource
JavaTimeModule javaTimeModule;
final JavaTimeModule javaTimeModule;
@Bean
public ObjectMapper objectMapper() {
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.core;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.PropertyKey;
/**
......@@ -23,13 +23,11 @@ import org.jetbrains.annotations.PropertyKey;
*/
@SuppressWarnings({ "unchecked", "unused" })
@ApiModel("Result")
@JsonInclude(JsonInclude.Include.NON_NULL)
@Slf4j
@Data
@Builder
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Result<T extends Serializable> implements Serializable {
public class Result<T> implements Serializable {
@Serial
private static final long serialVersionUID = -4802543396830024571L;
......@@ -46,49 +44,49 @@ public class Result<T extends Serializable> implements Serializable {
/**
* 接口响应时间
*/
@ApiModelProperty(value = "响应时间", example = "2021-01-01 00:00:00")
@Schema(description = "响应时间", example = "2021-01-01 00:00:00")
String timestamp;
/**
* 接口耗时(单位:秒)通常在调试阶段出现
*/
@ApiModelProperty(value = "耗时", example = "0.001s")
@Schema(description = "耗时", example = "0.001s")
String times;
/**
* 响应状态码
*/
@ApiModelProperty(value = "状态码", example = "200")
@Schema(description = "状态码", example = "200", defaultValue = "200")
Integer status;
/**
* 业务标识码
* 响应消息
*/
@ApiModelProperty(value = "业务标识码", example = "0")
Integer code;
@Schema(description = "消息", example = "OK", defaultValue = "OK")
String message;
/**
* 响应消息
* 业务标识码
*/
@ApiModelProperty(value = "消息", example = "OK")
String message;
@Schema(description = "业务标识码", example = "0", nullable = true)
Integer code;
/**
* 详细信息,通常为参数校验结果或自定义消息
*/
@ApiModelProperty(value = "详细信息", example = "Details message")
@Schema(description = "详细信息", nullable = true)
String details;
/**
* 异常信息,通常在出现服务器错误时会出现该异常
*/
@ApiModelProperty(value = "异常信息", notes = "出现错误时会出现该字段", example = "Error message")
@Schema(description = "异常信息", nullable = true)
String error;
/**
* 响应内容
*/
@ApiModelProperty("内容")
@Schema(description = "内容")
T body;
/**
......@@ -97,7 +95,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see com.yiring.common.core.Status
*/
public static <T extends Serializable> Result<T> ok() {
public static <T> Result<T> ok() {
return (Result<T>) Result.builder().status(Status.OK.value()).message(t(Status.OK.getReasonPhrase())).build();
}
......@@ -108,9 +106,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see com.yiring.common.core.Status
*/
public static <T extends Serializable> Result<T> ok(
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String body
) {
public static <T> Result<T> ok(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String body) {
return (Result<T>) Result
.builder()
.status(Status.OK.value())
......@@ -125,7 +121,7 @@ public class Result<T extends Serializable> implements Serializable {
* @param body {@link Object}
* @return Result
*/
public static <T extends Serializable> Result<T> ok(T body) {
public static <T> Result<T> ok(T body) {
return (Result<T>) Result
.builder()
.status(Status.OK.value())
......@@ -140,7 +136,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status#BAD_REQUEST
*/
public static <T extends Serializable> Result<T> no() {
public static <T> Result<T> no() {
return no(Status.BAD_REQUEST);
}
......@@ -150,9 +146,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status#BAD_REQUEST
*/
public static <T extends Serializable> Result<T> no(
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String details
) {
public static <T> Result<T> no(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String details) {
return no(Status.BAD_REQUEST, details);
}
......@@ -162,7 +156,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status#BAD_REQUEST
*/
public static <T extends Serializable> Result<T> no(Status status) {
public static <T> Result<T> no(Status status) {
return no(status, null, null, null);
}
......@@ -172,10 +166,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status
*/
public static <T extends Serializable> Result<T> no(
Status status,
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String details
) {
public static <T> Result<T> no(Status status, @PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String details) {
return no(status, null, details, null);
}
......@@ -185,7 +176,7 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status
*/
public static <T extends Serializable> Result<T> no(Status status, Throwable error) {
public static <T> Result<T> no(Status status, Throwable error) {
return no(status, null, null, error);
}
......@@ -195,12 +186,22 @@ public class Result<T extends Serializable> implements Serializable {
* @return Result
* @see Status
*/
public static <T extends Serializable> Result<T> no(
public static <T> Result<T> no(
Status status,
Integer code,
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String details,
Throwable error
) {
if (Objects.isNull(code)) {
String prefix = "Code.";
if (details.startsWith(prefix)) {
String codeText = details.replace(prefix, "");
code = Convert.toInt(codeText);
} else {
code = -1;
}
}
Result<T> result = (Result<T>) Result
.builder()
.status(status.value())
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.domain;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.vladmihalcea.hibernate.type.json.JsonType;
import com.yiring.common.snowflake.SnowflakeId;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.*;
import org.hibernate.snowflake.SnowflakeId;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* 基础表抽象类
......@@ -28,12 +30,8 @@ import org.hibernate.snowflake.SnowflakeId;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SuperBuilder(toBuilder = true)
@TypeDefs(
value = {
@TypeDef(name = "json", typeClass = JsonType.class), @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
}
)
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BasicEntity {
@Comment("主键")
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.exception;
import cn.hutool.core.convert.Convert;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Status;
import java.io.Serial;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.PropertyKey;
......@@ -22,7 +22,6 @@ import org.jetbrains.annotations.PropertyKey;
@SuppressWarnings("unused")
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class BusinessException extends RuntimeException {
......@@ -30,33 +29,28 @@ public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -4226669531686389671L;
/**
* 业务状态
* 状态码
*/
Integer code;
Status status;
/**
* 业务状态异常消息
*/
String message;
public BusinessException(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) {
String prefix = "Code.";
if (message.startsWith(prefix)) {
String code = message.replaceAll(".*(\\d+).*", "$1");
this.code = Convert.toInt(code);
this.message = message;
} else {
this.code = -1;
this.message = "Unknown Error";
}
}
public BusinessException(int code, @PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) {
this.code = code;
public BusinessException(Status status, @PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) {
this.status = status;
this.message = message;
}
public static BusinessException i18n(@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message) {
return new BusinessException(message);
return new BusinessException(Status.BAD_REQUEST, message);
}
public static BusinessException i18n(
@NonNull Status status,
@PropertyKey(resourceBundle = I18n.RESOURCE_BUNDLE) String message
) {
return new BusinessException(status, message);
}
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel(value = "IdParam", description = "公共的 ID 查询参数")
@Schema(name = "IdParam", description = "公共的 ID 查询参数")
@Data
@Builder
@NoArgsConstructor
......@@ -27,7 +27,7 @@ public class IdParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456893L;
@ApiModelProperty(value = "id", example = "1", required = true)
@Parameter(description = "id", example = "1")
@NotBlank
String id;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.validation.constraints.NotBlank;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -19,7 +19,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("IdsParam")
@Schema(name = "IdsParam")
@Data
@Builder
@NoArgsConstructor
......@@ -30,7 +30,7 @@ public class IdsParam implements Serializable {
@Serial
private static final long serialVersionUID = -8379896695668632733L;
@ApiModelProperty(value = "ids 多个以逗号分割", example = "1,2", required = true)
@Parameter(description = "ids 多个以逗号分割", example = "1,2")
@NotBlank
String ids;
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2022/4/27 08:53
*/
@ApiModel(value = "KeywordParam", description = "公共的关键字查询参数")
@Schema(name = "KeywordParam", description = "公共的关键字查询参数")
@Data
@Builder
@NoArgsConstructor
......@@ -27,7 +27,7 @@ public class KeywordParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456894L;
@ApiModelProperty(value = "关键字", example = "hi")
@Parameter(description = "关键字", example = "hi")
@NotBlank
String keyword;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
......@@ -26,7 +26,7 @@ import org.springframework.data.domain.Sort;
* @author ifzm
* @version 0.1 2019/3/10 16:29
*/
@ApiModel(value = "PageParam", description = "公共的分页排序查询参数")
@Schema(name = "PageParam", description = "公共的分页排序查询参数")
@Data
@SuperBuilder
@NoArgsConstructor
......@@ -37,20 +37,22 @@ public class PageParam implements Serializable {
@Serial
private static final long serialVersionUID = 6103761701912769946L;
@ApiModelProperty(value = "分页条数", example = "10")
@Parameter
@Schema(description = "分页条数", defaultValue = "10", example = "10", type = "integer")
@NotNull
@Range(min = 1, max = 100)
Integer pageSize;
@ApiModelProperty(value = "当前页数", example = "1")
@Parameter
@Schema(description = "当前页数", defaultValue = "1", example = "1", type = "integer")
@NotNull
@Min(1)
Integer pageNo;
@ApiModelProperty(value = "排序字段", example = "id")
@Schema(description = "排序字段", defaultValue = "id", example = "id")
String sortField;
@ApiModelProperty(value = "排序方向(ASC|DESC)", example = "DESC")
@Schema(description = "排序方向(ASC|DESC)", defaultValue = "DESC", example = "DESC")
Sort.Direction sortOrder;
/**
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel(value = "PidParam", description = "公共的父级 ID 查询参数")
@Schema(name = "PidParam", description = "公共的父级 ID 查询参数")
@Data
@Builder
@NoArgsConstructor
......@@ -27,7 +27,7 @@ public class PidParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456893L;
@ApiModelProperty(value = "pid", example = "0", required = true)
@Parameter(description = "pid", example = "0")
@NotBlank
String pid;
}
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.snowflake;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import org.springframework.stereotype.Component;
/**
* 基于雪花算法的 ID 生成器
* 生成 Long 类型
*
* @author ifzm
* @version 0.1
* 2020/1/14 16:18
*/
@Component
public class GenerateLongId implements IdentifierGenerator {
private Snowflake snowflake;
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return snowflake.nextId();
}
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
snowflake = IdUtil.getSnowflake();
}
}
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.snowflake;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import org.springframework.stereotype.Component;
/**
* 基于雪花算法的 ID 生成器
* 生成 String 类型
*
* @author ifzm
* @version 0.1
* 2020/1/14 16:18
*/
@Component
public class GenerateStringId implements IdentifierGenerator {
private Snowflake snowflake;
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return snowflake.nextIdStr();
}
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
snowflake = IdUtil.getSnowflake();
}
}
/* (C) 2023 YiRing, Inc. */
package com.yiring.common.snowflake;
import lombok.experimental.UtilityClass;
/**
* 雪花 ID 生成器常量
*
* @author ifzm
* @version 0.1
* 2020/8/10 15:35
*/
@UtilityClass
public class SnowflakeId {
public final String GENERATOR = "snowflake";
public class Strategy {
public static final String STRING = "com.yiring.common.snowflake.GenerateStringId";
public static final String LONG = "com.yiring.common.snowflake.GenerateLongId";
}
}
......@@ -4,11 +4,11 @@ package com.yiring.common.validation;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
* 枚举参数校验
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 枚举参数校验器
......
......@@ -2,11 +2,11 @@
package com.yiring.common.validation;
import com.yiring.common.util.Commons;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validation;
import jakarta.validation.ValidatorFactory;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import lombok.Cleanup;
import lombok.experimental.UtilityClass;
......@@ -34,7 +34,7 @@ public class ValidateUtil {
@Cleanup
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Set<ConstraintViolation<T>> constraintViolations = factory.getValidator().validate(t, groups);
if (!Commons.isNullOrEmpty(constraintViolations)) {
if (Commons.notEmpty(constraintViolations)) {
throw new ConstraintViolationException(constraintViolations);
}
}
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.validation.group;
import javax.validation.groups.Default;
import jakarta.validation.groups.Default;
/**
* validate group
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
/**
......@@ -16,7 +18,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2022/3/23 16:47
*/
@ApiModel(value = "DataVo", description = "公共数据响应输出")
@Schema(name = "DataVo", description = "公共数据响应输出")
@Data
@NoArgsConstructor
@AllArgsConstructor
......@@ -26,17 +28,18 @@ public class DataVo<T extends Serializable> implements Serializable {
@Serial
private static final long serialVersionUID = 2472779197432240431L;
@ApiModelProperty(value = "数据")
@Schema(description = "数据")
T data;
/**
* 通常在带有时效性的数据查询时有用途(可选参数)
*/
@ApiModelProperty(value = "数据最新时间")
@Schema(description = "数据最新时间")
LocalDateTime latest;
/**
* 构建一个 DataVo
*
* @param data 数据
* @return DataVo
*/
......@@ -47,7 +50,8 @@ public class DataVo<T extends Serializable> implements Serializable {
/**
* 构建一个 DataVo
* @param data 数据
*
* @param data 数据
* @param latest 数据最新时间
* @return DataVo
*/
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import lombok.*;
......@@ -16,7 +15,7 @@ import lombok.experimental.FieldDefaults;
* 2022/3/24 17:29
*/
@ApiModel(value = "KeyValueVo", description = "键值对响应输出")
@Schema(name = "KeyValueVo", description = "键值对响应输出")
@Data
@Builder
@NoArgsConstructor
......@@ -27,15 +26,15 @@ public class KeyValueVo implements Serializable {
@Serial
private static final long serialVersionUID = -5238793972067296346L;
@ApiModelProperty(value = "key", example = "key")
@Schema(description = "key", example = "key")
String key;
@ApiModelProperty(value = "value", example = "value")
@Schema(description = "value", example = "value")
String value;
/**
* 扩展字段,可用于文本输出
*/
@ApiModelProperty(value = "label", example = "label")
@Schema(description = "label", example = "label")
String label;
}
......@@ -2,14 +2,16 @@
package com.yiring.common.vo;
import com.yiring.common.util.Commons;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.data.domain.Page;
......@@ -19,7 +21,7 @@ import org.springframework.data.domain.Page;
* @author ifzm
* @version 0.1 2019/3/10 16:29
*/
@ApiModel(value = "PageVo", description = "公共分页查询响应输出")
@Schema(name = "PageVo", description = "公共分页查询响应输出")
@Data
@NoArgsConstructor
@AllArgsConstructor
......@@ -29,16 +31,16 @@ public class PageVo<T extends Serializable> implements Serializable {
@Serial
private static final long serialVersionUID = 6103761701912769946L;
@ApiModelProperty(value = "数据", required = true)
@Schema(description = "数据")
List<T> data;
@ApiModelProperty(value = "数据总数", example = "100", required = true)
@Schema(description = "数据总数", example = "100")
Long total;
/**
* 通常在带有时效性的数据查询时有用途(可选参数)
*/
@ApiModelProperty(value = "数据最新时间")
@Schema(description = "数据最新时间")
LocalDateTime latest;
/**
......
dependencies {
implementation project(":basic-common:core")
implementation project(":basic-common:i18n")
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// hutool-core
implementation "cn.hutool:hutool-core:${hutoolVersion}"
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.swagger;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.net.NetUtil;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import com.yiring.common.core.Status;
import io.swagger.annotations.Api;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import com.yiring.common.core.I18n;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.tags.Tag;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* Swagger Config
......@@ -42,9 +33,8 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Slf4j
@Profile("!prod")
@EnableSwagger2WebMvc
@Configuration
@Import(BeanValidatorPluginsConfiguration.class)
@RequiredArgsConstructor
public class SwaggerConfig implements CommandLineRunner {
@Value("${spring.application.name}")
......@@ -56,78 +46,110 @@ public class SwaggerConfig implements CommandLineRunner {
@Value("${server.servlet.context-path}")
String path;
@Resource
OpenApiExtensionResolver openApiExtensionResolver;
final I18n i18n;
@Bean
public OpenAPI openAPI() {
Info info = new Info()
.title("API Doc")
.description(applicationName)
.version("1.0")
.contact(new Contact().name("© YiRing").url("https://yiring.com").email("developer@yiring.com"));
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
}
@Bean(name = "api.any")
public Docket any() {
return api("default", List.of(""), PathSelectors.any());
public GroupedOpenApi any() {
return api("default", List.of("com.yiring"), List.of("/**"), Collections.emptyList());
}
@Bean(name = "api.auth")
public Docket auth() {
return api("① Auth", List.of("com.yiring.auth.web"), Predicate.not(PathSelectors.ant(path + "/sys/**")));
public GroupedOpenApi auth() {
return api("① Auth", List.of("com.yiring.auth.web"), List.of("/**"), List.of("/sys/**"));
}
@Bean(name = "api.common")
public Docket common() {
return api("② 公共", List.of("com.yiring.common.web", "com.yiring.app.web.common"), PathSelectors.any());
public GroupedOpenApi common() {
return api(
"② 公共",
List.of("com.yiring.common.web", "com.yiring.app.web.common"),
List.of("/**"),
Collections.emptyList()
);
}
@Bean(name = "api.manage")
public Docket manage() {
return api("③ 系统管理", List.of("com.yiring.auth.web.sys"), PathSelectors.any());
public GroupedOpenApi manage() {
return api("③ 系统管理", List.of("com.yiring.auth.web.sys"), List.of("/**"), Collections.emptyList());
}
@Bean(name = "api.example")
public Docket example() {
return api("④ 示例", List.of("com.yiring.app.web.example"), PathSelectors.any());
public GroupedOpenApi example() {
return api("④ 示例", List.of("com.yiring.app.web.example"), List.of("/**"), Collections.emptyList());
}
private Docket api(String group, List<String> basePackages, Predicate<String> paths) {
// 扫描多个包
Predicate<RequestHandler> predicate = basePackages
.stream()
.map(RequestHandlerSelectors::basePackage)
.reduce(Predicate::or)
.orElse(RequestHandlerSelectors.none());
return new Docket(DocumentationType.SWAGGER_2)
.groupName(group)
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.GET, buildGlobalResponseMessage())
.globalResponseMessage(RequestMethod.POST, buildGlobalResponseMessage())
.globalResponseMessage(RequestMethod.DELETE, buildGlobalResponseMessage())
.globalResponseMessage(RequestMethod.PUT, buildGlobalResponseMessage())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class).and(predicate))
.paths(paths)
.build()
.extensions(openApiExtensionResolver.buildExtensions(group));
@Bean
public OpenApiCustomizer sortTagCustom() {
String order = "x-order";
return api -> {
List<Tag> tags = api
.getTags()
.stream()
.sorted(
Comparator.comparing(tag ->
Convert.toInt(
Optional.ofNullable(tag.getExtensions()).orElseGet(HashMap::new).get(order),
Integer.MAX_VALUE
)
)
)
.peek(tag -> {
Map<String, Object> extensions = tag.getExtensions();
if (Objects.nonNull(extensions) && extensions.containsKey(order)) {
extensions.put(order, Convert.toInt(extensions.get(order)));
}
})
.toList();
api.setTags(tags);
};
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API Doc")
.description(applicationName)
.version("1.0")
.contact(new Contact("© YiRing", "https://yiring.com", "developer@yiring.com"))
// @Bean
// public OperationCustomizer addGlobalStatusResponse() {
// return (operation, handlerMethod) -> {
// ApiResponses responses = operation.getResponses();
// for (Status status : Status.values()) {
// if (Status.OK.equals(status)) {
// continue;
// }
//
// ApiResponse response = new ApiResponse()
// .description(i18n.get(status.getReasonPhrase()))
// .$ref("Response");
// responses.addApiResponse(String.valueOf(status.value()), response);
// }
//
// return operation;
// };
// }
private GroupedOpenApi api(
String group,
List<String> basePackages,
List<String> pathsToMatch,
List<String> pathsToExclude
) {
return GroupedOpenApi
.builder()
.group(group)
.packagesToScan(basePackages.toArray(new String[0]))
.addOpenApiMethodFilter(method -> method.isAnnotationPresent(Operation.class))
.pathsToMatch(pathsToMatch.toArray(new String[0]))
.pathsToExclude(pathsToExclude.toArray(new String[0]))
.build();
}
/**
* 构建全局响应消息
*
* @return 所有自定义状态码消息
*/
private List<ResponseMessage> buildGlobalResponseMessage() {
return Arrays
.stream(Status.values())
.map(status -> new ResponseMessageBuilder().code(status.value()).message(status.getReasonPhrase()).build())
.collect(Collectors.toList());
}
@Override
public void run(String... args) {
String link = NetUtil
......@@ -135,6 +157,6 @@ public class SwaggerConfig implements CommandLineRunner {
.stream()
.map(host -> "> http://" + host + ":" + port + path + "/doc.html")
.collect(Collectors.joining("\n\t\t"));
Console.log("\n\t📖 API Doc (Swagger2): \n\t\t{}\n", link);
Console.log("\n\t📖 API Doc (OpenAPI3): \n\t\t{}\n", link);
}
}
......@@ -7,6 +7,8 @@ import org.jetbrains.annotations.PropertyKey;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
......@@ -18,6 +20,7 @@ import org.springframework.stereotype.Component;
*/
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
@RequiredArgsConstructor
public class I18n {
......
Status.OK=OK
Status.OK=\u6210\u529F
Status.NON_AUTHORITATIVE_INFORMATION=\u8BA4\u8BC1\u5931\u8D25
Status.BAD_REQUEST=\u8BF7\u6C42\u5931\u8D25
Status.UNAUTHORIZED=\u51ED\u8BC1\u8FC7\u671F
......
......@@ -6,7 +6,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "com.github.xiaoymin:knife4j-openapi3-jakarta-spring-boot-starter:${knife4jOpen3Version}"
// minio
implementation "io.minio:minio:${minioVersion}"
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -17,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* 2022/7/5 15:29
*/
@ApiModel(value = "DownloadParam", description = "文件下载请求参数")
@Schema(name = "DownloadParam", description = "文件下载请求参数")
@Data
@Builder
@NoArgsConstructor
......@@ -28,11 +27,11 @@ public class DownloadParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456899L;
@ApiModelProperty(value = "bucket", example = "public", required = true)
@Schema(name = "bucket", example = "public")
@NotEmpty(message = "存储桶不能为空")
String bucket;
@ApiModelProperty(value = "object", example = "cat.jpg", required = true)
@Schema(name = "object", example = "cat.jpg")
@NotEmpty(message = "文件对象不能为空")
String object;
}
......@@ -3,7 +3,7 @@ package com.yiring.common.web;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.common.annotation.DownloadResponse;
import com.yiring.common.core.Minio;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
......@@ -13,16 +13,18 @@ import com.yiring.common.util.FileUtils;
import com.yiring.common.vo.ImageInfo;
import io.minio.GetObjectResponse;
import io.minio.StatObjectResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import java.sql.Timestamp;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
......@@ -36,9 +38,11 @@ import org.springframework.web.multipart.MultipartFile;
@Slf4j
@Validated
@SuppressWarnings({ "deprecation" })
@ApiSupport(order = -98)
@Api(tags = "文件管理", description = "file")
@Tag(
name = "文件管理",
description = "file",
extensions = { @Extension(properties = { @ExtensionProperty(name = "x-order", value = "-9997") }) }
)
@RequiredArgsConstructor
@RestController
@RequestMapping("/common/file/")
......@@ -50,9 +54,9 @@ public class MinioController {
/**
* minio 上传文件,成功返回文件 url
*/
@ApiOperation(value = "文件上传", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PostMapping(value = "upload", headers = HttpHeaders.CONTENT_TYPE + "=" + MediaType.MULTIPART_FORM_DATA_VALUE)
public Result<String> upload(@ApiParam(value = "文件", required = true) @RequestPart("file") MultipartFile file) {
@Operation(summary = "文件上传")
@PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result<String> upload(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) {
try {
// 获取文件名信息
String filename = file.getOriginalFilename();
......@@ -76,13 +80,13 @@ public class MinioController {
}
}
@ApiOperation(value = "Base64 图片上传")
@ApiImplicitParam(
@Operation(summary = "Base64 图片上传")
@Parameter(
name = "base64Image",
value = "Base64 图片信息",
description = "Base64 图片信息",
example = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAALCAYAAABYpyyrAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAATSURBVBhXYzAwNP6PjIeKgPF/ABj+RUX4hZfVAAAAAElFTkSuQmCC",
required = true,
paramType = "query"
in = ParameterIn.QUERY
)
@PostMapping(value = "uploadBase64Image")
public Result<String> uploadBase64Image(@NotBlank(message = "图片 Base64 信息不能为空") String base64Image) {
......@@ -112,9 +116,10 @@ public class MinioController {
* @param response HttpServletResponse
* @param param 请求参数
*/
@ApiOperation(value = "文件下载", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@GetMapping("download")
public void download(HttpServletResponse response, @Validated DownloadParam param) {
@DownloadResponse
@Operation(summary = "文件下载")
@GetMapping(value = "download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response, @ParameterObject @Validated DownloadParam param) {
try {
StatObjectResponse statObject = minio.objectStat(param.getBucket(), param.getObject());
GetObjectResponse object = minio.getObject(param.getBucket(), param.getObject());
......
......@@ -3,7 +3,7 @@ package com.yiring.common.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -25,10 +25,10 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
@Configuration
@RequiredArgsConstructor
public class RedisConfig {
@Resource
ObjectMapper objectMapper;
final ObjectMapper objectMapper;
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
......
......@@ -3,7 +3,7 @@ package com.yiring.common.core;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
......@@ -18,10 +18,10 @@ import org.springframework.stereotype.Component;
@SuppressWarnings({ "unused" })
@Slf4j
@Component
@RequiredArgsConstructor
public final class Redis {
@Resource
RedisTemplate<String, Object> redisTemplate;
final RedisTemplate<String, Object> redisTemplate;
/**
* 指定缓存失效时间
......@@ -83,7 +83,7 @@ public final class Redis {
/**
* 普通缓存获取
*
* @param key 键
* @param key
* @param type 类型
* @return 值
*/
......@@ -459,6 +459,7 @@ public final class Redis {
/**
* 获取所有 key
*
* @param pattern 查询规则
* @return 所有匹配的 Key 集合
*/
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.util;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Constructor;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import lombok.NonNull;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
......@@ -21,7 +21,9 @@ import org.springframework.beans.BeanUtils;
@UtilityClass
public class Commons {
/** 代理 IP 请求头 */
/**
* 代理 IP 请求头
*/
private static final String[] HEADERS_TO_TRY = {
"X-Forwarded-For",
"Proxy-Client-IP",
......@@ -69,8 +71,8 @@ public class Commons {
* @param collection 集合
* @return 是否为空
*/
public boolean isNullOrEmpty(Collection<?> collection) {
return collection == null || collection.isEmpty();
public boolean notEmpty(Collection<?> collection) {
return collection != null && !collection.isEmpty();
}
/**
......@@ -85,11 +87,12 @@ public class Commons {
/**
* 对象 Copy
* @param source 源对象
* @param type 目标类型
*
* @param source 源对象
* @param type 目标类型
* @param ignoreProperties 忽略属性
* @param <T> 目标类型
* @return 目标对象
* @param <T> 目标类型
*/
public <T> T transform(Object source, Class<T> type, String... ignoreProperties) {
try {
......@@ -106,11 +109,12 @@ public class Commons {
/**
* 将集合通过 BeanUtils 反射转换成指定类型集合
* @param list 原始数据集合
* @param type 目标类型
*
* @param list 原始数据集合
* @param type 目标类型
* @param ignoreProperties 忽略属性
* @param <T> 目标类型集合
* @param <S> 原类型集合
* @param <T> 目标类型集合
* @param <S> 原类型集合
* @return 目标集合
*/
public <T, S> List<T> transform(@NonNull List<S> list, Class<T> type, String... ignoreProperties) {
......@@ -119,12 +123,13 @@ public class Commons {
/**
* 将集合通过 BeanUtils 反射转换成指定类型集合
* @param list 原始数据集合
* @param type 目标类型
* @param fn 自定义处理函数
*
* @param list 原始数据集合
* @param type 目标类型
* @param fn 自定义处理函数
* @param ignoreProperties 忽略属性
* @param <T> 目标类型集合
* @param <S> 原类型集合
* @param <T> 目标类型集合
* @param <S> 原类型集合
* @return 目标集合
*/
public <T, S> List<T> transform(
......@@ -162,6 +167,7 @@ public class Commons {
public interface CallbackFunction<S, T> {
/**
* 执行方法
*
* @param s 源对象
* @param t 目标对象
*/
......
......@@ -5,6 +5,7 @@ import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import com.yiring.common.vo.ImageInfo;
import jakarta.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
......@@ -15,7 +16,6 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.apache.tomcat.util.http.fileupload.IOUtils;
......
plugins {
id 'java'
// https://start.spring.io
id 'org.springframework.boot' version '2.7.7'
id 'org.springframework.boot' version '3.0.1'
id 'org.graalvm.buildtools.native' version '0.9.18'
// https://plugins.gradle.org/plugin/io.spring.dependency-management
id 'io.spring.dependency-management' version '1.0.13.RELEASE'
id 'io.spring.dependency-management' version '1.1.0'
// https://plugins.gradle.org/plugin/com.diffplug.spotless
id "com.diffplug.spotless" version "6.3.0"
id "com.diffplug.spotless" version "6.12.1"
}
ext {
// Spotless
// https://www.npmjs.com/package/prettier
prettierVersion = '2.8.1'
prettierVersion = '2.8.2'
// https://www.npmjs.com/package/prettier-plugin-java
prettierJavaVersion = '2.0.0'
// SpringCloud
// https://start.spring.io/
springCloudVersion = '2021.0.4'
springCloudVersion = '2022.0.0'
// Dependencies
// https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter
knife4jVersion = '2.0.9'
// // https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter
knife4jOpen3Version = '4.0.0'
// https://mvnrepository.com/artifact/io.swagger/swagger-annotations
swaggerAnnotationsVersion = '1.6.9'
// https://mvnrepository.com/artifact/cn.dev33/sa-token-spring-boot-starter
saTokenVersion = '1.33.0'
// https://mvnrepository.com/artifact/cn.dev33/sa-token-spring-boot3-starter
saTokenVersion = '1.34.0'
// https://mvnrepository.com/artifact/cn.hutool/hutool-all
hutoolVersion = '5.8.11'
// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
......@@ -35,11 +36,11 @@ ext {
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
okhttpVersion = '4.10.0'
// https://mvnrepository.com/artifact/io.minio/minio
minioVersion = '8.4.6'
// https://mvnrepository.com/artifact/com.vladmihalcea/hibernate-types-55
hibernateTypesVersion = '2.21.1'
minioVersion = '8.5.1'
// https://mvnrepository.com/artifact/io.hypersistence/hypersistence-utils-hibernate-60
hibernateTypesVersion = '3.0.1'
// https://mvnrepository.com/artifact/org.hibernate/hibernate-spatial
hibernateSpatialVersion = '5.6.14.Final'
hibernateSpatialVersion = '6.1.6.Final'
// https://mvnrepository.com/artifact/org.locationtech.jts/jts-core
jtsVersion = '1.19.0'
// https://mvnrepository.com/artifact/com.github.liaochong/myexcel
......@@ -55,6 +56,7 @@ allprojects {
mavenLocal()
// Nexus
// maven { url 'http://10.111.102.83:8081/repository/aliyun-maven/' }
maven { url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
maven { url 'https://maven.aliyun.com/repository/public' }
mavenCentral()
}
......
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''))
// precomputed scope
const scopeComplete = execSync('git status --porcelain || true')
.toString()
.trim()
.split('\n')
.find((r) => ~r.indexOf('M src'))
?.replace(/(\/)/g, '%%')
?.match(/src%%((\w|-)*)/)?.[1]
?.replace(/s$/, '')
/** @type {import('cz-git').UserConfig} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release',
],
],
},
prompt: {
/** @use `yarn commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',
s: 'style: update code format',
b: 'build: bump dependencies',
c: 'chore: update config',
},
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
defaultScope: scopeComplete,
scopes: [...scopes, 'mock'],
allowEmptyIssuePrefixs: false,
allowCustomIssuePrefixs: false,
// English
typesAppend: [
{ value: 'wip', name: 'wip: work in process' },
{ value: 'workflow', name: 'workflow: workflow improvements' },
{ value: 'types', name: 'types: type definition file changes' },
],
// 中英文对照版
// messages: {
// type: '选择你要提交的类型 :',
// scope: '选择一个提交范围 (可选):',
// customScope: '请输入自定义的提交范围 :',
// subject: '填写简短精炼的变更描述 :\n',
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
// customFooterPrefixs: '输入自定义issue前缀 :',
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
// confirmCommit: '是否提交或修改commit ?',
// },
// types: [
// { value: 'feat', name: 'feat: 新增功能' },
// { value: 'fix', name: 'fix: 修复缺陷' },
// { value: 'docs', name: 'docs: 文档变更' },
// { value: 'style', name: 'style: 代码格式' },
// { value: 'refactor', name: 'refactor: 代码重构' },
// { value: 'perf', name: 'perf: 性能优化' },
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
// { value: 'revert', name: 'revert: 回滚 commit' },
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
// { value: 'wip', name: 'wip: 正在开发中' },
// { value: 'workflow', name: 'workflow: 工作流程改进' },
// { value: 'types', name: 'types: 类型定义文件修改' },
// ],
// emptyScopesAlias: 'empty: 不填写',
// customScopesAlias: 'custom: 自定义',
},
}
......@@ -4,7 +4,7 @@
<!-- prettier-ignore -->
- [SpringBoot v2.7.x](https://spring.io/projects/spring-boot)
- [SpringBoot v3.0.x](https://spring.io/projects/spring-boot)
- [Lombok](https://projectlombok.org/)
- [Spring Web](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html)
- [Spring Data Jpa](https://spring.io/projects/spring-data-jpa)
......
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
{
"name": "basic-api-project",
"name": "basic-api-boot",
"version": "0.0.1",
"scripts": {
"log": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"devDependencies": {
"@commitlint/cli": "^17.4.0",
"@commitlint/config-conventional": "^17.4.0",
"commitizen": "^4.2.6",
"conventional-changelog-cli": "^2.2.2",
"cz-conventional-changelog": "^3.3.0",
"conventional-changelog-cli": "^2.2.2"
"cz-customizable": "^7.0.0",
"cz-git": "^1.4.1"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
"path": "node_modules/cz-git"
}
}
}
lockfileVersion: 5.3
lockfileVersion: 5.4
specifiers:
'@commitlint/cli': ^17.4.0
'@commitlint/config-conventional': ^17.4.0
commitizen: ^4.2.6
conventional-changelog-cli: ^2.2.2
cz-conventional-changelog: ^3.3.0
cz-customizable: ^7.0.0
cz-git: ^1.4.1
devDependencies:
'@commitlint/cli': 17.4.1
'@commitlint/config-conventional': 17.4.0
commitizen: 4.2.6
conventional-changelog-cli: 2.2.2
cz-conventional-changelog: 3.3.0
cz-customizable: 7.0.0
cz-git: 1.4.1
packages:
......@@ -31,6 +41,33 @@ packages:
js-tokens: 4.0.0
dev: true
/@commitlint/cli/17.4.1:
resolution: {integrity: sha512-W8OJwz+izY+fVwyUt1HveCDmABMZNRVZHSVPw/Bh9Y62tp11SmmQaycgbsYLMiMy7JGn4mAJqEGlSHS9Uti9ZQ==}
engines: {node: '>=v14'}
hasBin: true
dependencies:
'@commitlint/format': 17.4.0
'@commitlint/lint': 17.4.0
'@commitlint/load': 17.4.1
'@commitlint/read': 17.4.0
'@commitlint/types': 17.4.0
execa: 5.1.1
lodash.isfunction: 3.0.9
resolve-from: 5.0.0
resolve-global: 1.0.0
yargs: 17.6.2
transitivePeerDependencies:
- '@swc/core'
- '@swc/wasm'
dev: true
/@commitlint/config-conventional/17.4.0:
resolution: {integrity: sha512-G4XBf45J4ZMspO4NwBFzY3g/1Kb+B42BcIxeikF8wucQxcyxcmhRdjeQpRpS1XEcBq5pdtEEQFipuB9IuiNFhw==}
engines: {node: '>=v14'}
dependencies:
conventional-changelog-conventionalcommits: 5.0.0
dev: true
/@commitlint/config-validator/16.2.1:
resolution: {integrity: sha512-hogSe0WGg7CKmp4IfNbdNES3Rq3UEI4XRPB8JL4EPgo/ORq5nrGTVzxJh78omibNuB8Ho4501Czb1Er1MoDWpw==}
engines: {node: '>=v12'}
......@@ -40,12 +77,63 @@ packages:
dev: true
optional: true
/@commitlint/config-validator/17.4.0:
resolution: {integrity: sha512-Sa/+8KNpDXz4zT4bVbz2fpFjvgkPO6u2V2fP4TKgt6FjmOw2z3eEX859vtfeaTav/ukBw0/0jr+5ZTZp9zCBhA==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.0
ajv: 8.12.0
dev: true
/@commitlint/ensure/17.4.0:
resolution: {integrity: sha512-7oAxt25je0jeQ/E0O/M8L3ADb1Cvweu/5lc/kYF8g/kXatI0wxGE5La52onnAUAWeWlsuvBNar15WcrmDmr5Mw==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.0
lodash.camelcase: 4.3.0
lodash.kebabcase: 4.1.1
lodash.snakecase: 4.1.1
lodash.startcase: 4.4.0
lodash.upperfirst: 4.3.1
dev: true
/@commitlint/execute-rule/16.2.1:
resolution: {integrity: sha512-oSls82fmUTLM6cl5V3epdVo4gHhbmBFvCvQGHBRdQ50H/690Uq1Dyd7hXMuKITCIdcnr9umyDkr8r5C6HZDF3g==}
engines: {node: '>=v12'}
dev: true
optional: true
/@commitlint/execute-rule/17.4.0:
resolution: {integrity: sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==}
engines: {node: '>=v14'}
dev: true
/@commitlint/format/17.4.0:
resolution: {integrity: sha512-Z2bWAU5+f1YZh9W76c84J8iLIWIvvm+mzqogTz0Nsc1x6EHW0Z2gI38g5HAjB0r0I3ZjR15IDEJKhsxyblcyhA==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.0
chalk: 4.1.2
dev: true
/@commitlint/is-ignored/17.4.0:
resolution: {integrity: sha512-mkRuBlPUaBimvSvJyIHEHEW1/jP1SqEI7NOoaO9/eyJkMbsaiv5b1QgDYL4ZXlHdS64RMV7Y21MVVzuIceImDA==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.0
semver: 7.3.8
dev: true
/@commitlint/lint/17.4.0:
resolution: {integrity: sha512-HG2YT4TUbQKs9v8QvpQjJ6OK+fhflsDB8M+D5tLrY79hbQOWA9mDKdRkABsW/AAhpNI9+zeGUWF3jj245jSHKw==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/is-ignored': 17.4.0
'@commitlint/parse': 17.4.0
'@commitlint/rules': 17.4.0
'@commitlint/types': 17.4.0
dev: true
/@commitlint/load/16.2.3:
resolution: {integrity: sha512-Hb4OUlMnBUK6UxJEZ/VJ5k0LocIS7PtEMbRXEAA7eSpOgORIFexC4K/RaRpVd5UTtu3M0ST3ddPPijF9rdW6nw==}
engines: {node: '>=v12'}
......@@ -58,7 +146,7 @@ packages:
'@types/node': 17.0.29
chalk: 4.1.2
cosmiconfig: 7.0.1
cosmiconfig-typescript-loader: 1.0.9_5281fe59fc32158e106b8b5e2bebb315
cosmiconfig-typescript-loader: 1.0.9_kka74wp4giky4edlrnpcx25tcu
lodash: 4.17.21
resolve-from: 5.0.0
typescript: 4.6.3
......@@ -68,6 +156,54 @@ packages:
dev: true
optional: true
/@commitlint/load/17.4.1:
resolution: {integrity: sha512-6A7/LhIaQpL4ieciIDcVvK2d5z/UI1GBrtDaHm6sQSCL0265clB2/F7XKQNTJHXv9yG4LByT2r+QCpM4GugIfw==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/config-validator': 17.4.0
'@commitlint/execute-rule': 17.4.0
'@commitlint/resolve-extends': 17.4.0
'@commitlint/types': 17.4.0
'@types/node': 17.0.29
chalk: 4.1.2
cosmiconfig: 8.0.0
cosmiconfig-typescript-loader: 4.3.0_asoaktcvsaefgrgziobsocgewq
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
resolve-from: 5.0.0
ts-node: 10.9.1_u3h3q7xqdg7nitfvwf64wuo7zy
typescript: 4.9.4
transitivePeerDependencies:
- '@swc/core'
- '@swc/wasm'
dev: true
/@commitlint/message/17.4.0:
resolution: {integrity: sha512-USGJDU9PPxcgQjKXCzvPUal65KAhxWq3hp+MrU1pNCN2itWM654CLIoY2LMIQ7rScTli9B5dTLH3vXhzbItmzA==}
engines: {node: '>=v14'}
dev: true
/@commitlint/parse/17.4.0:
resolution: {integrity: sha512-x8opKc5p+Hgs+CrMbq3VAnW2L2foPAX6arW8u9c8nTzksldGgFsENT+XVyPmpSMLlVBswZ1tndcz1xyKiY9TJA==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.0
conventional-changelog-angular: 5.0.13
conventional-commits-parser: 3.2.4
dev: true
/@commitlint/read/17.4.0:
resolution: {integrity: sha512-pGDeZpbkyvhxK8ZoCDUacPPRpauKPWF3n2XpDBEnuGreqUF2clq2PVJpwMMaNN5cHW8iFKCbcoOjXhD01sln0A==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/top-level': 17.4.0
'@commitlint/types': 17.4.0
fs-extra: 11.1.0
git-raw-commits: 2.0.11
minimist: 1.2.6
dev: true
/@commitlint/resolve-extends/16.2.1:
resolution: {integrity: sha512-NbbCMPKTFf2J805kwfP9EO+vV+XvnaHRcBy6ud5dF35dxMsvdJqke54W3XazXF1ZAxC4a3LBy4i/GNVBAthsEg==}
engines: {node: '>=v12'}
......@@ -81,6 +217,41 @@ packages:
dev: true
optional: true
/@commitlint/resolve-extends/17.4.0:
resolution: {integrity: sha512-3JsmwkrCzoK8sO22AzLBvNEvC1Pmdn/65RKXzEtQMy6oYMl0Snrq97a5bQQEFETF0VsvbtUuKttLqqgn99OXRQ==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/config-validator': 17.4.0
'@commitlint/types': 17.4.0
import-fresh: 3.3.0
lodash.mergewith: 4.6.2
resolve-from: 5.0.0
resolve-global: 1.0.0
dev: true
/@commitlint/rules/17.4.0:
resolution: {integrity: sha512-lz3i1jet2NNjTWpAMwjjQjMZCPWBIHK1Kkja9o09UmUtMjRdALTb8uMLe8gCyeq3DiiZ5lLYOhbsoPK56xGQKA==}
engines: {node: '>=v14'}
dependencies:
'@commitlint/ensure': 17.4.0
'@commitlint/message': 17.4.0
'@commitlint/to-lines': 17.4.0
'@commitlint/types': 17.4.0
execa: 5.1.1
dev: true
/@commitlint/to-lines/17.4.0:
resolution: {integrity: sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==}
engines: {node: '>=v14'}
dev: true
/@commitlint/top-level/17.4.0:
resolution: {integrity: sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==}
engines: {node: '>=v14'}
dependencies:
find-up: 5.0.0
dev: true
/@commitlint/types/16.2.1:
resolution: {integrity: sha512-7/z7pA7BM0i8XvMSBynO7xsB3mVQPUZbVn6zMIlp/a091XJ3qAXRXc+HwLYhiIdzzS5fuxxNIHZMGHVD4HJxdA==}
engines: {node: '>=v12'}
......@@ -89,44 +260,56 @@ packages:
dev: true
optional: true
/@cspotcode/source-map-consumer/0.8.0:
resolution: {integrity: sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==}
engines: {node: '>= 12'}
/@commitlint/types/17.4.0:
resolution: {integrity: sha512-2NjAnq5IcxY9kXtUeO2Ac0aPpvkuOmwbH/BxIm36XXK5LtWFObWJWjXOA+kcaABMrthjWu6la+FUpyYFMHRvbA==}
engines: {node: '>=v14'}
dependencies:
chalk: 4.1.2
dev: true
optional: true
/@cspotcode/source-map-support/0.7.0:
resolution: {integrity: sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==}
/@cspotcode/source-map-support/0.8.1:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
dependencies:
'@cspotcode/source-map-consumer': 0.8.0
'@jridgewell/trace-mapping': 0.3.9
dev: true
optional: true
/@hutson/parse-repository-url/3.0.2:
resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==}
engines: {node: '>=6.9.0'}
dev: true
/@jridgewell/resolve-uri/3.1.0:
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
engines: {node: '>=6.0.0'}
dev: true
/@jridgewell/sourcemap-codec/1.4.14:
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
dev: true
/@jridgewell/trace-mapping/0.3.9:
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
dependencies:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
/@tsconfig/node10/1.0.8:
resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==}
dev: true
optional: true
/@tsconfig/node12/1.0.9:
resolution: {integrity: sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==}
dev: true
optional: true
/@tsconfig/node14/1.0.1:
resolution: {integrity: sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==}
dev: true
optional: true
/@tsconfig/node16/1.0.2:
resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==}
dev: true
optional: true
/@types/minimist/1.2.2:
resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
......@@ -135,7 +318,6 @@ packages:
/@types/node/17.0.29:
resolution: {integrity: sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==}
dev: true
optional: true
/@types/normalize-package-data/2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
......@@ -158,14 +340,12 @@ packages:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
dev: true
optional: true
/acorn/8.7.1:
resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
optional: true
/add-stream/1.0.0:
resolution: {integrity: sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=}
......@@ -181,11 +361,27 @@ packages:
dev: true
optional: true
/ajv/8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
dev: true
/ansi-escapes/3.2.0:
resolution: {integrity: sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==}
engines: {node: '>=4'}
dev: true
/ansi-escapes/4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.21.3
dev: true
/ansi-regex/3.0.1:
resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==}
engines: {node: '>=4'}
......@@ -218,21 +414,41 @@ packages:
/arg/4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
dev: true
optional: true
/argparse/2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/array-ify/1.0.0:
resolution: {integrity: sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=}
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
dev: true
/arrify/1.0.1:
resolution: {integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=}
resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
engines: {node: '>=0.10.0'}
dev: true
/at-least-node/1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
dev: true
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: true
/bl/4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.0
dev: true
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
......@@ -247,8 +463,15 @@ packages:
fill-range: 7.0.1
dev: true
/cachedir/2.2.0:
resolution: {integrity: sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==}
/buffer/5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/cachedir/2.3.0:
resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
engines: {node: '>=6'}
dev: true
......@@ -256,7 +479,6 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: true
optional: true
/camelcase-keys/6.2.2:
resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
......@@ -288,23 +510,39 @@ packages:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: true
optional: true
/chardet/0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
dev: true
/cli-cursor/2.1.0:
resolution: {integrity: sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=}
resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==}
engines: {node: '>=4'}
dependencies:
restore-cursor: 2.0.0
dev: true
/cli-cursor/3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
dependencies:
restore-cursor: 3.1.0
dev: true
/cli-spinners/2.7.0:
resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
engines: {node: '>=6'}
dev: true
/cli-width/2.2.1:
resolution: {integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==}
dev: true
/cli-width/3.0.0:
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
engines: {node: '>= 10'}
dev: true
/cliui/7.0.4:
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
dependencies:
......@@ -313,6 +551,20 @@ packages:
wrap-ansi: 7.0.0
dev: true
/cliui/8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
dev: true
/clone/1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: true
/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
......@@ -327,32 +579,32 @@ packages:
dev: true
/color-name/1.1.3:
resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=}
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true
/color-name/1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/commitizen/4.2.4:
resolution: {integrity: sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==}
engines: {node: '>= 10'}
/commitizen/4.2.6:
resolution: {integrity: sha512-RyTM+EiD9GO01DJUn9MRRAet3XUHGfoUZoksLfr+1ym1Xt2q5EYJs9Fg2BtKSb5Mo53i0BtMBmWMHQXVlZ/L9w==}
engines: {node: '>= 12'}
hasBin: true
dependencies:
cachedir: 2.2.0
cz-conventional-changelog: 3.2.0
cachedir: 2.3.0
cz-conventional-changelog: 3.3.0
dedent: 0.7.0
detect-indent: 6.0.0
detect-indent: 6.1.0
find-node-modules: 2.1.3
find-root: 1.1.0
fs-extra: 8.1.0
glob: 7.1.4
inquirer: 6.5.2
fs-extra: 9.1.0
glob: 7.2.3
inquirer: 8.2.4
is-utf8: 0.2.1
lodash: 4.17.21
minimist: 1.2.5
minimist: 1.2.6
strip-bom: 4.0.0
strip-json-comments: 3.0.1
strip-json-comments: 3.1.1
transitivePeerDependencies:
- '@swc/core'
- '@swc/wasm'
......@@ -366,7 +618,7 @@ packages:
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/conventional-changelog-angular/5.0.13:
......@@ -412,6 +664,15 @@ packages:
q: 1.5.1
dev: true
/conventional-changelog-conventionalcommits/5.0.0:
resolution: {integrity: sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==}
engines: {node: '>=10'}
dependencies:
compare-func: 2.0.0
lodash: 4.17.21
q: 1.5.1
dev: true
/conventional-changelog-core/4.2.4:
resolution: {integrity: sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==}
engines: {node: '>=10'}
......@@ -523,8 +784,8 @@ packages:
engines: {node: '>=10'}
hasBin: true
dependencies:
is-text-path: 1.0.1
JSONStream: 1.3.5
is-text-path: 1.0.1
lodash: 4.17.21
meow: 8.1.2
split2: 3.2.2
......@@ -535,7 +796,7 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
/cosmiconfig-typescript-loader/1.0.9_5281fe59fc32158e106b8b5e2bebb315:
/cosmiconfig-typescript-loader/1.0.9_kka74wp4giky4edlrnpcx25tcu:
resolution: {integrity: sha512-tRuMRhxN4m1Y8hP9SNYfz7jRwt8lZdWxdjg/ohg5esKmsndJIn4yT96oJVcf5x0eA11taXl+sIp+ielu529k6g==}
engines: {node: '>=12', npm: '>=6'}
peerDependencies:
......@@ -544,7 +805,7 @@ packages:
dependencies:
'@types/node': 17.0.29
cosmiconfig: 7.0.1
ts-node: 10.7.0_5281fe59fc32158e106b8b5e2bebb315
ts-node: 10.9.1_kka74wp4giky4edlrnpcx25tcu
typescript: 4.6.3
transitivePeerDependencies:
- '@swc/core'
......@@ -552,6 +813,21 @@ packages:
dev: true
optional: true
/cosmiconfig-typescript-loader/4.3.0_asoaktcvsaefgrgziobsocgewq:
resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==}
engines: {node: '>=12', npm: '>=6'}
peerDependencies:
'@types/node': '*'
cosmiconfig: '>=7'
ts-node: '>=10'
typescript: '>=3'
dependencies:
'@types/node': 17.0.29
cosmiconfig: 8.0.0
ts-node: 10.9.1_u3h3q7xqdg7nitfvwf64wuo7zy
typescript: 4.9.4
dev: true
/cosmiconfig/7.0.1:
resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==}
engines: {node: '>=10'}
......@@ -564,26 +840,27 @@ packages:
dev: true
optional: true
/cosmiconfig/8.0.0:
resolution: {integrity: sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==}
engines: {node: '>=14'}
dependencies:
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
path-type: 4.0.0
dev: true
/create-require/1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
dev: true
optional: true
/cz-conventional-changelog/3.2.0:
resolution: {integrity: sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==}
engines: {node: '>= 10'}
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
dependencies:
chalk: 2.4.2
commitizen: 4.2.4
conventional-commit-types: 3.0.0
lodash.map: 4.6.0
longest: 2.0.1
word-wrap: 1.2.3
optionalDependencies:
'@commitlint/load': 16.2.3
transitivePeerDependencies:
- '@swc/core'
- '@swc/wasm'
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: true
/cz-conventional-changelog/3.3.0:
......@@ -591,7 +868,7 @@ packages:
engines: {node: '>= 10'}
dependencies:
chalk: 2.4.2
commitizen: 4.2.4
commitizen: 4.2.6
conventional-commit-types: 3.0.0
lodash.map: 4.6.0
longest: 2.0.1
......@@ -603,6 +880,22 @@ packages:
- '@swc/wasm'
dev: true
/cz-customizable/7.0.0:
resolution: {integrity: sha512-pQKkGSm+8SY9VY/yeJqDOla1MjrGaG7WG4EYLLEV4VNctGO7WdzdGtWEr2ydKSkrpmTs7f8fmBksg/FaTrUAyw==}
hasBin: true
dependencies:
editor: 1.0.0
find-config: 1.0.0
inquirer: 6.5.2
lodash: 4.17.21
temp: 0.9.4
word-wrap: 1.2.3
dev: true
/cz-git/1.4.1:
resolution: {integrity: sha512-EOtuitcnfxde8t3NNTKh2YxEJhLXGiVlKSVaZipK3+DVo135rEUifAfqxkslM66Nf6ZO7a+3JR+XAOLhMXUAjQ==}
dev: true
/dargs/7.0.0:
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
engines: {node: '>=8'}
......@@ -613,7 +906,7 @@ packages:
dev: true
/decamelize-keys/1.1.0:
resolution: {integrity: sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=}
resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==}
engines: {node: '>=0.10.0'}
dependencies:
decamelize: 1.2.0
......@@ -621,21 +914,27 @@ packages:
dev: true
/decamelize/1.2.0:
resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=}
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
dev: true
/dedent/0.7.0:
resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=}
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
dev: true
/defaults/1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
dependencies:
clone: 1.0.4
dev: true
/detect-file/1.0.0:
resolution: {integrity: sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=}
resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==}
engines: {node: '>=0.10.0'}
dev: true
/detect-indent/6.0.0:
resolution: {integrity: sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==}
/detect-indent/6.1.0:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
dev: true
......@@ -643,7 +942,6 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
dev: true
optional: true
/dot-prop/5.3.0:
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
......@@ -652,6 +950,10 @@ packages:
is-obj: 2.0.0
dev: true
/editor/1.0.0:
resolution: {integrity: sha512-SoRmbGStwNYHgKfjOrX2L0mUvp9bUVv0uPppZSOMAntEbcFtoC3MKF5b3T6HQPXKIV+QGY3xPO3JK5it5lVkuw==}
dev: true
/emoji-regex/8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
......@@ -668,12 +970,27 @@ packages:
dev: true
/escape-string-regexp/1.0.5:
resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
dev: true
/execa/5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 2.1.0
is-stream: 2.0.1
merge-stream: 2.0.0
npm-run-path: 4.0.1
onetime: 5.1.2
signal-exit: 3.0.7
strip-final-newline: 2.0.0
dev: true
/expand-tilde/2.0.2:
resolution: {integrity: sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=}
resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==}
engines: {node: '>=0.10.0'}
dependencies:
homedir-polyfill: 1.0.3
......@@ -691,7 +1008,6 @@ packages:
/fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
optional: true
/fast-json-stable-stringify/2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
......@@ -699,12 +1015,19 @@ packages:
optional: true
/figures/2.0.0:
resolution: {integrity: sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=}
resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==}
engines: {node: '>=4'}
dependencies:
escape-string-regexp: 1.0.5
dev: true
/figures/3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
dependencies:
escape-string-regexp: 1.0.5
dev: true
/fill-range/7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
......@@ -712,6 +1035,13 @@ packages:
to-regex-range: 5.0.1
dev: true
/find-config/1.0.0:
resolution: {integrity: sha512-Z+suHH+7LSE40WfUeZPIxSxypCWvrzdVc60xAjUShZeT5eMWM0/FQUduq3HjluyfAHWvC/aOBkT1pTZktyF/jg==}
engines: {node: '>= 0.12'}
dependencies:
user-home: 2.0.0
dev: true
/find-node-modules/2.1.3:
resolution: {integrity: sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==}
dependencies:
......@@ -724,7 +1054,7 @@ packages:
dev: true
/find-up/2.1.0:
resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=}
resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}
engines: {node: '>=4'}
dependencies:
locate-path: 2.0.0
......@@ -738,6 +1068,14 @@ packages:
path-exists: 4.0.0
dev: true
/find-up/5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: true
/findup-sync/4.0.0:
resolution: {integrity: sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==}
engines: {node: '>= 8'}
......@@ -748,17 +1086,27 @@ packages:
resolve-dir: 1.0.1
dev: true
/fs-extra/8.1.0:
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
engines: {node: '>=6 <7 || >=8'}
/fs-extra/11.1.0:
resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==}
engines: {node: '>=14.14'}
dependencies:
graceful-fs: 4.2.10
jsonfile: 4.0.0
universalify: 0.1.2
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs-extra/9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
engines: {node: '>=10'}
dependencies:
at-least-node: 1.0.0
graceful-fs: 4.2.10
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs.realpath/1.0.0:
resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=}
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/function-bind/1.1.1:
......@@ -781,6 +1129,11 @@ packages:
yargs: 16.2.0
dev: true
/get-stream/6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
dev: true
/git-raw-commits/2.0.11:
resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==}
engines: {node: '>=10'}
......@@ -816,8 +1169,8 @@ packages:
ini: 1.3.8
dev: true
/glob/7.1.4:
resolution: {integrity: sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==}
/glob/7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
......@@ -828,12 +1181,11 @@ packages:
dev: true
/global-dirs/0.1.1:
resolution: {integrity: sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=}
resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==}
engines: {node: '>=4'}
dependencies:
ini: 1.3.8
dev: true
optional: true
/global-modules/1.0.0:
resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==}
......@@ -845,7 +1197,7 @@ packages:
dev: true
/global-prefix/1.0.2:
resolution: {integrity: sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=}
resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==}
engines: {node: '>=0.10.0'}
dependencies:
expand-tilde: 2.0.2
......@@ -878,7 +1230,7 @@ packages:
dev: true
/has-flag/3.0.0:
resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=}
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
dev: true
......@@ -886,7 +1238,6 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: true
optional: true
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
......@@ -913,6 +1264,11 @@ packages:
lru-cache: 6.0.0
dev: true
/human-signals/2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
dev: true
/iconv-lite/0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
......@@ -920,6 +1276,10 @@ packages:
safer-buffer: 2.1.2
dev: true
/ieee754/1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/import-fresh/3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
......@@ -927,7 +1287,6 @@ packages:
parent-module: 1.0.1
resolve-from: 4.0.0
dev: true
optional: true
/indent-string/4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
......@@ -935,7 +1294,7 @@ packages:
dev: true
/inflight/1.0.6:
resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=}
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
......@@ -968,8 +1327,29 @@ packages:
through: 2.3.8
dev: true
/inquirer/8.2.4:
resolution: {integrity: sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==}
engines: {node: '>=12.0.0'}
dependencies:
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-cursor: 3.1.0
cli-width: 3.0.0
external-editor: 3.1.0
figures: 3.2.0
lodash: 4.17.21
mute-stream: 0.0.8
ora: 5.4.1
run-async: 2.4.1
rxjs: 7.8.0
string-width: 4.2.3
strip-ansi: 6.0.1
through: 2.3.8
wrap-ansi: 7.0.0
dev: true
/is-arrayish/0.2.1:
resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=}
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: true
/is-core-module/2.9.0:
......@@ -979,12 +1359,12 @@ packages:
dev: true
/is-extglob/2.1.1:
resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=}
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-fullwidth-code-point/2.0.0:
resolution: {integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=}
resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==}
engines: {node: '>=4'}
dev: true
......@@ -1000,6 +1380,11 @@ packages:
is-extglob: 2.1.1
dev: true
/is-interactive/1.0.0:
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
engines: {node: '>=8'}
dev: true
/is-number/7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
......@@ -1011,19 +1396,29 @@ packages:
dev: true
/is-plain-obj/1.1.0:
resolution: {integrity: sha1-caUMhCnfync8kqOQpKA7OfzVHT4=}
resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
engines: {node: '>=0.10.0'}
dev: true
/is-stream/2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: true
/is-text-path/1.0.1:
resolution: {integrity: sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=}
resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==}
engines: {node: '>=0.10.0'}
dependencies:
text-extensions: 1.9.0
dev: true
/is-unicode-supported/0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
dev: true
/is-utf8/0.2.1:
resolution: {integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=}
resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==}
dev: true
/is-windows/1.0.2:
......@@ -1036,13 +1431,20 @@ packages:
dev: true
/isexe/2.0.0:
resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=}
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml/4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: true
/json-parse-better-errors/1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
dev: true
......@@ -1056,18 +1458,24 @@ packages:
dev: true
optional: true
/json-schema-traverse/1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
dev: true
/json-stringify-safe/5.0.1:
resolution: {integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=}
dev: true
/jsonfile/4.0.0:
resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=}
/jsonfile/6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
dependencies:
universalify: 2.0.0
optionalDependencies:
graceful-fs: 4.2.10
dev: true
/jsonparse/1.3.1:
resolution: {integrity: sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=}
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
engines: {'0': node >= 0.2.0}
dev: true
......@@ -1091,7 +1499,7 @@ packages:
dev: true
/locate-path/2.0.0:
resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=}
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
engines: {node: '>=4'}
dependencies:
p-locate: 2.0.0
......@@ -1105,18 +1513,73 @@ packages:
p-locate: 4.1.0
dev: true
/locate-path/6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: true
/lodash.camelcase/4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
dev: true
/lodash.isfunction/3.0.9:
resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
dev: true
/lodash.ismatch/4.4.0:
resolution: {integrity: sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=}
dev: true
/lodash.isplainobject/4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: true
/lodash.kebabcase/4.1.1:
resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
dev: true
/lodash.map/4.6.0:
resolution: {integrity: sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=}
dev: true
/lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
/lodash.mergewith/4.6.2:
resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==}
dev: true
/lodash.snakecase/4.1.1:
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
dev: true
/lodash.startcase/4.4.0:
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
dev: true
/lodash.uniq/4.5.0:
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
dev: true
/lodash.upperfirst/4.3.1:
resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==}
dev: true
/lodash/4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: true
/log-symbols/4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
dependencies:
chalk: 4.1.2
is-unicode-supported: 0.1.0
dev: true
/longest/2.0.1:
resolution: {integrity: sha1-eB4YMpaqlPbU2RbcM10NF676I/g=}
engines: {node: '>=0.10.0'}
......@@ -1132,10 +1595,9 @@ packages:
/make-error/1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
dev: true
optional: true
/map-obj/1.0.1:
resolution: {integrity: sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=}
resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
engines: {node: '>=0.10.0'}
dev: true
......@@ -1161,6 +1623,10 @@ packages:
yargs-parser: 20.2.9
dev: true
/merge-stream/2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: true
/merge/2.1.1:
resolution: {integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==}
dev: true
......@@ -1178,6 +1644,11 @@ packages:
engines: {node: '>=4'}
dev: true
/mimic-fn/2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: true
/min-indent/1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
......@@ -1198,21 +1669,28 @@ packages:
kind-of: 6.0.3
dev: true
/minimist/1.2.5:
resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==}
dev: true
/minimist/1.2.6:
resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
dev: true
/mkdirp/0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
dependencies:
minimist: 1.2.6
dev: true
/modify-values/1.0.1:
resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
engines: {node: '>=0.10.0'}
dev: true
/mute-stream/0.0.7:
resolution: {integrity: sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=}
resolution: {integrity: sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==}
dev: true
/mute-stream/0.0.8:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
dev: true
/neo-async/2.6.2:
......@@ -1234,25 +1712,59 @@ packages:
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.9.0
semver: 7.3.7
semver: 7.3.8
validate-npm-package-license: 3.0.4
dev: true
/npm-run-path/4.0.1:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
dependencies:
path-key: 3.1.1
dev: true
/once/1.4.0:
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/onetime/2.0.1:
resolution: {integrity: sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=}
resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==}
engines: {node: '>=4'}
dependencies:
mimic-fn: 1.2.0
dev: true
/onetime/5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: true
/ora/5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
dependencies:
bl: 4.1.0
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.7.0
is-interactive: 1.0.0
is-unicode-supported: 0.1.0
log-symbols: 4.1.0
strip-ansi: 6.0.1
wcwidth: 1.0.1
dev: true
/os-homedir/1.0.2:
resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==}
engines: {node: '>=0.10.0'}
dev: true
/os-tmpdir/1.0.2:
resolution: {integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=}
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
dev: true
......@@ -1270,8 +1782,15 @@ packages:
p-try: 2.2.0
dev: true
/p-limit/3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: true
/p-locate/2.0.0:
resolution: {integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=}
resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
engines: {node: '>=4'}
dependencies:
p-limit: 1.3.0
......@@ -1284,8 +1803,15 @@ packages:
p-limit: 2.3.0
dev: true
/p-locate/5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: true
/p-try/1.0.0:
resolution: {integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=}
resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}
engines: {node: '>=4'}
dev: true
......@@ -1300,10 +1826,9 @@ packages:
dependencies:
callsites: 3.1.0
dev: true
optional: true
/parse-json/4.0.0:
resolution: {integrity: sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=}
resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
engines: {node: '>=4'}
dependencies:
error-ex: 1.3.2
......@@ -1321,12 +1846,12 @@ packages:
dev: true
/parse-passwd/1.0.0:
resolution: {integrity: sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=}
resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==}
engines: {node: '>=0.10.0'}
dev: true
/path-exists/3.0.0:
resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=}
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
engines: {node: '>=4'}
dev: true
......@@ -1336,10 +1861,15 @@ packages:
dev: true
/path-is-absolute/1.0.1:
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: true
/path-key/3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: true
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
......@@ -1355,7 +1885,6 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
dev: true
optional: true
/picomatch/2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
......@@ -1380,10 +1909,9 @@ packages:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
dev: true
optional: true
/q/1.5.1:
resolution: {integrity: sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=}
resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==}
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
dev: true
......@@ -1393,7 +1921,7 @@ packages:
dev: true
/read-pkg-up/3.0.0:
resolution: {integrity: sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=}
resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==}
engines: {node: '>=4'}
dependencies:
find-up: 2.1.0
......@@ -1410,7 +1938,7 @@ packages:
dev: true
/read-pkg/3.0.0:
resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=}
resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==}
engines: {node: '>=4'}
dependencies:
load-json-file: 4.0.0
......@@ -1458,12 +1986,17 @@ packages:
dev: true
/require-directory/2.1.1:
resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=}
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
dev: true
/require-from-string/2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
dev: true
/resolve-dir/1.0.1:
resolution: {integrity: sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=}
resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==}
engines: {node: '>=0.10.0'}
dependencies:
expand-tilde: 2.0.2
......@@ -1474,13 +2007,11 @@ packages:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: true
optional: true
/resolve-from/5.0.0:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
dev: true
optional: true
/resolve-global/1.0.0:
resolution: {integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==}
......@@ -1488,7 +2019,6 @@ packages:
dependencies:
global-dirs: 0.1.1
dev: true
optional: true
/resolve/1.22.0:
resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
......@@ -1500,13 +2030,28 @@ packages:
dev: true
/restore-cursor/2.0.0:
resolution: {integrity: sha1-n37ih/gv0ybU/RYpI9YhKe7g368=}
resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==}
engines: {node: '>=4'}
dependencies:
onetime: 2.0.1
signal-exit: 3.0.7
dev: true
/restore-cursor/3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
dependencies:
onetime: 5.1.2
signal-exit: 3.0.7
dev: true
/rimraf/2.6.3:
resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
hasBin: true
dependencies:
glob: 7.2.3
dev: true
/run-async/2.4.1:
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
engines: {node: '>=0.12.0'}
......@@ -1519,6 +2064,12 @@ packages:
tslib: 1.14.1
dev: true
/rxjs/7.8.0:
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
dependencies:
tslib: 2.4.1
dev: true
/safe-buffer/5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
dev: true
......@@ -1541,14 +2092,26 @@ packages:
hasBin: true
dev: true
/semver/7.3.7:
resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
/semver/7.3.8:
resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
dev: true
/shebang-command/2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: true
/shebang-regex/3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: true
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
......@@ -1622,7 +2185,7 @@ packages:
dev: true
/strip-ansi/4.0.0:
resolution: {integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=}
resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==}
engines: {node: '>=4'}
dependencies:
ansi-regex: 3.0.1
......@@ -1643,7 +2206,7 @@ packages:
dev: true
/strip-bom/3.0.0:
resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=}
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
dev: true
......@@ -1652,6 +2215,11 @@ packages:
engines: {node: '>=8'}
dev: true
/strip-final-newline/2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
dev: true
/strip-indent/3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
......@@ -1659,8 +2227,8 @@ packages:
min-indent: 1.0.1
dev: true
/strip-json-comments/3.0.1:
resolution: {integrity: sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==}
/strip-json-comments/3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
dev: true
......@@ -1677,7 +2245,6 @@ packages:
dependencies:
has-flag: 4.0.0
dev: true
optional: true
/supports-preserve-symlinks-flag/1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
......@@ -1689,6 +2256,14 @@ packages:
engines: {node: '>=8'}
dev: true
/temp/0.9.4:
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
engines: {node: '>=6.0.0'}
dependencies:
mkdirp: 0.5.6
rimraf: 2.6.3
dev: true
/tempfile/3.0.0:
resolution: {integrity: sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw==}
engines: {node: '>=8'}
......@@ -1703,7 +2278,7 @@ packages:
dev: true
/through/2.3.8:
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
/through2/2.0.5:
......@@ -1738,8 +2313,8 @@ packages:
engines: {node: '>=8'}
dev: true
/ts-node/10.7.0_5281fe59fc32158e106b8b5e2bebb315:
resolution: {integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==}
/ts-node/10.9.1_kka74wp4giky4edlrnpcx25tcu:
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
......@@ -1752,7 +2327,7 @@ packages:
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': 0.7.0
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.8
'@tsconfig/node12': 1.0.9
'@tsconfig/node14': 1.0.1
......@@ -1770,15 +2345,55 @@ packages:
dev: true
optional: true
/ts-node/10.9.1_u3h3q7xqdg7nitfvwf64wuo7zy:
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
'@types/node': '*'
typescript: '>=2.7'
peerDependenciesMeta:
'@swc/core':
optional: true
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.8
'@tsconfig/node12': 1.0.9
'@tsconfig/node14': 1.0.1
'@tsconfig/node16': 1.0.2
'@types/node': 17.0.29
acorn: 8.7.1
acorn-walk: 8.2.0
arg: 4.1.3
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 4.9.4
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
dev: true
/tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib/2.4.1:
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
dev: true
/type-fest/0.18.1:
resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
engines: {node: '>=10'}
dev: true
/type-fest/0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
dev: true
/type-fest/0.6.0:
resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
engines: {node: '>=8'}
......@@ -1796,6 +2411,12 @@ packages:
dev: true
optional: true
/typescript/4.9.4:
resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
/uglify-js/3.15.4:
resolution: {integrity: sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==}
engines: {node: '>=0.8.0'}
......@@ -1804,9 +2425,9 @@ packages:
dev: true
optional: true
/universalify/0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}
dev: true
/uri-js/4.4.1:
......@@ -1814,10 +2435,16 @@ packages:
dependencies:
punycode: 2.1.1
dev: true
optional: true
/user-home/2.0.0:
resolution: {integrity: sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==}
engines: {node: '>=0.10.0'}
dependencies:
os-homedir: 1.0.2
dev: true
/util-deprecate/1.0.2:
resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/uuid/3.4.0:
......@@ -1829,7 +2456,6 @@ packages:
/v8-compile-cache-lib/3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
dev: true
optional: true
/validate-npm-package-license/3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
......@@ -1838,6 +2464,12 @@ packages:
spdx-expression-parse: 3.0.1
dev: true
/wcwidth/1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
defaults: 1.0.4
dev: true
/which/1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
......@@ -1845,6 +2477,14 @@ packages:
isexe: 2.0.0
dev: true
/which/2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: true
/word-wrap/1.2.3:
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
engines: {node: '>=0.10.0'}
......@@ -1864,7 +2504,7 @@ packages:
dev: true
/wrappy/1.0.2:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/xtend/4.0.2:
......@@ -1892,6 +2532,11 @@ packages:
engines: {node: '>=10'}
dev: true
/yargs-parser/21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
dev: true
/yargs/16.2.0:
resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
engines: {node: '>=10'}
......@@ -1905,8 +2550,25 @@ packages:
yargs-parser: 20.2.9
dev: true
/yargs/17.6.2:
resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.1.1
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
dev: true
/yn/3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}
dev: true
optional: true
/yocto-queue/0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论