@oh-my-pi/pi-utils 17.2.8 → 17.2.10
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/CHANGELOG.md +32 -0
- package/dist/types/acp/connection.d.ts +118 -0
- package/dist/types/acp/protocol.d.ts +526 -0
- package/dist/types/acp/schema.d.ts +41 -0
- package/dist/types/acp/stream.d.ts +8 -0
- package/dist/types/acp/transport.d.ts +81 -0
- package/dist/types/acp.d.ts +6 -0
- package/dist/types/browsers.d.ts +68 -0
- package/dist/types/chalk.d.ts +125 -0
- package/dist/types/dates.d.ts +7 -0
- package/dist/types/docx/converter.d.ts +46 -0
- package/dist/types/docx/xml.d.ts +26 -0
- package/dist/types/docx/zip.d.ts +6 -0
- package/dist/types/docx.d.ts +11 -0
- package/dist/types/dom/core.d.ts +431 -0
- package/dist/types/dom/parser.d.ts +7 -0
- package/dist/types/dom/selector.d.ts +5 -0
- package/dist/types/dom.d.ts +5 -0
- package/dist/types/headers.d.ts +34 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/logger/rotating-file.d.ts +18 -0
- package/dist/types/lru.d.ts +46 -0
- package/dist/types/marked/core.d.ts +445 -0
- package/dist/types/marked.d.ts +2 -0
- package/dist/types/postmortem.d.ts +14 -0
- package/dist/types/procmgr.d.ts +16 -0
- package/dist/types/prompt.d.ts +2 -2
- package/dist/types/readability/readability.d.ts +9 -0
- package/dist/types/readability/readerable.d.ts +10 -0
- package/dist/types/readability/types.d.ts +70 -0
- package/dist/types/readability.d.ts +4 -0
- package/dist/types/template.d.ts +62 -0
- package/dist/types/turndown/gfm.d.ts +11 -0
- package/dist/types/turndown/html.d.ts +5 -0
- package/dist/types/turndown/service.d.ts +21 -0
- package/dist/types/turndown/types.d.ts +70 -0
- package/dist/types/turndown.d.ts +4 -0
- package/dist/types/version.d.ts +18 -0
- package/dist/types/vterm/buffer.d.ts +99 -0
- package/dist/types/vterm/terminal.d.ts +44 -0
- package/dist/types/vterm.d.ts +8 -0
- package/dist/types/xml.d.ts +31 -0
- package/package.json +2 -5
- package/src/acp/connection.ts +344 -0
- package/src/acp/protocol.ts +466 -0
- package/src/acp/schema.ts +160 -0
- package/src/acp/stream.ts +82 -0
- package/src/acp/transport.ts +213 -0
- package/src/acp.ts +6 -0
- package/src/browsers.ts +501 -0
- package/src/chalk.ts +312 -0
- package/src/dates.ts +194 -0
- package/src/docx/converter.ts +681 -0
- package/src/docx/xml.ts +166 -0
- package/src/docx/zip.ts +87 -0
- package/src/docx.ts +20 -0
- package/src/dom/core.ts +1254 -0
- package/src/dom/parser.ts +370 -0
- package/src/dom/selector.ts +290 -0
- package/src/dom.ts +33 -0
- package/src/fetch-retry.ts +7 -1
- package/src/frontmatter.ts +1 -1
- package/src/headers.ts +167 -0
- package/src/index.ts +1 -0
- package/src/logger/rotating-file.ts +149 -0
- package/src/logger.ts +12 -28
- package/src/lru.ts +185 -0
- package/src/marked/core.ts +1576 -0
- package/src/marked.ts +2 -0
- package/src/postmortem.ts +44 -1
- package/src/procmgr.ts +21 -4
- package/src/prompt.ts +5 -22
- package/src/readability/readability.ts +533 -0
- package/src/readability/readerable.ts +51 -0
- package/src/readability/types.ts +72 -0
- package/src/readability.ts +11 -0
- package/src/template.ts +586 -0
- package/src/turndown/gfm.ts +106 -0
- package/src/turndown/html.ts +257 -0
- package/src/turndown/service.ts +334 -0
- package/src/turndown/types.ts +81 -0
- package/src/turndown.ts +5 -0
- package/src/version.ts +99 -0
- package/src/vterm/buffer.ts +218 -0
- package/src/vterm/terminal.ts +773 -0
- package/src/vterm.ts +8 -0
- package/src/which.ts +6 -4
- package/src/xml.ts +313 -0
- package/src/winston-daily-rotate-file.d.ts +0 -6
package/src/vterm.ts
ADDED
package/src/which.ts
CHANGED
|
@@ -183,8 +183,8 @@ export interface WhichOptions extends Bun.WhichOptions {
|
|
|
183
183
|
|
|
184
184
|
// Darwin-specific "which" shim: consult Xcode/CLT toolchain directories after $PATH.
|
|
185
185
|
// Uses cached directory listings instead of per-command existsSync or xcrun subprocesses.
|
|
186
|
-
function darwinWhich(command: string,
|
|
187
|
-
const regular = Bun.which(command);
|
|
186
|
+
function darwinWhich(command: string, options?: Bun.WhichOptions): string | null {
|
|
187
|
+
const regular = Bun.which(command, options);
|
|
188
188
|
if (regular) return regular;
|
|
189
189
|
if (isXcodeBin(command)) {
|
|
190
190
|
return getMacosToolPaths().get(command) ?? null;
|
|
@@ -214,17 +214,19 @@ function cacheKey(command: string, options?: Bun.WhichOptions): CacheKey {
|
|
|
214
214
|
*/
|
|
215
215
|
export function $which(command: string, options?: WhichOptions): string | null {
|
|
216
216
|
const cachePolicy = options?.cache ?? WhichCachePolicy.Cached;
|
|
217
|
+
const lookupOptions =
|
|
218
|
+
options?.PATH !== undefined || process.env.PATH === undefined ? options : { ...options, PATH: process.env.PATH };
|
|
217
219
|
let key: CacheKey | undefined;
|
|
218
220
|
|
|
219
221
|
if (cachePolicy !== WhichCachePolicy.Bypass) {
|
|
220
|
-
key = cacheKey(command,
|
|
222
|
+
key = cacheKey(command, lookupOptions);
|
|
221
223
|
if (cachePolicy !== WhichCachePolicy.Fresh) {
|
|
222
224
|
const cached = toolCache.get(key);
|
|
223
225
|
if (cached !== undefined) return cached;
|
|
224
226
|
}
|
|
225
227
|
}
|
|
226
228
|
|
|
227
|
-
const result = whichFresh(command,
|
|
229
|
+
const result = whichFresh(command, lookupOptions);
|
|
228
230
|
if (key != null && cachePolicy !== WhichCachePolicy.ReadOnly) {
|
|
229
231
|
toolCache.set(key, result);
|
|
230
232
|
}
|
package/src/xml.ts
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/** Behavior-compatible reimplementation of fast-xml-parser's used surface. */
|
|
2
|
+
|
|
3
|
+
/** Context supplied to an array-selection callback. */
|
|
4
|
+
export type XMLArraySelector = (
|
|
5
|
+
tagName: string,
|
|
6
|
+
jPath: string,
|
|
7
|
+
isLeafNode: boolean,
|
|
8
|
+
isAttribute: boolean | null,
|
|
9
|
+
) => boolean;
|
|
10
|
+
|
|
11
|
+
/** Options supported by {@link XMLParser}. */
|
|
12
|
+
export interface XMLParserOptions {
|
|
13
|
+
/** Omits attributes when true (default). */
|
|
14
|
+
ignoreAttributes?: boolean;
|
|
15
|
+
/** Prefix applied to attribute property names. */
|
|
16
|
+
attributeNamePrefix?: string;
|
|
17
|
+
/** Property used for text alongside children or attributes. */
|
|
18
|
+
textNodeName?: string;
|
|
19
|
+
/** Trims ordinary text and attribute values. */
|
|
20
|
+
trimValues?: boolean;
|
|
21
|
+
/** Coerces numeric and boolean element text. */
|
|
22
|
+
parseTagValue?: boolean;
|
|
23
|
+
/** Coerces numeric and boolean attribute values. */
|
|
24
|
+
parseAttributeValue?: boolean;
|
|
25
|
+
/** Controls entity processing and its expansion ceiling. */
|
|
26
|
+
processEntities?: boolean | { maxTotalExpansions?: number };
|
|
27
|
+
/** Selects element or attribute properties that must always be arrays. */
|
|
28
|
+
isArray?: XMLArraySelector;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type XmlObject = Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
const STANDARD_ENTITIES: Record<string, string> = { amp: "&", apos: "'", gt: ">", lt: "<", quot: '"' };
|
|
34
|
+
|
|
35
|
+
interface ParsedElement {
|
|
36
|
+
name: string;
|
|
37
|
+
value: unknown;
|
|
38
|
+
leaf: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ParserSettings {
|
|
42
|
+
ignoreAttributes: boolean;
|
|
43
|
+
attributeNamePrefix: string;
|
|
44
|
+
textNodeName: string;
|
|
45
|
+
trimValues: boolean;
|
|
46
|
+
parseTagValue: boolean;
|
|
47
|
+
parseAttributeValue: boolean;
|
|
48
|
+
processEntities: boolean;
|
|
49
|
+
maxTotalExpansions: number;
|
|
50
|
+
isArray?: XMLArraySelector;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Parses XML into the object shape used by the document converters. */
|
|
54
|
+
export class XMLParser {
|
|
55
|
+
readonly #settings: ParserSettings;
|
|
56
|
+
|
|
57
|
+
constructor(options: XMLParserOptions = {}) {
|
|
58
|
+
this.#settings = {
|
|
59
|
+
ignoreAttributes: options.ignoreAttributes ?? true,
|
|
60
|
+
attributeNamePrefix: options.attributeNamePrefix ?? "@_",
|
|
61
|
+
textNodeName: options.textNodeName ?? "#text",
|
|
62
|
+
trimValues: options.trimValues ?? true,
|
|
63
|
+
parseTagValue: options.parseTagValue ?? true,
|
|
64
|
+
parseAttributeValue: options.parseAttributeValue ?? false,
|
|
65
|
+
processEntities: options.processEntities !== false,
|
|
66
|
+
maxTotalExpansions:
|
|
67
|
+
typeof options.processEntities === "object"
|
|
68
|
+
? (options.processEntities.maxTotalExpansions ?? 100_000)
|
|
69
|
+
: 100_000,
|
|
70
|
+
isArray: options.isArray,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Parses one XML document. */
|
|
75
|
+
parse(xml: string): unknown {
|
|
76
|
+
return new XmlReader(xml, this.#settings).parseDocument();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class XmlReader {
|
|
81
|
+
readonly #xml: string;
|
|
82
|
+
readonly #settings: ParserSettings;
|
|
83
|
+
readonly #entities = new Map<string, string>();
|
|
84
|
+
#position = 0;
|
|
85
|
+
#expansions = 0;
|
|
86
|
+
|
|
87
|
+
constructor(xml: string, settings: ParserSettings) {
|
|
88
|
+
this.#xml = xml.charCodeAt(0) === 0xfeff ? xml.slice(1) : xml;
|
|
89
|
+
this.#settings = settings;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
parseDocument(): XmlObject {
|
|
93
|
+
const document: XmlObject = {};
|
|
94
|
+
while (this.#position < this.#xml.length) {
|
|
95
|
+
if (this.#xml.startsWith("<!--", this.#position)) {
|
|
96
|
+
this.#skipThrough("-->");
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (this.#xml.startsWith("<!DOCTYPE", this.#position)) {
|
|
100
|
+
this.#readDoctype();
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (this.#xml.startsWith("<?", this.#position)) {
|
|
104
|
+
this.#readProcessingInstruction(document);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (this.#xml[this.#position] === "<") {
|
|
108
|
+
const element = this.#readElement("");
|
|
109
|
+
this.#addValue(document, element.name, element.name, element.value, element.leaf, null);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
this.#position++;
|
|
113
|
+
}
|
|
114
|
+
return document;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#readElement(parentPath: string): ParsedElement {
|
|
118
|
+
this.#position++;
|
|
119
|
+
const name = this.#readName();
|
|
120
|
+
const path = parentPath ? `${parentPath}.${name}` : name;
|
|
121
|
+
const attributes: [string, string][] = [];
|
|
122
|
+
let selfClosing = false;
|
|
123
|
+
while (this.#position < this.#xml.length) {
|
|
124
|
+
this.#skipWhitespace();
|
|
125
|
+
if (this.#xml.startsWith("/>", this.#position)) {
|
|
126
|
+
this.#position += 2;
|
|
127
|
+
selfClosing = true;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
if (this.#xml[this.#position] === ">") {
|
|
131
|
+
this.#position++;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
const attributeName = this.#readName();
|
|
135
|
+
this.#skipWhitespace();
|
|
136
|
+
let value = "true";
|
|
137
|
+
if (this.#xml[this.#position] === "=") {
|
|
138
|
+
this.#position++;
|
|
139
|
+
this.#skipWhitespace();
|
|
140
|
+
value = this.#readAttributeValue();
|
|
141
|
+
}
|
|
142
|
+
attributes.push([attributeName, value]);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const children: XmlObject = {};
|
|
146
|
+
let text = "";
|
|
147
|
+
let hasChildren = false;
|
|
148
|
+
if (!selfClosing) {
|
|
149
|
+
while (this.#position < this.#xml.length) {
|
|
150
|
+
if (this.#xml.startsWith(`</${name}`, this.#position)) {
|
|
151
|
+
this.#position += name.length + 2;
|
|
152
|
+
const close = this.#xml.indexOf(">", this.#position);
|
|
153
|
+
this.#position = close < 0 ? this.#xml.length : close + 1;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
if (this.#xml.startsWith("<![CDATA[", this.#position)) {
|
|
157
|
+
const end = this.#xml.indexOf("]]>", this.#position + 9);
|
|
158
|
+
const raw = this.#xml.slice(this.#position + 9, end < 0 ? this.#xml.length : end);
|
|
159
|
+
const normalized = raw;
|
|
160
|
+
text += this.#settings.parseTagValue ? String(coerceValue(normalized)) : normalized;
|
|
161
|
+
this.#position = end < 0 ? this.#xml.length : end + 3;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (this.#xml.startsWith("<!--", this.#position)) {
|
|
165
|
+
this.#skipThrough("-->");
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (this.#xml.startsWith("<?", this.#position)) {
|
|
169
|
+
this.#skipThrough("?>");
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (this.#xml[this.#position] === "<") {
|
|
173
|
+
const child = this.#readElement(path);
|
|
174
|
+
hasChildren = true;
|
|
175
|
+
this.#addValue(children, child.name, `${path}.${child.name}`, child.value, child.leaf, null);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const next = this.#xml.indexOf("<", this.#position);
|
|
179
|
+
const end = next < 0 ? this.#xml.length : next;
|
|
180
|
+
const normalized = this.#normalizeText(this.#xml.slice(this.#position, end), true);
|
|
181
|
+
text += this.#settings.parseTagValue ? String(coerceValue(normalized)) : normalized;
|
|
182
|
+
this.#position = end;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const hasAttributes = !this.#settings.ignoreAttributes && attributes.length > 0;
|
|
187
|
+
const parsedText = this.#settings.parseTagValue ? coerceValue(text) : text;
|
|
188
|
+
if (!hasChildren && !hasAttributes) return { name, value: parsedText, leaf: true };
|
|
189
|
+
if (text !== "") children[this.#settings.textNodeName] = parsedText;
|
|
190
|
+
if (hasAttributes) {
|
|
191
|
+
for (const [attributeName, raw] of attributes) {
|
|
192
|
+
const key = `${this.#settings.attributeNamePrefix}${attributeName}`;
|
|
193
|
+
const value = this.#settings.parseAttributeValue ? coerceValue(raw) : raw;
|
|
194
|
+
this.#addValue(children, key, `${path}.${attributeName}`, value, true, true);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { name, value: children, leaf: !hasChildren };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
#readAttributeValue(): string {
|
|
201
|
+
const quote = this.#xml[this.#position];
|
|
202
|
+
if (quote === '"' || quote === "'") {
|
|
203
|
+
const start = ++this.#position;
|
|
204
|
+
const end = this.#xml.indexOf(quote, start);
|
|
205
|
+
this.#position = end < 0 ? this.#xml.length : end + 1;
|
|
206
|
+
return this.#normalizeText(this.#xml.slice(start, end < 0 ? this.#xml.length : end), true);
|
|
207
|
+
}
|
|
208
|
+
const start = this.#position;
|
|
209
|
+
while (this.#position < this.#xml.length && !/[\s>]/.test(this.#xml[this.#position])) this.#position++;
|
|
210
|
+
return this.#normalizeText(this.#xml.slice(start, this.#position), true);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#readProcessingInstruction(target: XmlObject): void {
|
|
214
|
+
this.#position += 2;
|
|
215
|
+
const name = this.#readName();
|
|
216
|
+
const bodyStart = this.#position;
|
|
217
|
+
const end = this.#xml.indexOf("?>", bodyStart);
|
|
218
|
+
const body = this.#xml.slice(bodyStart, end < 0 ? this.#xml.length : end);
|
|
219
|
+
this.#position = end < 0 ? this.#xml.length : end + 2;
|
|
220
|
+
const value: XmlObject = {};
|
|
221
|
+
let hasAttribute = false;
|
|
222
|
+
const attributePattern = /([^\s=]+)\s*=\s*(["'])(.*?)\2/g;
|
|
223
|
+
for (const match of body.matchAll(attributePattern)) {
|
|
224
|
+
if (!this.#settings.ignoreAttributes) {
|
|
225
|
+
value[`${this.#settings.attributeNamePrefix}${match[1]}`] = this.#normalizeText(match[3]!, true);
|
|
226
|
+
hasAttribute = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
target[`?${name}`] = hasAttribute ? value : "";
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
#readDoctype(): void {
|
|
233
|
+
const start = this.#position;
|
|
234
|
+
let bracketDepth = 0;
|
|
235
|
+
let quote = "";
|
|
236
|
+
while (this.#position < this.#xml.length) {
|
|
237
|
+
const char = this.#xml[this.#position++];
|
|
238
|
+
if (quote) {
|
|
239
|
+
if (char === quote) quote = "";
|
|
240
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
241
|
+
else if (char === "[") bracketDepth++;
|
|
242
|
+
else if (char === "]") bracketDepth--;
|
|
243
|
+
else if (char === ">" && bracketDepth === 0) break;
|
|
244
|
+
}
|
|
245
|
+
const declaration = this.#xml.slice(start, this.#position);
|
|
246
|
+
const entityPattern = /<!ENTITY\s+([^\s]+)\s+(["'])(.*?)\2\s*>/gs;
|
|
247
|
+
for (const match of declaration.matchAll(entityPattern)) this.#entities.set(match[1]!, match[3]!);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
#normalizeText(value: string, entities: boolean): string {
|
|
251
|
+
let normalized = this.#settings.trimValues ? value.trim() : value;
|
|
252
|
+
if (entities && this.#settings.processEntities && normalized.includes("&"))
|
|
253
|
+
normalized = this.#expandEntities(normalized);
|
|
254
|
+
return normalized;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#expandEntities(value: string, stack?: ReadonlySet<string>): string {
|
|
258
|
+
return value.replace(/&([A-Za-z_:][\w.:-]*);/g, (whole, name: string) => {
|
|
259
|
+
const standard = STANDARD_ENTITIES[name];
|
|
260
|
+
if (standard !== undefined) return standard;
|
|
261
|
+
const replacement = this.#entities.get(name);
|
|
262
|
+
if (replacement === undefined || stack?.has(name)) return whole;
|
|
263
|
+
this.#expansions++;
|
|
264
|
+
if (this.#expansions > this.#settings.maxTotalExpansions) throw new Error("Entity expansion limit exceeded");
|
|
265
|
+
const nextStack = new Set(stack);
|
|
266
|
+
nextStack.add(name);
|
|
267
|
+
return this.#expandEntities(replacement, nextStack);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#addValue(
|
|
272
|
+
target: XmlObject,
|
|
273
|
+
name: string,
|
|
274
|
+
path: string,
|
|
275
|
+
value: unknown,
|
|
276
|
+
leaf: boolean,
|
|
277
|
+
attribute: boolean | null,
|
|
278
|
+
): void {
|
|
279
|
+
const present = Object.hasOwn(target, name);
|
|
280
|
+
if (present) {
|
|
281
|
+
const current = target[name];
|
|
282
|
+
if (Array.isArray(current)) current.push(value);
|
|
283
|
+
else target[name] = [current, value];
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const forceArray = this.#settings.isArray?.(name, path, leaf, attribute) ?? false;
|
|
287
|
+
target[name] = forceArray ? [value] : value;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#readName(): string {
|
|
291
|
+
const start = this.#position;
|
|
292
|
+
while (this.#position < this.#xml.length && !/[\s/>=]/.test(this.#xml[this.#position])) this.#position++;
|
|
293
|
+
return this.#xml.slice(start, this.#position);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
#skipWhitespace(): void {
|
|
297
|
+
while (this.#position < this.#xml.length && /\s/.test(this.#xml[this.#position])) this.#position++;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#skipThrough(marker: string): void {
|
|
301
|
+
const end = this.#xml.indexOf(marker, this.#position + marker.length);
|
|
302
|
+
this.#position = end < 0 ? this.#xml.length : end + marker.length;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function coerceValue(value: string): unknown {
|
|
307
|
+
if (value === "true") return true;
|
|
308
|
+
if (value === "false") return false;
|
|
309
|
+
if (value !== "" && /^[+-]?(?:0[xX][\da-fA-F]+|(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)$/.test(value)) {
|
|
310
|
+
return Number(value);
|
|
311
|
+
}
|
|
312
|
+
return value;
|
|
313
|
+
}
|