@toloka-platform/sdk 0.1.0-preview.5 → 0.1.0-preview.7
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 +7 -11
- package/dist/cli/toloka.js +211 -125
- package/dist/cli/toloka.js.jsc +0 -0
- package/dist/cli/toloka.js.jsc.sha256 +1 -1
- package/dist/cli/toloka.js.sha256 +1 -1
- package/docs/authoring.md +17 -4
- package/docs/cli-v2.md +3 -3
- package/docs/cli.md +55 -17
- package/docs/datasets.md +8 -9
- package/docs/getting-started.md +7 -12
- package/docs/limitations.md +10 -13
- package/docs/testing-examples.md +248 -0
- package/docs/testing.md +115 -0
- package/docs/troubleshooting.md +0 -11
- package/examples/face-image-collection/README.md +7 -1
- package/examples/face-image-collection/fields.ts +20 -8
- package/examples/face-image-collection/nodes/annotate-faces/node.ts +1 -9
- package/examples/face-image-collection/nodes/order-faces/node.ts +1 -1
- package/examples/face-image-collection/pipeline.browser.integration.spec.ts +78 -0
- package/examples/video-pair-rating/README.md +14 -6
- package/examples/video-pair-rating/nodes/adjudicate/node.ts +1 -3
- package/examples/video-pair-rating/nodes/adjudicate_op/node.ts +1 -3
- package/examples/video-pair-rating/nodes/overall_preference_pick/node.ts +1 -1
- package/examples/video-pair-rating/nodes/rate_pair/node.ts +1 -1
- package/examples/video-pair-rating/pipeline.browser.integration.spec.ts +267 -0
- package/openapi/gen/api.ts +819 -898
- package/openapi/gen/models/baseModel.ts +9 -0
- package/openapi/gen/models/baseModelId.ts +2 -0
- package/openapi/gen/models/baseModelIdProperty.ts +2 -0
- package/openapi/gen/models/createDatasetExportBody.ts +3 -3
- package/openapi/gen/models/createDatasetExportBodyOneOf.ts +6 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfFormat.ts +2 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThree.ts +10 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeContract.ts +2 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeFormat.ts +2 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilter.ts +9 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldSourcesItem.ts +6 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldSourcesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldSourcesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldSourcesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItem.ts +12 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItemOperator.ts +2 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/createDatasetExportBodyOneOfThreeItemFilterFieldValuesItemValue.ts +2 -0
- package/openapi/gen/models/createProjectModelBody.ts +8 -0
- package/openapi/gen/models/createProjectModelBodyDescription.ts +2 -0
- package/openapi/gen/models/datasetExportReport.ts +9 -0
- package/openapi/gen/models/datasetExportReportErrorsItem.ts +5 -0
- package/openapi/gen/models/datasetExportReportTokens.ts +7 -0
- package/openapi/gen/models/exportJob.ts +2 -0
- package/openapi/gen/models/exportJobReport.ts +3 -0
- package/openapi/gen/models/generationNodeSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/openapi/gen/models/index.ts +64 -0
- package/openapi/gen/models/listBaseModels200.ts +5 -0
- package/openapi/gen/models/listModelVersions200.ts +7 -0
- package/openapi/gen/models/listModelVersionsParams.ts +5 -0
- package/openapi/gen/models/listProjectModels200.ts +7 -0
- package/openapi/gen/models/listProjectModelsParams.ts +5 -0
- package/openapi/gen/models/model.ts +16 -0
- package/openapi/gen/models/modelArchivedAt.ts +2 -0
- package/openapi/gen/models/modelDescription.ts +2 -0
- package/openapi/gen/models/modelId.ts +2 -0
- package/openapi/gen/models/modelVersion.ts +9 -0
- package/openapi/gen/models/modelVersionId.ts +2 -0
- package/openapi/gen/models/pipelineGraphSnapshotGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/openapi/gen/models/sampleDatasetItemsBody.ts +4 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOf.ts +8 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilter.ts +9 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldSourcesItem.ts +6 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldSourcesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldSourcesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldSourcesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItem.ts +12 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItemOperator.ts +2 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfItemFilterFieldValuesItemValue.ts +2 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethree.ts +8 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilter.ts +9 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldSourcesItem.ts +6 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldSourcesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldSourcesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldSourcesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItem.ts +12 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItemOperator.ts +2 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItemSourcesItem.ts +4 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItemSourcesItemOneOf.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItemSourcesItemOneOfTwo.ts +5 -0
- package/openapi/gen/models/sampleDatasetItemsBodyAnyOfOnethreeItemFilterFieldValuesItemValue.ts +2 -0
- package/openapi/gen/models/sampleJob.ts +13 -0
- package/openapi/gen/models/sampleJobStatus.ts +2 -0
- package/openapi/gen/models/sampleResult.ts +5 -0
- package/openapi/gen/models/validatePipelineGraphBodyGraphNodesItemOneOfThreeoneSettingsAudienceAndPricingOneOfOneone.ts +1 -0
- package/package.json +23 -2
- package/skills/catalog.json +14 -6
- package/skills/toloka-build/SKILL.md +34 -12
- package/skills/toloka-build/references/node-semantics.md +27 -24
- package/skills/toloka-build/references/workflow-and-cli.md +67 -27
- package/skills/toloka-report-issue/references/report-template.md +1 -1
- package/src/checks/ast.ts +32 -0
- package/src/checks/index.ts +14 -0
- package/src/checks/postprocess-collisions.ts +145 -0
- package/src/checks/task-ui-declarations.generated.ts +19 -0
- package/src/checks/task-ui-typecheck.ts +345 -0
- package/src/checks/typescript-vfs.d.ts +26 -0
- package/src/checks/typescript-vfs.js +5 -0
- package/src/cli/analytics.ts +1 -0
- package/src/cli/check.ts +977 -0
- package/src/cli/data.ts +148 -25
- package/src/cli/models.ts +188 -0
- package/src/cli/program.ts +246 -20
- package/src/cli/project-context.ts +14 -4
- package/src/cli/runs.ts +21 -11
- package/src/cli/skill.ts +17 -6
- package/src/client.ts +109 -35
- package/src/errors.ts +25 -10
- package/src/testing/code-node.ts +160 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/task-ui-browser.ts +120 -0
- package/src/testing/task-ui-validation.ts +135 -0
- package/src/testing/task-ui.ts +557 -0
- package/src/testing/test-evidence.ts +170 -0
- package/src/testing/types.ts +141 -0
- package/src/transport.ts +16 -13
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { assert } from "es-toolkit";
|
|
5
|
+
import { type OxcError, parseSync } from "oxc-parser";
|
|
6
|
+
import ts from "typescript-api";
|
|
7
|
+
import { taskUiDeclarationSnapshot } from "./task-ui-declarations.generated";
|
|
8
|
+
import {
|
|
9
|
+
createDefaultMapFromNodeModules,
|
|
10
|
+
createSystem,
|
|
11
|
+
createVirtualTypeScriptEnvironment,
|
|
12
|
+
} from "./typescript-vfs.js";
|
|
13
|
+
|
|
14
|
+
const tsLibDirectory = path.dirname(createRequire(import.meta.url).resolve("typescript-api"));
|
|
15
|
+
|
|
16
|
+
const BLOCK_MARKERS = {
|
|
17
|
+
data: "DATA_INJECTION",
|
|
18
|
+
constants: "CONST_INJECTION",
|
|
19
|
+
preprocess: "PREPROCESS_INJECTION",
|
|
20
|
+
postprocess: "POSTPROCESS_INJECTION",
|
|
21
|
+
code: "CODE_INJECTION",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type TaskUiBlockKey = keyof typeof BLOCK_MARKERS;
|
|
25
|
+
|
|
26
|
+
export type TaskUiDiagnostic = {
|
|
27
|
+
severity: "error" | "warning";
|
|
28
|
+
text: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type TaskUiDiagnosticsReport = Record<TaskUiBlockKey, TaskUiDiagnostic[]>;
|
|
32
|
+
|
|
33
|
+
export type TaskUiSource = Record<TaskUiBlockKey, string>;
|
|
34
|
+
|
|
35
|
+
export type TaskUiDeclarationSource = {
|
|
36
|
+
readonly reactDeclaration: string;
|
|
37
|
+
readonly elementsDeclaration: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const FILE_NAME = "index.tsx";
|
|
41
|
+
|
|
42
|
+
const blockEntries: Array<[TaskUiBlockKey, string]> = [
|
|
43
|
+
["data", BLOCK_MARKERS.data],
|
|
44
|
+
["constants", BLOCK_MARKERS.constants],
|
|
45
|
+
["preprocess", BLOCK_MARKERS.preprocess],
|
|
46
|
+
["postprocess", BLOCK_MARKERS.postprocess],
|
|
47
|
+
["code", BLOCK_MARKERS.code],
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const emptyReport = (): TaskUiDiagnosticsReport => ({
|
|
51
|
+
data: [],
|
|
52
|
+
constants: [],
|
|
53
|
+
preprocess: [],
|
|
54
|
+
postprocess: [],
|
|
55
|
+
code: [],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const buildCompositeSource = (input: TaskUiSource): string => `
|
|
59
|
+
import * as React from 'react';
|
|
60
|
+
import { View, Field, Layout, SuspensePendingMarker, Validation, actions } from 'elements';
|
|
61
|
+
|
|
62
|
+
declare global {
|
|
63
|
+
const data: /* DATA_INJECTION_START */
|
|
64
|
+
(
|
|
65
|
+
${input.data}
|
|
66
|
+
)
|
|
67
|
+
/* DATA_INJECTION_END */ & { [key: string]: any };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declare global {
|
|
71
|
+
const CONST: /* CONST_INJECTION_START */
|
|
72
|
+
(
|
|
73
|
+
${input.constants}
|
|
74
|
+
)
|
|
75
|
+
/* CONST_INJECTION_END */ & { [key: string]: any };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
(() => /* PREPROCESS_INJECTION_START */
|
|
79
|
+
{
|
|
80
|
+
${input.preprocess}
|
|
81
|
+
}
|
|
82
|
+
/* PREPROCESS_INJECTION_END */ )()
|
|
83
|
+
|
|
84
|
+
(() => /* POSTPROCESS_INJECTION_START */
|
|
85
|
+
{
|
|
86
|
+
${input.postprocess}
|
|
87
|
+
}
|
|
88
|
+
/* POSTPROCESS_INJECTION_END */ )()
|
|
89
|
+
|
|
90
|
+
/* CODE_INJECTION_START */
|
|
91
|
+
(
|
|
92
|
+
${input.code}
|
|
93
|
+
)
|
|
94
|
+
/* CODE_INJECTION_END */
|
|
95
|
+
|
|
96
|
+
export {}`;
|
|
97
|
+
|
|
98
|
+
const buildRuntimeSource = (input: TaskUiSource): string => `
|
|
99
|
+
const data = (
|
|
100
|
+
/* DATA_INJECTION_START */
|
|
101
|
+
${input.data}
|
|
102
|
+
/* DATA_INJECTION_END */
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const CONST = (
|
|
106
|
+
/* CONST_INJECTION_START */
|
|
107
|
+
${input.constants}
|
|
108
|
+
/* CONST_INJECTION_END */
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const preprocess = (data) => {
|
|
112
|
+
/* PREPROCESS_INJECTION_START */
|
|
113
|
+
${input.preprocess}
|
|
114
|
+
/* PREPROCESS_INJECTION_END */
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const postprocess = (data) => {
|
|
118
|
+
/* POSTPROCESS_INJECTION_START */
|
|
119
|
+
${input.postprocess}
|
|
120
|
+
/* POSTPROCESS_INJECTION_END */
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const code = (
|
|
124
|
+
/* CODE_INJECTION_START */
|
|
125
|
+
${input.code}
|
|
126
|
+
/* CODE_INJECTION_END */
|
|
127
|
+
);
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const runtimeJavaScriptBlocks: TaskUiBlockKey[] = ["preprocess", "postprocess", "code"];
|
|
131
|
+
|
|
132
|
+
const mergeRuntimeDiagnostics = (
|
|
133
|
+
typeScriptReport: TaskUiDiagnosticsReport,
|
|
134
|
+
syntacticReport: TaskUiDiagnosticsReport,
|
|
135
|
+
runtimeReport: TaskUiDiagnosticsReport,
|
|
136
|
+
): TaskUiDiagnosticsReport => {
|
|
137
|
+
const report = { ...typeScriptReport };
|
|
138
|
+
|
|
139
|
+
for (const block of runtimeJavaScriptBlocks) {
|
|
140
|
+
const syntacticTexts = new Set(syntacticReport[block].map((diagnostic) => diagnostic.text));
|
|
141
|
+
const semanticDiagnostics = typeScriptReport[block].filter(
|
|
142
|
+
(diagnostic) =>
|
|
143
|
+
!syntacticTexts.has(diagnostic.text) && !/TS(?:7006|7031)\b/u.test(diagnostic.text),
|
|
144
|
+
);
|
|
145
|
+
const syntaxDiagnostics =
|
|
146
|
+
runtimeReport[block].length > 0 ? runtimeReport[block] : syntacticReport[block];
|
|
147
|
+
report[block] = [...semanticDiagnostics, ...syntaxDiagnostics];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return report;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const mapDiagnosticsToBlocks = (
|
|
154
|
+
source: string,
|
|
155
|
+
diagnostics: readonly ts.Diagnostic[],
|
|
156
|
+
): TaskUiDiagnosticsReport => {
|
|
157
|
+
const getDiagnosticsForBlock = (marker: string): TaskUiDiagnostic[] => {
|
|
158
|
+
const start = source.indexOf(`/* ${marker}_START */`) + `/* ${marker}_START */`.length + 1;
|
|
159
|
+
const end = source.indexOf(`/* ${marker}_END */`) - 1;
|
|
160
|
+
|
|
161
|
+
return diagnostics
|
|
162
|
+
.filter((diagnostic) => {
|
|
163
|
+
if (!diagnostic.file || diagnostic.start == null) return false;
|
|
164
|
+
return diagnostic.start >= start && diagnostic.start <= end;
|
|
165
|
+
})
|
|
166
|
+
.map((diagnostic) => {
|
|
167
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
168
|
+
const severity = diagnostic.category === ts.DiagnosticCategory.Error ? "error" : "warning";
|
|
169
|
+
assert(diagnostic.file && diagnostic.start != null, "Diagnostic location is missing");
|
|
170
|
+
const { line: startLine, character: startCharacter } =
|
|
171
|
+
diagnostic.file.getLineAndCharacterOfPosition(start);
|
|
172
|
+
const { line: originalLine, character: originalCharacter } =
|
|
173
|
+
diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
174
|
+
const line = originalLine - startLine;
|
|
175
|
+
const character =
|
|
176
|
+
originalLine === startLine ? originalCharacter - startCharacter : originalCharacter;
|
|
177
|
+
const lineText = diagnostic.file.text.split(/\r?\n/gu)[originalLine] ?? "";
|
|
178
|
+
const pointer =
|
|
179
|
+
" ".repeat(originalCharacter) +
|
|
180
|
+
"^".repeat(diagnostic.length && diagnostic.length > 0 ? diagnostic.length : 1);
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
severity,
|
|
184
|
+
text: [
|
|
185
|
+
`${line}:${character + 1} - [${ts.DiagnosticCategory[diagnostic.category]}] TS${diagnostic.code}`,
|
|
186
|
+
message,
|
|
187
|
+
"",
|
|
188
|
+
lineText,
|
|
189
|
+
pointer,
|
|
190
|
+
].join("\n"),
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
data: getDiagnosticsForBlock(BLOCK_MARKERS.data),
|
|
197
|
+
constants: getDiagnosticsForBlock(BLOCK_MARKERS.constants),
|
|
198
|
+
preprocess: getDiagnosticsForBlock(BLOCK_MARKERS.preprocess),
|
|
199
|
+
postprocess: getDiagnosticsForBlock(BLOCK_MARKERS.postprocess),
|
|
200
|
+
code: getDiagnosticsForBlock(BLOCK_MARKERS.code),
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const mapParseErrorsToBlocks = (
|
|
205
|
+
source: string,
|
|
206
|
+
errors: readonly OxcError[],
|
|
207
|
+
): TaskUiDiagnosticsReport => {
|
|
208
|
+
const lineStartOffsets = [0];
|
|
209
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
210
|
+
if (source[index] === "\n") lineStartOffsets.push(index + 1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const getLineAndCharacterOfPosition = (position: number) => {
|
|
214
|
+
let line = 0;
|
|
215
|
+
while (line + 1 < lineStartOffsets.length && lineStartOffsets[line + 1]! <= position) {
|
|
216
|
+
line += 1;
|
|
217
|
+
}
|
|
218
|
+
return { line, character: position - lineStartOffsets[line]! };
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const sourceLines = source.split(/\r?\n/gu);
|
|
222
|
+
const blocks = blockEntries.map(([key, marker]) => ({
|
|
223
|
+
key,
|
|
224
|
+
start: source.indexOf(`/* ${marker}_START */`) + `/* ${marker}_START */`.length + 1,
|
|
225
|
+
end: source.indexOf(`/* ${marker}_END */`) - 1,
|
|
226
|
+
}));
|
|
227
|
+
const findBlockForPosition = (position: number) => {
|
|
228
|
+
const containing = blocks.find((block) => position >= block.start && position <= block.end);
|
|
229
|
+
if (containing) return containing;
|
|
230
|
+
const preceding = blocks.filter((block) => block.start <= position);
|
|
231
|
+
const block = preceding.at(-1) ?? blocks[0];
|
|
232
|
+
assert(block, "Task UI diagnostic block is missing");
|
|
233
|
+
return block;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const report = emptyReport();
|
|
237
|
+
for (const error of errors) {
|
|
238
|
+
const label = error.labels[0];
|
|
239
|
+
const position = label?.start ?? source.length;
|
|
240
|
+
const block = findBlockForPosition(position);
|
|
241
|
+
const severity = error.severity === "Error" ? "error" : "warning";
|
|
242
|
+
const { line: startLine, character: startCharacter } = getLineAndCharacterOfPosition(
|
|
243
|
+
block.start,
|
|
244
|
+
);
|
|
245
|
+
const { line: originalLine, character: originalCharacter } =
|
|
246
|
+
getLineAndCharacterOfPosition(position);
|
|
247
|
+
const line = originalLine - startLine;
|
|
248
|
+
const character =
|
|
249
|
+
originalLine === startLine ? originalCharacter - startCharacter : originalCharacter;
|
|
250
|
+
const lineText = sourceLines[originalLine] ?? "";
|
|
251
|
+
const length = label ? label.end - label.start : 0;
|
|
252
|
+
const pointer = " ".repeat(originalCharacter) + "^".repeat(length > 0 ? length : 1);
|
|
253
|
+
|
|
254
|
+
report[block.key].push({
|
|
255
|
+
severity,
|
|
256
|
+
text: [
|
|
257
|
+
`${line}:${character + 1} - [${error.severity}]`,
|
|
258
|
+
error.message,
|
|
259
|
+
"",
|
|
260
|
+
lineText,
|
|
261
|
+
pointer,
|
|
262
|
+
].join("\n"),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return report;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export const createTaskUiTypechecker = ({
|
|
270
|
+
reactDeclaration,
|
|
271
|
+
elementsDeclaration,
|
|
272
|
+
}: TaskUiDeclarationSource) => ({
|
|
273
|
+
performTypeCheck: async (input: TaskUiSource): Promise<TaskUiDiagnosticsReport> => {
|
|
274
|
+
const source = buildCompositeSource(input);
|
|
275
|
+
const fsMap = createDefaultMapFromNodeModules(
|
|
276
|
+
{ target: ts.ScriptTarget.Latest },
|
|
277
|
+
ts,
|
|
278
|
+
tsLibDirectory,
|
|
279
|
+
);
|
|
280
|
+
fsMap.set("node_modules/@types/react/index.d.ts", reactDeclaration);
|
|
281
|
+
fsMap.set("node_modules/elements/index.d.ts", elementsDeclaration);
|
|
282
|
+
fsMap.set(FILE_NAME, source);
|
|
283
|
+
const system = createSystem(fsMap);
|
|
284
|
+
const { languageService } = createVirtualTypeScriptEnvironment(system, [FILE_NAME], ts, {
|
|
285
|
+
target: ts.ScriptTarget.Latest,
|
|
286
|
+
allowNonTsExtensions: true,
|
|
287
|
+
ignoreDeprecations: "6.0",
|
|
288
|
+
module: ts.ModuleKind.CommonJS,
|
|
289
|
+
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
290
|
+
noEmit: true,
|
|
291
|
+
typeRoots: ["node_modules/@types"],
|
|
292
|
+
jsx: ts.JsxEmit.React,
|
|
293
|
+
jsxFactory: "React.createElement",
|
|
294
|
+
noErrorTruncation: true,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
let syntacticDiagnostics: ts.Diagnostic[] = [];
|
|
298
|
+
let otherDiagnostics: ts.Diagnostic[] = [];
|
|
299
|
+
try {
|
|
300
|
+
syntacticDiagnostics = languageService.getSyntacticDiagnostics(FILE_NAME);
|
|
301
|
+
otherDiagnostics = [
|
|
302
|
+
...languageService.getSemanticDiagnostics(FILE_NAME),
|
|
303
|
+
...languageService.getSuggestionDiagnostics(FILE_NAME),
|
|
304
|
+
...languageService.getCompilerOptionsDiagnostics(),
|
|
305
|
+
];
|
|
306
|
+
} finally {
|
|
307
|
+
languageService.dispose();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const syntacticReport = mapDiagnosticsToBlocks(source, syntacticDiagnostics);
|
|
311
|
+
const typeScriptReport = mapDiagnosticsToBlocks(source, [
|
|
312
|
+
...syntacticDiagnostics,
|
|
313
|
+
...otherDiagnostics,
|
|
314
|
+
]);
|
|
315
|
+
const runtimeSource = buildRuntimeSource(input);
|
|
316
|
+
const runtimeReport = mapParseErrorsToBlocks(
|
|
317
|
+
runtimeSource,
|
|
318
|
+
parseSync("runtime.jsx", runtimeSource).errors,
|
|
319
|
+
);
|
|
320
|
+
return mergeRuntimeDiagnostics(typeScriptReport, syntacticReport, runtimeReport);
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
performSyntaxCheck: (input: TaskUiSource): TaskUiDiagnosticsReport => {
|
|
324
|
+
const typeScriptSource = buildCompositeSource(input);
|
|
325
|
+
const typeScriptReport = mapParseErrorsToBlocks(
|
|
326
|
+
typeScriptSource,
|
|
327
|
+
parseSync(FILE_NAME, typeScriptSource).errors,
|
|
328
|
+
);
|
|
329
|
+
const runtimeSource = buildRuntimeSource(input);
|
|
330
|
+
const runtimeReport = mapParseErrorsToBlocks(
|
|
331
|
+
runtimeSource,
|
|
332
|
+
parseSync("runtime.jsx", runtimeSource).errors,
|
|
333
|
+
);
|
|
334
|
+
return mergeRuntimeDiagnostics(typeScriptReport, typeScriptReport, runtimeReport);
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
export const createBundledTaskUiTypechecker = () =>
|
|
339
|
+
createTaskUiTypechecker({
|
|
340
|
+
reactDeclaration: taskUiDeclarationSnapshot.react.source,
|
|
341
|
+
elementsDeclaration: taskUiDeclarationSnapshot.elements.source,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
export type TaskUiTypechecker = ReturnType<typeof createTaskUiTypechecker>;
|
|
345
|
+
export { taskUiDeclarationSnapshot } from "./task-ui-declarations.generated";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type ts from "typescript-api";
|
|
2
|
+
|
|
3
|
+
export interface VirtualTypeScriptEnvironment {
|
|
4
|
+
sys: ts.System;
|
|
5
|
+
languageService: ts.LanguageService;
|
|
6
|
+
getSourceFile: (fileName: string) => ts.SourceFile | undefined;
|
|
7
|
+
createFile: (fileName: string, content: string) => void;
|
|
8
|
+
updateFile: (fileName: string, content: string, replaceTextSpan?: ts.TextSpan) => void;
|
|
9
|
+
deleteFile: (fileName: string) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export declare function createVirtualTypeScriptEnvironment(
|
|
13
|
+
sys: ts.System,
|
|
14
|
+
rootFiles: string[],
|
|
15
|
+
tsModule: typeof ts,
|
|
16
|
+
compilerOptions?: ts.CompilerOptions,
|
|
17
|
+
customTransformers?: ts.CustomTransformers,
|
|
18
|
+
): VirtualTypeScriptEnvironment;
|
|
19
|
+
|
|
20
|
+
export declare const createDefaultMapFromNodeModules: (
|
|
21
|
+
compilerOptions: ts.CompilerOptions,
|
|
22
|
+
tsModule: typeof ts,
|
|
23
|
+
tsLibDirectory: string,
|
|
24
|
+
) => Map<string, string>;
|
|
25
|
+
|
|
26
|
+
export declare function createSystem(files: Map<string, string>): ts.System;
|
package/src/cli/analytics.ts
CHANGED