first commit
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
5
json-class-interface/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
package-lock.json
|
||||
笔记.txt
|
||||
example.ts
|
||||
src/
|
||||
1
json-class-interface/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
f259e807-500b-424f-88db-2342f1ebdc6d
|
||||
1
json-class-interface/.workflow/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
d50b1a8c-81e3-4365-928b-1e5b39528942
|
||||
51
json-class-interface/.workflow/branch-pipeline.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
version: '1.0'
|
||||
name: branch-pipeline
|
||||
displayName: BranchPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@nodejs
|
||||
name: build_nodejs
|
||||
displayName: Nodejs 构建
|
||||
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
|
||||
nodeVersion: 14.16.0
|
||||
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
|
||||
commands:
|
||||
- npm install && rm -rf ./dist && npm run build
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
|
||||
path:
|
||||
- ./dist
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_nodejs
|
||||
- stage:
|
||||
name: release
|
||||
displayName: 发布
|
||||
steps:
|
||||
- step: publish@release_artifacts
|
||||
name: publish_release_artifacts
|
||||
displayName: '发布'
|
||||
# 上游上传制品任务的产出
|
||||
dependArtifact: output
|
||||
# 发布制品版本号
|
||||
version: '1.0.0.0'
|
||||
# 是否开启版本号自增,默认开启
|
||||
autoIncrement: true
|
||||
triggers:
|
||||
push:
|
||||
branches:
|
||||
exclude:
|
||||
- master
|
||||
include:
|
||||
- .*
|
||||
49
json-class-interface/.workflow/master-pipeline.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
version: '1.0'
|
||||
name: master-pipeline
|
||||
displayName: MasterPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@nodejs
|
||||
name: build_nodejs
|
||||
displayName: Nodejs 构建
|
||||
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
|
||||
nodeVersion: 14.16.0
|
||||
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
|
||||
commands:
|
||||
- npm install && rm -rf ./dist && npm run build
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
|
||||
path:
|
||||
- ./dist
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_nodejs
|
||||
- stage:
|
||||
name: release
|
||||
displayName: 发布
|
||||
steps:
|
||||
- step: publish@release_artifacts
|
||||
name: publish_release_artifacts
|
||||
displayName: '发布'
|
||||
# 上游上传制品任务的产出
|
||||
dependArtifact: output
|
||||
# 发布制品版本号
|
||||
version: '1.0.0.0'
|
||||
# 是否开启版本号自增,默认开启
|
||||
autoIncrement: true
|
||||
triggers:
|
||||
push:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
36
json-class-interface/.workflow/pr-pipeline.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
version: '1.0'
|
||||
name: pr-pipeline
|
||||
displayName: PRPipeline
|
||||
stages:
|
||||
- stage:
|
||||
name: compile
|
||||
displayName: 编译
|
||||
steps:
|
||||
- step: build@nodejs
|
||||
name: build_nodejs
|
||||
displayName: Nodejs 构建
|
||||
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
|
||||
nodeVersion: 14.16.0
|
||||
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
|
||||
commands:
|
||||
- npm install && rm -rf ./dist && npm run build
|
||||
# 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除
|
||||
artifacts:
|
||||
# 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
|
||||
- name: BUILD_ARTIFACT
|
||||
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
|
||||
path:
|
||||
- ./dist
|
||||
- step: publish@general_artifacts
|
||||
name: publish_general_artifacts
|
||||
displayName: 上传制品
|
||||
# 上游构建任务定义的产物名,默认BUILD_ARTIFACT
|
||||
dependArtifact: BUILD_ARTIFACT
|
||||
# 上传到制品库时的制品命名,默认output
|
||||
artifactName: output
|
||||
dependsOn: build_nodejs
|
||||
triggers:
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
200
json-class-interface/README.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# JsonToClassOrInterface
|
||||
|
||||
## 状态
|
||||
|
||||
持续开发中...
|
||||
|
||||
- 【完成】~~1: 将开发桌面端软件 和 web网页 进而 方便作为 独立的 工具来使用。~~
|
||||
- 【完成】~~2: 增加功能,将生成的 Interface 和 class 自动生成 xxx.ts 文件,并保存到你给的项目路径中,方便开发者将本插件和项目请求进行深度集成~~
|
||||
|
||||
**基于本插件,自己开发的支持MAC,Linux,Windows 的桌面端项目地址:**
|
||||
> [https://gitee.com/bmycode/json-class-desktop](https://gitee.com/bmycode/json-class-desktop)
|
||||
|
||||
## 前言
|
||||
顾名思义,这是一个把前端接口的`json`数据转化为 `typescript` 的`Interface`或`Class`的插件。
|
||||
|
||||
当你在用`typescript`开发项目,你是否烦恼过后端接口给我们一坨`json`数据的时候,我们需要为数据 **手动编写大量** 的`Interface`或`Class`,来为请求中间层的方法标注返回类型,然后才能在页面中使用并获得优雅的类型提示
|
||||
|
||||
**手动写...很麻烦的,为何不 根据 json 数据自动生成???!!!**
|
||||
|
||||
受到 [flutter](https://flutter.dev/) 的 [json to dart](https://javiercbk.github.io/json_to_dart/) 启发,进而开发本插件。
|
||||
|
||||
|
||||
## 注意
|
||||
|
||||
**本插件只能将json自动生成为 `Interface` 或 `Class`,避免我们手动编写的繁杂过程,但并不能实现类似 flutter json_serializable 将 json数据和类进行映射(序列化)的功能!!**
|
||||
|
||||
|
||||
如果你想实现全套 json_serializable 的功能,可以在调用 `toClass` 方法的时候将参数 `needProperty` 开启并设置为`true`(参数说明看下面)。
|
||||
|
||||
这时候将生成 `json-mapper-class` 插件所需要的 **序列化代码**
|
||||
|
||||
---
|
||||
|
||||
至于为什么需要 `json-mapper-class` 这个插件,相信开发过`flutter`的你应该很清楚,不清楚去看官网说的说明:
|
||||
|
||||
> [https://docs.flutter.dev/data-and-backend/serialization/json](https://docs.flutter.dev/data-and-backend/serialization/json)
|
||||
|
||||
---
|
||||
|
||||
如果你需要使用`json和类映射`,那么要在项目里下载引入本插件才能使用,插件地址:
|
||||
|
||||
> [json-mapper-class](https://www.npmjs.com/package/json-mapper-class)
|
||||
|
||||
---
|
||||
|
||||
可能你会疑惑甚至一脸懵逼,我知道你很急,但是你先别着急,看说明你思考下就明白了:
|
||||
|
||||
插件有两个:
|
||||
- json-class-interface
|
||||
- json-mapper-class
|
||||
|
||||
它们之间的使用关系举例说明如下:
|
||||
|
||||
- 假设 http://www.xxx.com/newsInfo 接口返回了 **新闻详情数据**
|
||||
- 这时我们 使用插件 `json-class-interface` 将接口返回数据转为 类(needProperty参数需要开启),然后将 插件返回的代码复制保存到 xxx.ts 中。
|
||||
- 最后 使用插件 `json-mapper-class` 将上一步的类和接口json传入,本插件会自动序列化json存储到类中,**请求中间层方法返回数据类型和页面上直接 使用 类 即可**
|
||||
|
||||
**当然你也可以把这两个插件和你的项目进行深度的集成,让它们更加`自动化`,`无感`,`便捷`,`高效`。**
|
||||
|
||||
## 安装
|
||||
|
||||
> npm i --save json-class-interface
|
||||
|
||||
## 使用案例
|
||||
|
||||
```typescript
|
||||
import { toClass, toInterface } from "json-class-interface";
|
||||
|
||||
// Json 数据
|
||||
let json1 = {
|
||||
status: 200,
|
||||
message: "请求成功",
|
||||
result_list: [
|
||||
{
|
||||
id: 1,
|
||||
name: "新闻1",
|
||||
tags_arr: [
|
||||
{
|
||||
tags_id: 1,
|
||||
tags_title: '标签标题1'
|
||||
},
|
||||
{
|
||||
tags_id: 1,
|
||||
tags_title: '标签标题1'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "新闻2",
|
||||
tags_arr: [
|
||||
{
|
||||
tags_id: 1,
|
||||
tags_title: '标签标题2'
|
||||
},
|
||||
{
|
||||
tags_id: 1,
|
||||
tags_title: '标签标题2'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// 1 转换为 Class
|
||||
|
||||
// JsonToClass: 第一层类的名称,随便自定义
|
||||
let type: string = toClass("JsonToClass", json1)
|
||||
console.log(type);
|
||||
|
||||
// json转换为class的结果输出:
|
||||
// export class TagsArr {
|
||||
// tags_id!: number;
|
||||
// tags_title!: string;
|
||||
// }
|
||||
|
||||
// export class ResultList {
|
||||
// id!: number;
|
||||
// name!: string;
|
||||
// tags_arr!: TagsArr[];
|
||||
// }
|
||||
|
||||
// export class JsonToClass {
|
||||
// status!: number;
|
||||
// message!: string;
|
||||
// result_list!: ResultList[];
|
||||
// }
|
||||
|
||||
|
||||
// 2 转化为 Interface
|
||||
|
||||
let Interface: string = toInterface("JsonToInterface", json1)
|
||||
console.log(Interface);
|
||||
|
||||
// json转换为Interface的结果输出:
|
||||
// export interface TagsArr {
|
||||
// tags_id: number;
|
||||
// tags_title: string;
|
||||
// }
|
||||
|
||||
// export interface ResultList {
|
||||
// id: number;
|
||||
// name: string;
|
||||
// tags_arr: TagsArr[];
|
||||
// }
|
||||
|
||||
// export interface JsonToInterface {
|
||||
// status: number;
|
||||
// message: string;
|
||||
// result_list: ResultList[];
|
||||
// }
|
||||
```
|
||||
|
||||
# 方法
|
||||
|
||||
|
||||
将 `json` 数据转化为 `class`
|
||||
|
||||
## toClass(className: string = "JsonToClass", rawJson: JosnType | string, options: ToClassOptions = {}): string
|
||||
|
||||
---
|
||||
|
||||
将 `json` 数据转化为 `interface`,本方法的效果 和 `toClass` 参数 `interfaceModel: true` 效果一样。为了方便使用,故提供`toInterface`方法
|
||||
|
||||
## toInterface(className: string = "JsonToInterface", rawJson: JosnType | string, options: ToClassOptions = {}): string
|
||||
|
||||
---
|
||||
|
||||
方法参数说明:
|
||||
|
||||
| 名称 | 类型 | 默认值 |
|
||||
| :-----:| :----: | :----: |
|
||||
| className | string | JsonToClass 或 JsonToInterface |
|
||||
| rawJson | JosnType 或 string | 不为空 |
|
||||
| options | ToClassOptions | {} |
|
||||
|
||||
|
||||
**JosnType 类型如下:**
|
||||
```
|
||||
export type JosnType = { [key: string]: any };
|
||||
```
|
||||
|
||||
**ToClassOptions 类型如下:**
|
||||
```
|
||||
export interface ToClassOptions {
|
||||
nullAlias?: string;
|
||||
needProperty?: boolean;
|
||||
needPropertyValue?: boolean;
|
||||
interfaceModel?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| :----:| :----:|:----:|:----:|
|
||||
| nullAlias | string | "string" | 如果对象值为null,转化为 class 或 interface 时候,给这个对象key个默认类型 |
|
||||
| needProperty | boolean | false | 是否需要生成Property装饰器,用到插件 json-mapper-class 才需要开启 |
|
||||
| needPropertyValue | boolean| false | 是否需要生成Property装饰器的默认值,用到插件 json-mapper-class 才需要开启|
|
||||
| interfaceModel | boolean| false | 是否需要生成 interface 模式 |
|
||||
|
||||
|
||||
1
json-class-interface/dist/.pydio
vendored
Normal file
@@ -0,0 +1 @@
|
||||
9b3befbc-a965-48c7-ae4b-8602394b74c8
|
||||
2
json-class-interface/dist/file.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { PathLike } from "fs";
|
||||
export declare const configFilePath: (path: PathLike) => void;
|
||||
11
json-class-interface/dist/file.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.configFilePath = void 0;
|
||||
const fs_1 = require("fs");
|
||||
const store_1 = require("./store");
|
||||
const configFilePath = (path) => {
|
||||
store_1.config.saveTypeFilePath = path;
|
||||
console.log("config.saveTypeFilePath: ", store_1.config.saveTypeFilePath);
|
||||
(0, fs_1.writeFileSync)(store_1.config.saveTypeFilePath, "testetststststststst");
|
||||
};
|
||||
exports.configFilePath = configFilePath;
|
||||
3
json-class-interface/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './toClass';
|
||||
export * from './toInterface';
|
||||
export * from './file';
|
||||
15
json-class-interface/dist/index.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./toClass"), exports);
|
||||
__exportStar(require("./toInterface"), exports);
|
||||
__exportStar(require("./file"), exports);
|
||||
2
json-class-interface/dist/store.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { Config } from "./typing";
|
||||
export declare const config: Config;
|
||||
6
json-class-interface/dist/store.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.config = void 0;
|
||||
exports.config = {
|
||||
saveTypeFilePath: ""
|
||||
};
|
||||
2
json-class-interface/dist/toClass.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { JosnType, ToClassOptions } from "./typing";
|
||||
export declare const toClass: (className: string, rawJson: JosnType | string, options?: ToClassOptions, repeat?: boolean) => string;
|
||||
38
json-class-interface/dist/toClass.js
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toClass = void 0;
|
||||
const utils_1 = require("./utils");
|
||||
let TextResult = "";
|
||||
const toClass = (className = "JsonToClass", rawJson, options = {}, repeat = false) => {
|
||||
typeof (rawJson) === "string" ? rawJson = JSON.parse(rawJson) : null;
|
||||
(0, utils_1.isArray)(rawJson) ? rawJson = rawJson[0] : null;
|
||||
if (!repeat) {
|
||||
TextResult = "";
|
||||
}
|
||||
let classText = (0, utils_1.stripIndent) `
|
||||
${(0, utils_1.setInterfaceModel)(options)} ${className} {
|
||||
${Object.keys(rawJson).map(key => {
|
||||
let ArrayInsideNotObject = false;
|
||||
if ((0, utils_1.isObjectOrArray)(rawJson[key])) {
|
||||
if ((0, utils_1.isArray)(rawJson[key]) && (0, utils_1.isObject)(rawJson[key][0])) {
|
||||
(0, exports.toClass)((0, utils_1.firstLetterCap)(key), rawJson[key], options, true);
|
||||
}
|
||||
if ((0, utils_1.isObject)(rawJson[key])) {
|
||||
ArrayInsideNotObject = false;
|
||||
(0, exports.toClass)((0, utils_1.firstLetterCap)(key), rawJson[key], options, true);
|
||||
}
|
||||
}
|
||||
return `${(0, utils_1.setDefaultNeedPropertyValue)(options, key) == null ? '' : (0, utils_1.setDefaultNeedPropertyValue)(options, key)}
|
||||
${(0, utils_1.setKeyNotNull)(options, key)}: ${ArrayInsideNotObject
|
||||
? `${typeof rawJson[key][0]}[]`
|
||||
: (0, utils_1.isObjectOrArray)(rawJson[key])
|
||||
? `${(0, utils_1.firstLetterCap)(key)}${(0, utils_1.isArray)(rawJson[key]) ? '[]' : ''}`
|
||||
: (0, utils_1.isNull)(rawJson[key]) ? (0, utils_1.setDefaultNull)(options) : typeof rawJson[key]};
|
||||
`;
|
||||
})}
|
||||
}
|
||||
`;
|
||||
TextResult += `${classText} \n\n`;
|
||||
return TextResult;
|
||||
};
|
||||
exports.toClass = toClass;
|
||||
2
json-class-interface/dist/toInterface.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { JosnType, ToClassOptions } from "./typing";
|
||||
export declare const toInterface: (className: string, rawJson: JosnType | string, options?: ToClassOptions) => string;
|
||||
9
json-class-interface/dist/toInterface.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toInterface = void 0;
|
||||
const toClass_1 = require("./toClass");
|
||||
const toInterface = (className = "JsonToInterface", rawJson, options = {}) => {
|
||||
options.interfaceModel = true;
|
||||
return (0, toClass_1.toClass)(className, rawJson, options);
|
||||
};
|
||||
exports.toInterface = toInterface;
|
||||
14
json-class-interface/dist/typing.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <reference types="node" />
|
||||
import { PathLike } from "fs";
|
||||
export declare type JosnType = {
|
||||
[key: string]: any;
|
||||
};
|
||||
export declare type Config = {
|
||||
saveTypeFilePath: PathLike;
|
||||
};
|
||||
export interface ToClassOptions {
|
||||
nullAlias?: string;
|
||||
needProperty?: boolean;
|
||||
needPropertyValue?: boolean;
|
||||
interfaceModel?: boolean;
|
||||
}
|
||||
2
json-class-interface/dist/typing.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
13
json-class-interface/dist/utils.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ToClassOptions } from "./typing";
|
||||
export declare const isNull: (val: any) => boolean;
|
||||
export declare const isUndefined: (val: any) => boolean;
|
||||
export declare const isNullOrUndefined: (val: any) => boolean;
|
||||
export declare const isArray: (val: any) => boolean;
|
||||
export declare const isObject: (val: any) => boolean;
|
||||
export declare const isObjectOrArray: (val: any) => boolean;
|
||||
export declare const firstLetterCap: (val: string) => string;
|
||||
export declare const setDefaultNull: (options: ToClassOptions) => string;
|
||||
export declare const setDefaultNeedPropertyValue: (options: ToClassOptions, key: string) => string;
|
||||
export declare const setInterfaceModel: (options: ToClassOptions) => "export interface" | "export class";
|
||||
export declare const setKeyNotNull: (options: ToClassOptions, key: string) => string;
|
||||
export declare const stripIndent: (template: TemplateStringsArray, ...expressions: any[]) => string;
|
||||
56
json-class-interface/dist/utils.js
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.stripIndent = exports.setKeyNotNull = exports.setInterfaceModel = exports.setDefaultNeedPropertyValue = exports.setDefaultNull = exports.firstLetterCap = exports.isObjectOrArray = exports.isObject = exports.isArray = exports.isNullOrUndefined = exports.isUndefined = exports.isNull = void 0;
|
||||
const isNull = (val) => val === null;
|
||||
exports.isNull = isNull;
|
||||
const isUndefined = (val) => val === undefined;
|
||||
exports.isUndefined = isUndefined;
|
||||
const isNullOrUndefined = (val) => (0, exports.isNull)(val) || (0, exports.isUndefined)(val);
|
||||
exports.isNullOrUndefined = isNullOrUndefined;
|
||||
const isArray = (val) => Array.isArray(val);
|
||||
exports.isArray = isArray;
|
||||
const isObject = (val) => (0, exports.isNull)(val) ? false : val.constructor === Object;
|
||||
exports.isObject = isObject;
|
||||
const isObjectOrArray = (val) => (0, exports.isObject)(val) || (0, exports.isArray)(val);
|
||||
exports.isObjectOrArray = isObjectOrArray;
|
||||
const firstLetterCap = (val) => {
|
||||
let splitArr = val.split("_");
|
||||
return splitArr.map(v => v.charAt(0).toUpperCase() + v.slice(1)).join("");
|
||||
};
|
||||
exports.firstLetterCap = firstLetterCap;
|
||||
const setDefaultNull = (options) => options?.nullAlias ? options?.nullAlias : "string";
|
||||
exports.setDefaultNull = setDefaultNull;
|
||||
const setDefaultNeedPropertyValue = (options, key) => {
|
||||
options.needProperty = options.needProperty || false;
|
||||
return options?.needProperty
|
||||
? options?.interfaceModel
|
||||
? null
|
||||
: options?.needPropertyValue
|
||||
? `\t\n@property("${key}")`
|
||||
: `@property()`
|
||||
: null;
|
||||
};
|
||||
exports.setDefaultNeedPropertyValue = setDefaultNeedPropertyValue;
|
||||
const setInterfaceModel = (options) => options?.interfaceModel ? 'export interface' : `export class`;
|
||||
exports.setInterfaceModel = setInterfaceModel;
|
||||
const setKeyNotNull = (options, key) => `${key}${options?.interfaceModel ? '' : '!'}`;
|
||||
exports.setKeyNotNull = setKeyNotNull;
|
||||
const stripIndent = (template, ...expressions) => {
|
||||
let result = template.reduce((prev, next, i) => {
|
||||
let expression = expressions[i - 1];
|
||||
if ((0, exports.isArray)(expression)) {
|
||||
expression = expression.join('');
|
||||
}
|
||||
return prev + expression + next;
|
||||
});
|
||||
const match = result.match(/^[^\S\n]*(?=\S)/gm);
|
||||
const indent = match && Math.min(...match.map(el => el.length));
|
||||
if (indent) {
|
||||
const regexp = new RegExp(`^.{${indent}}`, 'gm');
|
||||
result = result.replace(regexp, '');
|
||||
}
|
||||
result = result.replace(/^[^\S\n]+/gm, ' ');
|
||||
result = result.trim();
|
||||
return result;
|
||||
};
|
||||
exports.stripIndent = stripIndent;
|
||||
21
json-class-interface/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "json-class-interface",
|
||||
"version": "1.1.7",
|
||||
"description": "将json数据自动转换为class或interface",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"dev": "clear && ts-node example.ts",
|
||||
"build": "tsc -w",
|
||||
"publish": "npm publish",
|
||||
"git": "git add -A && git commit -m '提交' && git pull && git push ",
|
||||
"push": "npm run git && npm run publish "
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.7.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
24
json-class-interface/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"lib": [ "es6", "DOM" ]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
3
json-mapper-class/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
test.ts
|
||||
src/
|
||||
1
json-mapper-class/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
8df5a678-3cf4-4606-9f91-a723a276c56c
|
||||
489
json-mapper-class/README.md
Normal file
@@ -0,0 +1,489 @@
|
||||
# json-mapper-class
|
||||
|
||||
`json-mapper-class` 是类似flutter Json序列化的 **web前端 优雅 解决方案**,用来将接口 json 数据映射到 class 的工具,之后在我们的`TypeScript`项目中,可以通过 **类来为接口返回数据标注类型**,通过修改类属性达到不需要后端修改接口数据字段的情况下,前端来任意定义接口返回字段的效果,解决了实际项目中接口数据与页面深度耦合的过程,并提供其逆过程。
|
||||
|
||||
`json-mapper-class` 是一个独立的插件,可以与任何的 `TypeScript` 项目进行深度的集成(最好是class语法),同时提供了众多的装饰器,让你更加**优雅**的去编写 `TypeScript`,请仔细阅读文档。
|
||||
|
||||
同时为了方便 `json-mapper-class` 的方法 `toClass` 第二个参数的生成,也是为了避免手动编写`json-mapper-class` **标准类 模版代码** 的过程,本人开发第二个插件简化了过程,插件地址(请自信阅读文档):
|
||||
|
||||
> [json-class-interface](https://www.npmjs.com/package/json-class-interface)
|
||||
|
||||
|
||||
下面是一个案例:
|
||||
|
||||
```ts
|
||||
import { property, toClass } from 'json-mapper-class';
|
||||
|
||||
class UserModel {
|
||||
@property('i')
|
||||
id: number;
|
||||
|
||||
@property()
|
||||
name: string;
|
||||
}
|
||||
|
||||
const userRaw = {
|
||||
i: 1234,
|
||||
name: 'name',
|
||||
};
|
||||
|
||||
// 使用 toClass 将 json 转换成 class
|
||||
const userModel = toClass(userRaw, UserModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
id: 1234,
|
||||
name: 'name',
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 如何安装
|
||||
|
||||
```bash
|
||||
npm i json-mapper-class --save
|
||||
```
|
||||
|
||||
# 使用例子
|
||||
|
||||
## 聚合对象或数组
|
||||
|
||||
如果你想转换一个聚合对象,需要提供目标类。如果该对象的某个属性值是数组,则会递归该数组的所有元素(不管层级有多深),自动转换为目标类的实例。
|
||||
|
||||
列子:
|
||||
|
||||
```ts
|
||||
class NestedModel {
|
||||
@property('e', UserModel)
|
||||
employees: UserModel[];
|
||||
|
||||
@typed(UserModel)
|
||||
@property('u')
|
||||
user: UserModel;
|
||||
}
|
||||
|
||||
const model = toClass(
|
||||
{
|
||||
e: [
|
||||
{ i: 1, n: 'n1' },
|
||||
{ i: 2, n: 'n2' },
|
||||
],
|
||||
u: {
|
||||
i: 1,
|
||||
n: 'name',
|
||||
}
|
||||
},
|
||||
NestedModel,
|
||||
);
|
||||
// you will get like this
|
||||
{
|
||||
employees: [
|
||||
{ id: 1, name: 'n1' },
|
||||
{ id: 2, name: 'n2' },
|
||||
],
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'name'
|
||||
}
|
||||
}
|
||||
|
||||
const model = toPlain(
|
||||
{
|
||||
employees: [
|
||||
{ id: 1, name: 'n1' },
|
||||
{ id: 2, name: 'n2' },
|
||||
],
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'name'
|
||||
}
|
||||
},
|
||||
NestedModel,
|
||||
);
|
||||
// you will get like this
|
||||
{
|
||||
e: [
|
||||
{ i: 1, n: 'n1' },
|
||||
{ i: 2, n: 'n2' },
|
||||
],
|
||||
u: {
|
||||
i: 1,
|
||||
n: 'name'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 其他数据类型转换
|
||||
|
||||
```ts
|
||||
import * as moment from 'moment';
|
||||
|
||||
export class EduModel {
|
||||
@property('i')
|
||||
id: number;
|
||||
|
||||
@property('crt')
|
||||
@deserialize(value => moment(value).format('YYYY-MM-DD HH:mm:ss'))
|
||||
createTime: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖于其他属性值
|
||||
|
||||
```ts
|
||||
class EmailModel {
|
||||
@property('s')
|
||||
site: string;
|
||||
|
||||
@property('e')
|
||||
@deserialize((value, _instance, origin) => `${value}@${origin.s}`)
|
||||
email: string;
|
||||
}
|
||||
```
|
||||
|
||||
# 方法
|
||||
|
||||
## toClass(raw, clazzType, options?) / toClasses(raws, clazzType, options?)
|
||||
|
||||
将一个 json 对象映射成一个类实例
|
||||
|
||||
- `raw` / `raws` `<Object|Array<Object>>` 一个 josn 对象或者 json 对象数据
|
||||
- `clazzType` `<Class>` 类的构造函数
|
||||
- `options?` `<Object>` 配置
|
||||
- `ignoreDeserializer` `<Boolean>` 当设置为 true 时,不会调用使用 @deserialize 装饰器配置的方法
|
||||
- `ignoreBeforeDeserializer` `<Boolean>` 当设置为 true 时,不会调用使用 @beforeDeserialize 装饰器配置的方法
|
||||
- `distinguishNullAndUndefined` `<Boolean>` 当设置为 true 时,区分 null 和 undefined
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
const userRaw = {
|
||||
i: 1234,
|
||||
name: 'name',
|
||||
};
|
||||
const userRaws = [
|
||||
{
|
||||
i: 1000,
|
||||
name: 'name1',
|
||||
},
|
||||
{
|
||||
i: 2000,
|
||||
name: 'name2',
|
||||
},
|
||||
];
|
||||
const userModel = toClass(userRaw, UserModel);
|
||||
const userModels = toClasses(userRaws, UserModel);
|
||||
```
|
||||
|
||||
## toPlain(instance, clazzType, options?) / toPlains(instances, clazzType, options?)
|
||||
|
||||
将一个类实例或者 json 对象映射成另外一个 json 对象
|
||||
|
||||
- `instance` / `instances` `<Object|Array<Object>>` 一个 json 或类实例,或者一个json或类实例组成的数组
|
||||
- `clazzType` `<Class>` Constructor of the target class
|
||||
- `options?` `<Object>` 类的构造函数
|
||||
- `ignoreSerializer` `<Boolean>` 当设置为 true 时,不会调用使用 @serialize 装饰器配置的方法
|
||||
- `ignoreAfterSerializer` `<Boolean>` 当设置为 true 时,不会调用使用 @afterSerialize 装饰器配置的方法
|
||||
- `distinguishNullAndUndefined` `<Boolean>` 当设置为 true 时,区分 null 和 undefined
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
const userModel = {
|
||||
id: 1234,
|
||||
name: 'name',
|
||||
};
|
||||
const userModels = [
|
||||
{
|
||||
id: 1000,
|
||||
name: 'name1',
|
||||
},
|
||||
{
|
||||
id: 2000,
|
||||
name: 'name2',
|
||||
},
|
||||
];
|
||||
const userRaw = toPlain(userModel, UserModel);
|
||||
const userRaws = toPlains(userModels, UserModel);
|
||||
```
|
||||
|
||||
# 属性装饰器
|
||||
|
||||
调用不同的方法时,这些装饰器的执行顺序:
|
||||
|
||||
- `toClass/toClasses`: beforeDeserializer => typed(映射成一个类实例) => deserializer
|
||||
- `toPlain/toPlains`: serializer => typed(映射成一个对象) => afterSerializer
|
||||
|
||||
## property(originalKey?, clazzType?, optional = false)
|
||||
|
||||
将一个 key 映射到另外一个 key,如 `n => name`
|
||||
|
||||
- `originalKey` `<string>` 被映射的数据 key, 如果不传则默认同名
|
||||
- `clazzType` `<Class>` 自动将该属性的值映射到一个类实例,相当于调用了 `toClass` 方法
|
||||
- `optional` `<Boolean>` 是否可选
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class PropertyModel {
|
||||
@property('i')
|
||||
id: number;
|
||||
|
||||
@property()
|
||||
name: string;
|
||||
|
||||
@property('u', UserModel)
|
||||
user: UserModel;
|
||||
|
||||
@property('t', null, true)
|
||||
timeStamp: number;
|
||||
}
|
||||
|
||||
const model = toClass({ i: 234, name: 'property', u: { i: 123, n: 'name' } }, PropertyModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
id: 234,
|
||||
name: 'property',
|
||||
user: {
|
||||
id: 123,
|
||||
name: 'name'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## typed(clazzType)
|
||||
|
||||
设置一个目标类的构造器,相当于 property 装饰器的第二个参数
|
||||
|
||||
- `clazzType` `<Class>` 自动将该属性的值映射到一个类实例,相当于调用了 `toClass` 方法
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
// 与此设置一致 @property('n', UserModel)
|
||||
class TypedModel {
|
||||
@typed(UserModel)
|
||||
@property('u')
|
||||
user: UserModel;
|
||||
}
|
||||
|
||||
const model = toClass({ u: { i: 123, n: 'name' } }, TypedModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
user: {
|
||||
id: 123,
|
||||
name: 'name'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## optional()
|
||||
|
||||
设置一个属性为可选,相当于 property 装饰器的第三个参数
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
// 与此设置一致 @property('n', null, true)
|
||||
class OptionalModel {
|
||||
@optional()
|
||||
@property('n')
|
||||
name: string;
|
||||
}
|
||||
|
||||
const model = toClass({}, OptionalModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
}
|
||||
|
||||
const model = toClass({ n: 'name' }, OptionalModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
name: 'name';
|
||||
}
|
||||
```
|
||||
|
||||
## defaultVal(val)
|
||||
|
||||
给当前属性设置默认值
|
||||
|
||||
- `val` `<Any>` 要设置的默认值
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class DefaultValModel {
|
||||
@defaultVal(0)
|
||||
@property('i')
|
||||
id: number;
|
||||
}
|
||||
|
||||
const model = toClass({}, DefaultValModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
id: 0;
|
||||
}
|
||||
|
||||
const raw = toPLain({}, DefaultValModel);
|
||||
// 你将获得如下数据
|
||||
{
|
||||
i: 0;
|
||||
}
|
||||
```
|
||||
|
||||
## serializeTarget()
|
||||
|
||||
当调 `toPlain` 进行序列化时,用使用当前数据作为基准
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class SerializeTargetModel {
|
||||
@serializeTarget()
|
||||
@property('n')
|
||||
name: string;
|
||||
|
||||
@property('n')
|
||||
nick: string;
|
||||
}
|
||||
|
||||
const raw = toPlain(
|
||||
{
|
||||
name: 'name',
|
||||
nick: 'nick',
|
||||
},
|
||||
SerializeTargetModel,
|
||||
);
|
||||
|
||||
// 你将获得如下数据
|
||||
{
|
||||
n: 'name';
|
||||
}
|
||||
```
|
||||
|
||||
## beforeDeserialize(beforeDeserializer, disallowIgnoreBeforeDeserializer = false)
|
||||
|
||||
在 `@typed` 调用之前调用
|
||||
|
||||
- `beforeDeserializer` `<(value: any, instance: any, origin: any) => any>`
|
||||
- `value` `<Any>` 该属性在原始对象中的值
|
||||
- `instance` `<Instance>` 类实例(未完成解析)
|
||||
- `origin` `<Object>` 原始对象
|
||||
- `disallowIgnoreBeforeDeserializer` `<Boolean>` 默认为 false,如果设置为 true,则当调用 `toClass` 时,将强制调用 `@beforeDeserialize` 配置的方法
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class BeforeDeserializeModel {
|
||||
@beforeDeserialize((value: any) => JSON.parse(value))
|
||||
@property('m')
|
||||
mail: object;
|
||||
}
|
||||
|
||||
toClass(
|
||||
{
|
||||
m: '{"id":123}',
|
||||
},
|
||||
BeforeDeserializeModel,
|
||||
);
|
||||
|
||||
// 你将获得如下数据
|
||||
{
|
||||
mail: { id: 123 },
|
||||
};
|
||||
```
|
||||
|
||||
## deserialize(deserializer, disallowIgnoreDeserializer =false)
|
||||
|
||||
将原始对象序列化成自定义的数组格式,仅在调用 `toClass/toClasses` 时可用
|
||||
|
||||
- `deserializer` `(value: any, instance: any, origin: any) => any`
|
||||
- `value` `<Any>` 该属性的值经过 `@beforeDeserialize` 和 `@typed` 调用后的结果
|
||||
- `instance` `<Instance>` 类实例(未完成解析)
|
||||
- `origin` `<Object>` A raw object
|
||||
- `disallowIgnoreDeserializer` `<Boolean>` 默认为 false,如果设置为 true,则当调用 `toClass` 时,将强制调用 `@deserialize` 配置的方法
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class DeserializeModel {
|
||||
@deserialize((value: string) => `${value}@xxx.com`)
|
||||
@property('m')
|
||||
mail: string;
|
||||
}
|
||||
|
||||
toClass(
|
||||
{
|
||||
m: 'mail',
|
||||
},
|
||||
DeserializeModel,
|
||||
);
|
||||
|
||||
// 你将获得如下数据
|
||||
{
|
||||
mail: 'mail@xxx.com',
|
||||
};
|
||||
```
|
||||
|
||||
## serialize(serializer, disallowIgnoreSerializer = false)
|
||||
|
||||
自定义属性值的序列化方式,仅当调用 `toPlain/toPlains` 时可用
|
||||
|
||||
- `serializer` `(value: any, instance: any, origin: any) => any`
|
||||
- `value` `<Any>` 该属性在类实例中的值
|
||||
- `instance` `<Instance>` 当前类实例
|
||||
- `origin` `<Object>` 一个json对象(未完成序列化)
|
||||
- `disallowIgnoreSerializer` `<Boolean>` 默认为 false,如果设置为 true,则当调用 `toClass` 时,将强制调用 `@serialize` 配置的方法
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
class SerializeModel {
|
||||
@serialize((mail: string) => mail.replace('@xxx.com', ''))
|
||||
@property('e')
|
||||
mail: string;
|
||||
}
|
||||
|
||||
toPlain(
|
||||
{
|
||||
mail: 'mail@xxx.com',
|
||||
},
|
||||
SerializeModel,
|
||||
);
|
||||
|
||||
// 你将获得如下数据
|
||||
{
|
||||
e: 'mail@xxx.com',
|
||||
}
|
||||
```
|
||||
|
||||
## afterSerialize(afterSerializer, disallowIgnoreAfterSerializer = false)
|
||||
|
||||
Convert a key/value in instance to a target form data, it happened after serializer only
|
||||
|
||||
- `afterSerializer` `(value: any, instance: any, origin: any) => any`
|
||||
- `value` `<Any>` 该属性的值经过 `@serializer` 和 `@typed` 调用后的结果
|
||||
- `instance` `<Instance>` 当前类实例
|
||||
- `origin` `<Object>` 一个json对象(未完成序列化)
|
||||
- `disallowIgnoreAfterSerializer` `<Boolean>` 默认为 false,如果设置为 true,则当调用 `toClass` 时,将强制调用 `@afterSerialize` 配置的方法
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
class AfterSerializeModel {
|
||||
@afterSerialize((mail: string) => JSON.stringify(mail))
|
||||
@property('e')
|
||||
mail: string;
|
||||
}
|
||||
|
||||
toPlain(
|
||||
{
|
||||
mail: { id: 1000 },
|
||||
},
|
||||
SerializeModel,
|
||||
);
|
||||
|
||||
// 你将获得如下数据
|
||||
{
|
||||
e: '{"id":1000}',
|
||||
};
|
||||
```
|
||||
1
json-mapper-class/dist/.pydio
vendored
Normal file
@@ -0,0 +1 @@
|
||||
391e708b-cc22-49c3-8788-a0be45dd3948
|
||||
10
json-mapper-class/dist/decorators.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { StoreItemType } from './typing';
|
||||
export declare function serialize(serializer: StoreItemType['serializer'], disallowIgnore?: boolean): (target: any, propertyKey: string) => void;
|
||||
export declare function deserialize(deserializer: StoreItemType['deserializer'], disallowIgnore?: boolean): (target: any, propertyKey: string) => void;
|
||||
export declare function beforeDeserialize(beforeDeserializer: StoreItemType['beforeDeserializer'], disallowIgnore?: boolean): (target: any, propertyKey: string) => void;
|
||||
export declare function afterSerialize(afterSerializer: StoreItemType['afterSerializer'], disallowIgnore?: boolean): (target: any, propertyKey: string) => void;
|
||||
export declare function serializeTarget(): (target: any, propertyKey: string) => void;
|
||||
export declare function property(originalKey?: string, targetClass?: StoreItemType['targetClass'], isOptional?: boolean): (target: any, propertyKey: string) => void;
|
||||
export declare function typed(targetClass: StoreItemType['targetClass']): (target: any, propertyKey: string) => void;
|
||||
export declare function optional(): (target: any, propertyKey: string) => void;
|
||||
export declare function defaultVal(value: any): (target: any, propertyKey: string) => void;
|
||||
96
json-mapper-class/dist/decorators.js
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.defaultVal = exports.optional = exports.typed = exports.property = exports.serializeTarget = exports.afterSerialize = exports.beforeDeserialize = exports.deserialize = exports.serialize = void 0;
|
||||
const store_1 = require("./store");
|
||||
function serialize(serializer, disallowIgnore = false) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
serializer,
|
||||
disallowIgnoreSerializer: disallowIgnore,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.serialize = serialize;
|
||||
function deserialize(deserializer, disallowIgnore = false) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
deserializer,
|
||||
disallowIgnoreDeserializer: disallowIgnore,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.deserialize = deserialize;
|
||||
function beforeDeserialize(beforeDeserializer, disallowIgnore = false) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
beforeDeserializer,
|
||||
disallowIgnoreBeforeDeserializer: disallowIgnore,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.beforeDeserialize = beforeDeserialize;
|
||||
function afterSerialize(afterSerializer, disallowIgnore = false) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
afterSerializer,
|
||||
disallowIgnoreAfterSerializer: disallowIgnore,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.afterSerialize = afterSerialize;
|
||||
function serializeTarget() {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
serializeTarget: true,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.serializeTarget = serializeTarget;
|
||||
function property(originalKey, targetClass, isOptional = false) {
|
||||
return (target, propertyKey) => {
|
||||
const config = {
|
||||
originalKey: originalKey || propertyKey,
|
||||
key: propertyKey,
|
||||
};
|
||||
if (targetClass) {
|
||||
config.targetClass = targetClass.prototype.constructor;
|
||||
}
|
||||
if (isOptional) {
|
||||
config.optional = isOptional;
|
||||
}
|
||||
store_1.setStore(target, config);
|
||||
};
|
||||
}
|
||||
exports.property = property;
|
||||
function typed(targetClass) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
targetClass,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.typed = typed;
|
||||
function optional() {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
optional: true,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.optional = optional;
|
||||
function defaultVal(value) {
|
||||
return (target, propertyKey) => {
|
||||
store_1.setStore(target, {
|
||||
key: propertyKey,
|
||||
default: value,
|
||||
});
|
||||
};
|
||||
}
|
||||
exports.defaultVal = defaultVal;
|
||||
1
json-mapper-class/dist/decorators.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
|
||||
4
json-mapper-class/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './to-class';
|
||||
export * from './to-plain';
|
||||
export * from './decorators';
|
||||
export * from './typing';
|
||||
16
json-mapper-class/dist/index.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./to-class"), exports);
|
||||
__exportStar(require("./to-plain"), exports);
|
||||
__exportStar(require("./decorators"), exports);
|
||||
__exportStar(require("./typing"), exports);
|
||||
1
json-mapper-class/dist/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA2B;AAC3B,6CAA2B;AAC3B,+CAA6B;AAC7B,2CAAyB"}
|
||||
6
json-mapper-class/dist/store.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { StoreItemOptions, StoreItemType } from './typing';
|
||||
declare const store: Map<Function, Map<string, StoreItemType>>;
|
||||
export declare const originalKeyStores: Map<Function, Map<string, StoreItemOptions[]>>;
|
||||
export declare const keyStores: Map<Function, Map<string, StoreItemType>>;
|
||||
export declare const setStore: (target: Function, options: StoreItemOptions) => void;
|
||||
export default store;
|
||||
19
json-mapper-class/dist/store.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.setStore = exports.keyStores = exports.originalKeyStores = void 0;
|
||||
const store = new Map();
|
||||
exports.originalKeyStores = new Map();
|
||||
exports.keyStores = new Map();
|
||||
exports.setStore = (target, options) => {
|
||||
const { key, ...rest } = options;
|
||||
const storeKey = target.constructor;
|
||||
const targetStore = store.has(storeKey) ? store.get(storeKey) : new Map();
|
||||
let value = targetStore.has(key) ? targetStore.get(key) : {};
|
||||
value = {
|
||||
...value,
|
||||
...rest,
|
||||
};
|
||||
targetStore.set(key, value);
|
||||
store.set(storeKey, targetStore);
|
||||
};
|
||||
exports.default = store;
|
||||
1
json-mapper-class/dist/store.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":";;;AAEA,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwC,CAAC;AAEjD,QAAA,iBAAiB,GAAG,IAAI,GAAG,EAA6C,CAAC;AACzE,QAAA,SAAS,GAAG,IAAI,GAAG,EAAwC,CAAC;AAE5D,QAAA,QAAQ,GAAG,CAAC,MAAgB,EAAE,OAAyB,EAAE,EAAE;IACtE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACjC,oCAAoC;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;IACpC,sDAAsD;IACtD,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAyB,CAAC;IAEjG,iEAAiE;IACjE,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,KAAK,GAAG;QACN,GAAG,KAAK;QACR,GAAG,IAAI;KACR,CAAC;IAEF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACnC,CAAC,CAAC;AAEF,kBAAe,KAAK,CAAC"}
|
||||
4
json-mapper-class/dist/to-class.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { JosnType, BasicClass, ToClassOptions } from './typing';
|
||||
export declare const arrayItemToClass: <T>(arrayVal: any[], Clazz: BasicClass<T>, options: ToClassOptions) => any;
|
||||
export declare const toClasses: <T>(rawJson: JosnType[], Clazz: BasicClass<T>, options?: ToClassOptions) => T[];
|
||||
export declare const toClass: <T>(rawJson: JosnType, Clazz: BasicClass<T>, options?: ToClassOptions) => T;
|
||||
61
json-mapper-class/dist/to-class.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toClass = exports.toClasses = exports.arrayItemToClass = void 0;
|
||||
const isarray_1 = __importDefault(require("isarray"));
|
||||
const utils_1 = require("./utils");
|
||||
exports.arrayItemToClass = (arrayVal, Clazz, options) => {
|
||||
return arrayVal.map((v) => isarray_1.default(v) ? exports.arrayItemToClass(v, Clazz, options) : objectToClass(v, Clazz, options));
|
||||
};
|
||||
const objectToClass = (jsonObj, Clazz, options) => {
|
||||
const instance = new Clazz();
|
||||
const originalKeyStore = utils_1.getOriginalKeyStore(Clazz);
|
||||
originalKeyStore.forEach((propertiesOptions, originalKey) => {
|
||||
const originalValue = jsonObj[originalKey];
|
||||
propertiesOptions.forEach((storeItemoptions) => {
|
||||
const { key, beforeDeserializer, deserializer, targetClass, optional } = storeItemoptions;
|
||||
const disallowIgnoreDeserializer = storeItemoptions.disallowIgnoreDeserializer || !options.ignoreDeserializer;
|
||||
const disallowIgnoreBeforeDeserializer = storeItemoptions.disallowIgnoreBeforeDeserializer || !options.ignoreBeforeDeserializer;
|
||||
const isValueNotExist = options.distinguishNullAndUndefined ? utils_1.isUndefined : utils_1.isNullOrUndefined;
|
||||
let value = originalValue;
|
||||
if (isValueNotExist(value)) {
|
||||
if (!isValueNotExist(storeItemoptions.default)) {
|
||||
instance[key] = storeItemoptions.default;
|
||||
return;
|
||||
}
|
||||
if (!optional) {
|
||||
throw new Error(`Can't map '${originalKey}' to ${Clazz.name}.${key}, property '${originalKey}' not found`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
value =
|
||||
beforeDeserializer && disallowIgnoreBeforeDeserializer
|
||||
? beforeDeserializer(value, instance, jsonObj, options)
|
||||
: value;
|
||||
if (value && targetClass) {
|
||||
if (isarray_1.default(value)) {
|
||||
value = exports.arrayItemToClass(value, targetClass, options);
|
||||
}
|
||||
else {
|
||||
value = exports.toClass(value, targetClass, options);
|
||||
}
|
||||
}
|
||||
instance[key] =
|
||||
deserializer && disallowIgnoreDeserializer ? deserializer(value, instance, jsonObj, options) : value;
|
||||
});
|
||||
});
|
||||
return instance;
|
||||
};
|
||||
exports.toClasses = (rawJson, Clazz, options = {}) => {
|
||||
if (!isarray_1.default(rawJson)) {
|
||||
throw new Error(`rawJson ${rawJson} must be an array`);
|
||||
}
|
||||
const { constructor } = Clazz.prototype;
|
||||
return rawJson.map((item) => objectToClass(item, constructor, options));
|
||||
};
|
||||
exports.toClass = (rawJson, Clazz, options = {}) => {
|
||||
const { constructor } = Clazz.prototype;
|
||||
return objectToClass(rawJson, constructor, options);
|
||||
};
|
||||
1
json-mapper-class/dist/to-class.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"to-class.js","sourceRoot":"","sources":["../src/to-class.ts"],"names":[],"mappings":"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"}
|
||||
4
json-mapper-class/dist/to-plain.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { JosnType, BasicClass, ToPlainOptions } from './typing';
|
||||
export declare const arrayItemToObject: <T>(arrayVal: any[], Clazz: BasicClass<T>, options: ToPlainOptions) => any;
|
||||
export declare const toPlains: <T>(instances: (JosnType | T)[], Clazz: BasicClass<T>, options?: ToPlainOptions) => any[];
|
||||
export declare const toPlain: <T>(instance: JosnType | T, Clazz: BasicClass<T>, options?: ToPlainOptions) => any;
|
||||
49
json-mapper-class/dist/to-plain.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toPlain = exports.toPlains = exports.arrayItemToObject = void 0;
|
||||
const isarray_1 = __importDefault(require("isarray"));
|
||||
const utils_1 = require("./utils");
|
||||
exports.arrayItemToObject = (arrayVal, Clazz, options) => {
|
||||
return arrayVal.map((v) => isarray_1.default(v) ? exports.arrayItemToObject(v, Clazz, options) : classToObject(v, Clazz, options));
|
||||
};
|
||||
const classToObject = (instance, Clazz, options) => {
|
||||
const obj = {};
|
||||
const keyStore = utils_1.getKeyStore(Clazz);
|
||||
keyStore.forEach((propertiesOption, key) => {
|
||||
const isValueNotExist = options.distinguishNullAndUndefined ? utils_1.isUndefined : utils_1.isNullOrUndefined;
|
||||
const instanceValue = isValueNotExist(instance[key]) ? propertiesOption.default : instance[key];
|
||||
const { originalKey, afterSerializer, serializer, targetClass, optional } = propertiesOption;
|
||||
const disallowIgnoreSerializer = propertiesOption.disallowIgnoreSerializer || !options.ignoreSerializer;
|
||||
const disallowIgnoreAfterSerializer = propertiesOption.disallowIgnoreAfterSerializer || !options.ignoreAfterSerializer;
|
||||
if (isValueNotExist(instanceValue)) {
|
||||
if (!optional) {
|
||||
throw new Error(`Property '${Clazz.name}.${key}' not found`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let value = serializer && disallowIgnoreSerializer ? serializer(instanceValue, instance, obj, options) : instanceValue;
|
||||
if (value && targetClass) {
|
||||
if (isarray_1.default(value)) {
|
||||
value = exports.arrayItemToObject(value, targetClass, options);
|
||||
}
|
||||
else {
|
||||
value = exports.toPlain(value, targetClass, options);
|
||||
}
|
||||
}
|
||||
obj[originalKey] =
|
||||
afterSerializer && disallowIgnoreAfterSerializer ? afterSerializer(value, instance, obj, options) : value;
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
exports.toPlains = (instances, Clazz, options = {}) => {
|
||||
if (!isarray_1.default(instances)) {
|
||||
throw new Error(`${Clazz} instances must be an array`);
|
||||
}
|
||||
return instances.map((item) => classToObject(item, Clazz, options));
|
||||
};
|
||||
exports.toPlain = (instance, Clazz, options = {}) => {
|
||||
return classToObject(instance, Clazz, options);
|
||||
};
|
||||
1
json-mapper-class/dist/to-plain.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"to-plain.js","sourceRoot":"","sources":["../src/to-plain.ts"],"names":[],"mappings":"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"}
|
||||
35
json-mapper-class/dist/typing.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
export declare type StoreItemType = {
|
||||
originalKey?: string;
|
||||
targetClass?: BasicClass;
|
||||
serializer?: (value: any, instance: any, origin: any, options: ToPlainOptions) => any;
|
||||
disallowIgnoreSerializer?: boolean;
|
||||
afterSerializer?: (value: any, instance: any, origin: any, options: ToPlainOptions) => any;
|
||||
disallowIgnoreAfterSerializer?: boolean;
|
||||
deserializer?: (value: any, instance: any, origin: any, options: ToClassOptions) => any;
|
||||
disallowIgnoreDeserializer?: boolean;
|
||||
beforeDeserializer?: (value: any, instance: any, origin: any, options: ToClassOptions) => any;
|
||||
disallowIgnoreBeforeDeserializer?: boolean;
|
||||
default?: any;
|
||||
autoTypeDetection?: boolean;
|
||||
optional?: boolean;
|
||||
serializeTarget?: boolean;
|
||||
};
|
||||
export declare type StoreItemOptions = StoreItemType & {
|
||||
key: string;
|
||||
};
|
||||
export declare type BasicClass<T = any> = {
|
||||
new (...args: any[]): T;
|
||||
};
|
||||
export declare type JosnType = {
|
||||
[key: string]: any;
|
||||
};
|
||||
export interface ToClassOptions {
|
||||
ignoreDeserializer?: boolean;
|
||||
ignoreBeforeDeserializer?: boolean;
|
||||
distinguishNullAndUndefined?: boolean;
|
||||
}
|
||||
export interface ToPlainOptions {
|
||||
ignoreSerializer?: boolean;
|
||||
ignoreAfterSerializer?: boolean;
|
||||
distinguishNullAndUndefined?: boolean;
|
||||
}
|
||||
2
json-mapper-class/dist/typing.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
1
json-mapper-class/dist/typing.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"typing.js","sourceRoot":"","sources":["../src/typing.ts"],"names":[],"mappings":""}
|
||||
6
json-mapper-class/dist/utils.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { StoreItemOptions, StoreItemType, BasicClass } from './typing';
|
||||
export declare const isNull: (val: any) => boolean;
|
||||
export declare const isUndefined: (val: any) => boolean;
|
||||
export declare const isNullOrUndefined: (val: any) => boolean;
|
||||
export declare const getOriginalKeyStore: <T>(Clazz: BasicClass<T>) => Map<string, StoreItemOptions[]>;
|
||||
export declare const getKeyStore: <T>(Clazz: BasicClass<T>) => Map<string, StoreItemType>;
|
||||
82
json-mapper-class/dist/utils.js
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getKeyStore = exports.getOriginalKeyStore = exports.isNullOrUndefined = exports.isUndefined = exports.isNull = void 0;
|
||||
const store_1 = __importStar(require("./store"));
|
||||
exports.isNull = (val) => val === null;
|
||||
exports.isUndefined = (val) => val === undefined;
|
||||
exports.isNullOrUndefined = (val) => exports.isNull(val) || exports.isUndefined(val);
|
||||
exports.getOriginalKeyStore = (Clazz) => {
|
||||
let curLayer = Clazz;
|
||||
const cacheOriginalKeyStore = store_1.originalKeyStores.get(curLayer);
|
||||
if (cacheOriginalKeyStore) {
|
||||
return cacheOriginalKeyStore;
|
||||
}
|
||||
const originalKeyStore = new Map();
|
||||
while (curLayer.name && curLayer.prototype) {
|
||||
const { constructor } = curLayer.prototype;
|
||||
const targetStore = store_1.default.get(constructor);
|
||||
if (targetStore) {
|
||||
targetStore.forEach((storeItem, key) => {
|
||||
const item = {
|
||||
key,
|
||||
...storeItem,
|
||||
};
|
||||
if (!originalKeyStore.has(storeItem.originalKey)) {
|
||||
originalKeyStore.set(storeItem.originalKey, [item]);
|
||||
}
|
||||
else {
|
||||
const exists = originalKeyStore.get(storeItem.originalKey);
|
||||
if (!exists.find((exist) => exist.key === key)) {
|
||||
originalKeyStore.set(storeItem.originalKey, [...originalKeyStore.get(storeItem.originalKey), item]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
curLayer = Object.getPrototypeOf(constructor);
|
||||
}
|
||||
store_1.originalKeyStores.set(Clazz, originalKeyStore);
|
||||
return originalKeyStore;
|
||||
};
|
||||
exports.getKeyStore = (Clazz) => {
|
||||
const cacheKeyStore = store_1.keyStores.get(Clazz);
|
||||
if (cacheKeyStore) {
|
||||
return cacheKeyStore;
|
||||
}
|
||||
const keyStore = new Map();
|
||||
const originalKeyStore = exports.getOriginalKeyStore(Clazz);
|
||||
originalKeyStore.forEach(storeItems => {
|
||||
const [firstStoreItem] = storeItems;
|
||||
if (storeItems.length === 1) {
|
||||
keyStore.set(firstStoreItem.key, firstStoreItem);
|
||||
}
|
||||
else {
|
||||
const hasStoreItems = storeItems.filter(storeItem => storeItem.serializeTarget);
|
||||
if (hasStoreItems.length !== 1) {
|
||||
throw new Error(`Only one of keys(${storeItems.map(storeItem => storeItem.key).join(', ')}) in ${Clazz.name} can contain a serializeTarget when use toPlain`);
|
||||
}
|
||||
const hasStoreItem = hasStoreItems[0];
|
||||
keyStore.set(hasStoreItem.key, hasStoreItem);
|
||||
}
|
||||
});
|
||||
store_1.keyStores.set(Clazz, keyStore);
|
||||
return keyStore;
|
||||
};
|
||||
1
json-mapper-class/dist/utils.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
||||
27
json-mapper-class/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "json-mapper-class",
|
||||
"version": "1.0.2",
|
||||
"description": "Json Mapper To Class",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "ts-node test.ts",
|
||||
"publish": "npm publish"
|
||||
},
|
||||
"keywords": [
|
||||
"class",
|
||||
"json",
|
||||
"mapper",
|
||||
"typescript"
|
||||
],
|
||||
"dependencies": {
|
||||
"isarray": "^2.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/isarray": "^2.0.0",
|
||||
"@types/node": "^12.12.50",
|
||||
"moment": "^2.27.0",
|
||||
"ts-node": "^8.10.2",
|
||||
"typescript": "^3.9.7"
|
||||
}
|
||||
}
|
||||
19
json-mapper-class/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": false,
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"lib": ["es6"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
29
json-to-class/.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
test.json
|
||||
笔记.txt
|
||||
package-lock.json
|
||||
stats.html
|
||||
|
||||
src-tauri/target/*
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
1
json-to-class/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2b79c44f-8eec-46bb-8888-ea29805a9038
|
||||
89
json-to-class/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
<p align="center">
|
||||
<img style="width: 50px;height: 50px;" src="build/img/icon_128x128.png"/>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>JsonToClass</strong>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
帮助 TypeScript 项目,为API接口数据自动生成 TypeScript 类型
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://svelte.dev/">
|
||||
<img src="https://img.shields.io/badge/svelte-v4.0.5-orange" alt="svelte">
|
||||
</a>
|
||||
<a href="https://beta.tauri.app/">
|
||||
<img src="https://img.shields.io/badge/tauri-v2.0.0-brightgreen" alt="tauri">
|
||||
</a>
|
||||
<a href="https://www.typescriptlang.org/">
|
||||
<img src="https://img.shields.io/badge/typescript-v5.0.2-blue" alt="typescript">
|
||||
</a>
|
||||
<a href="https://vitejs.dev/">
|
||||
<img src="https://img.shields.io/badge/vite-v4.4.4-orange" alt="vitejs">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/json-class-interface">
|
||||
<img src="https://img.shields.io/badge/json__class__interface-v1.1.3-brightgreen" alt="json-class-interface">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
该软件是本人npm 插件 **[json-class-interface](https://www.npmjs.com/package/json-class-interface)** 的桌面端,为了方便使用所以开发!但为了学习新技术点,所以舍弃大而慢占内存的 electron,谁还用 electron?你用 ??electron 落伍了...
|
||||
|
||||
**`Tauri`谁用谁知道,本项目打包后,在Macos上可执行`app`才只有`5.5MB`,`dmg`可视化安装程序`3.1MB`,`app`还能再次优化到`2MB`
|
||||
左右!!**
|
||||
|
||||
> 使用场景:本软件可以用在任意 TypeScript 项目中!只要你调接口了,需要为接口返回数据编写类型,那么就可以用。同时为了解耦接口数据字段 和 页面 的深度绑定,可以使用本人的另一个插件 [json-mapper-class](https://www.npmjs.com/package/json-mapper-class)
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **Tauri**: 基于 `Rust` 的全新桌面端开发框架,这里使用2.x版本 **注意: 2.x作者还未开发完成,坑非常多,慎入,项目中用 1.x 即可**
|
||||
- **Rust**: `Mozilla`开发的为了替代`C++`的系统级编程语言,不建议前端轻易尝试学习
|
||||
- **Svelte**: 更快更高效更简单好用的 `Vue` 框架 替代者 & 竞争者!
|
||||
- **Vite**: 更好用快速的 **新型前端构建工具**
|
||||
- **TypeScript**: 基于 `JavaScript` 构建的强类型编程语言
|
||||
- **monaco-editor**: `vscode` 的代码编辑器
|
||||
- **json-class-interface**: 本人的`JSON`转换插件,强烈建议搭配我的另外一个插件 [json-mapper-class](https://www.npmjs.com/package/json-mapper-class) 一起使用
|
||||
- **svelte-spa-router**: `svelte`的第三方路由
|
||||
- **svelte-ui**: 唯一还能将就用的 `svelte` 第三方UI框架
|
||||
|
||||
## 已实现的功能
|
||||
|
||||
- [x] 1: `Json` 转换为 `Class` 类
|
||||
- [x] 2: `Json` 转换为 `Interface` 接口
|
||||
- [x] 3: 转换为**类**时候 自动生成 属性装饰器 `property`
|
||||
- [x] 4: 转换为**类**时候,可以通过**设置**决定是否为 属性装饰器 `property` 开启默认值
|
||||
- [x] 5: 可选 `Json` 数据中 `Value` 为 `null` 的类型
|
||||
- [x] 6: **自动存储** 生成 的代码 到 **你指定的路径**,并**配置文件名**
|
||||
- [x] 7: 手动 切换 **白天模式 & 夜间模式**,或是 **跟随操作系统自动切换**
|
||||
- [x] 8: 开关 **代码行号**
|
||||
- [x] 9: 开关 **代码小地图**
|
||||
- [x] 10: 开关 自动粘贴代码 进入**剪贴板**
|
||||
- [x] 11: 开机自启
|
||||
- [x] 12: 软件升级
|
||||
- [x] 13: 启动欢迎页面
|
||||
|
||||
## Windows & MacOs & Linux 下载
|
||||
|
||||
**下载地址:** [releases](https://gitee.com/bmycode/json-class-desktop/releases)
|
||||
|
||||
**文件说明:**
|
||||
|
||||
- Windows 版本:JsonToClass_x.x.x_x64-setup.exe
|
||||
- MacOs 版本:JsonToClass_x.x.x_x64.dmg
|
||||
- Linux 版本:JsonToClass_x.x.x_amd64.deb
|
||||
|
||||
**注意事项:**
|
||||
|
||||
1:MacOs 端由于没有`Apple`开发者账号无法进行软件签名,所以安装后打开的时候会提示风险,无法打开,具体参考这篇教程:
|
||||
[https://blog.csdn.net/m0_37482190/article/details/128957808](https://blog.csdn.net/m0_37482190/article/details/128957808)
|
||||
|
||||
2:**代码更新速度较快,所以 安装包 落后于 最新代码,有能力的推荐自己部署 Rust + Tauri 环境然后对代码进行打包即可!!!**
|
||||
|
||||
## 软件展示
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
1
json-to-class/build/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
4408a16a-b5c1-47d5-9698-a27572ed5880
|
||||
BIN
json-to-class/build/JsonToClass.icns
Normal file
1
json-to-class/build/JsonToClass.iconset/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
785daa35-f2c9-409b-ac24-288dc7e2af46
|
||||
BIN
json-to-class/build/JsonToClass.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_128x128@2x.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_16x16@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_32x32@2x.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_512x512.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
json-to-class/build/JsonToClass.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
json-to-class/build/JsonToClass.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
13
json-to-class/build/icns.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
sips -z 16 16 JsonToClass.png --out JsonToClass.iconset/icon_16x16.png
|
||||
sips -z 32 32 JsonToClass.png --out JsonToClass.iconset/icon_16x16@2x.png
|
||||
sips -z 32 32 JsonToClass.png --out JsonToClass.iconset/icon_32x32.png
|
||||
sips -z 64 64 JsonToClass.png --out JsonToClass.iconset/icon_32x32@2x.png
|
||||
sips -z 128 128 JsonToClass.png --out JsonToClass.iconset/icon_128x128.png
|
||||
sips -z 256 256 JsonToClass.png --out JsonToClass.iconset/icon_128x128@2x.png
|
||||
sips -z 256 256 JsonToClass.png --out JsonToClass.iconset/icon_256x256.png
|
||||
sips -z 512 512 JsonToClass.png --out JsonToClass.iconset/icon_256x256@2x.png
|
||||
sips -z 512 512 JsonToClass.png --out JsonToClass.iconset/icon_512x512.png
|
||||
sips -z 512 512 JsonToClass.png --out JsonToClass.iconset/icon_512x512@2x.png
|
||||
|
||||
iconutil -c icns JsonToClass.iconset -o JsonToClass.icns
|
||||
1
json-to-class/build/img/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
ee0f13d5-2393-42c0-9f2c-b24b7071070f
|
||||
BIN
json-to-class/build/img/0.png
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
json-to-class/build/img/1.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
BIN
json-to-class/build/img/2.png
Normal file
|
After Width: | Height: | Size: 6.1 MiB |
BIN
json-to-class/build/img/3.png
Normal file
|
After Width: | Height: | Size: 6.2 MiB |
BIN
json-to-class/build/img/4.png
Normal file
|
After Width: | Height: | Size: 6.1 MiB |
BIN
json-to-class/build/img/5.png
Normal file
|
After Width: | Height: | Size: 6.2 MiB |
BIN
json-to-class/build/img/6.png
Normal file
|
After Width: | Height: | Size: 6.2 MiB |
BIN
json-to-class/build/img/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
14
json-to-class/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="./iconfont/iconfont.css">
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
47
json-to-class/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "json-to-class",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"tauri-dev": "tauri dev",
|
||||
"tauri-build": "tauri build",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svelteuidev/composables": "^0.15.3",
|
||||
"@svelteuidev/core": "^0.15.3",
|
||||
"@tauri-apps/api": "^2.0.0-alpha.11",
|
||||
"@tauri-apps/plugin-autostart": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-dialog": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-fs": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-notification": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-shell": "^2.0.0-alpha.3",
|
||||
"@tauri-apps/plugin-window": "^2.0.0-alpha.1",
|
||||
"json-class-interface": "^1.1.7",
|
||||
"monaco-editor": "^0.43.0",
|
||||
"svelte-spa-router": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||
"@tauri-apps/cli": "^2.0.0-rc.3",
|
||||
"@tsconfig/svelte": "^5.0.0",
|
||||
"@types/node": "^20.9.0",
|
||||
"internal-ip": "^7.0.0",
|
||||
"less": "^4.2.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte-check": "^3.4.6",
|
||||
"svelte-preprocess-less": "^0.4.0",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.4",
|
||||
"vite-plugin-monaco-editor": "^1.1.0"
|
||||
}
|
||||
}
|
||||
1
json-to-class/public/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
217a9024-c835-4293-9269-e7be2a8dd55f
|
||||
1
json-to-class/public/iconfont/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
9b4a28d6-e012-4f66-bc67-f102e825d19a
|
||||
91
json-to-class/public/iconfont/iconfont.css
Normal file
@@ -0,0 +1,91 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4318577 */
|
||||
src: url('./iconfont.woff2?t=1700074221843') format('woff2'),
|
||||
url('./iconfont.woff?t=1700074221843') format('woff'),
|
||||
url('./iconfont.ttf?t=1700074221843') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont", serif !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.json-guanyu:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.json-cuowutishi-copy:before {
|
||||
content: "\e7a2";
|
||||
}
|
||||
|
||||
.json-wenjianjia:before {
|
||||
content: "\e67c";
|
||||
}
|
||||
|
||||
.json-sucai:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.json-open-folder:before {
|
||||
content: "\e677";
|
||||
}
|
||||
|
||||
.json-json:before {
|
||||
content: "\e7bd";
|
||||
}
|
||||
|
||||
.json-cunchuqia:before {
|
||||
content: "\e638";
|
||||
}
|
||||
|
||||
.json-cunchu:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.json-gengduo:before {
|
||||
content: "\ec1c";
|
||||
}
|
||||
|
||||
.json-shezhi:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.json-gengduo1:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.json-shezhi2:before {
|
||||
content: "\e6a9";
|
||||
}
|
||||
|
||||
.json-shezhi-xitongshezhi:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.json-moon:before {
|
||||
content: "\e6c2";
|
||||
}
|
||||
|
||||
.json-wo:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.json-wodewo:before {
|
||||
content: "\e6df";
|
||||
}
|
||||
|
||||
.json-31shezhi:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.json-shezhi1:before {
|
||||
content: "\e8b7";
|
||||
}
|
||||
|
||||
.json-taiyang:before {
|
||||
content: "\e709";
|
||||
}
|
||||
|
||||
BIN
json-to-class/public/iconfont/iconfont.ttf
Normal file
BIN
json-to-class/public/iconfont/iconfont.woff
Normal file
BIN
json-to-class/public/iconfont/iconfont.woff2
Normal file
1
json-to-class/public/img/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
7809e461-c368-4067-ae5e-0f0fdcd86be9
|
||||
BIN
json-to-class/public/img/JsonToClass.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
json-to-class/public/img/auto.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
json-to-class/public/img/dark.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
json-to-class/public/img/light.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
159
json-to-class/public/splashscreen.html
Normal file
@@ -0,0 +1,159 @@
|
||||
<!--
|
||||
~ Copyright (c) 2023.
|
||||
~
|
||||
~ 作者:bmy
|
||||
~ 邮箱:2271608011@qq.com
|
||||
~ gitee:https://gitee.com/bmycode
|
||||
~ github:https://github.com/helpcode
|
||||
~
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<style>
|
||||
body,ul,li,p,a{
|
||||
font-family: "Al Bayan", serif;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
.main {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding-top: 60px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.main img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.main .name {
|
||||
font-size: 18px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.main .desc {
|
||||
font-size: 13px;
|
||||
color: #bdbdbd;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.loading > div {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: block;
|
||||
font-size: 0;
|
||||
color: #bdbdbd;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.loading.la-dark {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.loading > div {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
background-color: currentColor;
|
||||
border: 0 solid currentColor;
|
||||
}
|
||||
|
||||
.loading > div {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.loading > div:first-child {
|
||||
transform: translateX(0%);
|
||||
animation: ball-newton-cradle-left 1s 0s ease-out infinite;
|
||||
}
|
||||
|
||||
.loading > div:last-child {
|
||||
transform: translateX(0%);
|
||||
animation: ball-newton-cradle-right 1s 0s ease-out infinite;
|
||||
}
|
||||
|
||||
.loading.la-sm {
|
||||
width: 20px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.loading.la-sm > div {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.loading.la-2x {
|
||||
width: 80px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.loading.la-2x > div {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.loading.la-3x {
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.loading.la-3x > div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
@keyframes ball-newton-cradle-left {
|
||||
25% {
|
||||
transform: translateX(-100%);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball-newton-cradle-right {
|
||||
50% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateX(100%);
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main" data-tauri-drag-region>
|
||||
<img src="./img/JsonToClass.png" alt="">
|
||||
<p class="name">Json To Class</p>
|
||||
<p class="desc">帮助您更快编码</p>
|
||||
|
||||
<div class="loading">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
4
json-to-class/src-tauri/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
1
json-to-class/src-tauri/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
66a6e945-2049-4334-8fa1-a7f788930e3e
|
||||
5061
json-to-class/src-tauri/Cargo.lock
generated
Normal file
50
json-to-class/src-tauri/Cargo.toml
Normal file
@@ -0,0 +1,50 @@
|
||||
[package]
|
||||
name = "json-to-calss"
|
||||
version = "1.0.2"
|
||||
description = "json转换为类或接口的桌面端工具"
|
||||
authors = ["bmy"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
name = "tauri_app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.0-alpha.11", features = [] }
|
||||
|
||||
[dependencies]
|
||||
# devtools
|
||||
tauri = { version = "2.0.0-alpha.17", features = ["macos-private-api"] }
|
||||
# 窗口
|
||||
tauri-plugin-window = "2.0.0-alpha.2"
|
||||
# shell 命令行
|
||||
tauri-plugin-shell = "2.0.0-alpha.4"
|
||||
# 开机自启
|
||||
tauri-plugin-autostart = "2.0.0-alpha.4"
|
||||
# 通知
|
||||
tauri-plugin-notification = "2.0.0-alpha.5"
|
||||
# fs 文件系统
|
||||
tauri-plugin-fs = "2.0.0-alpha.4"
|
||||
# 剪切板插件
|
||||
tauri-plugin-clipboard-manager = "2.0.0-alpha.4"
|
||||
# dialog
|
||||
tauri-plugin-dialog = "2.0.0-alpha.4"
|
||||
|
||||
serde_json = "1.0"
|
||||
window-vibrancy = "0.4.3"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort" # Strip expensive panic clean-up logic
|
||||
codegen-units = 1 # Compile crates one after another so the compiler can optimize better
|
||||
lto = true # Enables link to optimizations
|
||||
opt-level = "s" # Optimize for binary size
|
||||
strip = true # Remove debug symbols
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
3
json-to-class/src-tauri/build.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
1
json-to-class/src-tauri/icons/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
f9e7ed09-d338-436e-855a-9f6dc62c18fd
|
||||