@zat-design/sisyphus-react 4.6.1 → 4.6.3-beta.1
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/README.md +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/less.esm.css +1 -1
- package/es/ProEditTable/style/index.less +6 -0
- package/es/ProForm/components/combination/FormList/components/ActionButton.js +10 -8
- package/es/ProForm/components/combination/FormList/components/Empty.d.ts +2 -1
- package/es/ProForm/components/combination/FormList/components/Empty.js +13 -1
- package/es/ProForm/components/combination/FormList/components/TabsFields.d.ts +15 -0
- package/es/ProForm/components/combination/FormList/components/TabsFields.js +346 -0
- package/es/ProForm/components/combination/FormList/components/ToolbarButton.js +12 -46
- package/es/ProForm/components/combination/FormList/index.js +19 -0
- package/es/ProForm/components/combination/FormList/propsType.d.ts +1 -1
- package/es/ProForm/components/combination/FormList/style/index.less +143 -10
- package/es/ProForm/components/combination/FormList/tabsValidation.d.ts +14 -0
- package/es/ProForm/components/combination/FormList/tabsValidation.js +19 -0
- package/es/ProForm/components/combination/FormList/toolbarActions.d.ts +14 -0
- package/es/ProForm/components/combination/FormList/toolbarActions.js +47 -0
- package/es/ProForm/index.js +16 -1
- package/es/locale/en_US.d.ts +1 -0
- package/es/locale/en_US.js +1 -0
- package/es/locale/zh_CN.d.ts +1 -0
- package/es/locale/zh_CN.js +1 -0
- package/es/style/theme/tokens.less +3 -3
- package/es/tokens.js +3 -3
- package/package.json +4 -2
|
@@ -17,16 +17,6 @@
|
|
|
17
17
|
color: #949599;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
.single-delete {
|
|
21
|
-
width: 14px !important;
|
|
22
|
-
height: 14px !important;
|
|
23
|
-
color: @zaui-placeholder;
|
|
24
|
-
|
|
25
|
-
&:hover {
|
|
26
|
-
color: @zaui-aide-text;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
20
|
&:nth-child(1) {
|
|
31
21
|
flex: 1;
|
|
32
22
|
}
|
|
@@ -59,6 +49,30 @@
|
|
|
59
49
|
}
|
|
60
50
|
}
|
|
61
51
|
|
|
52
|
+
.pro-form-list,
|
|
53
|
+
.pro-form-list-tabs {
|
|
54
|
+
.@{ant-prefix}-tabs-nav {
|
|
55
|
+
margin-bottom: 0 !important;
|
|
56
|
+
}
|
|
57
|
+
&.@{ant-prefix}-tabs-card {
|
|
58
|
+
.@{ant-prefix}-tabs-tab {
|
|
59
|
+
padding: 0 !important;
|
|
60
|
+
margin-right: 4px !important;
|
|
61
|
+
min-width: 70px;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.single-delete {
|
|
66
|
+
width: 14px !important;
|
|
67
|
+
height: 14px !important;
|
|
68
|
+
color: @zaui-placeholder;
|
|
69
|
+
|
|
70
|
+
&:hover {
|
|
71
|
+
color: @zaui-aide-text;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
62
76
|
.pro-form-list-line {
|
|
63
77
|
padding: var(--zaui-height-size-md, 16px);
|
|
64
78
|
padding-bottom: 0;
|
|
@@ -102,6 +116,125 @@
|
|
|
102
116
|
background: transparent !important;
|
|
103
117
|
}
|
|
104
118
|
}
|
|
119
|
+
|
|
120
|
+
.pro-form-list-tool-btn-tabs {
|
|
121
|
+
width: auto;
|
|
122
|
+
min-width: 20px;
|
|
123
|
+
height: 20px;
|
|
124
|
+
padding: 0;
|
|
125
|
+
|
|
126
|
+
&:hover {
|
|
127
|
+
background: transparent !important;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.pro-form-list-tabs {
|
|
133
|
+
&.@{ant-prefix}-tabs > .@{ant-prefix}-tabs-nav {
|
|
134
|
+
.@{ant-prefix}-tabs-nav-wrap {
|
|
135
|
+
overflow-x: clip;
|
|
136
|
+
overflow-y: visible;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.@{ant-prefix}-tabs-nav-list {
|
|
140
|
+
overflow: visible;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&.@{ant-prefix}-tabs-card > .@{ant-prefix}-tabs-nav {
|
|
145
|
+
&::before {
|
|
146
|
+
border-bottom-color: var(--ant-color-border, #d9d9d9);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.@{ant-prefix}-tabs-tab {
|
|
150
|
+
padding: 0;
|
|
151
|
+
border-color: var(--ant-color-border, #d9d9d9);
|
|
152
|
+
border-radius: var(--zaui-border-radius, 8px) var(--zaui-border-radius, 8px) 0 0;
|
|
153
|
+
|
|
154
|
+
&.@{ant-prefix}-tabs-tab-active {
|
|
155
|
+
border-bottom-color: var(--ant-color-bg-container, #fff);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.@{ant-prefix}-tabs-tab + .@{ant-prefix}-tabs-tab,
|
|
160
|
+
.@{ant-prefix}-tabs-nav-add {
|
|
161
|
+
margin-left: 4px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.@{ant-prefix}-tabs-nav-add {
|
|
165
|
+
width: auto;
|
|
166
|
+
padding: 0 @zaui-space-size-xs;
|
|
167
|
+
border-color: var(--ant-color-border, #d9d9d9);
|
|
168
|
+
border-radius: var(--zaui-border-radius, 8px) var(--zaui-border-radius, 8px) 0 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.pro-form-list-tabs-label {
|
|
173
|
+
display: inline-flex;
|
|
174
|
+
align-items: center;
|
|
175
|
+
gap: 4px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.pro-form-list-tabs-title {
|
|
179
|
+
white-space: nowrap;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.pro-form-list-tabs-error-badge {
|
|
183
|
+
display: inline-flex;
|
|
184
|
+
|
|
185
|
+
.@{ant-prefix}-badge-count {
|
|
186
|
+
top: 0;
|
|
187
|
+
right: 0;
|
|
188
|
+
z-index: 2;
|
|
189
|
+
pointer-events: none;
|
|
190
|
+
transform: translate(50%, -50%);
|
|
191
|
+
box-shadow: 0 0 0 2px var(--ant-color-bg-container, #fff);
|
|
192
|
+
transition: none;
|
|
193
|
+
animation: none;
|
|
194
|
+
|
|
195
|
+
.@{ant-prefix}-scroll-number-only-unit {
|
|
196
|
+
transition: none;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.pro-form-list-tabs-title-content {
|
|
202
|
+
display: inline-flex;
|
|
203
|
+
gap: 4px;
|
|
204
|
+
align-items: center;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.pro-form-list-tabs-drag-handle {
|
|
208
|
+
display: inline-flex;
|
|
209
|
+
align-items: center;
|
|
210
|
+
.pro-icon {
|
|
211
|
+
cursor: move;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
.pro-form-list-delete-icon {
|
|
215
|
+
&:hover {
|
|
216
|
+
background: transparent !important;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.pro-form-list-tabs-add {
|
|
221
|
+
display: inline-flex;
|
|
222
|
+
gap: 4px;
|
|
223
|
+
align-items: center;
|
|
224
|
+
white-space: nowrap;
|
|
225
|
+
.pro-form-list-tabs-add-label {
|
|
226
|
+
font-size: 14px;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.pro-form-list-action {
|
|
231
|
+
padding-bottom: 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.pro-form-list-tabs-content {
|
|
235
|
+
padding: 12px 0 0;
|
|
236
|
+
border: 0;
|
|
237
|
+
}
|
|
105
238
|
}
|
|
106
239
|
|
|
107
240
|
.pro-form-list-empty {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FormInstance } from 'antd';
|
|
2
|
+
import type { InternalNamePath } from 'antd/es/form/interface';
|
|
3
|
+
export interface FormListTabsErrorField {
|
|
4
|
+
errors?: unknown[];
|
|
5
|
+
name: InternalNamePath;
|
|
6
|
+
}
|
|
7
|
+
export interface FormListTabsValidationEvent {
|
|
8
|
+
errorFields: FormListTabsErrorField[];
|
|
9
|
+
reason: 'fieldsChange' | 'submitFailed' | 'submitSuccess';
|
|
10
|
+
}
|
|
11
|
+
type FormListTabsValidationListener = (event: FormListTabsValidationEvent) => void;
|
|
12
|
+
export declare const subscribeFormListTabsValidation: (form: FormInstance, listener: FormListTabsValidationListener) => () => void;
|
|
13
|
+
export declare const notifyFormListTabsValidation: (form: FormInstance, event: FormListTabsValidationEvent) => void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const formListeners = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
const subscribeFormListTabsValidation = (form, listener) => {
|
|
3
|
+
const listeners = formListeners.get(form) || /* @__PURE__ */ new Set();
|
|
4
|
+
listeners.add(listener);
|
|
5
|
+
formListeners.set(form, listeners);
|
|
6
|
+
return () => {
|
|
7
|
+
listeners.delete(listener);
|
|
8
|
+
if (!listeners.size)
|
|
9
|
+
formListeners.delete(form);
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const notifyFormListTabsValidation = (form, event) => {
|
|
13
|
+
var _a;
|
|
14
|
+
(_a = formListeners.get(form)) == null ? void 0 : _a.forEach((listener) => listener(event));
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
notifyFormListTabsValidation,
|
|
18
|
+
subscribeFormListTabsValidation
|
|
19
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FormInstance, FormListOperation } from 'antd';
|
|
2
|
+
import type { InternalNamePath } from 'antd/es/form/interface';
|
|
3
|
+
import type { ToolbarActionType } from './propsType';
|
|
4
|
+
export declare const FORM_LIST_ACTION_ABORT: unique symbol;
|
|
5
|
+
export declare const normalizeToolbarActions: (toolbarProps?: ToolbarActionType[]) => ToolbarActionType[];
|
|
6
|
+
export declare const isToolbarActionVisible: (item: ToolbarActionType, form: FormInstance, namePath: InternalNamePath) => boolean;
|
|
7
|
+
interface ExecuteToolbarAddOptions {
|
|
8
|
+
action: ToolbarActionType;
|
|
9
|
+
form: FormInstance;
|
|
10
|
+
namePath: InternalNamePath;
|
|
11
|
+
operation: FormListOperation;
|
|
12
|
+
}
|
|
13
|
+
export declare const executeToolbarAdd: ({ action, form, namePath, operation, }: ExecuteToolbarAddOptions) => Promise<boolean>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import isFunction from "lodash/isFunction";
|
|
2
|
+
const defaultToolbarActions = [{ type: "add" }];
|
|
3
|
+
const FORM_LIST_ACTION_ABORT = Symbol("FORM_LIST_ACTION_ABORT");
|
|
4
|
+
const normalizeToolbarActions = (toolbarProps) => {
|
|
5
|
+
const actions = toolbarProps == null ? void 0 : toolbarProps.map((item) => ({
|
|
6
|
+
...item,
|
|
7
|
+
type: item.actionType || item.type
|
|
8
|
+
}));
|
|
9
|
+
if (!(actions == null ? void 0 : actions.some((item) => item.type === "add"))) {
|
|
10
|
+
return actions ? [...actions, ...defaultToolbarActions] : defaultToolbarActions;
|
|
11
|
+
}
|
|
12
|
+
return actions;
|
|
13
|
+
};
|
|
14
|
+
const isToolbarActionVisible = (item, form, namePath) => {
|
|
15
|
+
if (item.show === false)
|
|
16
|
+
return false;
|
|
17
|
+
if (isFunction(item.show)) {
|
|
18
|
+
return item.show(form.getFieldValue(namePath), { namePath, form });
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
const executeToolbarAdd = async ({
|
|
23
|
+
action,
|
|
24
|
+
form,
|
|
25
|
+
namePath,
|
|
26
|
+
operation
|
|
27
|
+
}) => {
|
|
28
|
+
const value = form.getFieldValue(namePath);
|
|
29
|
+
const index = (value == null ? void 0 : value.length) || 0;
|
|
30
|
+
const callback = action.onClick || action.onHandle;
|
|
31
|
+
const data = await (callback == null ? void 0 : callback(value, { operation, form, namePath, index }));
|
|
32
|
+
if (callback && data !== true && !data)
|
|
33
|
+
return false;
|
|
34
|
+
const insertIndex = typeof action.addIndex === "function" ? action.addIndex(value, { namePath, form, operation, index }) : action.addIndex;
|
|
35
|
+
if (insertIndex !== void 0) {
|
|
36
|
+
operation.add(data, insertIndex);
|
|
37
|
+
} else {
|
|
38
|
+
operation.add(data);
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
};
|
|
42
|
+
export {
|
|
43
|
+
FORM_LIST_ACTION_ABORT,
|
|
44
|
+
executeToolbarAdd,
|
|
45
|
+
isToolbarActionVisible,
|
|
46
|
+
normalizeToolbarActions
|
|
47
|
+
};
|
package/es/ProForm/index.js
CHANGED
|
@@ -29,6 +29,7 @@ import locale from "../locale";
|
|
|
29
29
|
import useWatch from "./hooks/useWatch";
|
|
30
30
|
import FormsProvider, { useContextForms, useForms } from "../FormsProvider";
|
|
31
31
|
import { useStep } from "../ProStep";
|
|
32
|
+
import { notifyFormListTabsValidation } from "./components/combination/FormList/tabsValidation";
|
|
32
33
|
const ProForm = (props, ref) => {
|
|
33
34
|
const {
|
|
34
35
|
mode = "search",
|
|
@@ -144,8 +145,20 @@ const ProForm = (props, ref) => {
|
|
|
144
145
|
}
|
|
145
146
|
};
|
|
146
147
|
const handleFinish = () => {
|
|
148
|
+
notifyFormListTabsValidation(form, { reason: "submitSuccess", errorFields: [] });
|
|
147
149
|
onFinish == null ? void 0 : onFinish(form.getFieldsValue());
|
|
148
150
|
};
|
|
151
|
+
const handleFieldsChange = (changedFields, allFields) => {
|
|
152
|
+
var _a;
|
|
153
|
+
notifyFormListTabsValidation(form, {
|
|
154
|
+
reason: "fieldsChange",
|
|
155
|
+
errorFields: allFields.filter((field) => {
|
|
156
|
+
var _a2;
|
|
157
|
+
return (_a2 = field.errors) == null ? void 0 : _a2.length;
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
(_a = otherProps.onFieldsChange) == null ? void 0 : _a.call(otherProps, changedFields, allFields);
|
|
161
|
+
};
|
|
149
162
|
const cls = classnames({
|
|
150
163
|
"pro-form": true,
|
|
151
164
|
"pro-form-view": isView,
|
|
@@ -177,7 +190,7 @@ const ProForm = (props, ref) => {
|
|
|
177
190
|
otherProps.layout = otherProps.layout || "vertical";
|
|
178
191
|
}
|
|
179
192
|
}
|
|
180
|
-
const filteredOtherProps = omit(otherProps, ["desensitizationKey"]);
|
|
193
|
+
const filteredOtherProps = omit(otherProps, ["desensitizationKey", "onFieldsChange"]);
|
|
181
194
|
return /* @__PURE__ */ jsxs(
|
|
182
195
|
Form,
|
|
183
196
|
{
|
|
@@ -194,10 +207,12 @@ const ProForm = (props, ref) => {
|
|
|
194
207
|
...omit(config, ["isDiffAll"]),
|
|
195
208
|
...filteredOtherProps,
|
|
196
209
|
labelAlign: labelAlign ?? config.labelAlign ?? "left",
|
|
210
|
+
onFieldsChange: handleFieldsChange,
|
|
197
211
|
onValuesChange: handleValuesChange,
|
|
198
212
|
onFinish: handleFinish,
|
|
199
213
|
onFinishFailed: ({ errorFields }) => {
|
|
200
214
|
var _a;
|
|
215
|
+
notifyFormListTabsValidation(form, { reason: "submitFailed", errorFields });
|
|
201
216
|
if (scrollToError && (errorFields == null ? void 0 : errorFields.length)) {
|
|
202
217
|
form.scrollToField((_a = errorFields[0]) == null ? void 0 : _a.name, {
|
|
203
218
|
block: "center",
|
package/es/locale/en_US.d.ts
CHANGED
package/es/locale/en_US.js
CHANGED
package/es/locale/zh_CN.d.ts
CHANGED
package/es/locale/zh_CN.js
CHANGED
|
@@ -44,6 +44,7 @@ var zh_CN_default = {
|
|
|
44
44
|
completeText: "请完整输入",
|
|
45
45
|
halfRuleText: "请输入第({total})个表单的值",
|
|
46
46
|
formListActions: ["新增", "删除", "复制", "上移", "下移", "新增一行", "点击添加"],
|
|
47
|
+
formListTabsAdd: "新增一列",
|
|
47
48
|
formListConfirmMessage: "确认删除吗?",
|
|
48
49
|
noData: "暂无数据",
|
|
49
50
|
moreItems: "更多{count}项...",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
@zaui-table-header-bg: var(--zaui-table-header-bg; #f2f3f5);
|
|
48
48
|
@zaui-table-strip-bg: var(--zaui-table-strip-bg; #fafafa);
|
|
49
49
|
@zaui-table-hover-bg: var(--zaui-table-hover-bg; #fafafa);
|
|
50
|
-
@zaui-table-selected-bg: var(--zaui-table-hover-bg #fafafa);
|
|
51
|
-
@zaui-table-selected-hover-bg: var(--zaui-table-hover-bg #fafafa);
|
|
52
|
-
@zaui-table-nested-bg: var(--zaui-table-nested-bg #fafcfe);
|
|
50
|
+
@zaui-table-selected-bg: var(--zaui-table-hover-bg; #fafafa);
|
|
51
|
+
@zaui-table-selected-hover-bg: var(--zaui-table-hover-bg; #fafafa);
|
|
52
|
+
@zaui-table-nested-bg: var(--zaui-table-nested-bg; #fafcfe);
|
|
53
53
|
@zaui-contract-bg: var(--zaui-contract-bg; #fffaa1); // 对比背景色
|
|
54
54
|
@zaui-contract-bg-add: var(--zaui-contract-bg-add; #d2fff4); // 新增对比背景色
|
|
55
55
|
@zaui-form-required-after: var(--zaui-form-required-after; inline);
|
package/es/tokens.js
CHANGED
|
@@ -47,9 +47,9 @@ const tokens = {
|
|
|
47
47
|
"@zaui-table-header-bg": "var(--zaui-table-header-bg, #f2f3f5)",
|
|
48
48
|
"@zaui-table-strip-bg": "var(--zaui-table-strip-bg, #fafafa)",
|
|
49
49
|
"@zaui-table-hover-bg": "var(--zaui-table-hover-bg, #fafafa)",
|
|
50
|
-
"@zaui-table-selected-bg": "var(--zaui-table-hover-bg #fafafa)",
|
|
51
|
-
"@zaui-table-selected-hover-bg": "var(--zaui-table-hover-bg #fafafa)",
|
|
52
|
-
"@zaui-table-nested-bg": "var(--zaui-table-nested-bg #FAFCFE)",
|
|
50
|
+
"@zaui-table-selected-bg": "var(--zaui-table-hover-bg, #fafafa)",
|
|
51
|
+
"@zaui-table-selected-hover-bg": "var(--zaui-table-hover-bg, #fafafa)",
|
|
52
|
+
"@zaui-table-nested-bg": "var(--zaui-table-nested-bg, #FAFCFE)",
|
|
53
53
|
"@zaui-form-required-after": "var(--zaui-form-required-after, inline)",
|
|
54
54
|
"@zaui-form-required-before": "var(--zaui-form-required-before, none)",
|
|
55
55
|
"@zaui-form-label-width": "var(--zaui-form-label-width, 130px)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zat-design/sisyphus-react",
|
|
3
|
-
"version": "4.6.1",
|
|
3
|
+
"version": "4.6.3-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
"scripts": {
|
|
64
64
|
"analyze": "ANALYZE=1 dumi build",
|
|
65
65
|
"build:demo": "father build && node ./scripts/build-esm.mjs",
|
|
66
|
-
"build": "npm run build:demo && npm run build:types && mv dist/index.min.css dist/index.esm.css && mv dist/less.min.css dist/less.esm.css
|
|
66
|
+
"build:package": "npm run build:demo && npm run build:types && mv dist/index.min.css dist/index.esm.css && mv dist/less.min.css dist/less.esm.css",
|
|
67
|
+
"build": "npm run build:package && npm run build:ai-meta",
|
|
67
68
|
"build:types": "tsc -p tsconfig.build.json",
|
|
68
69
|
"build:ai-meta": "node ./scripts/build-ai-meta.mjs",
|
|
69
70
|
"check:ai-meta": "npm run build:ai-meta && cd packages/sisyphus-react-mcp && npm run check",
|
|
@@ -90,6 +91,7 @@
|
|
|
90
91
|
"test": "umi-test",
|
|
91
92
|
"test:coverage": "umi-test --coverage",
|
|
92
93
|
"test:coverage:focused": "jest --config=jest.coverage.focused.js --coverage",
|
|
94
|
+
"test:coverage:focused:95": "COVERAGE_THRESHOLD=95 jest --config=jest.coverage.focused.js --coverage",
|
|
93
95
|
"coverage:report": "node ./scripts/coverage-gap-report.mjs --target=90 --scope=full",
|
|
94
96
|
"coverage:gate": "node ./scripts/coverage-directory-gate.mjs",
|
|
95
97
|
"tsc": "tsc --noEmit"
|