@parcel/diagnostic 2.0.0-beta.3.1 → 2.0.0-dev.1510
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/lib/diagnostic.d.ts +154 -0
- package/lib/diagnostic.js +120 -100
- package/package.json +8 -3
- package/src/diagnostic.js +134 -78
- package/test/JSONCodeHighlights.test.js +36 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { Mapping } from "@mischnic/json-sourcemap";
|
|
2
|
+
/** These positions are 1-based (so <code>1</code> is the first line/column) */
|
|
3
|
+
export type DiagnosticHighlightLocation = {
|
|
4
|
+
readonly line: number;
|
|
5
|
+
readonly column: number;
|
|
6
|
+
};
|
|
7
|
+
export type DiagnosticSeverity = "error" | "warn" | "info";
|
|
8
|
+
/**
|
|
9
|
+
* Note: A tab character is always counted as a single character
|
|
10
|
+
* This is to prevent any mismatch of highlighting across machines
|
|
11
|
+
*/
|
|
12
|
+
export type DiagnosticCodeHighlight = {
|
|
13
|
+
/** Location of the first character that should get highlighted for this highlight. */
|
|
14
|
+
start: DiagnosticHighlightLocation;
|
|
15
|
+
/** Location of the last character that should get highlighted for this highlight. */
|
|
16
|
+
end: DiagnosticHighlightLocation;
|
|
17
|
+
/** A message that should be displayed at this location in the code (optional). */
|
|
18
|
+
message?: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Describes how to format a code frame.
|
|
22
|
+
* A code frame is a visualization of a piece of code with a certain amount of
|
|
23
|
+
* code highlights that point to certain chunk(s) inside the code.
|
|
24
|
+
*/
|
|
25
|
+
export type DiagnosticCodeFrame = {
|
|
26
|
+
/**
|
|
27
|
+
* The contents of the source file.
|
|
28
|
+
*
|
|
29
|
+
* If no code is passed, it will be read in from filePath, remember that
|
|
30
|
+
* the asset's current code could be different from the input contents.
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
code?: string;
|
|
34
|
+
/** Path to the file this code frame is about (optional, absolute or relative to the project root) */
|
|
35
|
+
filePath?: string;
|
|
36
|
+
/** Language of the file this code frame is about (optional) */
|
|
37
|
+
language?: string;
|
|
38
|
+
codeHighlights: Array<DiagnosticCodeHighlight>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* A style agnostic way of emitting errors, warnings and info.
|
|
42
|
+
* Reporters are responsible for rendering the message, codeframes, hints, ...
|
|
43
|
+
*/
|
|
44
|
+
export type Diagnostic = {
|
|
45
|
+
/** This is the message you want to log. */
|
|
46
|
+
message: string;
|
|
47
|
+
/** Name of plugin or file that threw this error */
|
|
48
|
+
origin?: string;
|
|
49
|
+
/** A stacktrace of the error (optional) */
|
|
50
|
+
stack?: string;
|
|
51
|
+
/** Name of the error (optional) */
|
|
52
|
+
name?: string;
|
|
53
|
+
/** A code frame points to a certain location(s) in the file this diagnostic is linked to (optional) */
|
|
54
|
+
codeFrames?: Array<DiagnosticCodeFrame> | null | undefined;
|
|
55
|
+
/** An optional list of strings that suggest ways to resolve this issue */
|
|
56
|
+
hints?: Array<string>;
|
|
57
|
+
/** @private */
|
|
58
|
+
skipFormatting?: boolean;
|
|
59
|
+
/** A URL to documentation to learn more about the diagnostic. */
|
|
60
|
+
documentationURL?: string;
|
|
61
|
+
};
|
|
62
|
+
export interface PrintableError extends Error {
|
|
63
|
+
fileName?: string;
|
|
64
|
+
filePath?: string;
|
|
65
|
+
codeFrame?: string;
|
|
66
|
+
highlightedCodeFrame?: string;
|
|
67
|
+
loc?: {
|
|
68
|
+
column: number;
|
|
69
|
+
line: number;
|
|
70
|
+
} | null | undefined;
|
|
71
|
+
source?: string;
|
|
72
|
+
}
|
|
73
|
+
export type DiagnosticWithoutOrigin = Diagnostic & {
|
|
74
|
+
origin?: string;
|
|
75
|
+
};
|
|
76
|
+
/** Something that can be turned into a diagnostic. */
|
|
77
|
+
export type Diagnostifiable = Diagnostic | Array<Diagnostic> | ThrowableDiagnostic | PrintableError | Error | string;
|
|
78
|
+
/** Normalize the given value into a diagnostic. */
|
|
79
|
+
export declare function anyToDiagnostic(input: Diagnostifiable): Array<Diagnostic>;
|
|
80
|
+
/** Normalize the given error into a diagnostic. */
|
|
81
|
+
export declare function errorToDiagnostic(error: ThrowableDiagnostic | PrintableError | string, defaultValues?: {
|
|
82
|
+
origin?: string | null | undefined;
|
|
83
|
+
filePath?: string | null | undefined;
|
|
84
|
+
}): Array<Diagnostic>;
|
|
85
|
+
type ThrowableDiagnosticOpts = {
|
|
86
|
+
diagnostic: Diagnostic | Array<Diagnostic>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* An error wrapper around a diagnostic that can be <code>throw</code>n (e.g. to signal a
|
|
90
|
+
* build error).
|
|
91
|
+
*/
|
|
92
|
+
export default class ThrowableDiagnostic extends Error {
|
|
93
|
+
diagnostics: Array<Diagnostic>;
|
|
94
|
+
constructor(opts: ThrowableDiagnosticOpts);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Turns a list of positions in a JSON5 file with messages into a list of diagnostics.
|
|
98
|
+
* Uses <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>.
|
|
99
|
+
*
|
|
100
|
+
* @param code the JSON code
|
|
101
|
+
* @param ids A list of JSON keypaths (<code>key: "/some/parent/child"</code>) with corresponding messages, \
|
|
102
|
+
* <code>type</code> signifies whether the key of the value in a JSON object should be highlighted.
|
|
103
|
+
*/
|
|
104
|
+
export declare function generateJSONCodeHighlights(data: string | {
|
|
105
|
+
data: unknown;
|
|
106
|
+
pointers: Record<string, Mapping>;
|
|
107
|
+
}, ids: Array<{
|
|
108
|
+
key: string;
|
|
109
|
+
type?: ("key" | null | undefined) | "value";
|
|
110
|
+
message?: string;
|
|
111
|
+
}>): Array<DiagnosticCodeHighlight>;
|
|
112
|
+
/**
|
|
113
|
+
* Converts entries in <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>'s
|
|
114
|
+
* <code>result.pointers</code> array.
|
|
115
|
+
*/
|
|
116
|
+
export declare function getJSONHighlightLocation(pos: Mapping, type?: ("key" | null | undefined) | "value"): {
|
|
117
|
+
start: DiagnosticHighlightLocation;
|
|
118
|
+
end: DiagnosticHighlightLocation;
|
|
119
|
+
};
|
|
120
|
+
/** Result is 1-based, but end is exclusive */
|
|
121
|
+
export declare function getJSONSourceLocation(pos: Mapping, type?: ("key" | null | undefined) | "value"): {
|
|
122
|
+
start: {
|
|
123
|
+
readonly line: number;
|
|
124
|
+
readonly column: number;
|
|
125
|
+
};
|
|
126
|
+
end: {
|
|
127
|
+
readonly line: number;
|
|
128
|
+
readonly column: number;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
export declare function convertSourceLocationToHighlight<Location extends {
|
|
132
|
+
/** 1-based, inclusive */
|
|
133
|
+
readonly start: {
|
|
134
|
+
readonly line: number;
|
|
135
|
+
readonly column: number;
|
|
136
|
+
};
|
|
137
|
+
/** 1-based, exclusive */
|
|
138
|
+
readonly end: {
|
|
139
|
+
readonly line: number;
|
|
140
|
+
readonly column: number;
|
|
141
|
+
};
|
|
142
|
+
}>({ start, end }: Location, message?: string): DiagnosticCodeHighlight;
|
|
143
|
+
/** Sanitizes object keys before using them as <code>key</code> in generateJSONCodeHighlights */
|
|
144
|
+
export declare function encodeJSONKeyComponent(component: string): string;
|
|
145
|
+
export declare function escapeMarkdown(s: string): string;
|
|
146
|
+
type TemplateInput = any;
|
|
147
|
+
export declare function md(strings: Array<string>, ...params: Array<TemplateInput>): string;
|
|
148
|
+
export declare namespace md {
|
|
149
|
+
var bold: (s: any) => any;
|
|
150
|
+
var italic: (s: any) => any;
|
|
151
|
+
var underline: (s: any) => any;
|
|
152
|
+
var strikethrough: (s: any) => any;
|
|
153
|
+
}
|
|
154
|
+
export {};
|
package/lib/diagnostic.js
CHANGED
|
@@ -4,92 +4,96 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.anyToDiagnostic = anyToDiagnostic;
|
|
7
|
+
exports.convertSourceLocationToHighlight = convertSourceLocationToHighlight;
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
exports.encodeJSONKeyComponent = encodeJSONKeyComponent;
|
|
7
10
|
exports.errorToDiagnostic = errorToDiagnostic;
|
|
11
|
+
exports.escapeMarkdown = escapeMarkdown;
|
|
8
12
|
exports.generateJSONCodeHighlights = generateJSONCodeHighlights;
|
|
13
|
+
exports.getJSONHighlightLocation = getJSONHighlightLocation;
|
|
9
14
|
exports.getJSONSourceLocation = getJSONSourceLocation;
|
|
10
|
-
exports.encodeJSONKeyComponent = encodeJSONKeyComponent;
|
|
11
|
-
exports.escapeMarkdown = escapeMarkdown;
|
|
12
15
|
exports.md = md;
|
|
13
|
-
exports.default = void 0;
|
|
14
|
-
|
|
15
16
|
function _assert() {
|
|
16
17
|
const data = _interopRequireDefault(require("assert"));
|
|
17
|
-
|
|
18
18
|
_assert = function () {
|
|
19
19
|
return data;
|
|
20
20
|
};
|
|
21
|
-
|
|
22
21
|
return data;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
23
|
function _nullthrows() {
|
|
26
24
|
const data = _interopRequireDefault(require("nullthrows"));
|
|
27
|
-
|
|
28
25
|
_nullthrows = function () {
|
|
29
26
|
return data;
|
|
30
27
|
};
|
|
31
|
-
|
|
32
28
|
return data;
|
|
33
29
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
_jsonSourceMap = function () {
|
|
30
|
+
function _jsonSourcemap() {
|
|
31
|
+
const data = require("@mischnic/json-sourcemap");
|
|
32
|
+
_jsonSourcemap = function () {
|
|
39
33
|
return data;
|
|
40
34
|
};
|
|
41
|
-
|
|
42
35
|
return data;
|
|
43
36
|
}
|
|
44
|
-
|
|
45
37
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
/** These positions are 1-based (so <code>1</code> is the first line/column) */
|
|
39
|
+
/**
|
|
40
|
+
* Note: A tab character is always counted as a single character
|
|
41
|
+
* This is to prevent any mismatch of highlighting across machines
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Describes how to format a code frame.
|
|
45
|
+
* A code frame is a visualization of a piece of code with a certain amount of
|
|
46
|
+
* code highlights that point to certain chunk(s) inside the code.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* A style agnostic way of emitting errors, warnings and info.
|
|
50
|
+
* Reporters are responsible for rendering the message, codeframes, hints, ...
|
|
51
|
+
*/
|
|
52
|
+
// This type should represent all error formats Parcel can encounter...
|
|
53
|
+
/** Something that can be turned into a diagnostic. */
|
|
49
54
|
/** Normalize the given value into a diagnostic. */
|
|
50
55
|
function anyToDiagnostic(input) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
diagnostic = input.diagnostics;
|
|
56
|
+
if (Array.isArray(input)) {
|
|
57
|
+
return input;
|
|
58
|
+
} else if (input instanceof ThrowableDiagnostic) {
|
|
59
|
+
return input.diagnostics;
|
|
56
60
|
} else if (input instanceof Error) {
|
|
57
|
-
|
|
61
|
+
return errorToDiagnostic(input);
|
|
62
|
+
} else if (typeof input === 'string') {
|
|
63
|
+
return [{
|
|
64
|
+
message: input
|
|
65
|
+
}];
|
|
66
|
+
} else if (typeof input === 'object') {
|
|
67
|
+
return [input];
|
|
68
|
+
} else {
|
|
69
|
+
return errorToDiagnostic(input);
|
|
58
70
|
}
|
|
59
|
-
|
|
60
|
-
return Array.isArray(diagnostic) ? diagnostic : [diagnostic];
|
|
61
71
|
}
|
|
62
|
-
/** Normalize the given error into a diagnostic. */
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
function errorToDiagnostic(error, defaultValues = { ...null
|
|
66
|
-
}) {
|
|
67
|
-
var _defaultValues$origin2, _ref2, _ref3, _error$filePath, _ref4, _error$highlightedCod;
|
|
68
|
-
|
|
69
|
-
let codeFrame = undefined;
|
|
70
72
|
|
|
73
|
+
/** Normalize the given error into a diagnostic. */
|
|
74
|
+
function errorToDiagnostic(error, defaultValues) {
|
|
75
|
+
var _defaultValues$origin2, _ref4, _error$highlightedCod;
|
|
76
|
+
let codeFrames = undefined;
|
|
71
77
|
if (typeof error === 'string') {
|
|
72
78
|
var _defaultValues$origin;
|
|
73
|
-
|
|
74
79
|
return [{
|
|
75
80
|
origin: (_defaultValues$origin = defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.origin) !== null && _defaultValues$origin !== void 0 ? _defaultValues$origin : 'Error',
|
|
76
|
-
message: escapeMarkdown(error)
|
|
77
|
-
codeFrame
|
|
81
|
+
message: escapeMarkdown(error)
|
|
78
82
|
}];
|
|
79
83
|
}
|
|
80
|
-
|
|
81
84
|
if (error instanceof ThrowableDiagnostic) {
|
|
82
85
|
return error.diagnostics.map(d => {
|
|
83
86
|
var _ref, _d$origin;
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
return {
|
|
88
|
+
...d,
|
|
86
89
|
origin: (_ref = (_d$origin = d.origin) !== null && _d$origin !== void 0 ? _d$origin : defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.origin) !== null && _ref !== void 0 ? _ref : 'unknown'
|
|
87
90
|
};
|
|
88
91
|
});
|
|
89
92
|
}
|
|
90
|
-
|
|
91
93
|
if (error.loc && error.source != null) {
|
|
92
|
-
|
|
94
|
+
var _ref2, _ref3, _error$filePath;
|
|
95
|
+
codeFrames = [{
|
|
96
|
+
filePath: (_ref2 = (_ref3 = (_error$filePath = error.filePath) !== null && _error$filePath !== void 0 ? _error$filePath : error.fileName) !== null && _ref3 !== void 0 ? _ref3 : defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.filePath) !== null && _ref2 !== void 0 ? _ref2 : undefined,
|
|
93
97
|
code: error.source,
|
|
94
98
|
codeHighlights: [{
|
|
95
99
|
start: {
|
|
@@ -101,19 +105,16 @@ function errorToDiagnostic(error, defaultValues = { ...null
|
|
|
101
105
|
column: error.loc.column
|
|
102
106
|
}
|
|
103
107
|
}]
|
|
104
|
-
};
|
|
108
|
+
}];
|
|
105
109
|
}
|
|
106
|
-
|
|
107
110
|
return [{
|
|
108
111
|
origin: (_defaultValues$origin2 = defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.origin) !== null && _defaultValues$origin2 !== void 0 ? _defaultValues$origin2 : 'Error',
|
|
109
112
|
message: escapeMarkdown(error.message),
|
|
110
113
|
name: error.name,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
codeFrame
|
|
114
|
+
stack: codeFrames == null ? (_ref4 = (_error$highlightedCod = error.highlightedCodeFrame) !== null && _error$highlightedCod !== void 0 ? _error$highlightedCod : error.codeFrame) !== null && _ref4 !== void 0 ? _ref4 : error.stack : undefined,
|
|
115
|
+
codeFrames
|
|
114
116
|
}];
|
|
115
117
|
}
|
|
116
|
-
|
|
117
118
|
/**
|
|
118
119
|
* An error wrapper around a diagnostic that can be <code>throw</code>n (e.g. to signal a
|
|
119
120
|
* build error).
|
|
@@ -121,58 +122,58 @@ function errorToDiagnostic(error, defaultValues = { ...null
|
|
|
121
122
|
class ThrowableDiagnostic extends Error {
|
|
122
123
|
constructor(opts) {
|
|
123
124
|
var _diagnostics$0$stack, _diagnostics$0$name;
|
|
125
|
+
let diagnostics = Array.isArray(opts.diagnostic) ? opts.diagnostic : [opts.diagnostic];
|
|
124
126
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
// Construct error from diagnostics
|
|
127
128
|
super(diagnostics[0].message);
|
|
128
|
-
|
|
129
|
-
_defineProperty(this, "diagnostics", void 0);
|
|
130
|
-
|
|
129
|
+
// @ts-ignore
|
|
131
130
|
this.stack = (_diagnostics$0$stack = diagnostics[0].stack) !== null && _diagnostics$0$stack !== void 0 ? _diagnostics$0$stack : super.stack;
|
|
131
|
+
// @ts-ignore
|
|
132
132
|
this.name = (_diagnostics$0$name = diagnostics[0].name) !== null && _diagnostics$0$name !== void 0 ? _diagnostics$0$name : super.name;
|
|
133
133
|
this.diagnostics = diagnostics;
|
|
134
134
|
}
|
|
135
|
-
|
|
136
135
|
}
|
|
136
|
+
|
|
137
137
|
/**
|
|
138
|
-
* Turns a list of positions in a
|
|
139
|
-
* Uses <a href="https://github.com/
|
|
138
|
+
* Turns a list of positions in a JSON5 file with messages into a list of diagnostics.
|
|
139
|
+
* Uses <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>.
|
|
140
140
|
*
|
|
141
141
|
* @param code the JSON code
|
|
142
142
|
* @param ids A list of JSON keypaths (<code>key: "/some/parent/child"</code>) with corresponding messages, \
|
|
143
143
|
* <code>type</code> signifies whether the key of the value in a JSON object should be highlighted.
|
|
144
144
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
147
145
|
exports.default = ThrowableDiagnostic;
|
|
148
|
-
|
|
149
146
|
function generateJSONCodeHighlights(data, ids) {
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
let map = typeof data == 'string' ? (0, _jsonSourcemap().parse)(data, undefined, {
|
|
148
|
+
dialect: 'JSON5',
|
|
149
|
+
tabWidth: 1
|
|
150
|
+
}) : data;
|
|
152
151
|
return ids.map(({
|
|
153
152
|
key,
|
|
154
153
|
type,
|
|
155
154
|
message
|
|
156
155
|
}) => {
|
|
157
156
|
let pos = (0, _nullthrows().default)(map.pointers[key]);
|
|
158
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
...getJSONHighlightLocation(pos, type),
|
|
159
159
|
message
|
|
160
160
|
};
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
+
|
|
163
164
|
/**
|
|
164
|
-
* Converts entries in <a href="https://github.com/
|
|
165
|
+
* Converts entries in <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>'s
|
|
165
166
|
* <code>result.pointers</code> array.
|
|
166
167
|
*/
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!type &&
|
|
168
|
+
function getJSONHighlightLocation(pos, type) {
|
|
169
|
+
let key = 'key' in pos ? pos.key : undefined;
|
|
170
|
+
let keyEnd = 'keyEnd' in pos ? pos.keyEnd : undefined;
|
|
171
|
+
if (!type && key && pos.value) {
|
|
171
172
|
// key and value
|
|
172
173
|
return {
|
|
173
174
|
start: {
|
|
174
|
-
line:
|
|
175
|
-
column:
|
|
175
|
+
line: key.line + 1,
|
|
176
|
+
column: key.column + 1
|
|
176
177
|
},
|
|
177
178
|
end: {
|
|
178
179
|
line: pos.valueEnd.line + 1,
|
|
@@ -180,15 +181,15 @@ function getJSONSourceLocation(pos, type) {
|
|
|
180
181
|
}
|
|
181
182
|
};
|
|
182
183
|
} else if (type == 'key' || !pos.value) {
|
|
183
|
-
(0, _assert().default)(
|
|
184
|
+
(0, _assert().default)(key && keyEnd);
|
|
184
185
|
return {
|
|
185
186
|
start: {
|
|
186
|
-
line:
|
|
187
|
-
column:
|
|
187
|
+
line: key.line + 1,
|
|
188
|
+
column: key.column + 1
|
|
188
189
|
},
|
|
189
190
|
end: {
|
|
190
|
-
line:
|
|
191
|
-
column:
|
|
191
|
+
line: keyEnd.line + 1,
|
|
192
|
+
column: keyEnd.column
|
|
192
193
|
}
|
|
193
194
|
};
|
|
194
195
|
} else {
|
|
@@ -204,67 +205,86 @@ function getJSONSourceLocation(pos, type) {
|
|
|
204
205
|
};
|
|
205
206
|
}
|
|
206
207
|
}
|
|
207
|
-
/** Sanitizes object keys before using them as <code>key</code> in generateJSONCodeHighlights */
|
|
208
208
|
|
|
209
|
+
/** Result is 1-based, but end is exclusive */
|
|
210
|
+
function getJSONSourceLocation(pos, type) {
|
|
211
|
+
let v = getJSONHighlightLocation(pos, type);
|
|
212
|
+
return {
|
|
213
|
+
start: v.start,
|
|
214
|
+
end: {
|
|
215
|
+
line: v.end.line,
|
|
216
|
+
column: v.end.column + 1
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function convertSourceLocationToHighlight({
|
|
221
|
+
start,
|
|
222
|
+
end
|
|
223
|
+
}, message) {
|
|
224
|
+
return {
|
|
225
|
+
message,
|
|
226
|
+
start,
|
|
227
|
+
end: {
|
|
228
|
+
line: end.line,
|
|
229
|
+
column: end.column - 1
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
209
233
|
|
|
234
|
+
/** Sanitizes object keys before using them as <code>key</code> in generateJSONCodeHighlights */
|
|
210
235
|
function encodeJSONKeyComponent(component) {
|
|
211
|
-
return component.replace(/\//g, '~1');
|
|
236
|
+
return component.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
212
237
|
}
|
|
213
|
-
|
|
214
238
|
const escapeCharacters = ['\\', '*', '_', '~'];
|
|
215
|
-
|
|
216
239
|
function escapeMarkdown(s) {
|
|
217
240
|
let result = s;
|
|
218
|
-
|
|
219
241
|
for (const char of escapeCharacters) {
|
|
220
242
|
result = result.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
|
|
221
243
|
}
|
|
222
|
-
|
|
223
244
|
return result;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
245
|
+
}
|
|
227
246
|
const mdVerbatim = Symbol();
|
|
228
|
-
|
|
229
247
|
function md(strings, ...params) {
|
|
230
248
|
let result = [];
|
|
231
|
-
|
|
232
249
|
for (let i = 0; i < params.length; i++) {
|
|
250
|
+
result.push(strings[i]);
|
|
233
251
|
let param = params[i];
|
|
234
|
-
|
|
252
|
+
if (Array.isArray(param)) {
|
|
253
|
+
for (let j = 0; j < param.length; j++) {
|
|
254
|
+
var _param$j$mdVerbatim, _param$j;
|
|
255
|
+
result.push((_param$j$mdVerbatim = (_param$j = param[j]) === null || _param$j === void 0 ? void 0 : _param$j[mdVerbatim]) !== null && _param$j$mdVerbatim !== void 0 ? _param$j$mdVerbatim : escapeMarkdown(`${param[j]}`));
|
|
256
|
+
if (j < param.length - 1) {
|
|
257
|
+
result.push(', ');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
var _param$mdVerbatim;
|
|
262
|
+
result.push((_param$mdVerbatim = param === null || param === void 0 ? void 0 : param[mdVerbatim]) !== null && _param$mdVerbatim !== void 0 ? _param$mdVerbatim : escapeMarkdown(`${param}`));
|
|
263
|
+
}
|
|
235
264
|
}
|
|
236
|
-
|
|
237
265
|
return result.join('') + strings[strings.length - 1];
|
|
238
266
|
}
|
|
239
|
-
|
|
240
267
|
md.bold = function (s) {
|
|
241
268
|
// $FlowFixMe[invalid-computed-prop]
|
|
242
269
|
return {
|
|
243
|
-
[mdVerbatim]:
|
|
244
|
-
value: '**' + escapeMarkdown(`${s}`) + '**'
|
|
270
|
+
[mdVerbatim]: '**' + escapeMarkdown(`${s}`) + '**'
|
|
245
271
|
};
|
|
246
272
|
};
|
|
247
|
-
|
|
248
273
|
md.italic = function (s) {
|
|
249
274
|
// $FlowFixMe[invalid-computed-prop]
|
|
250
275
|
return {
|
|
251
|
-
[mdVerbatim]:
|
|
252
|
-
value: '_' + escapeMarkdown(`${s}`) + '_'
|
|
276
|
+
[mdVerbatim]: '_' + escapeMarkdown(`${s}`) + '_'
|
|
253
277
|
};
|
|
254
278
|
};
|
|
255
|
-
|
|
256
279
|
md.underline = function (s) {
|
|
257
280
|
// $FlowFixMe[invalid-computed-prop]
|
|
258
281
|
return {
|
|
259
|
-
[mdVerbatim]:
|
|
260
|
-
value: '__' + escapeMarkdown(`${s}`) + '__'
|
|
282
|
+
[mdVerbatim]: '__' + escapeMarkdown(`${s}`) + '__'
|
|
261
283
|
};
|
|
262
284
|
};
|
|
263
|
-
|
|
264
285
|
md.strikethrough = function (s) {
|
|
265
286
|
// $FlowFixMe[invalid-computed-prop]
|
|
266
287
|
return {
|
|
267
|
-
[mdVerbatim]:
|
|
268
|
-
value: '~~' + escapeMarkdown(`${s}`) + '~~'
|
|
288
|
+
[mdVerbatim]: '~~' + escapeMarkdown(`${s}`) + '~~'
|
|
269
289
|
};
|
|
270
290
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/diagnostic",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-dev.1510+a9bb85adf",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -15,12 +15,17 @@
|
|
|
15
15
|
},
|
|
16
16
|
"main": "lib/diagnostic.js",
|
|
17
17
|
"source": "src/diagnostic.js",
|
|
18
|
+
"types": "lib/diagnostic.d.ts",
|
|
18
19
|
"engines": {
|
|
19
20
|
"node": ">= 12.0.0"
|
|
20
21
|
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build-ts": "flow-to-ts src/*.js --write && tsc --emitDeclarationOnly --declaration --esModuleInterop src/*.ts && mkdir -p lib && mv src/*.d.ts lib/. && rm src/*.ts",
|
|
24
|
+
"check-ts": "tsc --noEmit lib/diagnostic.d.ts"
|
|
25
|
+
},
|
|
21
26
|
"dependencies": {
|
|
22
|
-
"json-
|
|
27
|
+
"@mischnic/json-sourcemap": "^0.1.0",
|
|
23
28
|
"nullthrows": "^1.1.1"
|
|
24
29
|
},
|
|
25
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "a9bb85adf8f3b38631e178b3aacaa30c78696e36"
|
|
26
31
|
}
|
package/src/diagnostic.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
|
-
import type {FilePath} from '@parcel/types';
|
|
3
2
|
|
|
4
3
|
import invariant from 'assert';
|
|
5
4
|
import nullthrows from 'nullthrows';
|
|
6
|
-
import
|
|
5
|
+
import {parse, type Mapping} from '@mischnic/json-sourcemap';
|
|
7
6
|
|
|
8
7
|
/** These positions are 1-based (so <code>1</code> is the first line/column) */
|
|
9
8
|
export type DiagnosticHighlightLocation = {|
|
|
@@ -35,11 +34,15 @@ export type DiagnosticCodeFrame = {|
|
|
|
35
34
|
/**
|
|
36
35
|
* The contents of the source file.
|
|
37
36
|
*
|
|
38
|
-
* If no code is passed, it will be read in from
|
|
37
|
+
* If no code is passed, it will be read in from filePath, remember that
|
|
39
38
|
* the asset's current code could be different from the input contents.
|
|
40
39
|
*
|
|
41
40
|
*/
|
|
42
41
|
code?: string,
|
|
42
|
+
/** Path to the file this code frame is about (optional, absolute or relative to the project root) */
|
|
43
|
+
filePath?: string,
|
|
44
|
+
/** Language of the file this code frame is about (optional) */
|
|
45
|
+
language?: string,
|
|
43
46
|
codeHighlights: Array<DiagnosticCodeHighlight>,
|
|
44
47
|
|};
|
|
45
48
|
|
|
@@ -58,35 +61,32 @@ export type Diagnostic = {|
|
|
|
58
61
|
/** Name of the error (optional) */
|
|
59
62
|
name?: string,
|
|
60
63
|
|
|
61
|
-
/** Path to the file this diagnostic is about (optional, absolute or relative to the project root) */
|
|
62
|
-
filePath?: FilePath,
|
|
63
|
-
/** Language of the file this diagnostic is about (optional) */
|
|
64
|
-
language?: string,
|
|
65
|
-
|
|
66
64
|
/** A code frame points to a certain location(s) in the file this diagnostic is linked to (optional) */
|
|
67
|
-
|
|
65
|
+
codeFrames?: ?Array<DiagnosticCodeFrame>,
|
|
68
66
|
|
|
69
67
|
/** An optional list of strings that suggest ways to resolve this issue */
|
|
70
68
|
hints?: Array<string>,
|
|
71
69
|
|
|
72
70
|
/** @private */
|
|
73
71
|
skipFormatting?: boolean,
|
|
72
|
+
|
|
73
|
+
/** A URL to documentation to learn more about the diagnostic. */
|
|
74
|
+
documentationURL?: string,
|
|
74
75
|
|};
|
|
75
76
|
|
|
76
77
|
// This type should represent all error formats Parcel can encounter...
|
|
77
|
-
export
|
|
78
|
-
fileName?: string
|
|
79
|
-
filePath?: string
|
|
80
|
-
codeFrame?: string
|
|
81
|
-
highlightedCodeFrame?: string
|
|
78
|
+
export interface PrintableError extends Error {
|
|
79
|
+
fileName?: string;
|
|
80
|
+
filePath?: string;
|
|
81
|
+
codeFrame?: string;
|
|
82
|
+
highlightedCodeFrame?: string;
|
|
82
83
|
loc?: ?{
|
|
83
84
|
column: number,
|
|
84
85
|
line: number,
|
|
85
86
|
...
|
|
86
|
-
}
|
|
87
|
-
source?: string
|
|
88
|
-
|
|
89
|
-
};
|
|
87
|
+
};
|
|
88
|
+
source?: string;
|
|
89
|
+
}
|
|
90
90
|
|
|
91
91
|
export type DiagnosticWithoutOrigin = {|
|
|
92
92
|
...Diagnostic,
|
|
@@ -99,38 +99,41 @@ export type Diagnostifiable =
|
|
|
99
99
|
| Array<Diagnostic>
|
|
100
100
|
| ThrowableDiagnostic
|
|
101
101
|
| PrintableError
|
|
102
|
+
| Error
|
|
102
103
|
| string;
|
|
103
104
|
|
|
104
105
|
/** Normalize the given value into a diagnostic. */
|
|
105
106
|
export function anyToDiagnostic(input: Diagnostifiable): Array<Diagnostic> {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
diagnostic = input.diagnostics;
|
|
107
|
+
if (Array.isArray(input)) {
|
|
108
|
+
return input;
|
|
109
|
+
} else if (input instanceof ThrowableDiagnostic) {
|
|
110
|
+
return input.diagnostics;
|
|
111
111
|
} else if (input instanceof Error) {
|
|
112
|
-
|
|
112
|
+
return errorToDiagnostic(input);
|
|
113
|
+
} else if (typeof input === 'string') {
|
|
114
|
+
return [{message: input}];
|
|
115
|
+
} else if (typeof input === 'object') {
|
|
116
|
+
return [input];
|
|
117
|
+
} else {
|
|
118
|
+
return errorToDiagnostic(input);
|
|
113
119
|
}
|
|
114
|
-
|
|
115
|
-
return Array.isArray(diagnostic) ? diagnostic : [diagnostic];
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
/** Normalize the given error into a diagnostic. */
|
|
119
123
|
export function errorToDiagnostic(
|
|
120
124
|
error: ThrowableDiagnostic | PrintableError | string,
|
|
121
|
-
defaultValues
|
|
125
|
+
defaultValues?: {|
|
|
122
126
|
origin?: ?string,
|
|
123
127
|
filePath?: ?string,
|
|
124
|
-
|}
|
|
128
|
+
|},
|
|
125
129
|
): Array<Diagnostic> {
|
|
126
|
-
let
|
|
130
|
+
let codeFrames: ?Array<DiagnosticCodeFrame> = undefined;
|
|
127
131
|
|
|
128
132
|
if (typeof error === 'string') {
|
|
129
133
|
return [
|
|
130
134
|
{
|
|
131
135
|
origin: defaultValues?.origin ?? 'Error',
|
|
132
136
|
message: escapeMarkdown(error),
|
|
133
|
-
codeFrame,
|
|
134
137
|
},
|
|
135
138
|
];
|
|
136
139
|
}
|
|
@@ -145,21 +148,28 @@ export function errorToDiagnostic(
|
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
if (error.loc && error.source != null) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
codeFrames = [
|
|
152
|
+
{
|
|
153
|
+
filePath:
|
|
154
|
+
error.filePath ??
|
|
155
|
+
error.fileName ??
|
|
156
|
+
defaultValues?.filePath ??
|
|
157
|
+
undefined,
|
|
158
|
+
code: error.source,
|
|
159
|
+
codeHighlights: [
|
|
160
|
+
{
|
|
161
|
+
start: {
|
|
162
|
+
line: error.loc.line,
|
|
163
|
+
column: error.loc.column,
|
|
164
|
+
},
|
|
165
|
+
end: {
|
|
166
|
+
line: error.loc.line,
|
|
167
|
+
column: error.loc.column,
|
|
168
|
+
},
|
|
159
169
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
];
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
return [
|
|
@@ -167,13 +177,11 @@ export function errorToDiagnostic(
|
|
|
167
177
|
origin: defaultValues?.origin ?? 'Error',
|
|
168
178
|
message: escapeMarkdown(error.message),
|
|
169
179
|
name: error.name,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
stack: error.highlightedCodeFrame ?? error.codeFrame ?? error.stack,
|
|
176
|
-
codeFrame,
|
|
180
|
+
stack:
|
|
181
|
+
codeFrames == null
|
|
182
|
+
? error.highlightedCodeFrame ?? error.codeFrame ?? error.stack
|
|
183
|
+
: undefined,
|
|
184
|
+
codeFrames,
|
|
177
185
|
},
|
|
178
186
|
];
|
|
179
187
|
}
|
|
@@ -197,7 +205,9 @@ export default class ThrowableDiagnostic extends Error {
|
|
|
197
205
|
|
|
198
206
|
// Construct error from diagnostics
|
|
199
207
|
super(diagnostics[0].message);
|
|
208
|
+
// @ts-ignore
|
|
200
209
|
this.stack = diagnostics[0].stack ?? super.stack;
|
|
210
|
+
// @ts-ignore
|
|
201
211
|
this.name = diagnostics[0].name ?? super.name;
|
|
202
212
|
|
|
203
213
|
this.diagnostics = diagnostics;
|
|
@@ -205,8 +215,8 @@ export default class ThrowableDiagnostic extends Error {
|
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
/**
|
|
208
|
-
* Turns a list of positions in a
|
|
209
|
-
* Uses <a href="https://github.com/
|
|
218
|
+
* Turns a list of positions in a JSON5 file with messages into a list of diagnostics.
|
|
219
|
+
* Uses <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>.
|
|
210
220
|
*
|
|
211
221
|
* @param code the JSON code
|
|
212
222
|
* @param ids A list of JSON keypaths (<code>key: "/some/parent/child"</code>) with corresponding messages, \
|
|
@@ -221,40 +231,43 @@ export function generateJSONCodeHighlights(
|
|
|
221
231
|
|},
|
|
222
232
|
ids: Array<{|key: string, type?: ?'key' | 'value', message?: string|}>,
|
|
223
233
|
): Array<DiagnosticCodeHighlight> {
|
|
224
|
-
// json-source-map doesn't support a tabWidth option (yet)
|
|
225
234
|
let map =
|
|
226
|
-
typeof data == 'string'
|
|
235
|
+
typeof data == 'string'
|
|
236
|
+
? parse(data, undefined, {dialect: 'JSON5', tabWidth: 1})
|
|
237
|
+
: data;
|
|
227
238
|
return ids.map(({key, type, message}) => {
|
|
228
239
|
let pos = nullthrows(map.pointers[key]);
|
|
229
240
|
return {
|
|
230
|
-
...
|
|
241
|
+
...getJSONHighlightLocation(pos, type),
|
|
231
242
|
message,
|
|
232
243
|
};
|
|
233
244
|
});
|
|
234
245
|
}
|
|
235
246
|
|
|
236
247
|
/**
|
|
237
|
-
* Converts entries in <a href="https://github.com/
|
|
248
|
+
* Converts entries in <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>'s
|
|
238
249
|
* <code>result.pointers</code> array.
|
|
239
250
|
*/
|
|
240
|
-
export function
|
|
251
|
+
export function getJSONHighlightLocation(
|
|
241
252
|
pos: Mapping,
|
|
242
253
|
type?: ?'key' | 'value',
|
|
243
254
|
): {|
|
|
244
255
|
start: DiagnosticHighlightLocation,
|
|
245
256
|
end: DiagnosticHighlightLocation,
|
|
246
257
|
|} {
|
|
247
|
-
|
|
258
|
+
let key = 'key' in pos ? pos.key : undefined;
|
|
259
|
+
let keyEnd = 'keyEnd' in pos ? pos.keyEnd : undefined;
|
|
260
|
+
if (!type && key && pos.value) {
|
|
248
261
|
// key and value
|
|
249
262
|
return {
|
|
250
|
-
start: {line:
|
|
263
|
+
start: {line: key.line + 1, column: key.column + 1},
|
|
251
264
|
end: {line: pos.valueEnd.line + 1, column: pos.valueEnd.column},
|
|
252
265
|
};
|
|
253
266
|
} else if (type == 'key' || !pos.value) {
|
|
254
|
-
invariant(
|
|
267
|
+
invariant(key && keyEnd);
|
|
255
268
|
return {
|
|
256
|
-
start: {line:
|
|
257
|
-
end: {line:
|
|
269
|
+
start: {line: key.line + 1, column: key.column + 1},
|
|
270
|
+
end: {line: keyEnd.line + 1, column: keyEnd.column},
|
|
258
271
|
};
|
|
259
272
|
} else {
|
|
260
273
|
return {
|
|
@@ -264,9 +277,45 @@ export function getJSONSourceLocation(
|
|
|
264
277
|
}
|
|
265
278
|
}
|
|
266
279
|
|
|
280
|
+
/** Result is 1-based, but end is exclusive */
|
|
281
|
+
export function getJSONSourceLocation(
|
|
282
|
+
pos: Mapping,
|
|
283
|
+
type?: ?'key' | 'value',
|
|
284
|
+
): {|
|
|
285
|
+
start: {|
|
|
286
|
+
+line: number,
|
|
287
|
+
+column: number,
|
|
288
|
+
|},
|
|
289
|
+
end: {|
|
|
290
|
+
+line: number,
|
|
291
|
+
+column: number,
|
|
292
|
+
|},
|
|
293
|
+
|} {
|
|
294
|
+
let v = getJSONHighlightLocation(pos, type);
|
|
295
|
+
return {start: v.start, end: {line: v.end.line, column: v.end.column + 1}};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export function convertSourceLocationToHighlight<
|
|
299
|
+
Location: {
|
|
300
|
+
/** 1-based, inclusive */
|
|
301
|
+
+start: {|
|
|
302
|
+
+line: number,
|
|
303
|
+
+column: number,
|
|
304
|
+
|},
|
|
305
|
+
/** 1-based, exclusive */
|
|
306
|
+
+end: {|
|
|
307
|
+
+line: number,
|
|
308
|
+
+column: number,
|
|
309
|
+
|},
|
|
310
|
+
...
|
|
311
|
+
},
|
|
312
|
+
>({start, end}: Location, message?: string): DiagnosticCodeHighlight {
|
|
313
|
+
return {message, start, end: {line: end.line, column: end.column - 1}};
|
|
314
|
+
}
|
|
315
|
+
|
|
267
316
|
/** Sanitizes object keys before using them as <code>key</code> in generateJSONCodeHighlights */
|
|
268
317
|
export function encodeJSONKeyComponent(component: string): string {
|
|
269
|
-
return component.replace(/\//g, '~1');
|
|
318
|
+
return component.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
270
319
|
}
|
|
271
320
|
|
|
272
321
|
const escapeCharacters = ['\\', '*', '_', '~'];
|
|
@@ -280,8 +329,7 @@ export function escapeMarkdown(s: string): string {
|
|
|
280
329
|
return result;
|
|
281
330
|
}
|
|
282
331
|
|
|
283
|
-
|
|
284
|
-
type TemplateInput = any;
|
|
332
|
+
type TemplateInput = $FlowFixMe;
|
|
285
333
|
|
|
286
334
|
const mdVerbatim = Symbol();
|
|
287
335
|
export function md(
|
|
@@ -290,31 +338,39 @@ export function md(
|
|
|
290
338
|
): string {
|
|
291
339
|
let result = [];
|
|
292
340
|
for (let i = 0; i < params.length; i++) {
|
|
341
|
+
result.push(strings[i]);
|
|
342
|
+
|
|
293
343
|
let param = params[i];
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
344
|
+
if (Array.isArray(param)) {
|
|
345
|
+
for (let j = 0; j < param.length; j++) {
|
|
346
|
+
result.push(param[j]?.[mdVerbatim] ?? escapeMarkdown(`${param[j]}`));
|
|
347
|
+
if (j < param.length - 1) {
|
|
348
|
+
result.push(', ');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
result.push(param?.[mdVerbatim] ?? escapeMarkdown(`${param}`));
|
|
353
|
+
}
|
|
298
354
|
}
|
|
299
355
|
return result.join('') + strings[strings.length - 1];
|
|
300
356
|
}
|
|
301
357
|
|
|
302
|
-
md.bold = function(s: TemplateInput):
|
|
358
|
+
md.bold = function (s: TemplateInput): TemplateInput {
|
|
303
359
|
// $FlowFixMe[invalid-computed-prop]
|
|
304
|
-
return {[mdVerbatim]:
|
|
360
|
+
return {[mdVerbatim]: '**' + escapeMarkdown(`${s}`) + '**'};
|
|
305
361
|
};
|
|
306
362
|
|
|
307
|
-
md.italic = function(s: TemplateInput):
|
|
363
|
+
md.italic = function (s: TemplateInput): TemplateInput {
|
|
308
364
|
// $FlowFixMe[invalid-computed-prop]
|
|
309
|
-
return {[mdVerbatim]:
|
|
365
|
+
return {[mdVerbatim]: '_' + escapeMarkdown(`${s}`) + '_'};
|
|
310
366
|
};
|
|
311
367
|
|
|
312
|
-
md.underline = function(s: TemplateInput):
|
|
368
|
+
md.underline = function (s: TemplateInput): TemplateInput {
|
|
313
369
|
// $FlowFixMe[invalid-computed-prop]
|
|
314
|
-
return {[mdVerbatim]:
|
|
370
|
+
return {[mdVerbatim]: '__' + escapeMarkdown(`${s}`) + '__'};
|
|
315
371
|
};
|
|
316
372
|
|
|
317
|
-
md.strikethrough = function(s: TemplateInput):
|
|
373
|
+
md.strikethrough = function (s: TemplateInput): TemplateInput {
|
|
318
374
|
// $FlowFixMe[invalid-computed-prop]
|
|
319
|
-
return {[mdVerbatim]:
|
|
375
|
+
return {[mdVerbatim]: '~~' + escapeMarkdown(`${s}`) + '~~'};
|
|
320
376
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
|
|
4
|
+
import {generateJSONCodeHighlights} from '../src/diagnostic';
|
|
5
|
+
|
|
6
|
+
describe('generateJSONCodeHighlights', () => {
|
|
7
|
+
it('returns an escaped string 01', () => {
|
|
8
|
+
let result = generateJSONCodeHighlights(
|
|
9
|
+
`{
|
|
10
|
+
"a": 1
|
|
11
|
+
}`,
|
|
12
|
+
[
|
|
13
|
+
{key: '/a', type: 'key', message: 'foo1'},
|
|
14
|
+
{key: '/a', type: 'value', message: 'foo2'},
|
|
15
|
+
{key: '/a', message: 'foo3'},
|
|
16
|
+
],
|
|
17
|
+
);
|
|
18
|
+
assert.deepEqual(result, [
|
|
19
|
+
{
|
|
20
|
+
start: {line: 2, column: 3},
|
|
21
|
+
end: {line: 2, column: 5},
|
|
22
|
+
message: 'foo1',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
start: {line: 2, column: 8},
|
|
26
|
+
end: {line: 2, column: 8},
|
|
27
|
+
message: 'foo2',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
start: {line: 2, column: 3},
|
|
31
|
+
end: {line: 2, column: 8},
|
|
32
|
+
message: 'foo3',
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
});
|