@open-feishu-card/validator 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +116 -24
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +117 -25
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -30,60 +30,152 @@ var DEPRECATED_PROPS = {
|
|
|
30
30
|
i18n_elements: "2.0 \u8BF7\u4F7F\u7528 body.elements + config.locale",
|
|
31
31
|
card_link: "2.0 \u8BF7\u4F7F\u7528 elements \u4E2D\u7684 button/open_url \u884C\u4E3A"
|
|
32
32
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
var BUILDER_ROOT_KEYS = /* @__PURE__ */ new Set(["name", "dsl", "variables"]);
|
|
34
|
+
function getProp(node, key) {
|
|
35
|
+
return node.properties.find((p) => p.key.value === key)?.value;
|
|
36
|
+
}
|
|
37
|
+
function validateBuilderEnvelope(resolved, diagnostics) {
|
|
38
|
+
if (resolved.kind !== "builder") return;
|
|
39
|
+
const root = resolved.rootAst;
|
|
40
|
+
for (const prop of root.properties) {
|
|
41
|
+
const key = prop.key.value;
|
|
42
|
+
if (!BUILDER_ROOT_KEYS.has(key)) {
|
|
43
|
+
diagnostics.push({
|
|
44
|
+
message: `\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u4E0D\u8BA4\u8BC6\u7684\u9876\u5C42\u5B57\u6BB5 "${key}"\uFF08\u4EC5\u652F\u6301 name / dsl / variables\uFF09`,
|
|
45
|
+
severity: "warning",
|
|
46
|
+
range: prop.key.range,
|
|
47
|
+
path: "/" + key,
|
|
48
|
+
code: "builder-unknown-key"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const nameNode = getProp(root, "name");
|
|
53
|
+
if (nameNode && nameNode.type !== "string") {
|
|
36
54
|
diagnostics.push({
|
|
37
|
-
message:
|
|
55
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "name" \u5E94\u4E3A\u5B57\u7B26\u4E32',
|
|
38
56
|
severity: "error",
|
|
39
|
-
range:
|
|
40
|
-
path: "/"
|
|
57
|
+
range: nameNode.range,
|
|
58
|
+
path: "/name",
|
|
59
|
+
code: "builder-envelope"
|
|
41
60
|
});
|
|
42
61
|
}
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
const variablesNode = getProp(root, "variables");
|
|
63
|
+
if (variablesNode && variablesNode.type !== "array") {
|
|
64
|
+
diagnostics.push({
|
|
65
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "variables" \u5E94\u4E3A\u6570\u7EC4',
|
|
66
|
+
severity: "error",
|
|
67
|
+
range: variablesNode.range,
|
|
68
|
+
path: "/variables",
|
|
69
|
+
code: "builder-envelope"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function validateCardAgainstSchema(cardAst, cardData, pathPrefix, options, diagnostics) {
|
|
74
|
+
const checkResult = schema.FeishuCardV2Schema.safeParse(cardData);
|
|
45
75
|
if (!checkResult.success) {
|
|
46
76
|
for (const issue of checkResult.error.issues) {
|
|
47
|
-
const node = findNodeAtPointer(
|
|
48
|
-
const range = node ? node.range : { start:
|
|
77
|
+
const node = findNodeAtPointer(cardAst, issue.path);
|
|
78
|
+
const range = node ? node.range : { start: cardAst.range.start, end: cardAst.range.start };
|
|
49
79
|
diagnostics.push({
|
|
50
80
|
message: issue.message,
|
|
51
81
|
severity: "error",
|
|
52
82
|
range,
|
|
53
|
-
path: pointerToString(issue.path)
|
|
83
|
+
path: parser.joinCardPointer(pathPrefix, pointerToString(issue.path))
|
|
54
84
|
});
|
|
55
85
|
}
|
|
56
86
|
}
|
|
57
87
|
const deprecated = { ...DEPRECATED_PROPS, ...options.deprecatedProps ?? {} };
|
|
58
|
-
for (const prop of
|
|
88
|
+
for (const prop of cardAst.properties) {
|
|
59
89
|
const hint = deprecated[prop.key.value];
|
|
60
90
|
if (hint) {
|
|
61
91
|
diagnostics.push({
|
|
62
92
|
message: `\u5E9F\u5F03\u5C5E\u6027 "${prop.key.value}": ${hint}`,
|
|
63
93
|
severity: "warning",
|
|
64
94
|
range: prop.key.range,
|
|
65
|
-
path: "/" + prop.key.value,
|
|
95
|
+
path: parser.joinCardPointer(pathPrefix, "/" + prop.key.value),
|
|
66
96
|
code: "deprecated-prop"
|
|
67
97
|
});
|
|
68
98
|
}
|
|
69
99
|
}
|
|
100
|
+
}
|
|
101
|
+
function validateAst(result, options = {}) {
|
|
102
|
+
const diagnostics = [];
|
|
103
|
+
for (const e of result.errors) {
|
|
104
|
+
diagnostics.push({
|
|
105
|
+
message: `JSON \u8BED\u6CD5\u9519\u8BEF: ${e.message}`,
|
|
106
|
+
severity: "error",
|
|
107
|
+
range: e.range,
|
|
108
|
+
path: "/"
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!result.ast || result.data === void 0) return diagnostics;
|
|
112
|
+
const resolved = parser.resolveCardDocument(result);
|
|
113
|
+
if (!resolved) return diagnostics;
|
|
114
|
+
validateBuilderEnvelope(resolved, diagnostics);
|
|
115
|
+
validateCardAgainstSchema(
|
|
116
|
+
resolved.cardAst,
|
|
117
|
+
resolved.cardData,
|
|
118
|
+
resolved.pathPrefix,
|
|
119
|
+
options,
|
|
120
|
+
diagnostics
|
|
121
|
+
);
|
|
70
122
|
return diagnostics;
|
|
71
123
|
}
|
|
72
124
|
function validate(source, options) {
|
|
73
125
|
return validateAst(parser.parse(source), options);
|
|
74
126
|
}
|
|
75
127
|
function validateData(data) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
128
|
+
const ZERO = {
|
|
129
|
+
start: { offset: 0, line: 1, column: 1 },
|
|
130
|
+
end: { offset: 0, line: 1, column: 1 }
|
|
131
|
+
};
|
|
132
|
+
const diagnostics = [];
|
|
133
|
+
if (parser.isBuilderDocument(data)) {
|
|
134
|
+
const rec = data;
|
|
135
|
+
for (const key of Object.keys(rec)) {
|
|
136
|
+
if (!BUILDER_ROOT_KEYS.has(key)) {
|
|
137
|
+
diagnostics.push({
|
|
138
|
+
message: `\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u4E0D\u8BA4\u8BC6\u7684\u9876\u5C42\u5B57\u6BB5 "${key}"\uFF08\u4EC5\u652F\u6301 name / dsl / variables\uFF09`,
|
|
139
|
+
severity: "warning",
|
|
140
|
+
range: ZERO,
|
|
141
|
+
path: "/" + key,
|
|
142
|
+
code: "builder-unknown-key"
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if ("name" in rec && typeof rec.name !== "string") {
|
|
147
|
+
diagnostics.push({
|
|
148
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "name" \u5E94\u4E3A\u5B57\u7B26\u4E32',
|
|
149
|
+
severity: "error",
|
|
150
|
+
range: ZERO,
|
|
151
|
+
path: "/name",
|
|
152
|
+
code: "builder-envelope"
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if ("variables" in rec && !Array.isArray(rec.variables)) {
|
|
156
|
+
diagnostics.push({
|
|
157
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "variables" \u5E94\u4E3A\u6570\u7EC4',
|
|
158
|
+
severity: "error",
|
|
159
|
+
range: ZERO,
|
|
160
|
+
path: "/variables",
|
|
161
|
+
code: "builder-envelope"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const card = parser.unwrapCardData(data);
|
|
166
|
+
const checkResult = schema.FeishuCardV2Schema.safeParse(card);
|
|
167
|
+
if (!checkResult.success) {
|
|
168
|
+
const prefix = parser.isBuilderDocument(data) ? "/dsl" : "";
|
|
169
|
+
for (const issue of checkResult.error.issues) {
|
|
170
|
+
diagnostics.push({
|
|
171
|
+
message: issue.message,
|
|
172
|
+
severity: "error",
|
|
173
|
+
range: ZERO,
|
|
174
|
+
path: parser.joinCardPointer(prefix, pointerToString(issue.path))
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return diagnostics;
|
|
87
179
|
}
|
|
88
180
|
|
|
89
181
|
exports.findNodeAtPointer = findNodeAtPointer;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 把 Zod Schema 2.0 的校验结果映射回 parser 产出的 AST 节点,
|
|
5
5
|
* 让每条诊断都精确定位到源码的 Line/Column/Range(字符级)。
|
|
6
|
+
*
|
|
7
|
+
* 输入可为裸 Card JSON,或搭建工具文档 `{ name, dsl, variables }`;
|
|
8
|
+
* Schema 只校验解包后的卡片层。
|
|
6
9
|
*/
|
|
7
10
|
import { type JsonNode, type JsonObjectNode, type ParseResult, type Range } from '@open-feishu-card/parser';
|
|
8
11
|
export type DiagnosticSeverity = 'error' | 'warning' | 'information' | 'hint';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,KAAK,EAEX,MAAM,0BAA0B,CAAC;AAGlC,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAE9E,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uCAAuC;AACvC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,QAAQ,GAAG,SAAS,CAgBnG;AAeD,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAsFD,6BAA6B;AAC7B,wBAAgB,WAAW,CACzB,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,eAAoB,GAC5B,UAAU,EAAE,CAyBd;AAED,wBAAwB;AACxB,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,UAAU,EAAE,CAEhF;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,EAAE,CAsDxD"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parse } from '@open-feishu-card/parser';
|
|
1
|
+
import { resolveCardDocument, parse, isBuilderDocument, unwrapCardData, joinCardPointer } from '@open-feishu-card/parser';
|
|
2
2
|
import { FeishuCardV2Schema } from '@open-feishu-card/schema';
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
@@ -28,60 +28,152 @@ var DEPRECATED_PROPS = {
|
|
|
28
28
|
i18n_elements: "2.0 \u8BF7\u4F7F\u7528 body.elements + config.locale",
|
|
29
29
|
card_link: "2.0 \u8BF7\u4F7F\u7528 elements \u4E2D\u7684 button/open_url \u884C\u4E3A"
|
|
30
30
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
var BUILDER_ROOT_KEYS = /* @__PURE__ */ new Set(["name", "dsl", "variables"]);
|
|
32
|
+
function getProp(node, key) {
|
|
33
|
+
return node.properties.find((p) => p.key.value === key)?.value;
|
|
34
|
+
}
|
|
35
|
+
function validateBuilderEnvelope(resolved, diagnostics) {
|
|
36
|
+
if (resolved.kind !== "builder") return;
|
|
37
|
+
const root = resolved.rootAst;
|
|
38
|
+
for (const prop of root.properties) {
|
|
39
|
+
const key = prop.key.value;
|
|
40
|
+
if (!BUILDER_ROOT_KEYS.has(key)) {
|
|
41
|
+
diagnostics.push({
|
|
42
|
+
message: `\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u4E0D\u8BA4\u8BC6\u7684\u9876\u5C42\u5B57\u6BB5 "${key}"\uFF08\u4EC5\u652F\u6301 name / dsl / variables\uFF09`,
|
|
43
|
+
severity: "warning",
|
|
44
|
+
range: prop.key.range,
|
|
45
|
+
path: "/" + key,
|
|
46
|
+
code: "builder-unknown-key"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const nameNode = getProp(root, "name");
|
|
51
|
+
if (nameNode && nameNode.type !== "string") {
|
|
34
52
|
diagnostics.push({
|
|
35
|
-
message:
|
|
53
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "name" \u5E94\u4E3A\u5B57\u7B26\u4E32',
|
|
36
54
|
severity: "error",
|
|
37
|
-
range:
|
|
38
|
-
path: "/"
|
|
55
|
+
range: nameNode.range,
|
|
56
|
+
path: "/name",
|
|
57
|
+
code: "builder-envelope"
|
|
39
58
|
});
|
|
40
59
|
}
|
|
41
|
-
|
|
42
|
-
|
|
60
|
+
const variablesNode = getProp(root, "variables");
|
|
61
|
+
if (variablesNode && variablesNode.type !== "array") {
|
|
62
|
+
diagnostics.push({
|
|
63
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "variables" \u5E94\u4E3A\u6570\u7EC4',
|
|
64
|
+
severity: "error",
|
|
65
|
+
range: variablesNode.range,
|
|
66
|
+
path: "/variables",
|
|
67
|
+
code: "builder-envelope"
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function validateCardAgainstSchema(cardAst, cardData, pathPrefix, options, diagnostics) {
|
|
72
|
+
const checkResult = FeishuCardV2Schema.safeParse(cardData);
|
|
43
73
|
if (!checkResult.success) {
|
|
44
74
|
for (const issue of checkResult.error.issues) {
|
|
45
|
-
const node = findNodeAtPointer(
|
|
46
|
-
const range = node ? node.range : { start:
|
|
75
|
+
const node = findNodeAtPointer(cardAst, issue.path);
|
|
76
|
+
const range = node ? node.range : { start: cardAst.range.start, end: cardAst.range.start };
|
|
47
77
|
diagnostics.push({
|
|
48
78
|
message: issue.message,
|
|
49
79
|
severity: "error",
|
|
50
80
|
range,
|
|
51
|
-
path: pointerToString(issue.path)
|
|
81
|
+
path: joinCardPointer(pathPrefix, pointerToString(issue.path))
|
|
52
82
|
});
|
|
53
83
|
}
|
|
54
84
|
}
|
|
55
85
|
const deprecated = { ...DEPRECATED_PROPS, ...options.deprecatedProps ?? {} };
|
|
56
|
-
for (const prop of
|
|
86
|
+
for (const prop of cardAst.properties) {
|
|
57
87
|
const hint = deprecated[prop.key.value];
|
|
58
88
|
if (hint) {
|
|
59
89
|
diagnostics.push({
|
|
60
90
|
message: `\u5E9F\u5F03\u5C5E\u6027 "${prop.key.value}": ${hint}`,
|
|
61
91
|
severity: "warning",
|
|
62
92
|
range: prop.key.range,
|
|
63
|
-
path: "/" + prop.key.value,
|
|
93
|
+
path: joinCardPointer(pathPrefix, "/" + prop.key.value),
|
|
64
94
|
code: "deprecated-prop"
|
|
65
95
|
});
|
|
66
96
|
}
|
|
67
97
|
}
|
|
98
|
+
}
|
|
99
|
+
function validateAst(result, options = {}) {
|
|
100
|
+
const diagnostics = [];
|
|
101
|
+
for (const e of result.errors) {
|
|
102
|
+
diagnostics.push({
|
|
103
|
+
message: `JSON \u8BED\u6CD5\u9519\u8BEF: ${e.message}`,
|
|
104
|
+
severity: "error",
|
|
105
|
+
range: e.range,
|
|
106
|
+
path: "/"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (!result.ast || result.data === void 0) return diagnostics;
|
|
110
|
+
const resolved = resolveCardDocument(result);
|
|
111
|
+
if (!resolved) return diagnostics;
|
|
112
|
+
validateBuilderEnvelope(resolved, diagnostics);
|
|
113
|
+
validateCardAgainstSchema(
|
|
114
|
+
resolved.cardAst,
|
|
115
|
+
resolved.cardData,
|
|
116
|
+
resolved.pathPrefix,
|
|
117
|
+
options,
|
|
118
|
+
diagnostics
|
|
119
|
+
);
|
|
68
120
|
return diagnostics;
|
|
69
121
|
}
|
|
70
122
|
function validate(source, options) {
|
|
71
123
|
return validateAst(parse(source), options);
|
|
72
124
|
}
|
|
73
125
|
function validateData(data) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
126
|
+
const ZERO = {
|
|
127
|
+
start: { offset: 0, line: 1, column: 1 },
|
|
128
|
+
end: { offset: 0, line: 1, column: 1 }
|
|
129
|
+
};
|
|
130
|
+
const diagnostics = [];
|
|
131
|
+
if (isBuilderDocument(data)) {
|
|
132
|
+
const rec = data;
|
|
133
|
+
for (const key of Object.keys(rec)) {
|
|
134
|
+
if (!BUILDER_ROOT_KEYS.has(key)) {
|
|
135
|
+
diagnostics.push({
|
|
136
|
+
message: `\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u4E0D\u8BA4\u8BC6\u7684\u9876\u5C42\u5B57\u6BB5 "${key}"\uFF08\u4EC5\u652F\u6301 name / dsl / variables\uFF09`,
|
|
137
|
+
severity: "warning",
|
|
138
|
+
range: ZERO,
|
|
139
|
+
path: "/" + key,
|
|
140
|
+
code: "builder-unknown-key"
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if ("name" in rec && typeof rec.name !== "string") {
|
|
145
|
+
diagnostics.push({
|
|
146
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "name" \u5E94\u4E3A\u5B57\u7B26\u4E32',
|
|
147
|
+
severity: "error",
|
|
148
|
+
range: ZERO,
|
|
149
|
+
path: "/name",
|
|
150
|
+
code: "builder-envelope"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if ("variables" in rec && !Array.isArray(rec.variables)) {
|
|
154
|
+
diagnostics.push({
|
|
155
|
+
message: '\u642D\u5EFA\u5DE5\u5177\u6587\u6863\u7684 "variables" \u5E94\u4E3A\u6570\u7EC4',
|
|
156
|
+
severity: "error",
|
|
157
|
+
range: ZERO,
|
|
158
|
+
path: "/variables",
|
|
159
|
+
code: "builder-envelope"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const card = unwrapCardData(data);
|
|
164
|
+
const checkResult = FeishuCardV2Schema.safeParse(card);
|
|
165
|
+
if (!checkResult.success) {
|
|
166
|
+
const prefix = isBuilderDocument(data) ? "/dsl" : "";
|
|
167
|
+
for (const issue of checkResult.error.issues) {
|
|
168
|
+
diagnostics.push({
|
|
169
|
+
message: issue.message,
|
|
170
|
+
severity: "error",
|
|
171
|
+
range: ZERO,
|
|
172
|
+
path: joinCardPointer(prefix, pointerToString(issue.path))
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return diagnostics;
|
|
85
177
|
}
|
|
86
178
|
|
|
87
179
|
export { findNodeAtPointer, validate, validateAst, validateData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-feishu-card/validator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "对比 AST 与 Schema 2.0,输出精确定位到源码字符级的诊断信息",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@open-feishu-card/parser": "0.1.
|
|
21
|
-
"@open-feishu-card/schema": "0.1.
|
|
20
|
+
"@open-feishu-card/parser": "0.1.3",
|
|
21
|
+
"@open-feishu-card/schema": "0.1.5"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"tsup": "^8.3.5",
|