@nocobase/client-v2 2.1.0-alpha.26 → 2.1.0-alpha.27
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/es/BaseApplication.d.ts +1 -0
- package/es/flow/actions/dataScopeFilter.d.ts +9 -0
- package/es/flow/components/Grid/index.d.ts +5 -3
- package/es/flow/components/code-editor/types.d.ts +1 -0
- package/es/flow/internal/utils/rebuildFieldSubModel.d.ts +2 -1
- package/es/flow/models/base/GridModel.d.ts +19 -2
- package/es/flow/models/blocks/filter-form/FilterFormGridModel.d.ts +1 -0
- package/es/flow/models/fields/JSFieldModel.d.ts +5 -0
- package/es/index.mjs +83 -83
- package/lib/index.js +83 -83
- package/package.json +5 -5
- package/src/BaseApplication.tsx +4 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +158 -0
- package/src/flow/actions/dataScope.tsx +6 -4
- package/src/flow/actions/dataScopeFilter.ts +70 -0
- package/src/flow/actions/setTargetDataScope.tsx +6 -5
- package/src/flow/components/Grid/index.tsx +66 -20
- package/src/flow/components/code-editor/__tests__/linter.test.ts +18 -0
- package/src/flow/components/code-editor/__tests__/runjsDiagnostics.test.ts +23 -0
- package/src/flow/components/code-editor/index.tsx +18 -17
- package/src/flow/components/code-editor/linter.ts +222 -158
- package/src/flow/components/code-editor/runjsDiagnostics.ts +161 -97
- package/src/flow/components/code-editor/types.ts +1 -0
- package/src/flow/internal/utils/__tests__/rebuildFieldSubModel.test.ts +77 -2
- package/src/flow/internal/utils/rebuildFieldSubModel.ts +21 -5
- package/src/flow/models/base/BlockGridModel.tsx +2 -2
- package/src/flow/models/base/GridModel.tsx +428 -195
- package/src/flow/models/base/__tests__/BlockGridModel.dragOverlayConfig.test.ts +44 -0
- package/src/flow/models/base/__tests__/GridModel.computeOverlayRect.test.ts +29 -0
- package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +181 -2
- package/src/flow/models/base/__tests__/GridModel.resizeLayout.test.ts +124 -0
- package/src/flow/models/base/__tests__/GridModel.visibleLayout.test.ts +55 -15
- package/src/flow/models/blocks/details/DetailsGridModel.tsx +6 -6
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +9 -5
- package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +54 -14
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormBlockModel.cleanup.test.ts +138 -0
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.toggleFormFieldsCollapse.test.ts +45 -0
- package/src/flow/models/blocks/form/FormGridModel.tsx +6 -6
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +22 -0
- package/src/flow/models/blocks/table/JSColumnModel.tsx +30 -2
- package/src/flow/models/blocks/table/TableBlockModel.tsx +8 -1
- package/src/flow/models/blocks/table/TableColumnModel.tsx +1 -0
- package/src/flow/models/blocks/table/__tests__/JSColumnModel.test.tsx +51 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +49 -0
- package/src/flow/models/fields/JSFieldModel.tsx +54 -14
|
@@ -16,6 +16,50 @@ import jsx from 'acorn-jsx';
|
|
|
16
16
|
// @ts-ignore
|
|
17
17
|
import * as acornWalk from 'acorn-walk';
|
|
18
18
|
|
|
19
|
+
const acornWalkBase = {
|
|
20
|
+
...(acornWalk as any).base,
|
|
21
|
+
JSXElement(node: any, state: any, callback: any) {
|
|
22
|
+
callback(node.openingElement, state);
|
|
23
|
+
for (const child of node.children || []) callback(child, state);
|
|
24
|
+
if (node.closingElement) callback(node.closingElement, state);
|
|
25
|
+
},
|
|
26
|
+
JSXFragment(node: any, state: any, callback: any) {
|
|
27
|
+
callback(node.openingFragment, state);
|
|
28
|
+
for (const child of node.children || []) callback(child, state);
|
|
29
|
+
callback(node.closingFragment, state);
|
|
30
|
+
},
|
|
31
|
+
JSXOpeningElement(node: any, state: any, callback: any) {
|
|
32
|
+
callback(node.name, state);
|
|
33
|
+
for (const attribute of node.attributes || []) callback(attribute, state);
|
|
34
|
+
},
|
|
35
|
+
JSXClosingElement(node: any, state: any, callback: any) {
|
|
36
|
+
callback(node.name, state);
|
|
37
|
+
},
|
|
38
|
+
JSXAttribute(node: any, state: any, callback: any) {
|
|
39
|
+
callback(node.name, state);
|
|
40
|
+
if (node.value) callback(node.value, state);
|
|
41
|
+
},
|
|
42
|
+
JSXExpressionContainer(node: any, state: any, callback: any) {
|
|
43
|
+
callback(node.expression, state);
|
|
44
|
+
},
|
|
45
|
+
JSXSpreadAttribute(node: any, state: any, callback: any) {
|
|
46
|
+
callback(node.argument, state);
|
|
47
|
+
},
|
|
48
|
+
JSXMemberExpression(node: any, state: any, callback: any) {
|
|
49
|
+
callback(node.object, state);
|
|
50
|
+
callback(node.property, state);
|
|
51
|
+
},
|
|
52
|
+
JSXNamespacedName(node: any, state: any, callback: any) {
|
|
53
|
+
callback(node.namespace, state);
|
|
54
|
+
callback(node.name, state);
|
|
55
|
+
},
|
|
56
|
+
JSXIdentifier() {},
|
|
57
|
+
JSXText() {},
|
|
58
|
+
JSXEmptyExpression() {},
|
|
59
|
+
JSXOpeningFragment() {},
|
|
60
|
+
JSXClosingFragment() {},
|
|
61
|
+
};
|
|
62
|
+
|
|
19
63
|
/**
|
|
20
64
|
* 创建 JavaScript 语法检查器 - 只检查语法错误
|
|
21
65
|
*/
|
|
@@ -673,72 +717,80 @@ export const computeDiagnosticsFromText = (
|
|
|
673
717
|
|
|
674
718
|
// 收集顶层声明(以及函数/参数名,粗粒度,尽量避免误报)
|
|
675
719
|
// 使用 full 方式更兼容,避免对特定 walker 键的依赖(如 VariableDeclarator 在某些打包环境下不可用)
|
|
676
|
-
acornWalk.full(
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
720
|
+
acornWalk.full(
|
|
721
|
+
ast,
|
|
722
|
+
(node: any) => {
|
|
723
|
+
switch (node?.type) {
|
|
724
|
+
case 'VariableDeclarator':
|
|
725
|
+
addPatternIds(node.id);
|
|
726
|
+
break;
|
|
727
|
+
case 'FunctionDeclaration':
|
|
728
|
+
addId(node.id);
|
|
729
|
+
(node.params || []).forEach(addPatternIds);
|
|
730
|
+
break;
|
|
731
|
+
case 'FunctionExpression':
|
|
732
|
+
// 具名函数表达式也记录 id
|
|
733
|
+
addId(node.id);
|
|
734
|
+
(node.params || []).forEach(addPatternIds);
|
|
735
|
+
break;
|
|
736
|
+
case 'ArrowFunctionExpression':
|
|
737
|
+
(node.params || []).forEach(addPatternIds);
|
|
738
|
+
break;
|
|
739
|
+
case 'CatchClause':
|
|
740
|
+
addPatternIds((node as any).param);
|
|
741
|
+
break;
|
|
742
|
+
case 'ClassDeclaration':
|
|
743
|
+
addId(node.id);
|
|
744
|
+
break;
|
|
745
|
+
default:
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
acornWalkBase,
|
|
750
|
+
);
|
|
703
751
|
|
|
704
752
|
// 1) 明显不可调用的调用表达式:如 123()、'x'()、(1+2)()
|
|
705
|
-
acornWalk.full(
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
callee
|
|
711
|
-
|
|
712
|
-
callee
|
|
713
|
-
callee.type === '
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
from
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
callee
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
753
|
+
acornWalk.full(
|
|
754
|
+
ast,
|
|
755
|
+
(node: any) => {
|
|
756
|
+
if (!node || typeof node.type !== 'string') return;
|
|
757
|
+
if (node.type === 'CallExpression') {
|
|
758
|
+
const callee = node.callee;
|
|
759
|
+
const isCallableLike =
|
|
760
|
+
callee &&
|
|
761
|
+
(callee.type === 'Identifier' ||
|
|
762
|
+
callee.type === 'MemberExpression' ||
|
|
763
|
+
callee.type === 'FunctionExpression' ||
|
|
764
|
+
callee.type === 'ArrowFunctionExpression' ||
|
|
765
|
+
callee.type === 'CallExpression' ||
|
|
766
|
+
callee.type === 'ChainExpression');
|
|
767
|
+
if (!isCallableLike) {
|
|
768
|
+
const from = (callee?.loc && (callee as any).start) ?? node.start;
|
|
769
|
+
const to = (callee?.loc && (callee as any).end) ?? node.end;
|
|
770
|
+
if (isIgnoredPos(from)) return;
|
|
771
|
+
diagnostics.push({
|
|
772
|
+
from,
|
|
773
|
+
to,
|
|
774
|
+
severity: 'warning',
|
|
775
|
+
source: 'no-noncallable-call',
|
|
776
|
+
message: 'This expression is not callable.',
|
|
777
|
+
actions: [],
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
} else if (node.type === 'NewExpression') {
|
|
781
|
+
const callee = node.callee;
|
|
782
|
+
const isConstructorLike =
|
|
783
|
+
callee &&
|
|
784
|
+
(callee.type === 'Identifier' || callee.type === 'MemberExpression' || callee.type === 'CallExpression');
|
|
785
|
+
if (!isConstructorLike) {
|
|
786
|
+
const from = (callee?.loc && (callee as any).start) ?? node.start;
|
|
787
|
+
const to = (callee?.loc && (callee as any).end) ?? node.end;
|
|
788
|
+
push(from, to, 'This constructor is not a function.');
|
|
789
|
+
}
|
|
739
790
|
}
|
|
740
|
-
}
|
|
741
|
-
|
|
791
|
+
},
|
|
792
|
+
acornWalkBase,
|
|
793
|
+
);
|
|
742
794
|
|
|
743
795
|
// 1.1) 可疑的 ctx 方法调用:ctx.xxx()
|
|
744
796
|
// - 当传入 knownCtxMemberRoots 时:对所有“不在已知 ctx API 列表中”的调用给出提示
|
|
@@ -751,124 +803,136 @@ export const computeDiagnosticsFromText = (
|
|
|
751
803
|
// Always allow some well-known ctx roots to avoid noisy false positives when doc is incomplete.
|
|
752
804
|
for (const k of ['t', 'logger', 'libs']) knownCtxRoots?.add(k);
|
|
753
805
|
const allowedShort = new Set<string>(['t']);
|
|
754
|
-
acornWalk.full(
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
let name: string | null = null;
|
|
764
|
-
if (!callee.computed && callee.property?.type === 'Identifier') name = callee.property.name;
|
|
765
|
-
else if (callee.computed && callee.property?.type === 'Literal' && typeof callee.property.value === 'string')
|
|
766
|
-
name = callee.property.value;
|
|
767
|
-
if (!name) return;
|
|
768
|
-
const normalized = String(name).trim();
|
|
769
|
-
if (!normalized || normalized.startsWith('_')) return;
|
|
770
|
-
if (knownCtxRoots) {
|
|
771
|
-
if (knownCtxRoots.has(normalized)) return;
|
|
772
|
-
} else {
|
|
773
|
-
if (normalized.length > 2) return;
|
|
774
|
-
if (allowedShort.has(normalized)) return;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
const from = (callee.property as any)?.start ?? callee.start ?? node.start;
|
|
778
|
-
const to = (callee.property as any)?.end ?? from + 1;
|
|
779
|
-
const key = `${normalized}@${from}`;
|
|
780
|
-
if (reportedCtxCalls.has(key)) return;
|
|
781
|
-
if (isIgnoredPos(from)) return;
|
|
782
|
-
diagnostics.push({
|
|
783
|
-
from,
|
|
784
|
-
to,
|
|
785
|
-
severity: 'warning',
|
|
786
|
-
source: RULE_CTX_CALL,
|
|
787
|
-
message: `Possible undefined ctx method call: ctx.${normalized}(). 可能是拼写错误或未在当前 ctx API 中定义。`,
|
|
788
|
-
actions: [],
|
|
789
|
-
});
|
|
790
|
-
reportedCtxCalls.add(key);
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
// 1.2) 可疑的 ctx 成员访问:ctx.xxx(包含 ctx.xxx.yyy 的 root 访问)
|
|
794
|
-
// 规则与方法调用保持一致,但会跳过 CallExpression.callee 的 member(避免与 1.1 重复)。
|
|
795
|
-
const reportedCtxMembers = new Set<string>();
|
|
796
|
-
acornWalk.ancestor(ast, {
|
|
797
|
-
MemberExpression(node: any, ancestors: any[]) {
|
|
798
|
-
// Only enable unknown-member detection when we have an explicit ctx API list;
|
|
799
|
-
// otherwise the false-positive rate is too high for plain member access.
|
|
800
|
-
if (!knownCtxRoots) return;
|
|
801
|
-
|
|
802
|
-
const parent = ancestors[ancestors.length - 2];
|
|
803
|
-
if (parent?.type === 'CallExpression') {
|
|
804
|
-
let callee = parent.callee;
|
|
805
|
-
if (callee?.type === 'ChainExpression') callee = callee.expression;
|
|
806
|
-
if (callee === node) return; // handled by call rule above
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
const obj = node?.object;
|
|
806
|
+
acornWalk.full(
|
|
807
|
+
ast,
|
|
808
|
+
(node: any) => {
|
|
809
|
+
if (!node || typeof node.type !== 'string') return;
|
|
810
|
+
if (node.type !== 'CallExpression') return;
|
|
811
|
+
let callee = node.callee;
|
|
812
|
+
if (callee?.type === 'ChainExpression') callee = callee.expression;
|
|
813
|
+
if (!callee || callee.type !== 'MemberExpression') return;
|
|
814
|
+
const obj = callee.object;
|
|
810
815
|
if (!obj || obj.type !== 'Identifier' || obj.name !== 'ctx') return;
|
|
811
816
|
|
|
812
817
|
let name: string | null = null;
|
|
813
|
-
if (!
|
|
814
|
-
else if (
|
|
815
|
-
name =
|
|
818
|
+
if (!callee.computed && callee.property?.type === 'Identifier') name = callee.property.name;
|
|
819
|
+
else if (callee.computed && callee.property?.type === 'Literal' && typeof callee.property.value === 'string')
|
|
820
|
+
name = callee.property.value;
|
|
816
821
|
if (!name) return;
|
|
817
822
|
const normalized = String(name).trim();
|
|
818
823
|
if (!normalized || normalized.startsWith('_')) return;
|
|
819
|
-
if (knownCtxRoots
|
|
824
|
+
if (knownCtxRoots) {
|
|
825
|
+
if (knownCtxRoots.has(normalized)) return;
|
|
826
|
+
} else {
|
|
827
|
+
if (normalized.length > 2) return;
|
|
828
|
+
if (allowedShort.has(normalized)) return;
|
|
829
|
+
}
|
|
820
830
|
|
|
821
|
-
const from = (
|
|
822
|
-
const to = (
|
|
831
|
+
const from = (callee.property as any)?.start ?? callee.start ?? node.start;
|
|
832
|
+
const to = (callee.property as any)?.end ?? from + 1;
|
|
823
833
|
const key = `${normalized}@${from}`;
|
|
824
|
-
if (
|
|
834
|
+
if (reportedCtxCalls.has(key)) return;
|
|
825
835
|
if (isIgnoredPos(from)) return;
|
|
826
|
-
|
|
827
836
|
diagnostics.push({
|
|
828
837
|
from,
|
|
829
838
|
to,
|
|
830
839
|
severity: 'warning',
|
|
831
|
-
source:
|
|
832
|
-
message: `Possible
|
|
840
|
+
source: RULE_CTX_CALL,
|
|
841
|
+
message: `Possible undefined ctx method call: ctx.${normalized}(). 可能是拼写错误或未在当前 ctx API 中定义。`,
|
|
833
842
|
actions: [],
|
|
834
843
|
});
|
|
835
|
-
|
|
844
|
+
reportedCtxCalls.add(key);
|
|
836
845
|
},
|
|
837
|
-
|
|
846
|
+
acornWalkBase,
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
// 1.2) 可疑的 ctx 成员访问:ctx.xxx(包含 ctx.xxx.yyy 的 root 访问)
|
|
850
|
+
// 规则与方法调用保持一致,但会跳过 CallExpression.callee 的 member(避免与 1.1 重复)。
|
|
851
|
+
const reportedCtxMembers = new Set<string>();
|
|
852
|
+
acornWalk.ancestor(
|
|
853
|
+
ast,
|
|
854
|
+
{
|
|
855
|
+
MemberExpression(node: any, ancestors: any[]) {
|
|
856
|
+
// Only enable unknown-member detection when we have an explicit ctx API list;
|
|
857
|
+
// otherwise the false-positive rate is too high for plain member access.
|
|
858
|
+
if (!knownCtxRoots) return;
|
|
859
|
+
|
|
860
|
+
const parent = ancestors[ancestors.length - 2];
|
|
861
|
+
if (parent?.type === 'CallExpression') {
|
|
862
|
+
let callee = parent.callee;
|
|
863
|
+
if (callee?.type === 'ChainExpression') callee = callee.expression;
|
|
864
|
+
if (callee === node) return; // handled by call rule above
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const obj = node?.object;
|
|
868
|
+
if (!obj || obj.type !== 'Identifier' || obj.name !== 'ctx') return;
|
|
869
|
+
|
|
870
|
+
let name: string | null = null;
|
|
871
|
+
if (!node.computed && node.property?.type === 'Identifier') name = node.property.name;
|
|
872
|
+
else if (node.computed && node.property?.type === 'Literal' && typeof node.property.value === 'string')
|
|
873
|
+
name = node.property.value;
|
|
874
|
+
if (!name) return;
|
|
875
|
+
const normalized = String(name).trim();
|
|
876
|
+
if (!normalized || normalized.startsWith('_')) return;
|
|
877
|
+
if (knownCtxRoots.has(normalized)) return;
|
|
878
|
+
|
|
879
|
+
const from = (node.property as any)?.start ?? node.start ?? 0;
|
|
880
|
+
const to = (node.property as any)?.end ?? from + 1;
|
|
881
|
+
const key = `${normalized}@${from}`;
|
|
882
|
+
if (reportedCtxMembers.has(key)) return;
|
|
883
|
+
if (isIgnoredPos(from)) return;
|
|
884
|
+
|
|
885
|
+
diagnostics.push({
|
|
886
|
+
from,
|
|
887
|
+
to,
|
|
888
|
+
severity: 'warning',
|
|
889
|
+
source: RULE_CTX_MEMBER,
|
|
890
|
+
message: `Possible unknown ctx member access: ctx.${normalized}. 可能是拼写错误或未在当前 ctx API 中定义。`,
|
|
891
|
+
actions: [],
|
|
892
|
+
});
|
|
893
|
+
reportedCtxMembers.add(key);
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
acornWalkBase,
|
|
897
|
+
);
|
|
838
898
|
} catch (_) {
|
|
839
899
|
// ignore
|
|
840
900
|
}
|
|
841
901
|
|
|
842
902
|
// 2) 疑似未定义变量(尽量减少误报:排除属性名与解构/声明)
|
|
843
903
|
const reported = new Set<string>();
|
|
844
|
-
acornWalk.ancestor(
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
(
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
904
|
+
acornWalk.ancestor(
|
|
905
|
+
ast,
|
|
906
|
+
{
|
|
907
|
+
Identifier(node: any, ancestors: any[]) {
|
|
908
|
+
const name = node.name;
|
|
909
|
+
if (!name || declared.has(name) || reported.has(name)) return;
|
|
910
|
+
const parent = ancestors[ancestors.length - 2];
|
|
911
|
+
if (!parent) return;
|
|
912
|
+
// 跳过声明位置 / 属性键 / 非计算属性
|
|
913
|
+
if (
|
|
914
|
+
(parent.type === 'VariableDeclarator' && parent.id === node) ||
|
|
915
|
+
(parent.type === 'FunctionDeclaration' && parent.id === node) ||
|
|
916
|
+
(parent.type === 'FunctionExpression' && parent.id === node) ||
|
|
917
|
+
(parent.type === 'ClassDeclaration' && parent.id === node) ||
|
|
918
|
+
(parent.type === 'ClassExpression' && parent.id === node) ||
|
|
919
|
+
(parent.type === 'Property' && parent.key === node && parent.computed !== true) ||
|
|
920
|
+
(parent.type === 'MemberExpression' && parent.property === node && parent.computed !== true) ||
|
|
921
|
+
(parent.type === 'LabeledStatement' && parent.label === node) ||
|
|
922
|
+
(parent.type === 'BreakStatement' && parent.label === node) ||
|
|
923
|
+
(parent.type === 'ContinueStatement' && parent.label === node)
|
|
924
|
+
) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
// 可能未定义的自由变量
|
|
928
|
+
const from = (node as any).start ?? 0;
|
|
929
|
+
const to = (node as any).end ?? from + 1;
|
|
930
|
+
push(from, to, `Possible undefined variable: ${name}`, 'warning');
|
|
931
|
+
reported.add(name);
|
|
932
|
+
},
|
|
870
933
|
},
|
|
871
|
-
|
|
934
|
+
acornWalkBase,
|
|
935
|
+
);
|
|
872
936
|
} catch (e) {
|
|
873
937
|
// 静态检查失败不影响编辑体验
|
|
874
938
|
// console.debug('[linter] static checks failed', e);
|