@bhsd/common 1.2.0 → 1.3.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/dist/index.d.ts CHANGED
@@ -3,6 +3,11 @@ declare interface JsonError {
3
3
  message: string;
4
4
  line: number;
5
5
  column: number;
6
+ endLine?: number;
7
+ endColumn?: number;
8
+ from: number;
9
+ to?: number;
10
+ /** @deprecated */
6
11
  position: number;
7
12
  }
8
13
  export type RegexGetter<T = string> = (s: T) => RegExp;
package/dist/index.js CHANGED
@@ -51,7 +51,8 @@ exports.splitColors = splitColors;
51
51
  * 清理内联样式中的`{`和`}`
52
52
  * @param style 内联样式
53
53
  */
54
- const sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, p => p === '{' ? '{' : '}');
54
+ const sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, p => p === '{' ? '{' : '}')
55
+ .replace(/^[\s;]+/u, p => p.replace(/;/gu, ' '));
55
56
  exports.sanitizeInlineStyle = sanitizeInlineStyle;
56
57
  function getRegex(f) {
57
58
  const map = new Map(), weakMap = new WeakMap();
@@ -91,25 +92,35 @@ exports.splitLines = splitLines;
91
92
  const mt2num = (mt) => mt && Number(mt[1]);
92
93
  const formatJsonError = (str, errors) => {
93
94
  let lines;
95
+ const offsetToPosition = (offset) => {
96
+ lines ??= (0, exports.splitLines)(str);
97
+ const line = lines.findIndex(([, , end]) => offset <= end) + 1;
98
+ return {
99
+ line,
100
+ column: offset - lines[line - 1][1] + 1,
101
+ };
102
+ };
94
103
  for (const error of errors) {
95
- const { line, column, position } = error;
96
- if (position === null || position === undefined) {
104
+ const { line, column, from, to } = error;
105
+ if (from === null || from === undefined) {
97
106
  if (line) {
98
107
  lines ??= (0, exports.splitLines)(str);
99
108
  error.column ??= 1;
100
- error.position = lines[line - 1][1] + (error.column - 1);
109
+ error.from = lines[line - 1][1] + (error.column - 1);
101
110
  }
102
111
  else {
103
- error.position = 0;
112
+ error.from = 0;
104
113
  error.line = 1;
105
114
  error.column = 1;
106
115
  }
107
116
  }
108
117
  else if (!line || !column) {
109
- lines ??= (0, exports.splitLines)(str);
110
- error.line = lines.findIndex(([, , end]) => position <= end) + 1;
111
- error.column = position - lines[error.line - 1][1] + 1;
118
+ Object.assign(error, offsetToPosition(from));
119
+ }
120
+ if (to !== undefined) {
121
+ ({ line: error.endLine, column: error.endColumn } = offsetToPosition(to));
112
122
  }
123
+ error.position = error.from;
113
124
  }
114
125
  return errors;
115
126
  };
@@ -124,8 +135,8 @@ const lintJSONNative = (str, force) => {
124
135
  JSON.parse(str);
125
136
  }
126
137
  catch (e) {
127
- const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), position = mt2num(/\bposition (\d+)/u.exec(message));
128
- return formatJsonError(str, [{ message, line, column, position, severity: 'error' }]);
138
+ const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), from = mt2num(/\bposition (\d+)/u.exec(message));
139
+ return formatJsonError(str, [{ message, line, column, from, severity: 'error' }]);
129
140
  }
130
141
  }
131
142
  return [];
package/dist/index.mjs CHANGED
@@ -1,52 +1,62 @@
1
1
  // src/json_parse.ts
