@hankchen/canvas-editor 0.3.0 → 0.5.0
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.d.ts +319 -111
- package/dist/index.js +476 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -501,6 +501,7 @@ function normalizeSchemaType(value) {
|
|
|
501
501
|
const primary = value.find((entry) => entry !== "null" && entry !== "");
|
|
502
502
|
return primary;
|
|
503
503
|
}
|
|
504
|
+
var FORMAT_ANNOTATIONS = /* @__PURE__ */ new Set(["date", "date-time"]);
|
|
504
505
|
function annotationsOf(raw) {
|
|
505
506
|
const node = {};
|
|
506
507
|
const rawType = raw["type"];
|
|
@@ -515,6 +516,10 @@ function annotationsOf(raw) {
|
|
|
515
516
|
if (typeof rawDescription === "string") node.description = rawDescription;
|
|
516
517
|
const rawTitle = raw["title"];
|
|
517
518
|
if (typeof rawTitle === "string") node.title = rawTitle;
|
|
519
|
+
const rawFormat = raw["format"];
|
|
520
|
+
if (node.type === "string" && typeof rawFormat === "string" && FORMAT_ANNOTATIONS.has(rawFormat)) {
|
|
521
|
+
node.format = rawFormat;
|
|
522
|
+
}
|
|
518
523
|
return node;
|
|
519
524
|
}
|
|
520
525
|
function pointerEscape(key) {
|
|
@@ -597,7 +602,6 @@ function compileRefNode(raw, rawRef, declPath, ctx) {
|
|
|
597
602
|
}
|
|
598
603
|
function compileInlineNode(raw, declPath, ctx) {
|
|
599
604
|
const node = annotationsOf(raw);
|
|
600
|
-
if (raw["additionalProperties"] === true) node.open = true;
|
|
601
605
|
const rawProperties = raw["properties"];
|
|
602
606
|
if (isPlainObject(rawProperties)) {
|
|
603
607
|
const properties = /* @__PURE__ */ new Map();
|
|
@@ -611,6 +615,23 @@ function compileInlineNode(raw, declPath, ctx) {
|
|
|
611
615
|
if (isPlainObject(rawItems)) node.items = compileSchemaNode(rawItems, `${declPath}/items`, ctx);
|
|
612
616
|
return node;
|
|
613
617
|
}
|
|
618
|
+
var OPEN_MAP_DETAIL_SUFFIX = "\u2014\u2014\u5F00\u653E\u6620\u5C04\u5951\u7EA6\u5DF2\u5E9F\u9664\uFF0C\u52A8\u6001\u952E\u8BF7\u7531\u5BBF\u4E3B\u7EC4\u88C5\u6210\u5177\u4F53 properties \u540E\u6CE8\u5165";
|
|
619
|
+
function findOpenMapping(raw, path) {
|
|
620
|
+
if (Array.isArray(raw)) {
|
|
621
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
622
|
+
const hit = findOpenMapping(raw[i], `${path}/${i}`);
|
|
623
|
+
if (hit !== null) return hit;
|
|
624
|
+
}
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
if (!isPlainObject(raw)) return null;
|
|
628
|
+
if (raw["additionalProperties"] === true) return path;
|
|
629
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
630
|
+
const hit = findOpenMapping(value, `${path}/${pointerEscape(key)}`);
|
|
631
|
+
if (hit !== null) return hit;
|
|
632
|
+
}
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
614
635
|
function parseExpressionSchema(raw) {
|
|
615
636
|
if (!isPlainObject(raw)) {
|
|
616
637
|
return { ok: false, reason: "invalid_schema", detail: "schema \u6839\u5FC5\u987B\u662F\u5BF9\u8C61\u58F0\u660E" };
|
|
@@ -626,6 +647,10 @@ function parseExpressionSchema(raw) {
|
|
|
626
647
|
if (!isPlainObject(rawProperties)) {
|
|
627
648
|
return { ok: false, reason: "invalid_schema", detail: "\u6839\u58F0\u660E\u7F3A properties \u5C42\u7EA7\uFF08schema \u5373\u8F7D\u8377\u5F62\u72B6\uFF0C\u5FC5\u987B\u58F0\u660E\u9876\u5C42\u952E\uFF09" };
|
|
628
649
|
}
|
|
650
|
+
const openPath = findOpenMapping(raw, "#");
|
|
651
|
+
if (openPath !== null) {
|
|
652
|
+
return { ok: false, reason: "open_map_unsupported", detail: `"${openPath}" \u58F0\u660E\u4E86 additionalProperties: true${OPEN_MAP_DETAIL_SUFFIX}` };
|
|
653
|
+
}
|
|
629
654
|
const diagnostics = [];
|
|
630
655
|
const schema = compileSchemaNode(raw, "#", { root: raw, diagnostics, activePath: /* @__PURE__ */ new Set() });
|
|
631
656
|
return { ok: true, schema, diagnostics };
|
|
@@ -667,7 +692,7 @@ function schemaNodeAtPath(node, segments) {
|
|
|
667
692
|
function schemaChildEntries(node) {
|
|
668
693
|
if (node.type === "array" || node.items !== void 0) return { entries: [] };
|
|
669
694
|
const entries = node.properties !== void 0 ? [...node.properties].map(([key, child]) => ({ key, node: child })) : [];
|
|
670
|
-
return
|
|
695
|
+
return { entries };
|
|
671
696
|
}
|
|
672
697
|
function resolveRowSchema(root, rowsPath) {
|
|
673
698
|
const segments = rowsPath.split(".");
|
|
@@ -692,15 +717,194 @@ function parseExpressionPath(expr) {
|
|
|
692
717
|
return { ok: true, head: { kind: "bare", name: head }, rest };
|
|
693
718
|
}
|
|
694
719
|
|
|
720
|
+
// src/shared/expressionCall.ts
|
|
721
|
+
var TRIM_CHARS = " \n\r\0\v";
|
|
722
|
+
var WS_CHARS = " \n\r";
|
|
723
|
+
var HEAD_STOP_CHARS = `()',.${TRIM_CHARS}`;
|
|
724
|
+
function phpTrim(value) {
|
|
725
|
+
let start = 0;
|
|
726
|
+
let end = value.length;
|
|
727
|
+
while (start < end && TRIM_CHARS.includes(value[start])) start += 1;
|
|
728
|
+
while (end > start && TRIM_CHARS.includes(value[end - 1])) end -= 1;
|
|
729
|
+
return value.slice(start, end);
|
|
730
|
+
}
|
|
731
|
+
function skipWs(expr, pos) {
|
|
732
|
+
while (pos < expr.length && WS_CHARS.includes(expr[pos])) pos += 1;
|
|
733
|
+
return pos;
|
|
734
|
+
}
|
|
735
|
+
function fail(kind, start, end) {
|
|
736
|
+
return { ok: false, error: "expression_syntax_error", kind, at: { start, end } };
|
|
737
|
+
}
|
|
738
|
+
function isCallFragment(expr) {
|
|
739
|
+
let head = 0;
|
|
740
|
+
while (head < expr.length && !HEAD_STOP_CHARS.includes(expr[head])) head += 1;
|
|
741
|
+
if (head === 0) return false;
|
|
742
|
+
let pos = head;
|
|
743
|
+
while (pos < expr.length && TRIM_CHARS.includes(expr[pos])) pos += 1;
|
|
744
|
+
return expr[pos] === "(";
|
|
745
|
+
}
|
|
746
|
+
function parseExpressionCall(expr) {
|
|
747
|
+
let head = 0;
|
|
748
|
+
while (head < expr.length && !HEAD_STOP_CHARS.includes(expr[head])) head += 1;
|
|
749
|
+
if (head === 0) return fail("invalid_path", 0, expr.length);
|
|
750
|
+
const name = expr.slice(0, head);
|
|
751
|
+
let pos = skipWs(expr, head);
|
|
752
|
+
if (pos >= expr.length || expr[pos] !== "(") return fail("missing_open_paren", head, expr.length);
|
|
753
|
+
const openParen = pos;
|
|
754
|
+
pos = skipWs(expr, pos + 1);
|
|
755
|
+
const args = [];
|
|
756
|
+
const spans = [];
|
|
757
|
+
if (pos < expr.length && expr[pos] === ")") {
|
|
758
|
+
pos += 1;
|
|
759
|
+
} else {
|
|
760
|
+
for (; ; ) {
|
|
761
|
+
if (pos >= expr.length) return fail("unbalanced_paren", openParen, expr.length);
|
|
762
|
+
const arg = parseCallArg(expr, pos);
|
|
763
|
+
if (!arg.ok) return arg;
|
|
764
|
+
args.push(arg.value);
|
|
765
|
+
spans.push({ start: arg.start, end: arg.end });
|
|
766
|
+
pos = skipWs(expr, arg.end);
|
|
767
|
+
if (pos >= expr.length) return fail("unbalanced_paren", openParen, expr.length);
|
|
768
|
+
if (expr[pos] === ",") {
|
|
769
|
+
const comma = pos;
|
|
770
|
+
pos = skipWs(expr, pos + 1);
|
|
771
|
+
if (pos < expr.length && expr[pos] === ")") {
|
|
772
|
+
return fail("empty_arg_slot", comma + 1, pos);
|
|
773
|
+
}
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
if (expr[pos] === ")") {
|
|
777
|
+
pos += 1;
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
return fail("bad_arg_syntax", pos, pos + 1);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
pos = skipWs(expr, pos);
|
|
784
|
+
if (pos !== expr.length) return fail("trailing_after_call", pos, expr.length);
|
|
785
|
+
if (args[0] !== void 0 && args[0].type !== "path") {
|
|
786
|
+
const span = spans[0];
|
|
787
|
+
return fail("first_arg_not_path", span.start, span.end);
|
|
788
|
+
}
|
|
789
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
790
|
+
const arg = args[i];
|
|
791
|
+
const span = spans[i];
|
|
792
|
+
if (arg.type === "path" && !parseExpressionPath(arg.value).ok) {
|
|
793
|
+
return fail("invalid_path_arg", span.start, span.end);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return { ok: true, name, args };
|
|
797
|
+
}
|
|
798
|
+
function parseCallArg(expr, pos) {
|
|
799
|
+
const len = expr.length;
|
|
800
|
+
const start = pos;
|
|
801
|
+
const ch = expr[pos];
|
|
802
|
+
if (ch === "'") {
|
|
803
|
+
let cursor = pos + 1;
|
|
804
|
+
let buf = "";
|
|
805
|
+
for (; ; ) {
|
|
806
|
+
if (cursor >= len) {
|
|
807
|
+
return { ok: false, error: "expression_syntax_error", kind: "unterminated_string", at: { start, end: len } };
|
|
808
|
+
}
|
|
809
|
+
if (expr[cursor] === "'") {
|
|
810
|
+
if (cursor + 1 < len && expr[cursor + 1] === "'") {
|
|
811
|
+
buf += "'";
|
|
812
|
+
cursor += 2;
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
cursor += 1;
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
buf += expr[cursor];
|
|
819
|
+
cursor += 1;
|
|
820
|
+
}
|
|
821
|
+
return { ok: true, value: { type: "string", value: buf }, start, end: cursor };
|
|
822
|
+
}
|
|
823
|
+
if (ch >= "0" && ch <= "9") {
|
|
824
|
+
const isDigitAt = (index) => {
|
|
825
|
+
const c = expr[index];
|
|
826
|
+
return c !== void 0 && c >= "0" && c <= "9";
|
|
827
|
+
};
|
|
828
|
+
while (isDigitAt(pos)) pos += 1;
|
|
829
|
+
if (pos < len && expr[pos] === "." && isDigitAt(pos + 1)) {
|
|
830
|
+
pos += 1;
|
|
831
|
+
while (isDigitAt(pos)) pos += 1;
|
|
832
|
+
}
|
|
833
|
+
return { ok: true, value: { type: "number", value: expr.slice(start, pos) }, start, end: pos };
|
|
834
|
+
}
|
|
835
|
+
while (pos < len && expr[pos] !== "," && expr[pos] !== ")") pos += 1;
|
|
836
|
+
const raw = phpTrim(expr.slice(start, pos));
|
|
837
|
+
if (raw === "") {
|
|
838
|
+
return { ok: false, error: "expression_syntax_error", kind: "empty_arg_slot", at: { start, end: pos } };
|
|
839
|
+
}
|
|
840
|
+
return { ok: true, value: { type: "path", value: raw }, start, end: pos };
|
|
841
|
+
}
|
|
842
|
+
function expressionCallSlotAtEnd(expr) {
|
|
843
|
+
let head = 0;
|
|
844
|
+
while (head < expr.length && !HEAD_STOP_CHARS.includes(expr[head])) head += 1;
|
|
845
|
+
if (head === 0) return null;
|
|
846
|
+
let pos = skipWs(expr, head);
|
|
847
|
+
if (pos >= expr.length || expr[pos] !== "(") return null;
|
|
848
|
+
pos = skipWs(expr, pos + 1);
|
|
849
|
+
let index = 0;
|
|
850
|
+
for (; ; ) {
|
|
851
|
+
if (pos >= expr.length) return { name: expr.slice(0, head), index, text: "", stringSlot: false };
|
|
852
|
+
const ch = expr[pos];
|
|
853
|
+
if (ch === "'") {
|
|
854
|
+
let cursor = pos + 1;
|
|
855
|
+
for (; ; ) {
|
|
856
|
+
if (cursor >= expr.length) {
|
|
857
|
+
return { name: expr.slice(0, head), index, text: expr.slice(pos + 1), stringSlot: true };
|
|
858
|
+
}
|
|
859
|
+
if (expr[cursor] === "'") {
|
|
860
|
+
if (cursor + 1 < expr.length && expr[cursor + 1] === "'") {
|
|
861
|
+
cursor += 2;
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
cursor += 1;
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
cursor += 1;
|
|
868
|
+
}
|
|
869
|
+
pos = cursor;
|
|
870
|
+
} else if (ch !== "," && ch !== ")") {
|
|
871
|
+
const argStart = pos;
|
|
872
|
+
while (pos < expr.length && expr[pos] !== "," && expr[pos] !== ")") pos += 1;
|
|
873
|
+
if (pos >= expr.length) {
|
|
874
|
+
return { name: expr.slice(0, head), index, text: phpTrim(expr.slice(argStart)), stringSlot: false };
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (pos >= expr.length) return { name: expr.slice(0, head), index: index + 1, text: "", stringSlot: false };
|
|
878
|
+
if (expr[pos] === ")") return null;
|
|
879
|
+
index += 1;
|
|
880
|
+
pos = skipWs(expr, pos + 1);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
695
884
|
// src/shared/expressionScan.ts
|
|
696
885
|
var PHP_TRIM_CHARS = " \n\r\0\v";
|
|
697
|
-
function
|
|
886
|
+
function phpTrim2(value) {
|
|
698
887
|
let start = 0;
|
|
699
888
|
let end = value.length;
|
|
700
889
|
while (start < end && PHP_TRIM_CHARS.includes(value[start])) start += 1;
|
|
701
890
|
while (end > start && PHP_TRIM_CHARS.includes(value[end - 1])) end -= 1;
|
|
702
891
|
return value.slice(start, end);
|
|
703
892
|
}
|
|
893
|
+
function fragmentDiagnostic(expr) {
|
|
894
|
+
if (expr === "") return { kind: "empty_fragment", at: { start: 0, end: 0 } };
|
|
895
|
+
if (isCallFragment(expr)) {
|
|
896
|
+
const parsed = parseExpressionCall(expr);
|
|
897
|
+
if (parsed.ok) return null;
|
|
898
|
+
return { kind: parsed.kind, at: parsed.at };
|
|
899
|
+
}
|
|
900
|
+
if (parseExpressionPath(expr).ok) return null;
|
|
901
|
+
return { kind: "invalid_path", at: { start: 0, end: expr.length } };
|
|
902
|
+
}
|
|
903
|
+
function leadingPhpTrim(value) {
|
|
904
|
+
let start = 0;
|
|
905
|
+
while (start < value.length && PHP_TRIM_CHARS.includes(value[start])) start += 1;
|
|
906
|
+
return start;
|
|
907
|
+
}
|
|
704
908
|
function scanExpressionFragments(template) {
|
|
705
909
|
const parts = [];
|
|
706
910
|
let pos = 0;
|
|
@@ -712,16 +916,34 @@ function scanExpressionFragments(template) {
|
|
|
712
916
|
parts.push({ kind: "literal", start: pos, end: open, text: template.slice(pos, open) });
|
|
713
917
|
}
|
|
714
918
|
const text = template.slice(open);
|
|
715
|
-
parts.push({ kind: "open", start: open, end: template.length, text, expr:
|
|
919
|
+
parts.push({ kind: "open", start: open, end: template.length, text, expr: phpTrim2(text.slice(2)) });
|
|
716
920
|
return { template, parts };
|
|
717
921
|
}
|
|
718
922
|
if (open > pos) {
|
|
719
923
|
parts.push({ kind: "literal", start: pos, end: open, text: template.slice(pos, open) });
|
|
720
924
|
}
|
|
721
925
|
const raw = template.slice(open + 2, close);
|
|
722
|
-
const expr =
|
|
723
|
-
|
|
724
|
-
|
|
926
|
+
const expr = phpTrim2(raw);
|
|
927
|
+
let diagnostic = null;
|
|
928
|
+
const found = fragmentDiagnostic(expr);
|
|
929
|
+
if (found) {
|
|
930
|
+
const exprStart = open + 2 + leadingPhpTrim(raw);
|
|
931
|
+
diagnostic = {
|
|
932
|
+
kind: found.kind,
|
|
933
|
+
start: open,
|
|
934
|
+
end: close + 2,
|
|
935
|
+
at: { start: exprStart + found.at.start, end: exprStart + found.at.end }
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
parts.push({
|
|
939
|
+
kind: "fragment",
|
|
940
|
+
start: open,
|
|
941
|
+
end: close + 2,
|
|
942
|
+
raw,
|
|
943
|
+
expr,
|
|
944
|
+
error: diagnostic !== null ? "expression_syntax_error" : null,
|
|
945
|
+
diagnostic
|
|
946
|
+
});
|
|
725
947
|
pos = close + 2;
|
|
726
948
|
open = template.indexOf("{{", pos);
|
|
727
949
|
}
|
|
@@ -2924,11 +3146,10 @@ var EditorSession = class {
|
|
|
2924
3146
|
* 进入文本编辑:路径必须解析到 TextLayer。会话只进 ui 分支(不进历史),
|
|
2925
3147
|
* live 文本住在绑定层的 textarea,内容层随即跳绘该层文本(防重影)。
|
|
2926
3148
|
*
|
|
2927
|
-
*
|
|
2928
|
-
*
|
|
2929
|
-
*
|
|
2930
|
-
*
|
|
2931
|
-
* 不重锚);换层进入按新层现状重锚。
|
|
3149
|
+
* 内容模式活标志(ADR 0019)初值按进入瞬间 `layer.expression !== null` 取定
|
|
3150
|
+
* (与文档现态一致),此后不再冻结——pill 切换与内核 toggleDataMode 会话期
|
|
3151
|
+
* 都只翻标志,提交去向由退出时现态裁决(见 commitTextEdit)。同路径重复进入
|
|
3152
|
+
* 短路(会话不重建,接管序号延续);换层进入按新层现状取初值。
|
|
2932
3153
|
*/
|
|
2933
3154
|
beginTextEdit(path) {
|
|
2934
3155
|
const layer = this.textLayerAt(path);
|
|
@@ -2944,14 +3165,14 @@ var EditorSession = class {
|
|
|
2944
3165
|
* 提交与随后 blur 竞态),会话清空后后续调用幂等,保证一次退出恰一步历史。
|
|
2945
3166
|
*
|
|
2946
3167
|
* 提交矩阵(canvas-web-expression-editing 工单 01,spec 决策 3,空串判定先于
|
|
2947
|
-
*
|
|
2948
|
-
*
|
|
2949
|
-
*
|
|
2950
|
-
*
|
|
3168
|
+
* 片段判定;对比对象与去向裁决按会话标志**退出时现态**——活标志语义,ADR
|
|
3169
|
+
* 0019,取代旧「进入时快照」):
|
|
3170
|
+
* - 串与文档一致:不进历史(进出编辑零噪声),返回 false——对比对象随退出时
|
|
3171
|
+
* 会话标志取:表达式现态对比 `layer.expression`、静态现态对比 `layer.text`;
|
|
2951
3172
|
* - 空串:删除该图层(复用 deleteLayer 的 splice/重映射语义),任何模式同语义;
|
|
2952
|
-
* -
|
|
3173
|
+
* - 表达式现态且串含 ≥1 语法有效闭合片段(hasValidExpressionFragment):
|
|
2953
3174
|
* updateDataExpression 标记写(保持标记、text 自动重镜像);
|
|
2954
|
-
* -
|
|
3175
|
+
* - 其余(静态现态恒走此支;表达式现态无合法片段回落):updateData 字面写、
|
|
2955
3176
|
* 字面接管解标——含 `{{...}}` 按字面保留,杜绝无片段标记层。
|
|
2956
3177
|
*/
|
|
2957
3178
|
commitTextEdit(text) {
|
|
@@ -2975,8 +3196,10 @@ var EditorSession = class {
|
|
|
2975
3196
|
/**
|
|
2976
3197
|
* 编辑 overlay 的布局描述:与绘制/命中同一套布局策略求出的盒几何与排版字段
|
|
2977
3198
|
* (textarea 以盒左上对位、盒尺寸占位,字号/行高/内边距按场景像素交给 CSS
|
|
2978
|
-
* transform
|
|
2979
|
-
*
|
|
3199
|
+
* transform 缩放)。对当前文档现算(canvas-web-edit-overlay-toolbar 工单 01,
|
|
3200
|
+
* ADR 0019 布局现算):会话期样式/几何权威写实时反映到查询值;verticalAnchorY
|
|
3201
|
+
* 按当前文档文本计算——live 键入只住 textarea 草稿不落文档,键入不触发文档
|
|
3202
|
+
* 变更,锚点天然稳定不跳。非文本层/路径失效返回 null。
|
|
2980
3203
|
*/
|
|
2981
3204
|
textEditLayout(path) {
|
|
2982
3205
|
const layer = this.textLayerAt(path);
|
|
@@ -3053,7 +3276,8 @@ var EditorSession = class {
|
|
|
3053
3276
|
* 原地不动——事务后派生列表在被替换处缩一位,原下标即「下一处」(「替换后
|
|
3054
3277
|
* 自动跳下一处」靠派生天然成立,末处替换则钳位停在尾)。写值经 replaceHitsInDraft
|
|
3055
3278
|
* 与文本编辑提交同门(text 直写 + expression 保持 null)。无文档/空 query/
|
|
3056
|
-
* 无命中空转返回 false
|
|
3279
|
+
* 无命中空转返回 false。命中编辑层时草稿接管(会话内容独占,工单 02——
|
|
3280
|
+
* 替换结果出现在正在编辑的框里)。
|
|
3057
3281
|
*/
|
|
3058
3282
|
replaceOne() {
|
|
3059
3283
|
const doc = this.store.doc;
|
|
@@ -3062,7 +3286,7 @@ var EditorSession = class {
|
|
|
3062
3286
|
const matches = scanTextMatches(doc, query);
|
|
3063
3287
|
const hit = matches[clampFindCursor(this.store.ui.find.cursor, matches.length)];
|
|
3064
3288
|
if (!hit) return false;
|
|
3065
|
-
this.
|
|
3289
|
+
this.transactContent([hit.path], (draft) => {
|
|
3066
3290
|
replaceHitsInDraft(draft, [hit], this.store.ui.find.replacement);
|
|
3067
3291
|
});
|
|
3068
3292
|
return true;
|
|
@@ -3071,7 +3295,8 @@ var EditorSession = class {
|
|
|
3071
3295
|
* 全部替换(查找条「全部替换」按钮):命中(path + 偏移对)在事务前按原文
|
|
3072
3296
|
* 快照一次算定,单事务内按同字段偏移降序应用、替换产物不重扫(replacement
|
|
3073
3297
|
* 含查询串不死循环)——一次调用 = 一步历史,undo 一次全回。返回应用处数
|
|
3074
|
-
* (计数反馈「已替换 N 处」);无文档/空 query 空转返回 0
|
|
3298
|
+
* (计数反馈「已替换 N 处」);无文档/空 query 空转返回 0。命中编辑层时
|
|
3299
|
+
* 草稿接管(会话内容独占,工单 02)。
|
|
3075
3300
|
*/
|
|
3076
3301
|
replaceAll() {
|
|
3077
3302
|
const doc = this.store.doc;
|
|
@@ -3080,7 +3305,7 @@ var EditorSession = class {
|
|
|
3080
3305
|
const hits = scanTextMatches(doc, query);
|
|
3081
3306
|
if (hits.length === 0) return 0;
|
|
3082
3307
|
let applied = 0;
|
|
3083
|
-
this.
|
|
3308
|
+
this.transactContent(hits.map((hit) => hit.path), (draft) => {
|
|
3084
3309
|
applied = replaceHitsInDraft(draft, hits, this.store.ui.find.replacement);
|
|
3085
3310
|
});
|
|
3086
3311
|
return applied;
|
|
@@ -3134,9 +3359,13 @@ var EditorSession = class {
|
|
|
3134
3359
|
* null,值与标记的镜像关系随之解除——标记态文档经字面编辑退化为字面态,
|
|
3135
3360
|
* 不可自动恢复属预期(spec §3.7 兼容面)。
|
|
3136
3361
|
* 表/行/格无数据字段,空转。
|
|
3362
|
+
*
|
|
3363
|
+
* 会话内容独占(工单 02,ADR 0019 内核底线面):命中编辑层的写落文档的同时
|
|
3364
|
+
* 草稿接管(draftSeq 递增,绑定层全量替换 textarea 草稿)——旁门程序化写的
|
|
3365
|
+
* 结果进编辑框草稿而非被退出提交覆盖,任何方向不丢字。
|
|
3137
3366
|
*/
|
|
3138
3367
|
updateData(path, value, options = {}) {
|
|
3139
|
-
this.
|
|
3368
|
+
this.transactContent([path], (draft) => {
|
|
3140
3369
|
const layer = resolveLayer(draft, path);
|
|
3141
3370
|
if (!layer) return;
|
|
3142
3371
|
switch (layer.type) {
|
|
@@ -3167,9 +3396,11 @@ var EditorSession = class {
|
|
|
3167
3396
|
* 字面态空值归一交给 updateData/decode 分支(这里不清值,字面接管语义)。
|
|
3168
3397
|
* - 仅三内容层生效,表/行/格/行模板空转(与 updateData 同门)。
|
|
3169
3398
|
* - updateData 语义不变:字面写解除标记仍成立(spec §1 明示两者并排)。
|
|
3399
|
+
* - 命中编辑层的旁门打标同走草稿接管(draftSeq 递增;会话标志不随动——
|
|
3400
|
+
* 活标志只归 pill/toggleDataMode 翻,见 toggleDataMode)。
|
|
3170
3401
|
*/
|
|
3171
3402
|
updateDataExpression(path, expression, options = {}) {
|
|
3172
|
-
this.
|
|
3403
|
+
this.transactContent([path], (draft) => {
|
|
3173
3404
|
const layer = resolveLayer(draft, path);
|
|
3174
3405
|
if (!layer) return;
|
|
3175
3406
|
switch (layer.type) {
|
|
@@ -3190,6 +3421,63 @@ var EditorSession = class {
|
|
|
3190
3421
|
}
|
|
3191
3422
|
}, options);
|
|
3192
3423
|
}
|
|
3424
|
+
/**
|
|
3425
|
+
* 数据字段取值方式切换(静态 ⇆ 表达式,工单 02 自面板收编内核):表达式现态
|
|
3426
|
+
* → 字面接管(updateData,值保持现镜像);静态现态 → 打标(updateDataExpression,
|
|
3427
|
+
* 初值 = 值字段原文)。各为独立一步历史(无 mergeKey)。三内容层分派各取值
|
|
3428
|
+
* 字段,表/行/格/悬空路径空转。
|
|
3429
|
+
*
|
|
3430
|
+
* 活标志防御路由(ADR 0019):路径即编辑中的层时只翻会话活标志(零文档变更
|
|
3431
|
+
* 零历史步)——会话期内容模式切换的唯一写入口是会话标志,文档面锁定归编辑框
|
|
3432
|
+
* 草稿;面板锁定段/pill 显式调用与宿主旁路调用都安全收敛到同一语义。
|
|
3433
|
+
*/
|
|
3434
|
+
toggleDataMode(path) {
|
|
3435
|
+
const editing = this.store.ui.editing;
|
|
3436
|
+
if (editing && pathsEqual(editing.path, path)) {
|
|
3437
|
+
this.store.setEditing({ ...editing, expression: !editing.expression });
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
const layer = this.store.doc ? resolveLayer(this.store.doc, path) : null;
|
|
3441
|
+
if (!layer) return;
|
|
3442
|
+
switch (layer.type) {
|
|
3443
|
+
case "TextLayer":
|
|
3444
|
+
if (layer.expression !== null) this.updateData(path, layer.text);
|
|
3445
|
+
else this.updateDataExpression(path, layer.text);
|
|
3446
|
+
return;
|
|
3447
|
+
case "ImageLayer":
|
|
3448
|
+
if (layer.expression !== null) this.updateData(path, layer.src ?? "");
|
|
3449
|
+
else this.updateDataExpression(path, layer.src ?? "");
|
|
3450
|
+
return;
|
|
3451
|
+
case "QrCodeLayer":
|
|
3452
|
+
if (layer.expression !== null) this.updateData(path, layer.value);
|
|
3453
|
+
else this.updateDataExpression(path, layer.value);
|
|
3454
|
+
return;
|
|
3455
|
+
default:
|
|
3456
|
+
return;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* 内容写事务的统一形(会话内容独占工单 02):transact 落库 + 命中编辑层的
|
|
3461
|
+
* 草稿接管收口——updateData/updateDataExpression/replaceOne/replaceAll 四个
|
|
3462
|
+
* 旁门写入口同门(接管判定见 takeoverDraftIfNeeded;零变更事务天然短路)。
|
|
3463
|
+
*/
|
|
3464
|
+
transactContent(paths, recipe, options = {}) {
|
|
3465
|
+
const docBefore = this.store.doc;
|
|
3466
|
+
this.store.transact(recipe, options);
|
|
3467
|
+
this.takeoverDraftIfNeeded(paths, docBefore);
|
|
3468
|
+
}
|
|
3469
|
+
/**
|
|
3470
|
+
* 草稿接管收口(工单 02):paths 中有编辑层且文档确实变更(引用比较——零变更
|
|
3471
|
+
* 事务 transact 空转不通知,接管序号也不动)时递增会话 draftSeq 并广播
|
|
3472
|
+
* ui.editing。绑定层据此全量替换 textarea 草稿为文档新值并刷新表达式诊断。
|
|
3473
|
+
* commitTextEdit 先清会话再落库,天然不复入接管。
|
|
3474
|
+
*/
|
|
3475
|
+
takeoverDraftIfNeeded(paths, docBefore) {
|
|
3476
|
+
const editing = this.store.ui.editing;
|
|
3477
|
+
if (!editing || this.store.doc === docBefore) return;
|
|
3478
|
+
if (!paths.some((path) => pathsEqual(path, editing.path))) return;
|
|
3479
|
+
this.store.setEditing({ ...editing, draftSeq: (editing.draftSeq ?? 0) + 1 });
|
|
3480
|
+
}
|
|
3193
3481
|
/** 更新画布级字段(未选中图层时面板的宽/高写入口);键由类型收窄为 width/height */
|
|
3194
3482
|
updateCanvasProp(key, value, options = {}) {
|
|
3195
3483
|
this.store.transact((draft) => {
|
|
@@ -3201,12 +3489,14 @@ var EditorSession = class {
|
|
|
3201
3489
|
* 注入数据源 schema 声明(载荷形态,D1 钉定:声明即 compile(canvas, dataset)
|
|
3202
3490
|
* 收到的 data 载荷形状,根上下文候选 = 载荷顶层键)。声明经
|
|
3203
3491
|
* normalizeExpressionSchemaSource 一次性编译收口——根级结构性问题(保留键
|
|
3204
|
-
* row/$ 前缀,前移填充期 reserved_root_key;根非对象/缺 properties
|
|
3205
|
-
*
|
|
3206
|
-
*
|
|
3207
|
-
*
|
|
3208
|
-
*
|
|
3209
|
-
*
|
|
3492
|
+
* row/$ 前缀,前移填充期 reserved_root_key;根非对象/缺 properties 层级)
|
|
3493
|
+
* 与开放映射契约废除(open_map_unsupported,ADR 0020:文档任意层
|
|
3494
|
+
* additionalProperties: true 显式拒绝,动态键归宿主组装成具体 properties 后
|
|
3495
|
+
* 注入)降级为无候选 + console 警告,局部故障($ref 断链/外部指针/环引用/
|
|
3496
|
+
* 目标形态不符)不拒绝:该节点降叶子 + 注入期汇总告警一次,树其余部分照常
|
|
3497
|
+
* 服务,不抛错不弹错(辅助声明不作权威);null/undefined = 清除声明。声明只
|
|
3498
|
+
* 住 store ui 分支:不进 graph、不落 localStorage、不进 wire;openDocument
|
|
3499
|
+
* 换文档不重置,重注入/清除走同一入口。签名与「注入即整体替换」语义不变(D6)。
|
|
3210
3500
|
*/
|
|
3211
3501
|
setDataSourceSchema(raw) {
|
|
3212
3502
|
this.store.setDataSourceSchema(
|
|
@@ -4081,6 +4371,45 @@ function classifyWheel(input) {
|
|
|
4081
4371
|
return "pan";
|
|
4082
4372
|
}
|
|
4083
4373
|
|
|
4374
|
+
// src/shared/expressionDiagnostics.ts
|
|
4375
|
+
function expressionDiagnostics(template) {
|
|
4376
|
+
const found = [];
|
|
4377
|
+
for (const part of scanExpressionFragments(template).parts) {
|
|
4378
|
+
if (part.kind === "fragment" && part.diagnostic !== null) found.push(part.diagnostic);
|
|
4379
|
+
}
|
|
4380
|
+
return found;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// src/shared/resourcePath.ts
|
|
4384
|
+
function wholeTemplateDiagnostic(template, kind) {
|
|
4385
|
+
return { kind, start: 0, end: template.length, at: { start: 0, end: template.length } };
|
|
4386
|
+
}
|
|
4387
|
+
function resourcePathDiagnostics(template) {
|
|
4388
|
+
const anchored = template.endsWith("\n") ? template.slice(0, -1) : template;
|
|
4389
|
+
const matched = /^\{\{([^{}]*)\}\}$/.exec(anchored);
|
|
4390
|
+
if (matched === null) return [wholeTemplateDiagnostic(template, "resource_not_single_ref")];
|
|
4391
|
+
const path = phpTrim2(matched[1] ?? "");
|
|
4392
|
+
if (path === "") return [wholeTemplateDiagnostic(template, "empty_fragment")];
|
|
4393
|
+
if (path.includes("(")) return [wholeTemplateDiagnostic(template, "resource_function_call")];
|
|
4394
|
+
return [];
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
// src/shared/expressionFunctions.ts
|
|
4398
|
+
var EXPRESSION_FUNCTIONS = [
|
|
4399
|
+
{ name: "date", signature: "date(path[, format])", summary: "\u65E5\u671F\u683C\u5F0F\u5316\uFF08moment \u98CE\u683C token\uFF0C\u9884\u8BBE date/datetime\uFF09" },
|
|
4400
|
+
{ name: "number", signature: "number(path[, n])", summary: "\u5343\u5206\u4F4D\u5206\u7EC4" },
|
|
4401
|
+
{ name: "fixed", signature: "fixed(path[, n])", summary: "\u5B9A\u70B9\u8865\u96F6\uFF08\u7F3A\u7701 2 \u4F4D\uFF09" },
|
|
4402
|
+
{ name: "percent", signature: "percent(path[, n])", summary: "\u767E\u5206\u6BD4\uFF08\u4E58 100\uFF09" }
|
|
4403
|
+
];
|
|
4404
|
+
var NUMBER_FUNCTION_SUGGESTIONS = EXPRESSION_FUNCTIONS.filter(
|
|
4405
|
+
(fn) => fn.name !== "date"
|
|
4406
|
+
);
|
|
4407
|
+
var DATE_FORMAT_SUGGESTIONS = [
|
|
4408
|
+
{ segment: "date", description: "\u9884\u8BBE \u2192 YYYY-MM-DD" },
|
|
4409
|
+
{ segment: "datetime", description: "\u9884\u8BBE \u2192 YYYY-MM-DD HH:mm:ss" },
|
|
4410
|
+
{ segment: "YYYY\u5E74MM\u6708DD\u65E5", description: "\u4E2D\u6587\u6A21\u677F\uFF08\u5199\u5373\u6240\u5F97\uFF09" }
|
|
4411
|
+
];
|
|
4412
|
+
|
|
4084
4413
|
// src/shared/expressionCandidates.ts
|
|
4085
4414
|
function headName(head) {
|
|
4086
4415
|
if (head.kind === "row") return "row";
|
|
@@ -4096,27 +4425,98 @@ function candidateMeta(node) {
|
|
|
4096
4425
|
}
|
|
4097
4426
|
function childCandidate(entry, prefix) {
|
|
4098
4427
|
const path = prefix === "" ? entry.key : `${prefix}.${entry.key}`;
|
|
4099
|
-
return { path, segment: entry.key, ...candidateMeta(entry.node) };
|
|
4100
|
-
}
|
|
4101
|
-
function
|
|
4428
|
+
return { path, segment: entry.key, kind: "path", ...candidateMeta(entry.node) };
|
|
4429
|
+
}
|
|
4430
|
+
function callCandidatesFor(entry, path, exprLen) {
|
|
4431
|
+
const extras = [];
|
|
4432
|
+
if (entry.node.format === "date" || entry.node.format === "date-time") {
|
|
4433
|
+
extras.push({
|
|
4434
|
+
path: `date(${path}, '')`,
|
|
4435
|
+
segment: `date(${path}, '')`,
|
|
4436
|
+
cursorBack: 2,
|
|
4437
|
+
replaceLen: exprLen,
|
|
4438
|
+
filterKey: entry.key,
|
|
4439
|
+
kind: "function",
|
|
4440
|
+
description: "\u65E5\u671F\u683C\u5F0F\u5316",
|
|
4441
|
+
type: "\u51FD\u6570"
|
|
4442
|
+
});
|
|
4443
|
+
} else if (entry.node.type === "number") {
|
|
4444
|
+
for (const fn of NUMBER_FUNCTION_SUGGESTIONS) {
|
|
4445
|
+
extras.push({
|
|
4446
|
+
path: `${fn.name}(${path})`,
|
|
4447
|
+
segment: `${fn.name}(${path})`,
|
|
4448
|
+
replaceLen: exprLen,
|
|
4449
|
+
filterKey: entry.key,
|
|
4450
|
+
kind: "function",
|
|
4451
|
+
description: fn.summary,
|
|
4452
|
+
type: "\u51FD\u6570"
|
|
4453
|
+
});
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
return extras;
|
|
4457
|
+
}
|
|
4458
|
+
function childCandidates(entry, prefix, exprLen, withBuckets) {
|
|
4459
|
+
const base = childCandidate(entry, prefix);
|
|
4460
|
+
if (!withBuckets) return [base];
|
|
4461
|
+
return [base, ...callCandidatesFor(entry, base.path, exprLen)];
|
|
4462
|
+
}
|
|
4463
|
+
function functionCandidates() {
|
|
4464
|
+
return EXPRESSION_FUNCTIONS.map((fn) => ({
|
|
4465
|
+
path: fn.signature,
|
|
4466
|
+
segment: `${fn.name}()`,
|
|
4467
|
+
cursorBack: 1,
|
|
4468
|
+
kind: "function",
|
|
4469
|
+
description: fn.summary,
|
|
4470
|
+
type: "\u51FD\u6570"
|
|
4471
|
+
}));
|
|
4472
|
+
}
|
|
4473
|
+
function dateFormatCandidates() {
|
|
4474
|
+
return DATE_FORMAT_SUGGESTIONS.map((suggestion) => ({
|
|
4475
|
+
path: suggestion.segment,
|
|
4476
|
+
segment: suggestion.segment,
|
|
4477
|
+
description: suggestion.description,
|
|
4478
|
+
type: "\u683C\u5F0F"
|
|
4479
|
+
}));
|
|
4480
|
+
}
|
|
4481
|
+
function headCandidates(schema, context, rowSchema, exprLen, withBuckets) {
|
|
4102
4482
|
const view = schemaChildEntries(schema);
|
|
4103
|
-
const candidates = view.entries.
|
|
4104
|
-
candidates.push({ path: "$root", segment: "$root" });
|
|
4483
|
+
const candidates = view.entries.flatMap((entry) => childCandidates(entry, "", exprLen, withBuckets));
|
|
4484
|
+
candidates.push({ path: "$root", segment: "$root", kind: "path" });
|
|
4105
4485
|
if (context === "row") {
|
|
4106
|
-
candidates.push(rowSchema ? { path: "row", segment: "row", ...candidateMeta(rowSchema) } : { path: "row", segment: "row" });
|
|
4107
|
-
candidates.push({ path: "$index", segment: "$index" });
|
|
4486
|
+
candidates.push(rowSchema ? { path: "row", segment: "row", kind: "path", ...candidateMeta(rowSchema) } : { path: "row", segment: "row", kind: "path" });
|
|
4487
|
+
candidates.push({ path: "$index", segment: "$index", kind: "path" });
|
|
4108
4488
|
}
|
|
4109
|
-
return
|
|
4489
|
+
return candidates;
|
|
4110
4490
|
}
|
|
4111
|
-
function
|
|
4491
|
+
function callSlotResult(schema, query) {
|
|
4492
|
+
const slot = expressionCallSlotAtEnd(query.expr);
|
|
4493
|
+
if (slot === null) {
|
|
4494
|
+
return { ok: true, prefix: "", partial: "", candidates: [] };
|
|
4495
|
+
}
|
|
4496
|
+
if (slot.stringSlot && slot.index >= 1 && slot.name === "date") {
|
|
4497
|
+
return { ok: true, prefix: "", partial: slot.text, candidates: dateFormatCandidates() };
|
|
4498
|
+
}
|
|
4499
|
+
if (slot.index === 0 && !isCallFragment(slot.text)) {
|
|
4500
|
+
const sub = enumeratePathCandidates(schema, query, slot.text, false);
|
|
4501
|
+
if (!sub.ok) return { ok: true, prefix: "", partial: "", candidates: [] };
|
|
4502
|
+
return sub;
|
|
4503
|
+
}
|
|
4504
|
+
return { ok: true, prefix: "", partial: "", candidates: [] };
|
|
4505
|
+
}
|
|
4506
|
+
function enumeratePathCandidates(schema, query, expr, allowCallSuggestions) {
|
|
4112
4507
|
if (schema === null) {
|
|
4113
4508
|
return { ok: true, prefix: "", partial: "", candidates: [] };
|
|
4114
4509
|
}
|
|
4115
|
-
const hadTrailingDot =
|
|
4116
|
-
const stripped = hadTrailingDot ?
|
|
4510
|
+
const hadTrailingDot = expr.endsWith(".");
|
|
4511
|
+
const stripped = hadTrailingDot ? expr.slice(0, -1) : expr;
|
|
4117
4512
|
if (stripped === "") {
|
|
4118
|
-
if (
|
|
4119
|
-
return {
|
|
4513
|
+
if (expr === "") {
|
|
4514
|
+
return {
|
|
4515
|
+
ok: true,
|
|
4516
|
+
prefix: "",
|
|
4517
|
+
partial: "",
|
|
4518
|
+
candidates: headCandidates(schema, query.context, query.rowSchema, expr.length, false)
|
|
4519
|
+
};
|
|
4120
4520
|
}
|
|
4121
4521
|
return { ok: false, reason: "expression_syntax_error" };
|
|
4122
4522
|
}
|
|
@@ -4137,8 +4537,16 @@ function enumerateExpressionCandidates(schema, query) {
|
|
|
4137
4537
|
prefixPath = [];
|
|
4138
4538
|
partial = headName(head);
|
|
4139
4539
|
}
|
|
4540
|
+
const withBuckets = allowCallSuggestions && partial !== "";
|
|
4140
4541
|
if (prefixPath.length === 0) {
|
|
4141
|
-
|
|
4542
|
+
const view2 = headCandidates(schema, query.context, query.rowSchema, expr.length, withBuckets);
|
|
4543
|
+
const fns = allowCallSuggestions && expr !== "" ? functionCandidates() : [];
|
|
4544
|
+
return {
|
|
4545
|
+
ok: true,
|
|
4546
|
+
prefix: "",
|
|
4547
|
+
partial,
|
|
4548
|
+
candidates: [...view2, ...fns]
|
|
4549
|
+
};
|
|
4142
4550
|
}
|
|
4143
4551
|
let base;
|
|
4144
4552
|
let segments;
|
|
@@ -4167,17 +4575,25 @@ function enumerateExpressionCandidates(schema, query) {
|
|
|
4167
4575
|
ok: true,
|
|
4168
4576
|
prefix,
|
|
4169
4577
|
partial,
|
|
4170
|
-
candidates: view.entries.
|
|
4171
|
-
...view.open === true ? { open: true } : {}
|
|
4578
|
+
candidates: view.entries.flatMap((entry) => childCandidates(entry, prefix, expr.length, withBuckets))
|
|
4172
4579
|
};
|
|
4173
4580
|
}
|
|
4581
|
+
function enumerateExpressionCandidates(schema, query) {
|
|
4582
|
+
if (schema === null) {
|
|
4583
|
+
return { ok: true, prefix: "", partial: "", candidates: [] };
|
|
4584
|
+
}
|
|
4585
|
+
if (isCallFragment(query.expr)) {
|
|
4586
|
+
return callSlotResult(schema, query);
|
|
4587
|
+
}
|
|
4588
|
+
return enumeratePathCandidates(schema, query, query.expr, true);
|
|
4589
|
+
}
|
|
4174
4590
|
|
|
4175
4591
|
// src/shared/rowsPathCandidates.ts
|
|
4176
4592
|
function isArrayNode(node) {
|
|
4177
4593
|
return node.type === "array" || node.items !== void 0;
|
|
4178
4594
|
}
|
|
4179
4595
|
function isScalarNode(node) {
|
|
4180
|
-
return !isArrayNode(node) && node.properties === void 0
|
|
4596
|
+
return !isArrayNode(node) && node.properties === void 0;
|
|
4181
4597
|
}
|
|
4182
4598
|
function childCandidate2(key, node, prefix) {
|
|
4183
4599
|
const candidate = {
|
|
@@ -4197,7 +4613,7 @@ function levelCandidates(base, prefix) {
|
|
|
4197
4613
|
candidates.push(childCandidate2(key, child, prefix));
|
|
4198
4614
|
}
|
|
4199
4615
|
}
|
|
4200
|
-
return
|
|
4616
|
+
return candidates;
|
|
4201
4617
|
}
|
|
4202
4618
|
function enumerateRowsPathCandidates(startSchema, input) {
|
|
4203
4619
|
if (startSchema === null) return null;
|
|
@@ -4213,11 +4629,7 @@ function enumerateRowsPathCandidates(startSchema, input) {
|
|
|
4213
4629
|
}
|
|
4214
4630
|
if (isArrayNode(base) || isScalarNode(base)) return null;
|
|
4215
4631
|
const view = levelCandidates(base, completed.join("."));
|
|
4216
|
-
return {
|
|
4217
|
-
partial,
|
|
4218
|
-
candidates: view.candidates,
|
|
4219
|
-
...view.open === true ? { open: true } : {}
|
|
4220
|
-
};
|
|
4632
|
+
return { partial, candidates: view };
|
|
4221
4633
|
}
|
|
4222
4634
|
function resolveRowsPathStartSchema(doc, path, rootSchema) {
|
|
4223
4635
|
if (rootSchema === null) return null;
|
|
@@ -4320,15 +4732,18 @@ export {
|
|
|
4320
4732
|
ANCHORS,
|
|
4321
4733
|
ARM_CREATE_LAYER_TYPES,
|
|
4322
4734
|
CREATE_DEAD_ZONE_SCREEN_PX,
|
|
4735
|
+
DATE_FORMAT_SUGGESTIONS,
|
|
4323
4736
|
DEFAULT_EDITOR_SHORTCUTS,
|
|
4324
4737
|
DEFAULT_ZOOM_BOUNDS,
|
|
4325
4738
|
EDITOR_STATE_SCHEMA_VERSION,
|
|
4739
|
+
EXPRESSION_FUNCTIONS,
|
|
4326
4740
|
EditorSession,
|
|
4327
4741
|
EditorStore,
|
|
4328
4742
|
FontCatalog,
|
|
4329
4743
|
HORIZONTAL_ALIGNS,
|
|
4330
4744
|
LAYER_TYPES,
|
|
4331
4745
|
MAX_HISTORY_STEPS,
|
|
4746
|
+
NUMBER_FUNCTION_SUGGESTIONS,
|
|
4332
4747
|
PACKAGE_NAME,
|
|
4333
4748
|
PAN_TO_BOX_MARGIN_PX,
|
|
4334
4749
|
PASTE_OFFSET_PX,
|
|
@@ -4366,6 +4781,8 @@ export {
|
|
|
4366
4781
|
deleteLayerInDraft,
|
|
4367
4782
|
enumerateExpressionCandidates,
|
|
4368
4783
|
enumerateRowsPathCandidates,
|
|
4784
|
+
expressionCallSlotAtEnd,
|
|
4785
|
+
expressionDiagnostics,
|
|
4369
4786
|
expressionFragmentAtCursor,
|
|
4370
4787
|
fitRect,
|
|
4371
4788
|
fitViewport,
|
|
@@ -4375,6 +4792,7 @@ export {
|
|
|
4375
4792
|
hitTest,
|
|
4376
4793
|
insertRootLayerAdjacentInDraft,
|
|
4377
4794
|
insertRootLayerInDraft,
|
|
4795
|
+
isCallFragment,
|
|
4378
4796
|
isImageContentUndrawn,
|
|
4379
4797
|
isLayerPath,
|
|
4380
4798
|
isLockedPath,
|
|
@@ -4393,11 +4811,13 @@ export {
|
|
|
4393
4811
|
normalizeExpressionSchemaSource,
|
|
4394
4812
|
panBy,
|
|
4395
4813
|
panToBox,
|
|
4814
|
+
parseExpressionCall,
|
|
4396
4815
|
parseExpressionPath,
|
|
4397
4816
|
parseExpressionSchema,
|
|
4398
4817
|
pastePosition,
|
|
4399
4818
|
pathStartsWith,
|
|
4400
4819
|
pathsEqual,
|
|
4820
|
+
phpTrim2 as phpTrim,
|
|
4401
4821
|
pickNextTextStylePatch,
|
|
4402
4822
|
prepareRootPaste,
|
|
4403
4823
|
readSpecField,
|
|
@@ -4414,6 +4834,7 @@ export {
|
|
|
4414
4834
|
resolveRowsPathStartSchema,
|
|
4415
4835
|
resolveSnap,
|
|
4416
4836
|
resolveSnapPoints,
|
|
4837
|
+
resourcePathDiagnostics,
|
|
4417
4838
|
rootLayerOf,
|
|
4418
4839
|
scanExpressionFragments,
|
|
4419
4840
|
scanTextMatches,
|