@open-feishu-card/adapter 0.3.18 → 0.3.19
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 +97 -50
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -50
- package/dist/raw-to-dsl.d.ts +19 -2
- package/dist/raw-to-dsl.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1013,14 +1013,15 @@ function behaviorsToActions(behaviors) {
|
|
|
1013
1013
|
for (const b of behaviors) {
|
|
1014
1014
|
if (!isRecord2(b)) continue;
|
|
1015
1015
|
const type = typeof b.type === "string" ? b.type : "open_url";
|
|
1016
|
-
if (type === "callback") {
|
|
1017
|
-
|
|
1016
|
+
if (type === "callback" || type === "action_request") {
|
|
1017
|
+
const value = isRecord2(b.value) || typeof b.value === "string" ? b.value : {};
|
|
1018
|
+
out.push({ type: "action_request", action: { value } });
|
|
1018
1019
|
continue;
|
|
1019
1020
|
}
|
|
1020
1021
|
const action = { url: normalizeUrl(b.default_url) };
|
|
1021
|
-
if (typeof b.pc_url === "string" && b.pc_url) action.
|
|
1022
|
-
if (typeof b.ios_url === "string" && b.ios_url) action.
|
|
1023
|
-
if (typeof b.android_url === "string" && b.android_url) action.
|
|
1022
|
+
if (typeof b.pc_url === "string" && b.pc_url) action.pc_url = b.pc_url;
|
|
1023
|
+
if (typeof b.ios_url === "string" && b.ios_url) action.ios_url = b.ios_url;
|
|
1024
|
+
if (typeof b.android_url === "string" && b.android_url) action.android_url = b.android_url;
|
|
1024
1025
|
out.push({ type, action });
|
|
1025
1026
|
}
|
|
1026
1027
|
return out;
|
|
@@ -1028,10 +1029,10 @@ function behaviorsToActions(behaviors) {
|
|
|
1028
1029
|
function multiUrlToOpenUrlAction(multi) {
|
|
1029
1030
|
const url = typeof multi.url === "string" ? multi.url : typeof multi.default_url === "string" ? multi.default_url : "";
|
|
1030
1031
|
const action = { url };
|
|
1031
|
-
if (typeof multi.pc_url === "string" && multi.pc_url) action.
|
|
1032
|
-
if (typeof multi.ios_url === "string" && multi.ios_url) action.
|
|
1032
|
+
if (typeof multi.pc_url === "string" && multi.pc_url) action.pc_url = multi.pc_url;
|
|
1033
|
+
if (typeof multi.ios_url === "string" && multi.ios_url) action.ios_url = multi.ios_url;
|
|
1033
1034
|
if (typeof multi.android_url === "string" && multi.android_url) {
|
|
1034
|
-
action.
|
|
1035
|
+
action.android_url = multi.android_url;
|
|
1035
1036
|
}
|
|
1036
1037
|
return { type: "open_url", action };
|
|
1037
1038
|
}
|
|
@@ -1343,7 +1344,7 @@ function isRawCardEnvelope(value) {
|
|
|
1343
1344
|
const v = value;
|
|
1344
1345
|
return typeof v.json_card === "string" && typeof v.card_schema === "number";
|
|
1345
1346
|
}
|
|
1346
|
-
function rawCardToDsl(envelope) {
|
|
1347
|
+
function rawCardToDsl(envelope, options) {
|
|
1347
1348
|
if (!isRawCardEnvelope(envelope)) return envelope;
|
|
1348
1349
|
const env = envelope;
|
|
1349
1350
|
let inner;
|
|
@@ -1354,7 +1355,8 @@ function rawCardToDsl(envelope) {
|
|
|
1354
1355
|
}
|
|
1355
1356
|
const ctx = makeCtx({
|
|
1356
1357
|
images: env.json_attachment?.images ?? {},
|
|
1357
|
-
atUsers: env.json_attachment?.at_users ?? {}
|
|
1358
|
+
atUsers: env.json_attachment?.at_users ?? {},
|
|
1359
|
+
onWarn: options?.onWarn
|
|
1358
1360
|
});
|
|
1359
1361
|
return convertRoot(inner, ctx);
|
|
1360
1362
|
}
|
|
@@ -1362,7 +1364,8 @@ function makeCtx(partial) {
|
|
|
1362
1364
|
return {
|
|
1363
1365
|
images: partial?.images ?? {},
|
|
1364
1366
|
atUsers: partial?.atUsers ?? {},
|
|
1365
|
-
colors: createColorRegistry()
|
|
1367
|
+
colors: createColorRegistry(),
|
|
1368
|
+
onWarn: partial?.onWarn
|
|
1366
1369
|
};
|
|
1367
1370
|
}
|
|
1368
1371
|
var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -1786,6 +1789,67 @@ function openUrlFieldsToMultiUrl(fields) {
|
|
|
1786
1789
|
if (fields.android_url) multi.android_url = fields.android_url;
|
|
1787
1790
|
return multi;
|
|
1788
1791
|
}
|
|
1792
|
+
var RAW_CALLBACK_TYPES = /* @__PURE__ */ new Set(["callback", "action_request"]);
|
|
1793
|
+
function callbackValueFromRaw(inner, ownerTag, warn) {
|
|
1794
|
+
const v = inner.value;
|
|
1795
|
+
if (isRecord3(v)) return v;
|
|
1796
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
1797
|
+
const hadObjectValue = inner.isValueObjectType === true;
|
|
1798
|
+
const hasActionId = typeof inner.actionID === "string" && inner.actionID.length > 0;
|
|
1799
|
+
if (hadObjectValue) {
|
|
1800
|
+
warn?.({
|
|
1801
|
+
code: "callback_payload_cleared",
|
|
1802
|
+
ownerTag,
|
|
1803
|
+
message: `\u670D\u52A1\u7AEF\u628A\u56DE\u8C03\u5BF9\u8C61\u8F7D\u8377\u6362\u6210\u4E86 actionID \u5F15\u7528${hasActionId ? ` (${String(inner.actionID)})` : ""}\uFF0C\u6295\u5F71\u51FA\u7684 behaviors.value \u662F\u7A7A\u5BF9\u8C61\uFF0C\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\u3002\u4FDD\u4F4F\u53C2\u6570\u9700\u53D1\u9001\u4FA7\u7559\u5B58\u539F\u59CB DSL\u3002`
|
|
1804
|
+
});
|
|
1805
|
+
return {};
|
|
1806
|
+
}
|
|
1807
|
+
if (hasActionId) {
|
|
1808
|
+
warn?.({
|
|
1809
|
+
code: "callback_payload_cleared",
|
|
1810
|
+
ownerTag,
|
|
1811
|
+
message: `\u670D\u52A1\u7AEF\u628A\u56DE\u8C03\u8F7D\u8377\u6362\u6210\u4E86 actionID \u5F15\u7528 (${String(inner.actionID)})\uFF0C\u539F\u503C\u5DF2\u4E0D\u53EF\u89C1\uFF1B\u6295\u5F71\u51FA\u7684 behaviors.value \u4FDD\u7559\u7A7A\u5B57\u7B26\u4E32\uFF0C\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\u3002`
|
|
1812
|
+
});
|
|
1813
|
+
return "";
|
|
1814
|
+
}
|
|
1815
|
+
if (v === void 0) {
|
|
1816
|
+
warn?.({
|
|
1817
|
+
code: "callback_payload_cleared",
|
|
1818
|
+
ownerTag,
|
|
1819
|
+
message: "\u56DE\u8C03 action \u6CA1\u6709 value\uFF08\u670D\u52A1\u7AEF\u56DE\u8BFB\u5F62\u6001\uFF09\uFF0C\u6295\u5F71\u4E3A behaviors.value: {}\uFF1B\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\uFF0C\u9700\u53D1\u9001\u4FA7\u7559\u5B58\u539F\u59CB DSL\u3002"
|
|
1820
|
+
});
|
|
1821
|
+
return {};
|
|
1822
|
+
}
|
|
1823
|
+
return "";
|
|
1824
|
+
}
|
|
1825
|
+
function actionEntryToBehavior(entry, ownerTag, ctx, onWarn = ctx.onWarn) {
|
|
1826
|
+
if (!isRecord3(entry)) return void 0;
|
|
1827
|
+
const inner = isRecord3(entry.action) ? entry.action : {};
|
|
1828
|
+
const type = typeof entry.type === "string" ? entry.type : void 0;
|
|
1829
|
+
if (type === "open_url") {
|
|
1830
|
+
const fields = projectOpenUrlFields(inner);
|
|
1831
|
+
return fields ? { type: "open_url", ...fields } : void 0;
|
|
1832
|
+
}
|
|
1833
|
+
if (type && RAW_CALLBACK_TYPES.has(type)) {
|
|
1834
|
+
return {
|
|
1835
|
+
type: "callback",
|
|
1836
|
+
value: callbackValueFromRaw(inner, ownerTag, onWarn ?? void 0)
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
const kept = {};
|
|
1840
|
+
for (const [k, v] of Object.entries(entry)) {
|
|
1841
|
+
if (k === "type" || k === "action") continue;
|
|
1842
|
+
kept[snake(k)] = convertGeneric(v, ctx);
|
|
1843
|
+
}
|
|
1844
|
+
if (type) kept.type = type;
|
|
1845
|
+
if (Object.keys(inner).length > 0) kept.action = convertGeneric(inner, ctx);
|
|
1846
|
+
onWarn?.({
|
|
1847
|
+
code: "unknown_action_type",
|
|
1848
|
+
ownerTag,
|
|
1849
|
+
message: `\u672A\u8BC6\u522B\u7684 action type: ${type ?? "(\u65E0 type)"}\uFF1B\u5DF2\u6309\u539F\u6837\u4FDD\u7559\u8FDB behaviors\uFF0C\u53D1\u5F80\u98DE\u4E66\u524D\u8BF7\u6E05\u6D17\u3002`
|
|
1850
|
+
});
|
|
1851
|
+
return kept;
|
|
1852
|
+
}
|
|
1789
1853
|
function convertProperty(property, ownerTag, ctx) {
|
|
1790
1854
|
const out = {};
|
|
1791
1855
|
const siblings = {
|
|
@@ -1923,19 +1987,7 @@ function convertField(rawKey, rawValue, ownerTag, ctx, siblings = {}) {
|
|
|
1923
1987
|
}
|
|
1924
1988
|
if (ownerTag === "button" && key === "action_type") return DROP;
|
|
1925
1989
|
if (ownerTag === "button" && key === "actions" && Array.isArray(rawValue)) {
|
|
1926
|
-
const behaviors =
|
|
1927
|
-
for (const a of rawValue) {
|
|
1928
|
-
if (!isRecord3(a)) continue;
|
|
1929
|
-
const inner = isRecord3(a.action) ? a.action : {};
|
|
1930
|
-
const t = typeof a.type === "string" ? a.type : void 0;
|
|
1931
|
-
if (t === "callback") {
|
|
1932
|
-
behaviors.push({ type: "callback", value: isRecord3(inner.value) ? inner.value : {} });
|
|
1933
|
-
continue;
|
|
1934
|
-
}
|
|
1935
|
-
if (t !== "open_url") continue;
|
|
1936
|
-
const fields = projectOpenUrlFields(inner);
|
|
1937
|
-
if (fields) behaviors.push({ type: "open_url", ...fields });
|
|
1938
|
-
}
|
|
1990
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx)).filter((b) => b !== void 0);
|
|
1939
1991
|
if (behaviors.length === 0) return DROP;
|
|
1940
1992
|
if (siblings.buttonActionType === "link" && behaviors.length === 1 && behaviors[0]?.type === "open_url") {
|
|
1941
1993
|
const only = behaviors[0];
|
|
@@ -1945,29 +1997,23 @@ function convertField(rawKey, rawValue, ownerTag, ctx, siblings = {}) {
|
|
|
1945
1997
|
return ["behaviors", behaviors];
|
|
1946
1998
|
}
|
|
1947
1999
|
if (ownerTag === "interactive_container" && key === "actions" && Array.isArray(rawValue)) {
|
|
1948
|
-
const behaviors = rawValue.map((a) =>
|
|
1949
|
-
if (!isRecord3(a)) return void 0;
|
|
1950
|
-
const inner = isRecord3(a.action) ? a.action : {};
|
|
1951
|
-
const t = typeof a.type === "string" ? a.type : void 0;
|
|
1952
|
-
if (t === "open_url") {
|
|
1953
|
-
const fields = projectOpenUrlFields(inner);
|
|
1954
|
-
return fields ? { type: "open_url", ...fields } : void 0;
|
|
1955
|
-
}
|
|
1956
|
-
if (t === "callback") {
|
|
1957
|
-
return { type: "callback", value: inner.value ?? {} };
|
|
1958
|
-
}
|
|
1959
|
-
return void 0;
|
|
1960
|
-
}).filter((b) => b !== void 0);
|
|
2000
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx)).filter((b) => b !== void 0);
|
|
1961
2001
|
if (behaviors.length === 0) return DROP;
|
|
1962
2002
|
return ["behaviors", behaviors];
|
|
1963
2003
|
}
|
|
1964
2004
|
if ((ownerTag === "column_set" || ownerTag === "column") && key === "actions" && Array.isArray(rawValue)) {
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2005
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx, null)).filter((b) => b !== void 0);
|
|
2006
|
+
const openUrl = behaviors.find((b) => b.type === "open_url");
|
|
2007
|
+
const unrepresentable = behaviors.filter((b) => b.type !== "open_url");
|
|
2008
|
+
if (unrepresentable.length > 0) {
|
|
2009
|
+
ctx.onWarn?.({
|
|
2010
|
+
code: "unrepresentable_action",
|
|
2011
|
+
ownerTag,
|
|
2012
|
+
message: `${ownerTag} \u7684 actions \u542B ${unrepresentable.map((b) => String(b.type)).join(" / ")}\uFF0C\u516C\u5F00 DSL \u7684 ColumnAction \u53EA\u6709 multi_url\uFF0C\u65E0\u6CD5\u6295\u5F71\uFF1B\u8BE5 action \u4E0D\u4F1A\u51FA\u73B0\u5728 DSL \u91CC\u3002`
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
if (openUrl) {
|
|
2016
|
+
const { type: _t, ...fields } = openUrl;
|
|
1971
2017
|
return ["action", { multi_url: openUrlFieldsToMultiUrl(fields) }];
|
|
1972
2018
|
}
|
|
1973
2019
|
return DROP;
|
|
@@ -2449,11 +2495,11 @@ function pixelOf(side) {
|
|
|
2449
2495
|
function snake(key) {
|
|
2450
2496
|
return key.replace(/ID$/g, "_id").replace(/URL$/g, "_url").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
|
|
2451
2497
|
}
|
|
2452
|
-
function rawToDsl(raw) {
|
|
2453
|
-
if (isRawCardEnvelope(raw)) return rawCardToDsl(raw);
|
|
2498
|
+
function rawToDsl(raw, options) {
|
|
2499
|
+
if (isRawCardEnvelope(raw)) return rawCardToDsl(raw, options);
|
|
2454
2500
|
if (typeof raw === "string") {
|
|
2455
2501
|
try {
|
|
2456
|
-
return rawToDsl(JSON.parse(raw));
|
|
2502
|
+
return rawToDsl(JSON.parse(raw), options);
|
|
2457
2503
|
} catch {
|
|
2458
2504
|
return raw;
|
|
2459
2505
|
}
|
|
@@ -2471,19 +2517,20 @@ function rawToDsl(raw) {
|
|
|
2471
2517
|
const attachment = isRecord3(raw.json_attachment) ? raw.json_attachment : {};
|
|
2472
2518
|
const ctx = makeCtx({
|
|
2473
2519
|
images: isRecord3(attachment.images) ? attachment.images : {},
|
|
2474
|
-
atUsers: isRecord3(attachment.at_users) ? attachment.at_users : {}
|
|
2520
|
+
atUsers: isRecord3(attachment.at_users) ? attachment.at_users : {},
|
|
2521
|
+
onWarn: options?.onWarn
|
|
2475
2522
|
});
|
|
2476
2523
|
return convertRoot(inner, ctx);
|
|
2477
2524
|
}
|
|
2478
2525
|
if (isRecord3(raw.card)) {
|
|
2479
2526
|
const card = raw.card;
|
|
2480
2527
|
if (typeof card.json_card === "string" || isRecord3(card.json_card)) {
|
|
2481
|
-
return rawToDsl(card);
|
|
2528
|
+
return rawToDsl(card, options);
|
|
2482
2529
|
}
|
|
2483
|
-
return convertRoot(card, makeCtx());
|
|
2530
|
+
return convertRoot(card, makeCtx({ onWarn: options?.onWarn }));
|
|
2484
2531
|
}
|
|
2485
2532
|
if ("body" in raw || "header" in raw || "schema" in raw) {
|
|
2486
|
-
return convertRoot(raw, makeCtx());
|
|
2533
|
+
return convertRoot(raw, makeCtx({ onWarn: options?.onWarn }));
|
|
2487
2534
|
}
|
|
2488
2535
|
return raw;
|
|
2489
2536
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { dslToRaw } from './dsl-to-raw.js';
|
|
10
10
|
export { rawToDsl, rawCardToDsl, isRawCardEnvelope, degradeUnknown, } from './raw-to-dsl.js';
|
|
11
|
+
export type { RawToDslOptions, RawToDslWarning } from './raw-to-dsl.js';
|
|
11
12
|
export { normalizeStoredCardColors, createColorRegistry, registerColorEntry } from './normalize-stored-colors.js';
|
|
12
13
|
export type { CustomColorEntry } from './normalize-stored-colors.js';
|
|
13
14
|
export { readThemeColorLight, readThemeColorDark, resolveCustomBackgroundLight, resolveCustomBorderLight, resolveTextStyleColor, resolveTextStyleCustomColorPair, themePairToColorEntry, isCustomHexColor, } from './custom-colors.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClH,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,+BAA+B,EAC/B,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClH,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,+BAA+B,EAC/B,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1011,14 +1011,15 @@ function behaviorsToActions(behaviors) {
|
|
|
1011
1011
|
for (const b of behaviors) {
|
|
1012
1012
|
if (!isRecord2(b)) continue;
|
|
1013
1013
|
const type = typeof b.type === "string" ? b.type : "open_url";
|
|
1014
|
-
if (type === "callback") {
|
|
1015
|
-
|
|
1014
|
+
if (type === "callback" || type === "action_request") {
|
|
1015
|
+
const value = isRecord2(b.value) || typeof b.value === "string" ? b.value : {};
|
|
1016
|
+
out.push({ type: "action_request", action: { value } });
|
|
1016
1017
|
continue;
|
|
1017
1018
|
}
|
|
1018
1019
|
const action = { url: normalizeUrl(b.default_url) };
|
|
1019
|
-
if (typeof b.pc_url === "string" && b.pc_url) action.
|
|
1020
|
-
if (typeof b.ios_url === "string" && b.ios_url) action.
|
|
1021
|
-
if (typeof b.android_url === "string" && b.android_url) action.
|
|
1020
|
+
if (typeof b.pc_url === "string" && b.pc_url) action.pc_url = b.pc_url;
|
|
1021
|
+
if (typeof b.ios_url === "string" && b.ios_url) action.ios_url = b.ios_url;
|
|
1022
|
+
if (typeof b.android_url === "string" && b.android_url) action.android_url = b.android_url;
|
|
1022
1023
|
out.push({ type, action });
|
|
1023
1024
|
}
|
|
1024
1025
|
return out;
|
|
@@ -1026,10 +1027,10 @@ function behaviorsToActions(behaviors) {
|
|
|
1026
1027
|
function multiUrlToOpenUrlAction(multi) {
|
|
1027
1028
|
const url = typeof multi.url === "string" ? multi.url : typeof multi.default_url === "string" ? multi.default_url : "";
|
|
1028
1029
|
const action = { url };
|
|
1029
|
-
if (typeof multi.pc_url === "string" && multi.pc_url) action.
|
|
1030
|
-
if (typeof multi.ios_url === "string" && multi.ios_url) action.
|
|
1030
|
+
if (typeof multi.pc_url === "string" && multi.pc_url) action.pc_url = multi.pc_url;
|
|
1031
|
+
if (typeof multi.ios_url === "string" && multi.ios_url) action.ios_url = multi.ios_url;
|
|
1031
1032
|
if (typeof multi.android_url === "string" && multi.android_url) {
|
|
1032
|
-
action.
|
|
1033
|
+
action.android_url = multi.android_url;
|
|
1033
1034
|
}
|
|
1034
1035
|
return { type: "open_url", action };
|
|
1035
1036
|
}
|
|
@@ -1341,7 +1342,7 @@ function isRawCardEnvelope(value) {
|
|
|
1341
1342
|
const v = value;
|
|
1342
1343
|
return typeof v.json_card === "string" && typeof v.card_schema === "number";
|
|
1343
1344
|
}
|
|
1344
|
-
function rawCardToDsl(envelope) {
|
|
1345
|
+
function rawCardToDsl(envelope, options) {
|
|
1345
1346
|
if (!isRawCardEnvelope(envelope)) return envelope;
|
|
1346
1347
|
const env = envelope;
|
|
1347
1348
|
let inner;
|
|
@@ -1352,7 +1353,8 @@ function rawCardToDsl(envelope) {
|
|
|
1352
1353
|
}
|
|
1353
1354
|
const ctx = makeCtx({
|
|
1354
1355
|
images: env.json_attachment?.images ?? {},
|
|
1355
|
-
atUsers: env.json_attachment?.at_users ?? {}
|
|
1356
|
+
atUsers: env.json_attachment?.at_users ?? {},
|
|
1357
|
+
onWarn: options?.onWarn
|
|
1356
1358
|
});
|
|
1357
1359
|
return convertRoot(inner, ctx);
|
|
1358
1360
|
}
|
|
@@ -1360,7 +1362,8 @@ function makeCtx(partial) {
|
|
|
1360
1362
|
return {
|
|
1361
1363
|
images: partial?.images ?? {},
|
|
1362
1364
|
atUsers: partial?.atUsers ?? {},
|
|
1363
|
-
colors: createColorRegistry()
|
|
1365
|
+
colors: createColorRegistry(),
|
|
1366
|
+
onWarn: partial?.onWarn
|
|
1364
1367
|
};
|
|
1365
1368
|
}
|
|
1366
1369
|
var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -1784,6 +1787,67 @@ function openUrlFieldsToMultiUrl(fields) {
|
|
|
1784
1787
|
if (fields.android_url) multi.android_url = fields.android_url;
|
|
1785
1788
|
return multi;
|
|
1786
1789
|
}
|
|
1790
|
+
var RAW_CALLBACK_TYPES = /* @__PURE__ */ new Set(["callback", "action_request"]);
|
|
1791
|
+
function callbackValueFromRaw(inner, ownerTag, warn) {
|
|
1792
|
+
const v = inner.value;
|
|
1793
|
+
if (isRecord3(v)) return v;
|
|
1794
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
1795
|
+
const hadObjectValue = inner.isValueObjectType === true;
|
|
1796
|
+
const hasActionId = typeof inner.actionID === "string" && inner.actionID.length > 0;
|
|
1797
|
+
if (hadObjectValue) {
|
|
1798
|
+
warn?.({
|
|
1799
|
+
code: "callback_payload_cleared",
|
|
1800
|
+
ownerTag,
|
|
1801
|
+
message: `\u670D\u52A1\u7AEF\u628A\u56DE\u8C03\u5BF9\u8C61\u8F7D\u8377\u6362\u6210\u4E86 actionID \u5F15\u7528${hasActionId ? ` (${String(inner.actionID)})` : ""}\uFF0C\u6295\u5F71\u51FA\u7684 behaviors.value \u662F\u7A7A\u5BF9\u8C61\uFF0C\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\u3002\u4FDD\u4F4F\u53C2\u6570\u9700\u53D1\u9001\u4FA7\u7559\u5B58\u539F\u59CB DSL\u3002`
|
|
1802
|
+
});
|
|
1803
|
+
return {};
|
|
1804
|
+
}
|
|
1805
|
+
if (hasActionId) {
|
|
1806
|
+
warn?.({
|
|
1807
|
+
code: "callback_payload_cleared",
|
|
1808
|
+
ownerTag,
|
|
1809
|
+
message: `\u670D\u52A1\u7AEF\u628A\u56DE\u8C03\u8F7D\u8377\u6362\u6210\u4E86 actionID \u5F15\u7528 (${String(inner.actionID)})\uFF0C\u539F\u503C\u5DF2\u4E0D\u53EF\u89C1\uFF1B\u6295\u5F71\u51FA\u7684 behaviors.value \u4FDD\u7559\u7A7A\u5B57\u7B26\u4E32\uFF0C\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\u3002`
|
|
1810
|
+
});
|
|
1811
|
+
return "";
|
|
1812
|
+
}
|
|
1813
|
+
if (v === void 0) {
|
|
1814
|
+
warn?.({
|
|
1815
|
+
code: "callback_payload_cleared",
|
|
1816
|
+
ownerTag,
|
|
1817
|
+
message: "\u56DE\u8C03 action \u6CA1\u6709 value\uFF08\u670D\u52A1\u7AEF\u56DE\u8BFB\u5F62\u6001\uFF09\uFF0C\u6295\u5F71\u4E3A behaviors.value: {}\uFF1B\u70B9\u51FB\u56DE\u8C03\u62FF\u4E0D\u5230\u539F\u59CB\u53C2\u6570\uFF0C\u9700\u53D1\u9001\u4FA7\u7559\u5B58\u539F\u59CB DSL\u3002"
|
|
1818
|
+
});
|
|
1819
|
+
return {};
|
|
1820
|
+
}
|
|
1821
|
+
return "";
|
|
1822
|
+
}
|
|
1823
|
+
function actionEntryToBehavior(entry, ownerTag, ctx, onWarn = ctx.onWarn) {
|
|
1824
|
+
if (!isRecord3(entry)) return void 0;
|
|
1825
|
+
const inner = isRecord3(entry.action) ? entry.action : {};
|
|
1826
|
+
const type = typeof entry.type === "string" ? entry.type : void 0;
|
|
1827
|
+
if (type === "open_url") {
|
|
1828
|
+
const fields = projectOpenUrlFields(inner);
|
|
1829
|
+
return fields ? { type: "open_url", ...fields } : void 0;
|
|
1830
|
+
}
|
|
1831
|
+
if (type && RAW_CALLBACK_TYPES.has(type)) {
|
|
1832
|
+
return {
|
|
1833
|
+
type: "callback",
|
|
1834
|
+
value: callbackValueFromRaw(inner, ownerTag, onWarn ?? void 0)
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
const kept = {};
|
|
1838
|
+
for (const [k, v] of Object.entries(entry)) {
|
|
1839
|
+
if (k === "type" || k === "action") continue;
|
|
1840
|
+
kept[snake(k)] = convertGeneric(v, ctx);
|
|
1841
|
+
}
|
|
1842
|
+
if (type) kept.type = type;
|
|
1843
|
+
if (Object.keys(inner).length > 0) kept.action = convertGeneric(inner, ctx);
|
|
1844
|
+
onWarn?.({
|
|
1845
|
+
code: "unknown_action_type",
|
|
1846
|
+
ownerTag,
|
|
1847
|
+
message: `\u672A\u8BC6\u522B\u7684 action type: ${type ?? "(\u65E0 type)"}\uFF1B\u5DF2\u6309\u539F\u6837\u4FDD\u7559\u8FDB behaviors\uFF0C\u53D1\u5F80\u98DE\u4E66\u524D\u8BF7\u6E05\u6D17\u3002`
|
|
1848
|
+
});
|
|
1849
|
+
return kept;
|
|
1850
|
+
}
|
|
1787
1851
|
function convertProperty(property, ownerTag, ctx) {
|
|
1788
1852
|
const out = {};
|
|
1789
1853
|
const siblings = {
|
|
@@ -1921,19 +1985,7 @@ function convertField(rawKey, rawValue, ownerTag, ctx, siblings = {}) {
|
|
|
1921
1985
|
}
|
|
1922
1986
|
if (ownerTag === "button" && key === "action_type") return DROP;
|
|
1923
1987
|
if (ownerTag === "button" && key === "actions" && Array.isArray(rawValue)) {
|
|
1924
|
-
const behaviors =
|
|
1925
|
-
for (const a of rawValue) {
|
|
1926
|
-
if (!isRecord3(a)) continue;
|
|
1927
|
-
const inner = isRecord3(a.action) ? a.action : {};
|
|
1928
|
-
const t = typeof a.type === "string" ? a.type : void 0;
|
|
1929
|
-
if (t === "callback") {
|
|
1930
|
-
behaviors.push({ type: "callback", value: isRecord3(inner.value) ? inner.value : {} });
|
|
1931
|
-
continue;
|
|
1932
|
-
}
|
|
1933
|
-
if (t !== "open_url") continue;
|
|
1934
|
-
const fields = projectOpenUrlFields(inner);
|
|
1935
|
-
if (fields) behaviors.push({ type: "open_url", ...fields });
|
|
1936
|
-
}
|
|
1988
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx)).filter((b) => b !== void 0);
|
|
1937
1989
|
if (behaviors.length === 0) return DROP;
|
|
1938
1990
|
if (siblings.buttonActionType === "link" && behaviors.length === 1 && behaviors[0]?.type === "open_url") {
|
|
1939
1991
|
const only = behaviors[0];
|
|
@@ -1943,29 +1995,23 @@ function convertField(rawKey, rawValue, ownerTag, ctx, siblings = {}) {
|
|
|
1943
1995
|
return ["behaviors", behaviors];
|
|
1944
1996
|
}
|
|
1945
1997
|
if (ownerTag === "interactive_container" && key === "actions" && Array.isArray(rawValue)) {
|
|
1946
|
-
const behaviors = rawValue.map((a) =>
|
|
1947
|
-
if (!isRecord3(a)) return void 0;
|
|
1948
|
-
const inner = isRecord3(a.action) ? a.action : {};
|
|
1949
|
-
const t = typeof a.type === "string" ? a.type : void 0;
|
|
1950
|
-
if (t === "open_url") {
|
|
1951
|
-
const fields = projectOpenUrlFields(inner);
|
|
1952
|
-
return fields ? { type: "open_url", ...fields } : void 0;
|
|
1953
|
-
}
|
|
1954
|
-
if (t === "callback") {
|
|
1955
|
-
return { type: "callback", value: inner.value ?? {} };
|
|
1956
|
-
}
|
|
1957
|
-
return void 0;
|
|
1958
|
-
}).filter((b) => b !== void 0);
|
|
1998
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx)).filter((b) => b !== void 0);
|
|
1959
1999
|
if (behaviors.length === 0) return DROP;
|
|
1960
2000
|
return ["behaviors", behaviors];
|
|
1961
2001
|
}
|
|
1962
2002
|
if ((ownerTag === "column_set" || ownerTag === "column") && key === "actions" && Array.isArray(rawValue)) {
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2003
|
+
const behaviors = rawValue.map((a) => actionEntryToBehavior(a, ownerTag, ctx, null)).filter((b) => b !== void 0);
|
|
2004
|
+
const openUrl = behaviors.find((b) => b.type === "open_url");
|
|
2005
|
+
const unrepresentable = behaviors.filter((b) => b.type !== "open_url");
|
|
2006
|
+
if (unrepresentable.length > 0) {
|
|
2007
|
+
ctx.onWarn?.({
|
|
2008
|
+
code: "unrepresentable_action",
|
|
2009
|
+
ownerTag,
|
|
2010
|
+
message: `${ownerTag} \u7684 actions \u542B ${unrepresentable.map((b) => String(b.type)).join(" / ")}\uFF0C\u516C\u5F00 DSL \u7684 ColumnAction \u53EA\u6709 multi_url\uFF0C\u65E0\u6CD5\u6295\u5F71\uFF1B\u8BE5 action \u4E0D\u4F1A\u51FA\u73B0\u5728 DSL \u91CC\u3002`
|
|
2011
|
+
});
|
|
2012
|
+
}
|
|
2013
|
+
if (openUrl) {
|
|
2014
|
+
const { type: _t, ...fields } = openUrl;
|
|
1969
2015
|
return ["action", { multi_url: openUrlFieldsToMultiUrl(fields) }];
|
|
1970
2016
|
}
|
|
1971
2017
|
return DROP;
|
|
@@ -2447,11 +2493,11 @@ function pixelOf(side) {
|
|
|
2447
2493
|
function snake(key) {
|
|
2448
2494
|
return key.replace(/ID$/g, "_id").replace(/URL$/g, "_url").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
|
|
2449
2495
|
}
|
|
2450
|
-
function rawToDsl(raw) {
|
|
2451
|
-
if (isRawCardEnvelope(raw)) return rawCardToDsl(raw);
|
|
2496
|
+
function rawToDsl(raw, options) {
|
|
2497
|
+
if (isRawCardEnvelope(raw)) return rawCardToDsl(raw, options);
|
|
2452
2498
|
if (typeof raw === "string") {
|
|
2453
2499
|
try {
|
|
2454
|
-
return rawToDsl(JSON.parse(raw));
|
|
2500
|
+
return rawToDsl(JSON.parse(raw), options);
|
|
2455
2501
|
} catch {
|
|
2456
2502
|
return raw;
|
|
2457
2503
|
}
|
|
@@ -2469,19 +2515,20 @@ function rawToDsl(raw) {
|
|
|
2469
2515
|
const attachment = isRecord3(raw.json_attachment) ? raw.json_attachment : {};
|
|
2470
2516
|
const ctx = makeCtx({
|
|
2471
2517
|
images: isRecord3(attachment.images) ? attachment.images : {},
|
|
2472
|
-
atUsers: isRecord3(attachment.at_users) ? attachment.at_users : {}
|
|
2518
|
+
atUsers: isRecord3(attachment.at_users) ? attachment.at_users : {},
|
|
2519
|
+
onWarn: options?.onWarn
|
|
2473
2520
|
});
|
|
2474
2521
|
return convertRoot(inner, ctx);
|
|
2475
2522
|
}
|
|
2476
2523
|
if (isRecord3(raw.card)) {
|
|
2477
2524
|
const card = raw.card;
|
|
2478
2525
|
if (typeof card.json_card === "string" || isRecord3(card.json_card)) {
|
|
2479
|
-
return rawToDsl(card);
|
|
2526
|
+
return rawToDsl(card, options);
|
|
2480
2527
|
}
|
|
2481
|
-
return convertRoot(card, makeCtx());
|
|
2528
|
+
return convertRoot(card, makeCtx({ onWarn: options?.onWarn }));
|
|
2482
2529
|
}
|
|
2483
2530
|
if ("body" in raw || "header" in raw || "schema" in raw) {
|
|
2484
|
-
return convertRoot(raw, makeCtx());
|
|
2531
|
+
return convertRoot(raw, makeCtx({ onWarn: options?.onWarn }));
|
|
2485
2532
|
}
|
|
2486
2533
|
return raw;
|
|
2487
2534
|
}
|
package/dist/raw-to-dsl.d.ts
CHANGED
|
@@ -45,14 +45,31 @@
|
|
|
45
45
|
* downstream sees an unknown field rather than silently losing data.
|
|
46
46
|
*/
|
|
47
47
|
export declare function isRawCardEnvelope(value: unknown): boolean;
|
|
48
|
-
export declare function rawCardToDsl(envelope: unknown): unknown;
|
|
48
|
+
export declare function rawCardToDsl(envelope: unknown, options?: RawToDslOptions): unknown;
|
|
49
|
+
/** rawToDsl 的诊断级别。默认静默:只有传了 onWarn 才会回调。 */
|
|
50
|
+
export interface RawToDslWarning {
|
|
51
|
+
/**
|
|
52
|
+
* unknown_action_type: action.type 不认识(已原样保留进 behaviors)
|
|
53
|
+
* callback_payload_cleared: 服务端把回调载荷换成了 actionID / 清空
|
|
54
|
+
* unrepresentable_action: 该宿主(column_set / column)的公开 schema 没有可放 action 的字段
|
|
55
|
+
*/
|
|
56
|
+
code: "unknown_action_type" | "callback_payload_cleared" | "unrepresentable_action";
|
|
57
|
+
/** 可读诊断,中文 */
|
|
58
|
+
message: string;
|
|
59
|
+
/** 持有 actions 的元素 tag:button / interactive_container / column_set / column */
|
|
60
|
+
ownerTag?: string;
|
|
61
|
+
}
|
|
62
|
+
/** 诊断通道;不传则完全不打扰调用方。 */
|
|
63
|
+
export interface RawToDslOptions {
|
|
64
|
+
onWarn?: (warning: RawToDslWarning) => void;
|
|
65
|
+
}
|
|
49
66
|
/**
|
|
50
67
|
* Flexible entry used by this monorepo:
|
|
51
68
|
* - raw envelope (`json_card` + `card_schema`) → same as `rawCardToDsl`
|
|
52
69
|
* - already-parsed `{ json_card: object, json_attachment? }`
|
|
53
70
|
* - `{ card: ... }` / bare card (e.g. output of `dslToRaw`) → `convertRoot`
|
|
54
71
|
*/
|
|
55
|
-
export declare function rawToDsl(raw: unknown): unknown;
|
|
72
|
+
export declare function rawToDsl(raw: unknown, options?: RawToDslOptions): unknown;
|
|
56
73
|
/**
|
|
57
74
|
* Optional helper: wrap a private/unknown element as
|
|
58
75
|
* `{ tag: 'unknown', raw_tag, fallback }`.
|
package/dist/raw-to-dsl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-to-dsl.d.ts","sourceRoot":"","sources":["../src/raw-to-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAwBH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"raw-to-dsl.d.ts","sourceRoot":"","sources":["../src/raw-to-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAwBH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAeT;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,IAAI,EAAE,qBAAqB,GAAG,0BAA0B,GAAG,wBAAwB,CAAC;IACpF,cAAc;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAwB;AACxB,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CAC7C;AA+2DD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CA+CzE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGnF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-feishu-card/adapter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.19",
|
|
4
4
|
"description": "公开 DSL 与飞书内部 RAW JSON 的双向适配器;raw→DSL 对齐 feishu-raw-card-to-dsl",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"tsx": "^4.19.3",
|
|
23
23
|
"typescript": "^7.0.2",
|
|
24
24
|
"vitest": "^2.1.9",
|
|
25
|
-
"@open-feishu-card/schema": "0.1.
|
|
25
|
+
"@open-feishu-card/schema": "0.1.9"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"publishConfig": {
|