2
+ var escapee = {
3
+ '"': '"',
4
+ "\\": "\\",
5
+ "/": "/",
6
+ b: "\b",
7
+ f: "\f",
8
+ n: "\n",
9
+ r: "\r",
10
+ t: " "
11
+ };
12
+ var spaces = /* @__PURE__ */ new Set([" ", " ", "\n", "\r"]);
13
+ var stringify = (c) => {
14
+ if (c === "") {
15
+ return "end of input";
16
+ }
17
+ return c === '"' ? `'"'` : JSON.stringify(c);
18
+ };
2
19
  var json_parse = /* @__PURE__ */ (() => {
3
20
  let at;
4
21
  let ch;
5
- const escapee = {
6
- '"': '"',
7
- "\\": "\\",
8
- "/": "/",
9
- b: "\b",
10
- f: "\f",
11
- n: "\n",
12
- r: "\r",
13
- t: " "
14
- };
15
- const spaces = /* @__PURE__ */ new Set([" ", " ", "\n", "\r"]);
16
22
  let text;
17
23
  let warnings;
18
- const stringify = (c) => {
19
- if (c === "") {
20
- return "end of input";
24
+ const prepareError = (e, from, to) => {
25
+ if (from === void 0) {
26
+ e.from = at - 1;
27
+ } else {
28
+ e.from = from;
29
+ e.to = to ?? at - 1;
21
30
  }
22
- return c === '"' ? `'"'` : JSON.stringify(c);
23
31
  };
24
- const warn = (m) => {
25
- warnings.push({
26
- message: m,
27
- position: at - 1,
32
+ const warn = (message, from, to) => {
33
+ const warning = {
34
+ message,
28
35
  severity: "warning"
29
- });
36
+ };
37
+ prepareError(warning, from, to);
38
+ warnings.push(warning);
30
39
  };
31
- const error = (m) => {
32
- throw {
40
+ const error = (message, from, to) => {
41
+ const e = {
33
42
  warnings,
34
- message: m,
35
- position: at - 1,
43
+ message,
36
44
  severity: "error"
37
45
  };
46
+ prepareError(e, from, to);
47
+ throw e;
38
48
  };
39
49
  const next = (c) => {
40
50
  if (c && c !== ch) {
41
51
  error(`Expected ${stringify(c)} instead of ${stringify(ch)}`);
42
52
  }
43
53
  ch = text.charAt(at);
44
- at += 1;
54
+ at++;
45
55
  return ch;
46
56
  };
47
57
  const number = () => {
48
- let value2;
49
58
  let string2 = "";
59
+ const from = at - 1;
50
60
  if (ch === "-") {
51
61
  string2 = "-";
52
62
  next();
@@ -66,10 +76,11 @@ var json_parse = /* @__PURE__ */ (() => {
66
76
  error("No number after minus sign");
67
77
  }
68
78
  if (ch !== "." && ch !== "e" && ch !== "E") {
69
- value2 = Number(string2);
70
- if (!Number.isSafeInteger(value2)) {
71
- warn("Not a safe integer");
79
+ const value3 = Number(string2);
80
+ if (!Number.isSafeInteger(value3)) {
81
+ warn("Not a safe integer", from);
72
82
  }
83
+ return;
73
84
  }
74
85
  if (ch === ".") {
75
86
  string2 += ".";
@@ -94,44 +105,43 @@ var json_parse = /* @__PURE__ */ (() => {
94
105
  next();
95
106
  }
96
107
  }
97
- value2 ??= Number(string2);
108
+ const value2 = Number(string2);
98
109
  if (!Number.isFinite(value2)) {
99
110
  error("Bad number");
100
111
  }
101
112
  };
102
113
  const string = () => {
103
- let hex;
104
- let i;
105
114
  let value2 = "";
106
- let uffff;
107
115
  if (ch === '"') {
108
116
  while (next()) {
109
117
  if (ch === '"') {
110
118
  next();
111
119
  return value2;
112
120
  }
121
+ const from = at - 1;
113
122
  if (ch === "\\") {
114
123
  next();
115
124
  if (ch === "u") {
116
- uffff = 0;
117
- for (i = 0; i < 4; i++) {
118
- hex = parseInt(next(), 16);
125
+ let i = 0;
126
+ let uffff = 0;
127
+ for (; i < 4; i++) {
128
+ const hex = parseInt(next(), 16);
119
129
  if (!isFinite(hex)) {
120
130
  break;
121
131
  }
122
132
  uffff = uffff * 16 + hex;
123
133
  }
124
134
  if (i < 4) {
125
- error("Bad unicode escape");
135
+ error("Bad unicode escape", from);
126
136
  }
127
137
  value2 += String.fromCharCode(uffff);
128
138
  } else if (typeof escapee[ch] === "string") {
129
139
  value2 += escapee[ch];
130
140
  } else {
131
- error("Bad escaped character");
141
+ error("Bad escaped character", from, at);
132
142
  }
133
143
  } else if (ch < " ") {
134
- error("Bad control character");
144
+ error("Bad control character", from, at);
135
145
  } else {
136
146
  value2 += ch;
137
147
  }
@@ -172,15 +182,16 @@ var json_parse = /* @__PURE__ */ (() => {
172
182
  }
173
183
  };
174
184
  const array = () => {
175
- next("[");
185
+ next();
176
186
  white();
177
187
  if (ch === "]") {
178
188
  next();
179
189
  return;
180
190
  }
191
+ let from;
181
192
  while (ch) {
182
193
  if (ch === "]") {
183
- error("Trailing comma in array");
194
+ error("Trailing comma in array", from, from + 1);
184
195
  }
185
196
  value();
186
197
  white();
@@ -188,6 +199,7 @@ var json_parse = /* @__PURE__ */ (() => {
188
199
  next();
189
200
  return;
190
201
  } else if (ch === ",") {
202
+ from = at - 1;
191
203
  next();
192
204
  white();
193
205
  } else {
@@ -197,23 +209,25 @@ var json_parse = /* @__PURE__ */ (() => {
197
209
  error("Unterminated array");
198
210
  };
199
211
  const object = () => {
200
- let key;
201
212
  const keys = /* @__PURE__ */ new Set();
202
- next("{");
213
+ next();
203
214
  white();
204
215
  if (ch === "}") {
205
216
  next();
206
217
  return;
207
218
  }
219
+ let from;
208
220
  while (ch) {
209
221
  if (ch === "}") {
210
- error("Trailing comma in object");
222
+ error("Trailing comma in object", from, from + 1);
211
223
  }
212
- key = string();
224
+ from = at;
225
+ const key = string();
226
+ const to = at - 2;
213
227
  white();
214
228
  next(":");
215
229
  if (keys.has(key)) {
216
- warn(`Duplicate key ${stringify(key)}`);
230
+ warn(`Duplicate key ${stringify(key)}`, from, to);
217
231
  } else {
218
232
  keys.add(key);
219
233
  }
@@ -223,6 +237,7 @@ var json_parse = /* @__PURE__ */ (() => {
223
237
  next();
224
238
  return;
225
239
  } else if (ch === ",") {
240
+ from = at - 1;
226
241
  next();
227
242
  white();
228
243
  } else {
@@ -290,7 +305,7 @@ var splitColors = (str, hsl = true) => {
290
305
  }
291
306
  return pieces;
292
307
  };
293
- var sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, (p) => p === "{" ? "{" : "}");
308
+ var sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, (p) => p === "{" ? "{" : "}").replace(/^[\s;]+/u, (p) => p.replace(/;/gu, " "));
294
309
  function getRegex(f) {
295
310
  const map = /* @__PURE__ */ new Map(), weakMap = /* @__PURE__ */ new WeakMap();
296
311
  return (s) => {
@@ -319,23 +334,33 @@ var splitLines = (str) => {
319
334
  var mt2num = (mt) => mt && Number(mt[1]);
320
335
  var formatJsonError = (str, errors) => {
321
336
  let lines;
337
+ const offsetToPosition = (offset) => {
338
+ lines ??= splitLines(str);
339
+ const line = lines.findIndex(([, , end]) => offset <= end) + 1;
340
+ return {
341
+ line,
342
+ column: offset - lines[line - 1][1] + 1
343
+ };
344
+ };
322
345
  for (const error of errors) {
323
- const { line, column, position } = error;
324
- if (position === null || position === void 0) {
346
+ const { line, column, from, to } = error;
347
+ if (from === null || from === void 0) {
325
348
  if (line) {
326
349
  lines ??= splitLines(str);
327
350
  error.column ??= 1;
328
- error.position = lines[line - 1][1] + (error.column - 1);
351
+ error.from = lines[line - 1][1] + (error.column - 1);
329
352
  } else {
330
- error.position = 0;
353
+ error.from = 0;
331
354
  error.line = 1;
332
355
  error.column = 1;
333
356
  }
334
357
  } else if (!line || !column) {
335
- lines ??= splitLines(str);
336
- error.line = lines.findIndex(([, , end]) => position <= end) + 1;
337
- error.column = position - lines[error.line - 1][1] + 1;
358
+ Object.assign(error, offsetToPosition(from));
359
+ }
360
+ if (to !== void 0) {
361
+ ({ line: error.endLine, column: error.endColumn } = offsetToPosition(to));
338
362
  }
363
+ error.position = error.from;
339
364
  }
340
365
  return errors;
341
366
  };
@@ -344,8 +369,8 @@ var lintJSONNative = (str, force) => {
344
369
  try {
345
370
  JSON.parse(str);
346
371
  } catch (e) {
347
- const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), position = mt2num(/\bposition (\d+)/u.exec(message));
348
- return formatJsonError(str, [{ message, line, column, position, severity: "error" }]);
372
+ const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), from = mt2num(/\bposition (\d+)/u.exec(message));
373
+ return formatJsonError(str, [{ message, line, column, from, severity: "error" }]);
349
374
  }
350
375
  }
351
376
  return [];
@@ -29,6 +29,23 @@
29
29
  */
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
31
  exports.json_parse = void 0;
32
+ const escapee = {
33
+ '"': '"',
34
+ "\\": "\\",
35
+ "/": "/",
36
+ b: "\b",
37
+ f: "\f",
38
+ n: "\n",
39
+ r: "\r",
40
+ t: "\t",
41
+ };
42
+ const spaces = new Set([" ", "\t", "\n", "\r"]);
43
+ const stringify = (c) => {
44
+ if (c === "") {
45
+ return "end of input";
46
+ }
47
+ return c === '"' ? `'"'` : JSON.stringify(c);
48
+ };
32
49
  exports.json_parse = (() => {
33
50
  // This is a function that can parse a JSON text.
34
51
  // It is a simple, recursive descent parser.
@@ -37,41 +54,35 @@ exports.json_parse = (() => {
37
54
  // We are defining the function inside of another function to avoid creating global variables.
38
55
  let at; // The index of the current character
39
56
  let ch; // The current character
40
- const escapee = {
41
- '"': '"',
42
- "\\": "\\",
43
- "/": "/",
44
- b: "\b",
45
- f: "\f",
46
- n: "\n",
47
- r: "\r",
48
- t: "\t",
49
- };
50
- const spaces = new Set([" ", "\t", "\n", "\r"]);
51
57
  let text;
52
58
  let warnings;
53
- const stringify = (c) => {
54
- if (c === "") {
55
- return "end of input";
59
+ const prepareError = (e, from, to) => {
60
+ if (from === undefined) {
61
+ e.from = at - 1;
62
+ }
63
+ else {
64
+ e.from = from;
65
+ e.to = to ?? at - 1;
56
66
  }
57
- return c === '"' ? `'"'` : JSON.stringify(c);
58
67
  };
59
- const warn = (m) => {
68
+ const warn = (message, from, to) => {
60
69
  // Log warning when something is wrong.
61
- warnings.push({
62
- message: m,
63
- position: at - 1,
70
+ const warning = {
71
+ message,
64
72
  severity: "warning",
65
- });
73
+ };
74
+ prepareError(warning, from, to);
75
+ warnings.push(warning);
66
76
  };
67
- const error = (m) => {
77
+ const error = (message, from, to) => {
68
78
  // Call error when something is wrong.
69
- throw {
79
+ const e = {
70
80
  warnings,
71
- message: m,
72
- position: at - 1,
81
+ message,
73
82
  severity: "error",
74
83
  };
84
+ prepareError(e, from, to);
85
+ throw e;
75
86
  };
76
87
  const next = (c) => {
77
88
  // If a c parameter is provided, verify that it matches the current character.
@@ -80,13 +91,13 @@ exports.json_parse = (() => {
80
91
  }
81
92
  // Get the next character. When there are no more characters, return the empty string.
82
93
  ch = text.charAt(at);
83
- at += 1;
94
+ at++;
84
95
  return ch;
85
96
  };
86
97
  const number = () => {
87
98
  // Parse a number value.
88
- let value;
89
99
  let string = "";
100
+ const from = at - 1;
90
101
  if (ch === "-") {
91
102
  string = "-";
92
103
  next();
@@ -108,10 +119,11 @@ exports.json_parse = (() => {
108
119
  error("No number after minus sign");
109
120
  }
110
121
  if (ch !== "." && ch !== "e" && ch !== "E") {
111
- value = Number(string);
122
+ const value = Number(string);
112
123
  if (!Number.isSafeInteger(value)) {
113
- warn("Not a safe integer");
124
+ warn("Not a safe integer", from);
114
125
  }
126
+ return;
115
127
  }
116
128
  if (ch === ".") {
117
129
  string += ".";
@@ -137,17 +149,14 @@ exports.json_parse = (() => {
137
149
  next();
138
150
  }
139
151
  }
140
- value ??= Number(string);
152
+ const value = Number(string);
141
153
  if (!Number.isFinite(value)) {
142
154
  error("Bad number");
143
155
  }
144
156
  };
145
157
  const string = () => {
146
158
  // Parse a string value.
147
- let hex;
148
- let i;
149
159
  let value = "";
150
- let uffff;
151
160
  // When parsing for string values, we must look for " and \ characters.
152
161
  if (ch === '"') {
153
162
  while (next()) {
@@ -155,19 +164,21 @@ exports.json_parse = (() => {
155
164
  next();
156
165
  return value;
157
166
  }
167
+ const from = at - 1;
158
168
  if (ch === "\\") {
159
169
  next();
160
170
  if (ch === "u") {
161
- uffff = 0;
162
- for (i = 0; i < 4; i++) {
163
- hex = parseInt(next(), 16);
171
+ let i = 0;
172
+ let uffff = 0;
173
+ for (; i < 4; i++) {
174
+ const hex = parseInt(next(), 16);
164
175
  if (!isFinite(hex)) {
165
176
  break;
166
177
  }
167
178
  uffff = uffff * 16 + hex;
168
179
  }
169
180
  if (i < 4) {
170
- error("Bad unicode escape");
181
+ error("Bad unicode escape", from);
171
182
  }
172
183
  value += String.fromCharCode(uffff);
173
184
  }
@@ -175,11 +186,11 @@ exports.json_parse = (() => {
175
186
  value += escapee[ch];
176
187
  }
177
188
  else {
178
- error("Bad escaped character");
189
+ error("Bad escaped character", from, at);
179
190
  }
180
191
  }
181
192
  else if (ch < " ") {
182
- error("Bad control character");
193
+ error("Bad control character", from, at);
183
194
  }
184
195
  else {
185
196
  value += ch;
@@ -225,15 +236,16 @@ exports.json_parse = (() => {
225
236
  };
226
237
  const array = () => {
227
238
  // Parse an array value.
228
- next("[");
239
+ next();
229
240
  white();
230
241
  if (ch === "]") {
231
242
  next();
232
243
  return; // empty array
233
244
  }
245
+ let from;
234
246
  while (ch) {
235
247
  if (ch === "]") {
236
- error("Trailing comma in array");
248
+ error("Trailing comma in array", from, from + 1);
237
249
  }
238
250
  value();
239
251
  white();
@@ -242,6 +254,7 @@ exports.json_parse = (() => {
242
254
  return;
243
255
  }
244
256
  else if (ch === ",") {
257
+ from = at - 1;
245
258
  next();
246
259
  white();
247
260
  }
@@ -253,23 +266,25 @@ exports.json_parse = (() => {
253
266
  };
254
267
  const object = () => {
255
268
  // Parse an object value.
256
- let key;
257
269
  const keys = new Set();
258
- next("{");
270
+ next();
259
271
  white();
260
272
  if (ch === "}") {
261
273
  next();
262
274
  return; // empty object
263
275
  }
276
+ let from;
264
277
  while (ch) {
265
278
  if (ch === "}") {
266
- error("Trailing comma in object");
279
+ error("Trailing comma in object", from, from + 1);
267
280
  }
268
- key = string();
281
+ from = at;
282
+ const key = string();
283
+ const to = at - 2;
269
284
  white();
270
285
  next(":");
271
286
  if (keys.has(key)) {
272
- warn(`Duplicate key ${stringify(key)}`);
287
+ warn(`Duplicate key ${stringify(key)}`, from, to);
273
288
  }
274
289
  else {
275
290
  keys.add(key);
@@ -281,6 +296,7 @@ exports.json_parse = (() => {
281
296
  return;
282
297
  }
283
298
  else if (ch === ",") {
299
+ from = at - 1;
284
300
  next();
285
301
  white();
286
302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhsd/common",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "homepage": "https://github.com/bhsd-harry/common#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/bhsd-harry/common/issues"