@deployxai/dxc 0.1.0
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 +131 -0
- package/dist/chunks/chunk-I6VZLNRZ.js +2118 -0
- package/dist/chunks/chunk-XIHX5YAF.js +16391 -0
- package/dist/chunks/knowledge-Q6MHPG6I.js +1248 -0
- package/dist/chunks/monitor-VPRVRQIS.js +694 -0
- package/dist/index.js +32367 -0
- package/docs/00-project-context.md +125 -0
- package/docs/01-north-star-architecture.md +234 -0
- package/docs/02-mvp-technical-design.md +553 -0
- package/docs/03-domain-state-api.md +599 -0
- package/docs/04-security-and-operations.md +413 -0
- package/docs/05-delivery-plan.md +407 -0
- package/docs/README.md +44 -0
- package/docs/decisions/0001-initial-architecture.md +57 -0
- package/docs/decisions/0002-mongodb-environment-boundary.md +42 -0
- package/docs/decisions/0003-staged-production-topology.md +33 -0
- package/docs/decisions/0004-local-first-agent-research-runtime.md +71 -0
- package/docs/decisions/0005-official-skill-orchestration-and-local-content-memory.md +97 -0
- package/docs/decisions/0006-separate-wechat-user-login-from-account-authorization.md +87 -0
- package/docs/decisions/0007-explicit-personal-wechat-start.md +67 -0
- package/docs/decisions/0008-end-to-end-content-workflow-continuity.md +115 -0
- package/docs/decisions/0009-privileged-multitenant-draft-scheduling.md +36 -0
- package/docs/decisions/0009-versioned-cloud-template-catalog.md +39 -0
- package/docs/eight-stage-implementation-audit.md +62 -0
- package/docs/first-user-guide.md +187 -0
- package/docs/history/content-forge-prd-v0.2-summary.md +81 -0
- package/docs/local-development.md +511 -0
- package/docs/references/aliyun-oss-production-setup.md +89 -0
- package/docs/references/legacy-content-to-wechat-contract.md +223 -0
- package/docs/references/renderer-compatibility-report.md +68 -0
- package/docs/references/source-inventory.md +179 -0
- package/docs/references/wechat-renderer-platform-validation.md +92 -0
- package/docs/references/wechat-third-party-platform-setup.md +159 -0
- package/docs/references/wechat-website-login-setup.md +137 -0
- package/docs/references/wemd-template-attribution.md +25 -0
- package/docs/research-monitoring-design.md +235 -0
- package/docs/todo-preview-local-first.md +31 -0
- package/docs/workbuddy-first-user-runbook.md +246 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-b-research-analyst/SKILL.md +230 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-c-outline-architect/SKILL.md +194 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-d-content-writer/SKILL.md +296 -0
- package/docs//345/221/230/345/267/245BCDE/347/232/204skill/employee-e-visual-designer/SKILL.md +268 -0
- package/package.json +25 -0
- package/skills/dxc-article-outline/SKILL.md +82 -0
- package/skills/dxc-article-outline/agents/openai.yaml +6 -0
- package/skills/dxc-article-outline/references/outline-methods.md +38 -0
- package/skills/dxc-article-write/SKILL.md +85 -0
- package/skills/dxc-article-write/agents/openai.yaml +6 -0
- package/skills/dxc-article-write/references/writing-methods.md +42 -0
- package/skills/dxc-content-brief/SKILL.md +81 -0
- package/skills/dxc-content-brief/agents/openai.yaml +6 -0
- package/skills/dxc-content-brief/references/brief-method.md +34 -0
- package/skills/dxc-content-review/SKILL.md +84 -0
- package/skills/dxc-content-review/agents/openai.yaml +6 -0
- package/skills/dxc-content-review/references/review-checklist.md +35 -0
- package/skills/dxc-content-workflow/SKILL.md +190 -0
- package/skills/dxc-content-workflow/agents/openai.yaml +6 -0
- package/skills/dxc-content-workflow/references/catalog.json +136 -0
- package/skills/dxc-content-workflow/references/onboarding-questions.md +107 -0
- package/skills/dxc-content-workflow/references/stage-contract.md +70 -0
- package/skills/dxc-research/SKILL.md +110 -0
- package/skills/dxc-research/agents/openai.yaml +6 -0
- package/skills/dxc-research/references/research-method.md +53 -0
- package/skills/dxc-title-write/SKILL.md +112 -0
- package/skills/dxc-title-write/agents/openai.yaml +6 -0
- package/skills/dxc-title-write/references/title-methods.md +26 -0
- package/skills/dxc-visual-plan/SKILL.md +119 -0
- package/skills/dxc-visual-plan/agents/openai.yaml +6 -0
- package/skills/dxc-visual-plan/references/visual-methods.md +35 -0
- package/skills/dxc-wechat-publisher/SKILL.md +157 -0
- package/skills/dxc-wechat-publisher/agents/openai.yaml +6 -0
|
@@ -0,0 +1,2118 @@
|
|
|
1
|
+
import { createRequire as __dxcCreateRequire } from "node:module"; const require = __dxcCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
sourceFetchResultSchema
|
|
4
|
+
} from "./chunk-XIHX5YAF.js";
|
|
5
|
+
|
|
6
|
+
// apps/cli/src/source.ts
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { lookup as systemLookup } from "node:dns/promises";
|
|
9
|
+
import { isIP } from "node:net";
|
|
10
|
+
|
|
11
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/util.js
|
|
12
|
+
var nameStartChar = ":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
|
13
|
+
var nameChar = nameStartChar + "\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
|
14
|
+
var nameRegexp = "[" + nameStartChar + "][" + nameChar + "]*";
|
|
15
|
+
var regexName = new RegExp("^" + nameRegexp + "$");
|
|
16
|
+
function getAllMatches(string, regex) {
|
|
17
|
+
const matches = [];
|
|
18
|
+
let match = regex.exec(string);
|
|
19
|
+
while (match) {
|
|
20
|
+
const allmatches = [];
|
|
21
|
+
allmatches.startIndex = regex.lastIndex - match[0].length;
|
|
22
|
+
const len = match.length;
|
|
23
|
+
for (let index = 0; index < len; index++) {
|
|
24
|
+
allmatches.push(match[index]);
|
|
25
|
+
}
|
|
26
|
+
matches.push(allmatches);
|
|
27
|
+
match = regex.exec(string);
|
|
28
|
+
}
|
|
29
|
+
return matches;
|
|
30
|
+
}
|
|
31
|
+
var isName = function(string) {
|
|
32
|
+
const match = regexName.exec(string);
|
|
33
|
+
return !(match === null || typeof match === "undefined");
|
|
34
|
+
};
|
|
35
|
+
function isExist(v) {
|
|
36
|
+
return typeof v !== "undefined";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/validator.js
|
|
40
|
+
var defaultOptions = {
|
|
41
|
+
allowBooleanAttributes: false,
|
|
42
|
+
//A tag can have attributes without any value
|
|
43
|
+
unpairedTags: []
|
|
44
|
+
};
|
|
45
|
+
function validate(xmlData, options) {
|
|
46
|
+
options = Object.assign({}, defaultOptions, options);
|
|
47
|
+
const tags = [];
|
|
48
|
+
let tagFound = false;
|
|
49
|
+
let reachedRoot = false;
|
|
50
|
+
if (xmlData[0] === "\uFEFF") {
|
|
51
|
+
xmlData = xmlData.substr(1);
|
|
52
|
+
}
|
|
53
|
+
for (let i = 0; i < xmlData.length; i++) {
|
|
54
|
+
if (xmlData[i] === "<" && xmlData[i + 1] === "?") {
|
|
55
|
+
i += 2;
|
|
56
|
+
i = readPI(xmlData, i);
|
|
57
|
+
if (i.err) return i;
|
|
58
|
+
} else if (xmlData[i] === "<") {
|
|
59
|
+
let tagStartPos = i;
|
|
60
|
+
i++;
|
|
61
|
+
if (xmlData[i] === "!") {
|
|
62
|
+
i = readCommentAndCDATA(xmlData, i);
|
|
63
|
+
continue;
|
|
64
|
+
} else {
|
|
65
|
+
let closingTag = false;
|
|
66
|
+
if (xmlData[i] === "/") {
|
|
67
|
+
closingTag = true;
|
|
68
|
+
i++;
|
|
69
|
+
}
|
|
70
|
+
let tagName = "";
|
|
71
|
+
for (; i < xmlData.length && xmlData[i] !== ">" && xmlData[i] !== " " && xmlData[i] !== " " && xmlData[i] !== "\n" && xmlData[i] !== "\r"; i++) {
|
|
72
|
+
tagName += xmlData[i];
|
|
73
|
+
}
|
|
74
|
+
tagName = tagName.trim();
|
|
75
|
+
if (tagName[tagName.length - 1] === "/") {
|
|
76
|
+
tagName = tagName.substring(0, tagName.length - 1);
|
|
77
|
+
i--;
|
|
78
|
+
}
|
|
79
|
+
if (!validateTagName(tagName)) {
|
|
80
|
+
let msg;
|
|
81
|
+
if (tagName.trim().length === 0) {
|
|
82
|
+
msg = "Invalid space after '<'.";
|
|
83
|
+
} else {
|
|
84
|
+
msg = "Tag '" + tagName + "' is an invalid name.";
|
|
85
|
+
}
|
|
86
|
+
return getErrorObject("InvalidTag", msg, getLineNumberForPosition(xmlData, i));
|
|
87
|
+
}
|
|
88
|
+
const result = readAttributeStr(xmlData, i);
|
|
89
|
+
if (result === false) {
|
|
90
|
+
return getErrorObject("InvalidAttr", "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i));
|
|
91
|
+
}
|
|
92
|
+
let attrStr = result.value;
|
|
93
|
+
i = result.index;
|
|
94
|
+
if (attrStr[attrStr.length - 1] === "/") {
|
|
95
|
+
const attrStrStart = i - attrStr.length;
|
|
96
|
+
attrStr = attrStr.substring(0, attrStr.length - 1);
|
|
97
|
+
const isValid = validateAttributeString(attrStr, options);
|
|
98
|
+
if (isValid === true) {
|
|
99
|
+
tagFound = true;
|
|
100
|
+
} else {
|
|
101
|
+
return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
|
|
102
|
+
}
|
|
103
|
+
} else if (closingTag) {
|
|
104
|
+
if (!result.tagClosed) {
|
|
105
|
+
return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
|
|
106
|
+
} else if (attrStr.trim().length > 0) {
|
|
107
|
+
return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
|
|
108
|
+
} else if (tags.length === 0) {
|
|
109
|
+
return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
|
|
110
|
+
} else {
|
|
111
|
+
const otg = tags.pop();
|
|
112
|
+
if (tagName !== otg.tagName) {
|
|
113
|
+
let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
|
|
114
|
+
return getErrorObject(
|
|
115
|
+
"InvalidTag",
|
|
116
|
+
"Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.",
|
|
117
|
+
getLineNumberForPosition(xmlData, tagStartPos)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (tags.length == 0) {
|
|
121
|
+
reachedRoot = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
const isValid = validateAttributeString(attrStr, options);
|
|
126
|
+
if (isValid !== true) {
|
|
127
|
+
return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
|
|
128
|
+
}
|
|
129
|
+
if (reachedRoot === true) {
|
|
130
|
+
return getErrorObject("InvalidXml", "Multiple possible root nodes found.", getLineNumberForPosition(xmlData, i));
|
|
131
|
+
} else if (options.unpairedTags.indexOf(tagName) !== -1) {
|
|
132
|
+
} else {
|
|
133
|
+
tags.push({ tagName, tagStartPos });
|
|
134
|
+
}
|
|
135
|
+
tagFound = true;
|
|
136
|
+
}
|
|
137
|
+
for (i++; i < xmlData.length; i++) {
|
|
138
|
+
if (xmlData[i] === "<") {
|
|
139
|
+
if (xmlData[i + 1] === "!") {
|
|
140
|
+
i++;
|
|
141
|
+
i = readCommentAndCDATA(xmlData, i);
|
|
142
|
+
continue;
|
|
143
|
+
} else if (xmlData[i + 1] === "?") {
|
|
144
|
+
i = readPI(xmlData, ++i);
|
|
145
|
+
if (i.err) return i;
|
|
146
|
+
} else {
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
} else if (xmlData[i] === "&") {
|
|
150
|
+
const afterAmp = validateAmpersand(xmlData, i);
|
|
151
|
+
if (afterAmp == -1)
|
|
152
|
+
return getErrorObject("InvalidChar", "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
|
|
153
|
+
i = afterAmp;
|
|
154
|
+
} else {
|
|
155
|
+
if (reachedRoot === true && !isWhiteSpace(xmlData[i])) {
|
|
156
|
+
return getErrorObject("InvalidXml", "Extra text at the end", getLineNumberForPosition(xmlData, i));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (xmlData[i] === "<") {
|
|
161
|
+
i--;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
if (isWhiteSpace(xmlData[i])) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
return getErrorObject("InvalidChar", "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!tagFound) {
|
|
172
|
+
return getErrorObject("InvalidXml", "Start tag expected.", 1);
|
|
173
|
+
} else if (tags.length == 1) {
|
|
174
|
+
return getErrorObject("InvalidTag", "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
|
|
175
|
+
} else if (tags.length > 0) {
|
|
176
|
+
return getErrorObject("InvalidXml", "Invalid '" + JSON.stringify(tags.map((t) => t.tagName), null, 4).replace(/\r?\n/g, "") + "' found.", { line: 1, col: 1 });
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
function isWhiteSpace(char) {
|
|
181
|
+
return char === " " || char === " " || char === "\n" || char === "\r";
|
|
182
|
+
}
|
|
183
|
+
function readPI(xmlData, i) {
|
|
184
|
+
const start = i;
|
|
185
|
+
for (; i < xmlData.length; i++) {
|
|
186
|
+
if (xmlData[i] == "?" || xmlData[i] == " ") {
|
|
187
|
+
const tagname = xmlData.substr(start, i - start);
|
|
188
|
+
if (i > 5 && tagname === "xml") {
|
|
189
|
+
return getErrorObject("InvalidXml", "XML declaration allowed only at the start of the document.", getLineNumberForPosition(xmlData, i));
|
|
190
|
+
} else if (xmlData[i] == "?" && xmlData[i + 1] == ">") {
|
|
191
|
+
i++;
|
|
192
|
+
break;
|
|
193
|
+
} else {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return i;
|
|
199
|
+
}
|
|
200
|
+
function readCommentAndCDATA(xmlData, i) {
|
|
201
|
+
if (xmlData.length > i + 5 && xmlData[i + 1] === "-" && xmlData[i + 2] === "-") {
|
|
202
|
+
for (i += 3; i < xmlData.length; i++) {
|
|
203
|
+
if (xmlData[i] === "-" && xmlData[i + 1] === "-" && xmlData[i + 2] === ">") {
|
|
204
|
+
i += 2;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} else if (xmlData.length > i + 8 && xmlData[i + 1] === "D" && xmlData[i + 2] === "O" && xmlData[i + 3] === "C" && xmlData[i + 4] === "T" && xmlData[i + 5] === "Y" && xmlData[i + 6] === "P" && xmlData[i + 7] === "E") {
|
|
209
|
+
let angleBracketsCount = 1;
|
|
210
|
+
for (i += 8; i < xmlData.length; i++) {
|
|
211
|
+
if (xmlData[i] === "<") {
|
|
212
|
+
angleBracketsCount++;
|
|
213
|
+
} else if (xmlData[i] === ">") {
|
|
214
|
+
angleBracketsCount--;
|
|
215
|
+
if (angleBracketsCount === 0) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} else if (xmlData.length > i + 9 && xmlData[i + 1] === "[" && xmlData[i + 2] === "C" && xmlData[i + 3] === "D" && xmlData[i + 4] === "A" && xmlData[i + 5] === "T" && xmlData[i + 6] === "A" && xmlData[i + 7] === "[") {
|
|
221
|
+
for (i += 8; i < xmlData.length; i++) {
|
|
222
|
+
if (xmlData[i] === "]" && xmlData[i + 1] === "]" && xmlData[i + 2] === ">") {
|
|
223
|
+
i += 2;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return i;
|
|
229
|
+
}
|
|
230
|
+
var doubleQuote = '"';
|
|
231
|
+
var singleQuote = "'";
|
|
232
|
+
function readAttributeStr(xmlData, i) {
|
|
233
|
+
let attrStr = "";
|
|
234
|
+
let startChar = "";
|
|
235
|
+
let tagClosed = false;
|
|
236
|
+
for (; i < xmlData.length; i++) {
|
|
237
|
+
if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) {
|
|
238
|
+
if (startChar === "") {
|
|
239
|
+
startChar = xmlData[i];
|
|
240
|
+
} else if (startChar !== xmlData[i]) {
|
|
241
|
+
} else {
|
|
242
|
+
startChar = "";
|
|
243
|
+
}
|
|
244
|
+
} else if (xmlData[i] === ">") {
|
|
245
|
+
if (startChar === "") {
|
|
246
|
+
tagClosed = true;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
attrStr += xmlData[i];
|
|
251
|
+
}
|
|
252
|
+
if (startChar !== "") {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
value: attrStr,
|
|
257
|
+
index: i,
|
|
258
|
+
tagClosed
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
var validAttrStrRegxp = new RegExp(`(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['"])(([\\s\\S])*?)\\5)?`, "g");
|
|
262
|
+
function validateAttributeString(attrStr, options) {
|
|
263
|
+
const matches = getAllMatches(attrStr, validAttrStrRegxp);
|
|
264
|
+
const attrNames = {};
|
|
265
|
+
for (let i = 0; i < matches.length; i++) {
|
|
266
|
+
if (matches[i][1].length === 0) {
|
|
267
|
+
return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i]));
|
|
268
|
+
} else if (matches[i][3] !== void 0 && matches[i][4] === void 0) {
|
|
269
|
+
return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' is without value.", getPositionFromMatch(matches[i]));
|
|
270
|
+
} else if (matches[i][3] === void 0 && !options.allowBooleanAttributes) {
|
|
271
|
+
return getErrorObject("InvalidAttr", "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i]));
|
|
272
|
+
}
|
|
273
|
+
const attrName = matches[i][2];
|
|
274
|
+
if (!validateAttrName(attrName)) {
|
|
275
|
+
return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i]));
|
|
276
|
+
}
|
|
277
|
+
if (!attrNames.hasOwnProperty(attrName)) {
|
|
278
|
+
attrNames[attrName] = 1;
|
|
279
|
+
} else {
|
|
280
|
+
return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i]));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
function validateNumberAmpersand(xmlData, i) {
|
|
286
|
+
let re = /\d/;
|
|
287
|
+
if (xmlData[i] === "x") {
|
|
288
|
+
i++;
|
|
289
|
+
re = /[\da-fA-F]/;
|
|
290
|
+
}
|
|
291
|
+
for (; i < xmlData.length; i++) {
|
|
292
|
+
if (xmlData[i] === ";")
|
|
293
|
+
return i;
|
|
294
|
+
if (!xmlData[i].match(re))
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
return -1;
|
|
298
|
+
}
|
|
299
|
+
function validateAmpersand(xmlData, i) {
|
|
300
|
+
i++;
|
|
301
|
+
if (xmlData[i] === ";")
|
|
302
|
+
return -1;
|
|
303
|
+
if (xmlData[i] === "#") {
|
|
304
|
+
i++;
|
|
305
|
+
return validateNumberAmpersand(xmlData, i);
|
|
306
|
+
}
|
|
307
|
+
let count = 0;
|
|
308
|
+
for (; i < xmlData.length; i++, count++) {
|
|
309
|
+
if (xmlData[i].match(/\w/) && count < 20)
|
|
310
|
+
continue;
|
|
311
|
+
if (xmlData[i] === ";")
|
|
312
|
+
break;
|
|
313
|
+
return -1;
|
|
314
|
+
}
|
|
315
|
+
return i;
|
|
316
|
+
}
|
|
317
|
+
function getErrorObject(code, message, lineNumber) {
|
|
318
|
+
return {
|
|
319
|
+
err: {
|
|
320
|
+
code,
|
|
321
|
+
msg: message,
|
|
322
|
+
line: lineNumber.line || lineNumber,
|
|
323
|
+
col: lineNumber.col
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function validateAttrName(attrName) {
|
|
328
|
+
return isName(attrName);
|
|
329
|
+
}
|
|
330
|
+
function validateTagName(tagname) {
|
|
331
|
+
return isName(tagname);
|
|
332
|
+
}
|
|
333
|
+
function getLineNumberForPosition(xmlData, index) {
|
|
334
|
+
const lines = xmlData.substring(0, index).split(/\r?\n/);
|
|
335
|
+
return {
|
|
336
|
+
line: lines.length,
|
|
337
|
+
// column number is last line's length + 1, because column numbering starts at 1:
|
|
338
|
+
col: lines[lines.length - 1].length + 1
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function getPositionFromMatch(match) {
|
|
342
|
+
return match.startIndex + match[1].length;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
|
|
346
|
+
var defaultOptions2 = {
|
|
347
|
+
preserveOrder: false,
|
|
348
|
+
attributeNamePrefix: "@_",
|
|
349
|
+
attributesGroupName: false,
|
|
350
|
+
textNodeName: "#text",
|
|
351
|
+
ignoreAttributes: true,
|
|
352
|
+
removeNSPrefix: false,
|
|
353
|
+
// remove NS from tag name or attribute name if true
|
|
354
|
+
allowBooleanAttributes: false,
|
|
355
|
+
//a tag can have attributes without any value
|
|
356
|
+
//ignoreRootElement : false,
|
|
357
|
+
parseTagValue: true,
|
|
358
|
+
parseAttributeValue: false,
|
|
359
|
+
trimValues: true,
|
|
360
|
+
//Trim string values of tag and attributes
|
|
361
|
+
cdataPropName: false,
|
|
362
|
+
numberParseOptions: {
|
|
363
|
+
hex: true,
|
|
364
|
+
leadingZeros: true,
|
|
365
|
+
eNotation: true
|
|
366
|
+
},
|
|
367
|
+
tagValueProcessor: function(tagName, val) {
|
|
368
|
+
return val;
|
|
369
|
+
},
|
|
370
|
+
attributeValueProcessor: function(attrName, val) {
|
|
371
|
+
return val;
|
|
372
|
+
},
|
|
373
|
+
stopNodes: [],
|
|
374
|
+
//nested tags will not be parsed even for errors
|
|
375
|
+
alwaysCreateTextNode: false,
|
|
376
|
+
isArray: () => false,
|
|
377
|
+
commentPropName: false,
|
|
378
|
+
unpairedTags: [],
|
|
379
|
+
processEntities: true,
|
|
380
|
+
htmlEntities: false,
|
|
381
|
+
ignoreDeclaration: false,
|
|
382
|
+
ignorePiTags: false,
|
|
383
|
+
transformTagName: false,
|
|
384
|
+
transformAttributeName: false,
|
|
385
|
+
updateTag: function(tagName, jPath, attrs) {
|
|
386
|
+
return tagName;
|
|
387
|
+
},
|
|
388
|
+
// skipEmptyListItem: false
|
|
389
|
+
captureMetaData: false
|
|
390
|
+
};
|
|
391
|
+
var buildOptions = function(options) {
|
|
392
|
+
return Object.assign({}, defaultOptions2, options);
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
|
|
396
|
+
var METADATA_SYMBOL;
|
|
397
|
+
if (typeof Symbol !== "function") {
|
|
398
|
+
METADATA_SYMBOL = "@@xmlMetadata";
|
|
399
|
+
} else {
|
|
400
|
+
METADATA_SYMBOL = /* @__PURE__ */ Symbol("XML Node Metadata");
|
|
401
|
+
}
|
|
402
|
+
var XmlNode = class {
|
|
403
|
+
constructor(tagname) {
|
|
404
|
+
this.tagname = tagname;
|
|
405
|
+
this.child = [];
|
|
406
|
+
this[":@"] = {};
|
|
407
|
+
}
|
|
408
|
+
add(key, val) {
|
|
409
|
+
if (key === "__proto__") key = "#__proto__";
|
|
410
|
+
this.child.push({ [key]: val });
|
|
411
|
+
}
|
|
412
|
+
addChild(node, startIndex) {
|
|
413
|
+
if (node.tagname === "__proto__") node.tagname = "#__proto__";
|
|
414
|
+
if (node[":@"] && Object.keys(node[":@"]).length > 0) {
|
|
415
|
+
this.child.push({ [node.tagname]: node.child, [":@"]: node[":@"] });
|
|
416
|
+
} else {
|
|
417
|
+
this.child.push({ [node.tagname]: node.child });
|
|
418
|
+
}
|
|
419
|
+
if (startIndex !== void 0) {
|
|
420
|
+
this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/** symbol used for metadata */
|
|
424
|
+
static getMetaDataSymbol() {
|
|
425
|
+
return METADATA_SYMBOL;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
|
|
430
|
+
var DocTypeReader = class {
|
|
431
|
+
constructor(processEntities) {
|
|
432
|
+
this.suppressValidationErr = !processEntities;
|
|
433
|
+
}
|
|
434
|
+
readDocType(xmlData, i) {
|
|
435
|
+
const entities = {};
|
|
436
|
+
if (xmlData[i + 3] === "O" && xmlData[i + 4] === "C" && xmlData[i + 5] === "T" && xmlData[i + 6] === "Y" && xmlData[i + 7] === "P" && xmlData[i + 8] === "E") {
|
|
437
|
+
i = i + 9;
|
|
438
|
+
let angleBracketsCount = 1;
|
|
439
|
+
let hasBody = false, comment = false;
|
|
440
|
+
let exp = "";
|
|
441
|
+
for (; i < xmlData.length; i++) {
|
|
442
|
+
if (xmlData[i] === "<" && !comment) {
|
|
443
|
+
if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
|
|
444
|
+
i += 7;
|
|
445
|
+
let entityName, val;
|
|
446
|
+
[entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
|
|
447
|
+
if (val.indexOf("&") === -1)
|
|
448
|
+
entities[entityName] = {
|
|
449
|
+
regx: RegExp(`&${entityName};`, "g"),
|
|
450
|
+
val
|
|
451
|
+
};
|
|
452
|
+
} else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
|
|
453
|
+
i += 8;
|
|
454
|
+
const { index } = this.readElementExp(xmlData, i + 1);
|
|
455
|
+
i = index;
|
|
456
|
+
} else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) {
|
|
457
|
+
i += 8;
|
|
458
|
+
} else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) {
|
|
459
|
+
i += 9;
|
|
460
|
+
const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr);
|
|
461
|
+
i = index;
|
|
462
|
+
} else if (hasSeq(xmlData, "!--", i)) comment = true;
|
|
463
|
+
else throw new Error(`Invalid DOCTYPE`);
|
|
464
|
+
angleBracketsCount++;
|
|
465
|
+
exp = "";
|
|
466
|
+
} else if (xmlData[i] === ">") {
|
|
467
|
+
if (comment) {
|
|
468
|
+
if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") {
|
|
469
|
+
comment = false;
|
|
470
|
+
angleBracketsCount--;
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
angleBracketsCount--;
|
|
474
|
+
}
|
|
475
|
+
if (angleBracketsCount === 0) {
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
} else if (xmlData[i] === "[") {
|
|
479
|
+
hasBody = true;
|
|
480
|
+
} else {
|
|
481
|
+
exp += xmlData[i];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (angleBracketsCount !== 0) {
|
|
485
|
+
throw new Error(`Unclosed DOCTYPE`);
|
|
486
|
+
}
|
|
487
|
+
} else {
|
|
488
|
+
throw new Error(`Invalid Tag instead of DOCTYPE`);
|
|
489
|
+
}
|
|
490
|
+
return { entities, i };
|
|
491
|
+
}
|
|
492
|
+
readEntityExp(xmlData, i) {
|
|
493
|
+
i = skipWhitespace(xmlData, i);
|
|
494
|
+
let entityName = "";
|
|
495
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i]) && xmlData[i] !== '"' && xmlData[i] !== "'") {
|
|
496
|
+
entityName += xmlData[i];
|
|
497
|
+
i++;
|
|
498
|
+
}
|
|
499
|
+
validateEntityName(entityName);
|
|
500
|
+
i = skipWhitespace(xmlData, i);
|
|
501
|
+
if (!this.suppressValidationErr) {
|
|
502
|
+
if (xmlData.substring(i, i + 6).toUpperCase() === "SYSTEM") {
|
|
503
|
+
throw new Error("External entities are not supported");
|
|
504
|
+
} else if (xmlData[i] === "%") {
|
|
505
|
+
throw new Error("Parameter entities are not supported");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
let entityValue = "";
|
|
509
|
+
[i, entityValue] = this.readIdentifierVal(xmlData, i, "entity");
|
|
510
|
+
i--;
|
|
511
|
+
return [entityName, entityValue, i];
|
|
512
|
+
}
|
|
513
|
+
readNotationExp(xmlData, i) {
|
|
514
|
+
i = skipWhitespace(xmlData, i);
|
|
515
|
+
let notationName = "";
|
|
516
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
517
|
+
notationName += xmlData[i];
|
|
518
|
+
i++;
|
|
519
|
+
}
|
|
520
|
+
!this.suppressValidationErr && validateEntityName(notationName);
|
|
521
|
+
i = skipWhitespace(xmlData, i);
|
|
522
|
+
const identifierType = xmlData.substring(i, i + 6).toUpperCase();
|
|
523
|
+
if (!this.suppressValidationErr && identifierType !== "SYSTEM" && identifierType !== "PUBLIC") {
|
|
524
|
+
throw new Error(`Expected SYSTEM or PUBLIC, found "${identifierType}"`);
|
|
525
|
+
}
|
|
526
|
+
i += identifierType.length;
|
|
527
|
+
i = skipWhitespace(xmlData, i);
|
|
528
|
+
let publicIdentifier = null;
|
|
529
|
+
let systemIdentifier = null;
|
|
530
|
+
if (identifierType === "PUBLIC") {
|
|
531
|
+
[i, publicIdentifier] = this.readIdentifierVal(xmlData, i, "publicIdentifier");
|
|
532
|
+
i = skipWhitespace(xmlData, i);
|
|
533
|
+
if (xmlData[i] === '"' || xmlData[i] === "'") {
|
|
534
|
+
[i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
|
|
535
|
+
}
|
|
536
|
+
} else if (identifierType === "SYSTEM") {
|
|
537
|
+
[i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
|
|
538
|
+
if (!this.suppressValidationErr && !systemIdentifier) {
|
|
539
|
+
throw new Error("Missing mandatory system identifier for SYSTEM notation");
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return { notationName, publicIdentifier, systemIdentifier, index: --i };
|
|
543
|
+
}
|
|
544
|
+
readIdentifierVal(xmlData, i, type) {
|
|
545
|
+
let identifierVal = "";
|
|
546
|
+
const startChar = xmlData[i];
|
|
547
|
+
if (startChar !== '"' && startChar !== "'") {
|
|
548
|
+
throw new Error(`Expected quoted string, found "${startChar}"`);
|
|
549
|
+
}
|
|
550
|
+
i++;
|
|
551
|
+
while (i < xmlData.length && xmlData[i] !== startChar) {
|
|
552
|
+
identifierVal += xmlData[i];
|
|
553
|
+
i++;
|
|
554
|
+
}
|
|
555
|
+
if (xmlData[i] !== startChar) {
|
|
556
|
+
throw new Error(`Unterminated ${type} value`);
|
|
557
|
+
}
|
|
558
|
+
i++;
|
|
559
|
+
return [i, identifierVal];
|
|
560
|
+
}
|
|
561
|
+
readElementExp(xmlData, i) {
|
|
562
|
+
i = skipWhitespace(xmlData, i);
|
|
563
|
+
let elementName = "";
|
|
564
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
565
|
+
elementName += xmlData[i];
|
|
566
|
+
i++;
|
|
567
|
+
}
|
|
568
|
+
if (!this.suppressValidationErr && !isName(elementName)) {
|
|
569
|
+
throw new Error(`Invalid element name: "${elementName}"`);
|
|
570
|
+
}
|
|
571
|
+
i = skipWhitespace(xmlData, i);
|
|
572
|
+
let contentModel = "";
|
|
573
|
+
if (xmlData[i] === "E" && hasSeq(xmlData, "MPTY", i)) i += 4;
|
|
574
|
+
else if (xmlData[i] === "A" && hasSeq(xmlData, "NY", i)) i += 2;
|
|
575
|
+
else if (xmlData[i] === "(") {
|
|
576
|
+
i++;
|
|
577
|
+
while (i < xmlData.length && xmlData[i] !== ")") {
|
|
578
|
+
contentModel += xmlData[i];
|
|
579
|
+
i++;
|
|
580
|
+
}
|
|
581
|
+
if (xmlData[i] !== ")") {
|
|
582
|
+
throw new Error("Unterminated content model");
|
|
583
|
+
}
|
|
584
|
+
} else if (!this.suppressValidationErr) {
|
|
585
|
+
throw new Error(`Invalid Element Expression, found "${xmlData[i]}"`);
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
elementName,
|
|
589
|
+
contentModel: contentModel.trim(),
|
|
590
|
+
index: i
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
readAttlistExp(xmlData, i) {
|
|
594
|
+
i = skipWhitespace(xmlData, i);
|
|
595
|
+
let elementName = "";
|
|
596
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
597
|
+
elementName += xmlData[i];
|
|
598
|
+
i++;
|
|
599
|
+
}
|
|
600
|
+
validateEntityName(elementName);
|
|
601
|
+
i = skipWhitespace(xmlData, i);
|
|
602
|
+
let attributeName = "";
|
|
603
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
604
|
+
attributeName += xmlData[i];
|
|
605
|
+
i++;
|
|
606
|
+
}
|
|
607
|
+
if (!validateEntityName(attributeName)) {
|
|
608
|
+
throw new Error(`Invalid attribute name: "${attributeName}"`);
|
|
609
|
+
}
|
|
610
|
+
i = skipWhitespace(xmlData, i);
|
|
611
|
+
let attributeType = "";
|
|
612
|
+
if (xmlData.substring(i, i + 8).toUpperCase() === "NOTATION") {
|
|
613
|
+
attributeType = "NOTATION";
|
|
614
|
+
i += 8;
|
|
615
|
+
i = skipWhitespace(xmlData, i);
|
|
616
|
+
if (xmlData[i] !== "(") {
|
|
617
|
+
throw new Error(`Expected '(', found "${xmlData[i]}"`);
|
|
618
|
+
}
|
|
619
|
+
i++;
|
|
620
|
+
let allowedNotations = [];
|
|
621
|
+
while (i < xmlData.length && xmlData[i] !== ")") {
|
|
622
|
+
let notation = "";
|
|
623
|
+
while (i < xmlData.length && xmlData[i] !== "|" && xmlData[i] !== ")") {
|
|
624
|
+
notation += xmlData[i];
|
|
625
|
+
i++;
|
|
626
|
+
}
|
|
627
|
+
notation = notation.trim();
|
|
628
|
+
if (!validateEntityName(notation)) {
|
|
629
|
+
throw new Error(`Invalid notation name: "${notation}"`);
|
|
630
|
+
}
|
|
631
|
+
allowedNotations.push(notation);
|
|
632
|
+
if (xmlData[i] === "|") {
|
|
633
|
+
i++;
|
|
634
|
+
i = skipWhitespace(xmlData, i);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
if (xmlData[i] !== ")") {
|
|
638
|
+
throw new Error("Unterminated list of notations");
|
|
639
|
+
}
|
|
640
|
+
i++;
|
|
641
|
+
attributeType += " (" + allowedNotations.join("|") + ")";
|
|
642
|
+
} else {
|
|
643
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
644
|
+
attributeType += xmlData[i];
|
|
645
|
+
i++;
|
|
646
|
+
}
|
|
647
|
+
const validTypes = ["CDATA", "ID", "IDREF", "IDREFS", "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS"];
|
|
648
|
+
if (!this.suppressValidationErr && !validTypes.includes(attributeType.toUpperCase())) {
|
|
649
|
+
throw new Error(`Invalid attribute type: "${attributeType}"`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
i = skipWhitespace(xmlData, i);
|
|
653
|
+
let defaultValue = "";
|
|
654
|
+
if (xmlData.substring(i, i + 8).toUpperCase() === "#REQUIRED") {
|
|
655
|
+
defaultValue = "#REQUIRED";
|
|
656
|
+
i += 8;
|
|
657
|
+
} else if (xmlData.substring(i, i + 7).toUpperCase() === "#IMPLIED") {
|
|
658
|
+
defaultValue = "#IMPLIED";
|
|
659
|
+
i += 7;
|
|
660
|
+
} else {
|
|
661
|
+
[i, defaultValue] = this.readIdentifierVal(xmlData, i, "ATTLIST");
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
elementName,
|
|
665
|
+
attributeName,
|
|
666
|
+
attributeType,
|
|
667
|
+
defaultValue,
|
|
668
|
+
index: i
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
var skipWhitespace = (data, index) => {
|
|
673
|
+
while (index < data.length && /\s/.test(data[index])) {
|
|
674
|
+
index++;
|
|
675
|
+
}
|
|
676
|
+
return index;
|
|
677
|
+
};
|
|
678
|
+
function hasSeq(data, seq, i) {
|
|
679
|
+
for (let j = 0; j < seq.length; j++) {
|
|
680
|
+
if (seq[j] !== data[i + j + 1]) return false;
|
|
681
|
+
}
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
function validateEntityName(name) {
|
|
685
|
+
if (isName(name))
|
|
686
|
+
return name;
|
|
687
|
+
else
|
|
688
|
+
throw new Error(`Invalid entity name ${name}`);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/digitTable.js
|
|
692
|
+
var SCRIPT_ZEROS = [
|
|
693
|
+
// Basic Latin (ASCII) — included for completeness / pass-through
|
|
694
|
+
48,
|
|
695
|
+
// 0-9
|
|
696
|
+
// Arabic scripts
|
|
697
|
+
1632,
|
|
698
|
+
// Arabic-Indic ٠١٢٣٤٥٦٧٨٩
|
|
699
|
+
1776,
|
|
700
|
+
// Extended Arabic-Indic (Urdu/Persian/Sindhi) ۰۱۲۳
|
|
701
|
+
// Indic scripts
|
|
702
|
+
2406,
|
|
703
|
+
// Devanagari ०१२३४५६७८९
|
|
704
|
+
2534,
|
|
705
|
+
// Bengali ০১২৩৪৫৬৭৮৯
|
|
706
|
+
2662,
|
|
707
|
+
// Gurmukhi ੦੧੨੩੪੫੬੭੮੯
|
|
708
|
+
2790,
|
|
709
|
+
// Gujarati ૦૧૨૩૪૫૬૭૮૯
|
|
710
|
+
2918,
|
|
711
|
+
// Odia ୦୧୨୩୪୫୬୭୮୯
|
|
712
|
+
3046,
|
|
713
|
+
// Tamil ௦௧௨௩௪௫௬௭௮௯
|
|
714
|
+
3174,
|
|
715
|
+
// Telugu ౦౧౨౩౪౫౬౭౮౯
|
|
716
|
+
3302,
|
|
717
|
+
// Kannada ೦೧೨೩೪೫೬೭೮೯
|
|
718
|
+
3430,
|
|
719
|
+
// Malayalam ൦൧൨൩൪൫൬൭൮൯
|
|
720
|
+
3558,
|
|
721
|
+
// Sinhala Archaic ෦෧෨෩෪෫෬෭෮෯
|
|
722
|
+
// Southeast Asian scripts
|
|
723
|
+
3664,
|
|
724
|
+
// Thai ๐๑๒๓๔๕๖๗๘๙
|
|
725
|
+
3792,
|
|
726
|
+
// Lao ໐໑໒໓໔໕໖໗໘໙
|
|
727
|
+
3872,
|
|
728
|
+
// Tibetan ༠༡༢༣༤༥༦༧༨༩
|
|
729
|
+
4160,
|
|
730
|
+
// Myanmar ၀၁၂၃၄၅၆၇၈၉
|
|
731
|
+
4240,
|
|
732
|
+
// Myanmar Shan ႐႑႒႓႔႕႖႗႘႙
|
|
733
|
+
6112,
|
|
734
|
+
// Khmer ០១២៣៤៥៦៧៨៩
|
|
735
|
+
6160,
|
|
736
|
+
// Mongolian ᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙
|
|
737
|
+
6470,
|
|
738
|
+
// Limbu ᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏
|
|
739
|
+
6608,
|
|
740
|
+
// New Tai Lue ᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙
|
|
741
|
+
6784,
|
|
742
|
+
// Tai Tham Hora ᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉
|
|
743
|
+
6800,
|
|
744
|
+
// Tai Tham Tham ᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙
|
|
745
|
+
6992,
|
|
746
|
+
// Balinese ᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙
|
|
747
|
+
7088,
|
|
748
|
+
// Sundanese ᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹
|
|
749
|
+
7232,
|
|
750
|
+
// Lepcha ᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉
|
|
751
|
+
7248,
|
|
752
|
+
// Ol Chiki ᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙
|
|
753
|
+
// Fullwidth (CJK context)
|
|
754
|
+
65296,
|
|
755
|
+
// Fullwidth 0123456789
|
|
756
|
+
// Mathematical digit variants (Unicode math block)
|
|
757
|
+
120782,
|
|
758
|
+
// Mathematical Bold
|
|
759
|
+
120792,
|
|
760
|
+
// Mathematical Double-Struck
|
|
761
|
+
120802,
|
|
762
|
+
// Mathematical Sans-Serif
|
|
763
|
+
120812,
|
|
764
|
+
// Mathematical Sans-Serif Bold
|
|
765
|
+
120822,
|
|
766
|
+
// Mathematical Monospace
|
|
767
|
+
// Other scripts
|
|
768
|
+
66720,
|
|
769
|
+
// Osmanya 𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩
|
|
770
|
+
68912,
|
|
771
|
+
// Hanifi Rohingya 𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹
|
|
772
|
+
69734,
|
|
773
|
+
// Brahmi 𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯
|
|
774
|
+
69872,
|
|
775
|
+
// Sora Sompeng 𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹
|
|
776
|
+
69942,
|
|
777
|
+
// Chakma 𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿
|
|
778
|
+
70096,
|
|
779
|
+
// Sharada 𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙
|
|
780
|
+
70384,
|
|
781
|
+
// Khudawadi 𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹
|
|
782
|
+
70736,
|
|
783
|
+
// Newa 𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙
|
|
784
|
+
70864,
|
|
785
|
+
// Tirhuta 𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙
|
|
786
|
+
71248,
|
|
787
|
+
// Modi 𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙
|
|
788
|
+
71360,
|
|
789
|
+
// Takri 𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉
|
|
790
|
+
71472,
|
|
791
|
+
// Ahom 𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹
|
|
792
|
+
71904,
|
|
793
|
+
// Warang Citi 𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩
|
|
794
|
+
72016,
|
|
795
|
+
// Dives Akuru 𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙
|
|
796
|
+
72688,
|
|
797
|
+
// Khitan Small Script
|
|
798
|
+
72784,
|
|
799
|
+
// Bhaiksuki 𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙
|
|
800
|
+
73040,
|
|
801
|
+
// Masaram Gondi 𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙
|
|
802
|
+
73120,
|
|
803
|
+
// Gunjala Gondi 𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩
|
|
804
|
+
73552,
|
|
805
|
+
// Kawi 𑽐𑽑𑽒𑽓𑽔𑽕𑽖𑽗𑽘𑽙
|
|
806
|
+
92768,
|
|
807
|
+
// Mro 𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩
|
|
808
|
+
92864,
|
|
809
|
+
// Tangsa 𖫀𖫁𖫂𖫃𖫄𖫅𖫆𖫇𖫈𖫉
|
|
810
|
+
93008,
|
|
811
|
+
// Pahawh Hmong 𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙
|
|
812
|
+
123200,
|
|
813
|
+
// Nyiakeng Puachue Hmong 𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉
|
|
814
|
+
123632,
|
|
815
|
+
// Wancho 𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹
|
|
816
|
+
124144,
|
|
817
|
+
// Nag Mundari 𞓰𞓱𞓲𞓳𞓴𞓵𞓶𞓷𞓸𞓹
|
|
818
|
+
125264,
|
|
819
|
+
// Adlam 𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙
|
|
820
|
+
130032
|
|
821
|
+
// Segmented digit symbols 🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹
|
|
822
|
+
];
|
|
823
|
+
var NOT_DIGIT = 255;
|
|
824
|
+
var HIGH_MAP = /* @__PURE__ */ new Map();
|
|
825
|
+
var LOW_MAX = 65535;
|
|
826
|
+
var LOW_MIN = 1632;
|
|
827
|
+
var TABLE_OFFSET = LOW_MIN;
|
|
828
|
+
var TABLE_SIZE = LOW_MAX - LOW_MIN + 1;
|
|
829
|
+
var TABLE = new Uint8Array(TABLE_SIZE).fill(NOT_DIGIT);
|
|
830
|
+
for (const zero of SCRIPT_ZEROS) {
|
|
831
|
+
for (let d = 0; d < 10; d++) {
|
|
832
|
+
const cp = zero + d;
|
|
833
|
+
if (cp <= LOW_MAX) {
|
|
834
|
+
TABLE[cp - TABLE_OFFSET] = d;
|
|
835
|
+
} else {
|
|
836
|
+
HIGH_MAP.set(cp, d);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/anynum.js
|
|
842
|
+
var CHAR_0 = 48;
|
|
843
|
+
var CHAR_9 = 57;
|
|
844
|
+
var CHAR_MINUS = 45;
|
|
845
|
+
var MINUS_SET = /* @__PURE__ */ new Set([8722, 65293, 65123]);
|
|
846
|
+
function anynum(str) {
|
|
847
|
+
if (typeof str !== "string") return str;
|
|
848
|
+
const len = str.length;
|
|
849
|
+
if (len === 0) return str;
|
|
850
|
+
let firstHit = -1;
|
|
851
|
+
for (let i = 0; i < len; i++) {
|
|
852
|
+
const cc = str.charCodeAt(i);
|
|
853
|
+
if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) continue;
|
|
854
|
+
if (cc < TABLE_OFFSET) {
|
|
855
|
+
if (MINUS_SET.has(cc)) {
|
|
856
|
+
firstHit = i;
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
if (cc >= 55296 && cc <= 56319) {
|
|
862
|
+
if (i + 1 < len) {
|
|
863
|
+
const low = str.charCodeAt(i + 1);
|
|
864
|
+
if (low >= 56320 && low <= 57343) {
|
|
865
|
+
const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
|
|
866
|
+
if (HIGH_MAP.has(cp)) {
|
|
867
|
+
firstHit = i;
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
if (TABLE[cc - TABLE_OFFSET] !== NOT_DIGIT || MINUS_SET.has(cc)) {
|
|
875
|
+
firstHit = i;
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (firstHit === -1) return str;
|
|
880
|
+
const chars = [];
|
|
881
|
+
if (firstHit > 0) chars.push(str.slice(0, firstHit));
|
|
882
|
+
for (let i = firstHit; i < len; i++) {
|
|
883
|
+
const cc = str.charCodeAt(i);
|
|
884
|
+
if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) {
|
|
885
|
+
chars.push(str[i]);
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if (cc < TABLE_OFFSET) {
|
|
889
|
+
chars.push(MINUS_SET.has(cc) ? "-" : str[i]);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (cc >= 55296 && cc <= 56319) {
|
|
893
|
+
if (i + 1 < len) {
|
|
894
|
+
const low = str.charCodeAt(i + 1);
|
|
895
|
+
if (low >= 56320 && low <= 57343) {
|
|
896
|
+
const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
|
|
897
|
+
const d2 = HIGH_MAP.get(cp);
|
|
898
|
+
if (d2 !== void 0) {
|
|
899
|
+
chars.push(String.fromCharCode(d2 + 48));
|
|
900
|
+
i++;
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
chars.push(str[i]);
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (MINUS_SET.has(cc)) {
|
|
909
|
+
chars.push("-");
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
const d = TABLE[cc - TABLE_OFFSET];
|
|
913
|
+
chars.push(d !== NOT_DIGIT ? String.fromCharCode(d + 48) : str[i]);
|
|
914
|
+
}
|
|
915
|
+
return chars.join("");
|
|
916
|
+
}
|
|
917
|
+
var anynum_default = anynum;
|
|
918
|
+
|
|
919
|
+
// node_modules/.pnpm/strnum@2.4.1/node_modules/strnum/strnum.js
|
|
920
|
+
var hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
|
|
921
|
+
var binRegex = /^0b[01]+$/;
|
|
922
|
+
var octRegex = /^0o[0-7]+$/;
|
|
923
|
+
var numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
|
|
924
|
+
var consider = {
|
|
925
|
+
hex: true,
|
|
926
|
+
binary: false,
|
|
927
|
+
octal: false,
|
|
928
|
+
leadingZeros: true,
|
|
929
|
+
decimalPoint: ".",
|
|
930
|
+
eNotation: true,
|
|
931
|
+
//skipLike: /regex/,
|
|
932
|
+
infinity: "original",
|
|
933
|
+
// "null", "infinity" (Infinity type), "string" ("Infinity" (the string literal))
|
|
934
|
+
unicode: false
|
|
935
|
+
};
|
|
936
|
+
function toNumber(str, options = {}) {
|
|
937
|
+
options = Object.assign({}, consider, options);
|
|
938
|
+
if (!str || typeof str !== "string") return str;
|
|
939
|
+
let trimmedStr = str.trim();
|
|
940
|
+
if (trimmedStr.length === 0) return str;
|
|
941
|
+
else if (options.skipLike !== void 0 && options.skipLike.test(trimmedStr)) return str;
|
|
942
|
+
else if (trimmedStr === "0") return 0;
|
|
943
|
+
if (options.unicode) {
|
|
944
|
+
trimmedStr = anynum_default(trimmedStr);
|
|
945
|
+
if (trimmedStr === "0") return 0;
|
|
946
|
+
}
|
|
947
|
+
if (options.hex && hexRegex.test(trimmedStr)) {
|
|
948
|
+
return parse_int(trimmedStr, 16);
|
|
949
|
+
} else if (options.binary && binRegex.test(trimmedStr)) {
|
|
950
|
+
return parse_int(trimmedStr, 2);
|
|
951
|
+
} else if (options.octal && octRegex.test(trimmedStr)) {
|
|
952
|
+
return parse_int(trimmedStr, 8);
|
|
953
|
+
} else if (!isFinite(trimmedStr)) {
|
|
954
|
+
return handleInfinity(str, Number(trimmedStr), options);
|
|
955
|
+
} else if (trimmedStr.includes("e") || trimmedStr.includes("E")) {
|
|
956
|
+
return resolveEnotation(str, trimmedStr, options);
|
|
957
|
+
} else {
|
|
958
|
+
const match = numRegex.exec(trimmedStr);
|
|
959
|
+
if (match) {
|
|
960
|
+
const sign = match[1] || "";
|
|
961
|
+
const leadingZeros = match[2];
|
|
962
|
+
let numTrimmedByZeros = trimZeros(match[3]);
|
|
963
|
+
const decimalAdjacentToLeadingZeros = sign ? (
|
|
964
|
+
// 0., -00., 000.
|
|
965
|
+
str[leadingZeros.length + 1] === "."
|
|
966
|
+
) : str[leadingZeros.length] === ".";
|
|
967
|
+
if (!options.leadingZeros && (leadingZeros.length > 1 || leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros)) {
|
|
968
|
+
return str;
|
|
969
|
+
} else {
|
|
970
|
+
const num = Number(trimmedStr);
|
|
971
|
+
const parsedStr = String(num);
|
|
972
|
+
if (num === 0) return num;
|
|
973
|
+
if (parsedStr.search(/[eE]/) !== -1) {
|
|
974
|
+
if (options.eNotation) return num;
|
|
975
|
+
else return str;
|
|
976
|
+
} else if (trimmedStr.indexOf(".") !== -1) {
|
|
977
|
+
if (parsedStr === "0") return num;
|
|
978
|
+
else if (parsedStr === numTrimmedByZeros) return num;
|
|
979
|
+
else if (parsedStr === `${sign}${numTrimmedByZeros}`) return num;
|
|
980
|
+
else return str;
|
|
981
|
+
}
|
|
982
|
+
let n = leadingZeros ? numTrimmedByZeros : trimmedStr;
|
|
983
|
+
if (leadingZeros) {
|
|
984
|
+
return n === parsedStr || sign + n === parsedStr ? num : str;
|
|
985
|
+
} else {
|
|
986
|
+
return n === parsedStr || n === sign + parsedStr ? num : str;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
} else {
|
|
990
|
+
return str;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
var eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
|
|
995
|
+
function resolveEnotation(str, trimmedStr, options) {
|
|
996
|
+
if (!options.eNotation) return str;
|
|
997
|
+
const notation = trimmedStr.match(eNotationRegx);
|
|
998
|
+
if (notation) {
|
|
999
|
+
let sign = notation[1] || "";
|
|
1000
|
+
const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
|
|
1001
|
+
const leadingZeros = notation[2];
|
|
1002
|
+
const eAdjacentToLeadingZeros = sign ? (
|
|
1003
|
+
// 0E.
|
|
1004
|
+
str[leadingZeros.length + 1] === eChar
|
|
1005
|
+
) : str[leadingZeros.length] === eChar;
|
|
1006
|
+
if (leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
|
|
1007
|
+
else if (leadingZeros.length === 1 && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)) {
|
|
1008
|
+
return Number(trimmedStr);
|
|
1009
|
+
} else if (leadingZeros.length > 0) {
|
|
1010
|
+
if (options.leadingZeros && !eAdjacentToLeadingZeros) {
|
|
1011
|
+
trimmedStr = (notation[1] || "") + notation[3];
|
|
1012
|
+
return Number(trimmedStr);
|
|
1013
|
+
} else return str;
|
|
1014
|
+
} else {
|
|
1015
|
+
return Number(trimmedStr);
|
|
1016
|
+
}
|
|
1017
|
+
} else {
|
|
1018
|
+
return str;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function trimZeros(numStr) {
|
|
1022
|
+
if (numStr && numStr.indexOf(".") !== -1) {
|
|
1023
|
+
numStr = numStr.replace(/0+$/, "");
|
|
1024
|
+
if (numStr === ".") numStr = "0";
|
|
1025
|
+
else if (numStr[0] === ".") numStr = "0" + numStr;
|
|
1026
|
+
else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
|
|
1027
|
+
return numStr;
|
|
1028
|
+
}
|
|
1029
|
+
return numStr;
|
|
1030
|
+
}
|
|
1031
|
+
function parse_int(numStr, base) {
|
|
1032
|
+
const str = numStr.trim();
|
|
1033
|
+
if (base === 2 || base === 8) numStr = str.substring(2);
|
|
1034
|
+
if (parseInt) return parseInt(numStr, base);
|
|
1035
|
+
else if (Number.parseInt) return Number.parseInt(numStr, base);
|
|
1036
|
+
else if (window && window.parseInt) return window.parseInt(numStr, base);
|
|
1037
|
+
else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported");
|
|
1038
|
+
}
|
|
1039
|
+
function handleInfinity(str, num, options) {
|
|
1040
|
+
const isPositive = num === Infinity;
|
|
1041
|
+
switch (options.infinity.toLowerCase()) {
|
|
1042
|
+
case "null":
|
|
1043
|
+
return null;
|
|
1044
|
+
case "infinity":
|
|
1045
|
+
return num;
|
|
1046
|
+
// Return Infinity or -Infinity
|
|
1047
|
+
case "string":
|
|
1048
|
+
return isPositive ? "Infinity" : "-Infinity";
|
|
1049
|
+
case "original":
|
|
1050
|
+
default:
|
|
1051
|
+
return str;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/ignoreAttributes.js
|
|
1056
|
+
function getIgnoreAttributesFn(ignoreAttributes) {
|
|
1057
|
+
if (typeof ignoreAttributes === "function") {
|
|
1058
|
+
return ignoreAttributes;
|
|
1059
|
+
}
|
|
1060
|
+
if (Array.isArray(ignoreAttributes)) {
|
|
1061
|
+
return (attrName) => {
|
|
1062
|
+
for (const pattern of ignoreAttributes) {
|
|
1063
|
+
if (typeof pattern === "string" && attrName === pattern) {
|
|
1064
|
+
return true;
|
|
1065
|
+
}
|
|
1066
|
+
if (pattern instanceof RegExp && pattern.test(attrName)) {
|
|
1067
|
+
return true;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
return () => false;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
|
|
1076
|
+
var OrderedObjParser = class {
|
|
1077
|
+
constructor(options) {
|
|
1078
|
+
this.options = options;
|
|
1079
|
+
this.currentNode = null;
|
|
1080
|
+
this.tagsNodeStack = [];
|
|
1081
|
+
this.docTypeEntities = {};
|
|
1082
|
+
this.lastEntities = {
|
|
1083
|
+
"apos": { regex: /&(apos|#39|#x27);/g, val: "'" },
|
|
1084
|
+
"gt": { regex: /&(gt|#62|#x3E);/g, val: ">" },
|
|
1085
|
+
"lt": { regex: /&(lt|#60|#x3C);/g, val: "<" },
|
|
1086
|
+
"quot": { regex: /&(quot|#34|#x22);/g, val: '"' }
|
|
1087
|
+
};
|
|
1088
|
+
this.ampEntity = { regex: /&(amp|#38|#x26);/g, val: "&" };
|
|
1089
|
+
this.htmlEntities = {
|
|
1090
|
+
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
|
1091
|
+
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
|
1092
|
+
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
|
1093
|
+
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
|
1094
|
+
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
|
1095
|
+
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
|
1096
|
+
"cent": { regex: /&(cent|#162);/g, val: "\xA2" },
|
|
1097
|
+
"pound": { regex: /&(pound|#163);/g, val: "\xA3" },
|
|
1098
|
+
"yen": { regex: /&(yen|#165);/g, val: "\xA5" },
|
|
1099
|
+
"euro": { regex: /&(euro|#8364);/g, val: "\u20AC" },
|
|
1100
|
+
"copyright": { regex: /&(copy|#169);/g, val: "\xA9" },
|
|
1101
|
+
"reg": { regex: /&(reg|#174);/g, val: "\xAE" },
|
|
1102
|
+
"inr": { regex: /&(inr|#8377);/g, val: "\u20B9" },
|
|
1103
|
+
"num_dec": { regex: /&#([0-9]{1,7});/g, val: (_, str) => String.fromCodePoint(Number.parseInt(str, 10)) },
|
|
1104
|
+
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val: (_, str) => String.fromCodePoint(Number.parseInt(str, 16)) }
|
|
1105
|
+
};
|
|
1106
|
+
this.addExternalEntities = addExternalEntities;
|
|
1107
|
+
this.parseXml = parseXml;
|
|
1108
|
+
this.parseTextData = parseTextData;
|
|
1109
|
+
this.resolveNameSpace = resolveNameSpace;
|
|
1110
|
+
this.buildAttributesMap = buildAttributesMap;
|
|
1111
|
+
this.isItStopNode = isItStopNode;
|
|
1112
|
+
this.replaceEntitiesValue = replaceEntitiesValue;
|
|
1113
|
+
this.readStopNodeData = readStopNodeData;
|
|
1114
|
+
this.saveTextToParentTag = saveTextToParentTag;
|
|
1115
|
+
this.addChild = addChild;
|
|
1116
|
+
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
|
|
1117
|
+
if (this.options.stopNodes && this.options.stopNodes.length > 0) {
|
|
1118
|
+
this.stopNodesExact = /* @__PURE__ */ new Set();
|
|
1119
|
+
this.stopNodesWildcard = /* @__PURE__ */ new Set();
|
|
1120
|
+
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
|
1121
|
+
const stopNodeExp = this.options.stopNodes[i];
|
|
1122
|
+
if (typeof stopNodeExp !== "string") continue;
|
|
1123
|
+
if (stopNodeExp.startsWith("*.")) {
|
|
1124
|
+
this.stopNodesWildcard.add(stopNodeExp.substring(2));
|
|
1125
|
+
} else {
|
|
1126
|
+
this.stopNodesExact.add(stopNodeExp);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
function addExternalEntities(externalEntities) {
|
|
1133
|
+
const entKeys = Object.keys(externalEntities);
|
|
1134
|
+
for (let i = 0; i < entKeys.length; i++) {
|
|
1135
|
+
const ent = entKeys[i];
|
|
1136
|
+
this.lastEntities[ent] = {
|
|
1137
|
+
regex: new RegExp("&" + ent + ";", "g"),
|
|
1138
|
+
val: externalEntities[ent]
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
|
|
1143
|
+
if (val !== void 0) {
|
|
1144
|
+
if (this.options.trimValues && !dontTrim) {
|
|
1145
|
+
val = val.trim();
|
|
1146
|
+
}
|
|
1147
|
+
if (val.length > 0) {
|
|
1148
|
+
if (!escapeEntities) val = this.replaceEntitiesValue(val);
|
|
1149
|
+
const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
|
|
1150
|
+
if (newval === null || newval === void 0) {
|
|
1151
|
+
return val;
|
|
1152
|
+
} else if (typeof newval !== typeof val || newval !== val) {
|
|
1153
|
+
return newval;
|
|
1154
|
+
} else if (this.options.trimValues) {
|
|
1155
|
+
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
|
1156
|
+
} else {
|
|
1157
|
+
const trimmedVal = val.trim();
|
|
1158
|
+
if (trimmedVal === val) {
|
|
1159
|
+
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
|
1160
|
+
} else {
|
|
1161
|
+
return val;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
function resolveNameSpace(tagname) {
|
|
1168
|
+
if (this.options.removeNSPrefix) {
|
|
1169
|
+
const tags = tagname.split(":");
|
|
1170
|
+
const prefix = tagname.charAt(0) === "/" ? "/" : "";
|
|
1171
|
+
if (tags[0] === "xmlns") {
|
|
1172
|
+
return "";
|
|
1173
|
+
}
|
|
1174
|
+
if (tags.length === 2) {
|
|
1175
|
+
tagname = prefix + tags[1];
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return tagname;
|
|
1179
|
+
}
|
|
1180
|
+
var attrsRegx = new RegExp(`([^\\s=]+)\\s*(=\\s*(['"])([\\s\\S]*?)\\3)?`, "gm");
|
|
1181
|
+
function buildAttributesMap(attrStr, jPath) {
|
|
1182
|
+
if (this.options.ignoreAttributes !== true && typeof attrStr === "string") {
|
|
1183
|
+
const matches = getAllMatches(attrStr, attrsRegx);
|
|
1184
|
+
const len = matches.length;
|
|
1185
|
+
const attrs = {};
|
|
1186
|
+
for (let i = 0; i < len; i++) {
|
|
1187
|
+
const attrName = this.resolveNameSpace(matches[i][1]);
|
|
1188
|
+
if (this.ignoreAttributesFn(attrName, jPath)) {
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
let oldVal = matches[i][4];
|
|
1192
|
+
let aName = this.options.attributeNamePrefix + attrName;
|
|
1193
|
+
if (attrName.length) {
|
|
1194
|
+
if (this.options.transformAttributeName) {
|
|
1195
|
+
aName = this.options.transformAttributeName(aName);
|
|
1196
|
+
}
|
|
1197
|
+
if (aName === "__proto__") aName = "#__proto__";
|
|
1198
|
+
if (oldVal !== void 0) {
|
|
1199
|
+
if (this.options.trimValues) {
|
|
1200
|
+
oldVal = oldVal.trim();
|
|
1201
|
+
}
|
|
1202
|
+
oldVal = this.replaceEntitiesValue(oldVal);
|
|
1203
|
+
const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath);
|
|
1204
|
+
if (newVal === null || newVal === void 0) {
|
|
1205
|
+
attrs[aName] = oldVal;
|
|
1206
|
+
} else if (typeof newVal !== typeof oldVal || newVal !== oldVal) {
|
|
1207
|
+
attrs[aName] = newVal;
|
|
1208
|
+
} else {
|
|
1209
|
+
attrs[aName] = parseValue(
|
|
1210
|
+
oldVal,
|
|
1211
|
+
this.options.parseAttributeValue,
|
|
1212
|
+
this.options.numberParseOptions
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
} else if (this.options.allowBooleanAttributes) {
|
|
1216
|
+
attrs[aName] = true;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
if (!Object.keys(attrs).length) {
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
if (this.options.attributesGroupName) {
|
|
1224
|
+
const attrCollection = {};
|
|
1225
|
+
attrCollection[this.options.attributesGroupName] = attrs;
|
|
1226
|
+
return attrCollection;
|
|
1227
|
+
}
|
|
1228
|
+
return attrs;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
var parseXml = function(xmlData) {
|
|
1232
|
+
xmlData = xmlData.replace(/\r\n?/g, "\n");
|
|
1233
|
+
const xmlObj = new XmlNode("!xml");
|
|
1234
|
+
let currentNode = xmlObj;
|
|
1235
|
+
let textData = "";
|
|
1236
|
+
let jPath = "";
|
|
1237
|
+
const docTypeReader = new DocTypeReader(this.options.processEntities);
|
|
1238
|
+
for (let i = 0; i < xmlData.length; i++) {
|
|
1239
|
+
const ch = xmlData[i];
|
|
1240
|
+
if (ch === "<") {
|
|
1241
|
+
if (xmlData[i + 1] === "/") {
|
|
1242
|
+
const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.");
|
|
1243
|
+
let tagName = xmlData.substring(i + 2, closeIndex).trim();
|
|
1244
|
+
if (this.options.removeNSPrefix) {
|
|
1245
|
+
const colonIndex = tagName.indexOf(":");
|
|
1246
|
+
if (colonIndex !== -1) {
|
|
1247
|
+
tagName = tagName.substr(colonIndex + 1);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
if (this.options.transformTagName) {
|
|
1251
|
+
tagName = this.options.transformTagName(tagName);
|
|
1252
|
+
}
|
|
1253
|
+
if (currentNode) {
|
|
1254
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1255
|
+
}
|
|
1256
|
+
const lastTagName = jPath.substring(jPath.lastIndexOf(".") + 1);
|
|
1257
|
+
if (tagName && this.options.unpairedTags.indexOf(tagName) !== -1) {
|
|
1258
|
+
throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
|
|
1259
|
+
}
|
|
1260
|
+
let propIndex = 0;
|
|
1261
|
+
if (lastTagName && this.options.unpairedTags.indexOf(lastTagName) !== -1) {
|
|
1262
|
+
propIndex = jPath.lastIndexOf(".", jPath.lastIndexOf(".") - 1);
|
|
1263
|
+
this.tagsNodeStack.pop();
|
|
1264
|
+
} else {
|
|
1265
|
+
propIndex = jPath.lastIndexOf(".");
|
|
1266
|
+
}
|
|
1267
|
+
jPath = jPath.substring(0, propIndex);
|
|
1268
|
+
currentNode = this.tagsNodeStack.pop();
|
|
1269
|
+
textData = "";
|
|
1270
|
+
i = closeIndex;
|
|
1271
|
+
} else if (xmlData[i + 1] === "?") {
|
|
1272
|
+
let tagData = readTagExp(xmlData, i, false, "?>");
|
|
1273
|
+
if (!tagData) throw new Error("Pi Tag is not closed.");
|
|
1274
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1275
|
+
if (this.options.ignoreDeclaration && tagData.tagName === "?xml" || this.options.ignorePiTags) {
|
|
1276
|
+
} else {
|
|
1277
|
+
const childNode = new XmlNode(tagData.tagName);
|
|
1278
|
+
childNode.add(this.options.textNodeName, "");
|
|
1279
|
+
if (tagData.tagName !== tagData.tagExp && tagData.attrExpPresent) {
|
|
1280
|
+
childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath);
|
|
1281
|
+
}
|
|
1282
|
+
this.addChild(currentNode, childNode, jPath, i);
|
|
1283
|
+
}
|
|
1284
|
+
i = tagData.closeIndex + 1;
|
|
1285
|
+
} else if (xmlData.substr(i + 1, 3) === "!--") {
|
|
1286
|
+
const endIndex = findClosingIndex(xmlData, "-->", i + 4, "Comment is not closed.");
|
|
1287
|
+
if (this.options.commentPropName) {
|
|
1288
|
+
const comment = xmlData.substring(i + 4, endIndex - 2);
|
|
1289
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1290
|
+
currentNode.add(this.options.commentPropName, [{ [this.options.textNodeName]: comment }]);
|
|
1291
|
+
}
|
|
1292
|
+
i = endIndex;
|
|
1293
|
+
} else if (xmlData.substr(i + 1, 2) === "!D") {
|
|
1294
|
+
const result = docTypeReader.readDocType(xmlData, i);
|
|
1295
|
+
this.docTypeEntities = result.entities;
|
|
1296
|
+
i = result.i;
|
|
1297
|
+
} else if (xmlData.substr(i + 1, 2) === "![") {
|
|
1298
|
+
const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
|
|
1299
|
+
const tagExp = xmlData.substring(i + 9, closeIndex);
|
|
1300
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1301
|
+
let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true, true);
|
|
1302
|
+
if (val == void 0) val = "";
|
|
1303
|
+
if (this.options.cdataPropName) {
|
|
1304
|
+
currentNode.add(this.options.cdataPropName, [{ [this.options.textNodeName]: tagExp }]);
|
|
1305
|
+
} else {
|
|
1306
|
+
currentNode.add(this.options.textNodeName, val);
|
|
1307
|
+
}
|
|
1308
|
+
i = closeIndex + 2;
|
|
1309
|
+
} else {
|
|
1310
|
+
let result = readTagExp(xmlData, i, this.options.removeNSPrefix);
|
|
1311
|
+
let tagName = result.tagName;
|
|
1312
|
+
const rawTagName = result.rawTagName;
|
|
1313
|
+
let tagExp = result.tagExp;
|
|
1314
|
+
let attrExpPresent = result.attrExpPresent;
|
|
1315
|
+
let closeIndex = result.closeIndex;
|
|
1316
|
+
if (this.options.transformTagName) {
|
|
1317
|
+
const newTagName = this.options.transformTagName(tagName);
|
|
1318
|
+
if (tagExp === tagName) {
|
|
1319
|
+
tagExp = newTagName;
|
|
1320
|
+
}
|
|
1321
|
+
tagName = newTagName;
|
|
1322
|
+
}
|
|
1323
|
+
if (currentNode && textData) {
|
|
1324
|
+
if (currentNode.tagname !== "!xml") {
|
|
1325
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
const lastTag = currentNode;
|
|
1329
|
+
if (lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1) {
|
|
1330
|
+
currentNode = this.tagsNodeStack.pop();
|
|
1331
|
+
jPath = jPath.substring(0, jPath.lastIndexOf("."));
|
|
1332
|
+
}
|
|
1333
|
+
if (tagName !== xmlObj.tagname) {
|
|
1334
|
+
jPath += jPath ? "." + tagName : tagName;
|
|
1335
|
+
}
|
|
1336
|
+
const startIndex = i;
|
|
1337
|
+
if (this.isItStopNode(this.stopNodesExact, this.stopNodesWildcard, jPath, tagName)) {
|
|
1338
|
+
let tagContent = "";
|
|
1339
|
+
if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
|
|
1340
|
+
if (tagName[tagName.length - 1] === "/") {
|
|
1341
|
+
tagName = tagName.substr(0, tagName.length - 1);
|
|
1342
|
+
jPath = jPath.substr(0, jPath.length - 1);
|
|
1343
|
+
tagExp = tagName;
|
|
1344
|
+
} else {
|
|
1345
|
+
tagExp = tagExp.substr(0, tagExp.length - 1);
|
|
1346
|
+
}
|
|
1347
|
+
i = result.closeIndex;
|
|
1348
|
+
} else if (this.options.unpairedTags.indexOf(tagName) !== -1) {
|
|
1349
|
+
i = result.closeIndex;
|
|
1350
|
+
} else {
|
|
1351
|
+
const result2 = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
|
|
1352
|
+
if (!result2) throw new Error(`Unexpected end of ${rawTagName}`);
|
|
1353
|
+
i = result2.i;
|
|
1354
|
+
tagContent = result2.tagContent;
|
|
1355
|
+
}
|
|
1356
|
+
const childNode = new XmlNode(tagName);
|
|
1357
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1358
|
+
childNode[":@"] = this.buildAttributesMap(
|
|
1359
|
+
tagExp,
|
|
1360
|
+
jPath
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
if (tagContent) {
|
|
1364
|
+
tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
|
|
1365
|
+
}
|
|
1366
|
+
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
1367
|
+
childNode.add(this.options.textNodeName, tagContent);
|
|
1368
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1369
|
+
} else {
|
|
1370
|
+
if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
|
|
1371
|
+
if (tagName[tagName.length - 1] === "/") {
|
|
1372
|
+
tagName = tagName.substr(0, tagName.length - 1);
|
|
1373
|
+
jPath = jPath.substr(0, jPath.length - 1);
|
|
1374
|
+
tagExp = tagName;
|
|
1375
|
+
} else {
|
|
1376
|
+
tagExp = tagExp.substr(0, tagExp.length - 1);
|
|
1377
|
+
}
|
|
1378
|
+
if (this.options.transformTagName) {
|
|
1379
|
+
const newTagName = this.options.transformTagName(tagName);
|
|
1380
|
+
if (tagExp === tagName) {
|
|
1381
|
+
tagExp = newTagName;
|
|
1382
|
+
}
|
|
1383
|
+
tagName = newTagName;
|
|
1384
|
+
}
|
|
1385
|
+
const childNode = new XmlNode(tagName);
|
|
1386
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1387
|
+
childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
|
|
1388
|
+
}
|
|
1389
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1390
|
+
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
1391
|
+
} else {
|
|
1392
|
+
const childNode = new XmlNode(tagName);
|
|
1393
|
+
this.tagsNodeStack.push(currentNode);
|
|
1394
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1395
|
+
childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
|
|
1396
|
+
}
|
|
1397
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1398
|
+
currentNode = childNode;
|
|
1399
|
+
}
|
|
1400
|
+
textData = "";
|
|
1401
|
+
i = closeIndex;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
} else {
|
|
1405
|
+
textData += xmlData[i];
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return xmlObj.child;
|
|
1409
|
+
};
|
|
1410
|
+
function addChild(currentNode, childNode, jPath, startIndex) {
|
|
1411
|
+
if (!this.options.captureMetaData) startIndex = void 0;
|
|
1412
|
+
const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"]);
|
|
1413
|
+
if (result === false) {
|
|
1414
|
+
} else if (typeof result === "string") {
|
|
1415
|
+
childNode.tagname = result;
|
|
1416
|
+
currentNode.addChild(childNode, startIndex);
|
|
1417
|
+
} else {
|
|
1418
|
+
currentNode.addChild(childNode, startIndex);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
var replaceEntitiesValue = function(val) {
|
|
1422
|
+
if (this.options.processEntities) {
|
|
1423
|
+
for (let entityName in this.docTypeEntities) {
|
|
1424
|
+
const entity = this.docTypeEntities[entityName];
|
|
1425
|
+
val = val.replace(entity.regx, entity.val);
|
|
1426
|
+
}
|
|
1427
|
+
for (let entityName in this.lastEntities) {
|
|
1428
|
+
const entity = this.lastEntities[entityName];
|
|
1429
|
+
val = val.replace(entity.regex, entity.val);
|
|
1430
|
+
}
|
|
1431
|
+
if (this.options.htmlEntities) {
|
|
1432
|
+
for (let entityName in this.htmlEntities) {
|
|
1433
|
+
const entity = this.htmlEntities[entityName];
|
|
1434
|
+
val = val.replace(entity.regex, entity.val);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
val = val.replace(this.ampEntity.regex, this.ampEntity.val);
|
|
1438
|
+
}
|
|
1439
|
+
return val;
|
|
1440
|
+
};
|
|
1441
|
+
function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
|
|
1442
|
+
if (textData) {
|
|
1443
|
+
if (isLeafNode === void 0) isLeafNode = currentNode.child.length === 0;
|
|
1444
|
+
textData = this.parseTextData(
|
|
1445
|
+
textData,
|
|
1446
|
+
currentNode.tagname,
|
|
1447
|
+
jPath,
|
|
1448
|
+
false,
|
|
1449
|
+
currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false,
|
|
1450
|
+
isLeafNode
|
|
1451
|
+
);
|
|
1452
|
+
if (textData !== void 0 && textData !== "")
|
|
1453
|
+
currentNode.add(this.options.textNodeName, textData);
|
|
1454
|
+
textData = "";
|
|
1455
|
+
}
|
|
1456
|
+
return textData;
|
|
1457
|
+
}
|
|
1458
|
+
function isItStopNode(stopNodesExact, stopNodesWildcard, jPath, currentTagName) {
|
|
1459
|
+
if (stopNodesWildcard && stopNodesWildcard.has(currentTagName)) return true;
|
|
1460
|
+
if (stopNodesExact && stopNodesExact.has(jPath)) return true;
|
|
1461
|
+
return false;
|
|
1462
|
+
}
|
|
1463
|
+
function tagExpWithClosingIndex(xmlData, i, closingChar = ">") {
|
|
1464
|
+
let attrBoundary;
|
|
1465
|
+
let tagExp = "";
|
|
1466
|
+
for (let index = i; index < xmlData.length; index++) {
|
|
1467
|
+
let ch = xmlData[index];
|
|
1468
|
+
if (attrBoundary) {
|
|
1469
|
+
if (ch === attrBoundary) attrBoundary = "";
|
|
1470
|
+
} else if (ch === '"' || ch === "'") {
|
|
1471
|
+
attrBoundary = ch;
|
|
1472
|
+
} else if (ch === closingChar[0]) {
|
|
1473
|
+
if (closingChar[1]) {
|
|
1474
|
+
if (xmlData[index + 1] === closingChar[1]) {
|
|
1475
|
+
return {
|
|
1476
|
+
data: tagExp,
|
|
1477
|
+
index
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
return {
|
|
1482
|
+
data: tagExp,
|
|
1483
|
+
index
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
} else if (ch === " ") {
|
|
1487
|
+
ch = " ";
|
|
1488
|
+
}
|
|
1489
|
+
tagExp += ch;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
function findClosingIndex(xmlData, str, i, errMsg) {
|
|
1493
|
+
const closingIndex = xmlData.indexOf(str, i);
|
|
1494
|
+
if (closingIndex === -1) {
|
|
1495
|
+
throw new Error(errMsg);
|
|
1496
|
+
} else {
|
|
1497
|
+
return closingIndex + str.length - 1;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
function readTagExp(xmlData, i, removeNSPrefix, closingChar = ">") {
|
|
1501
|
+
const result = tagExpWithClosingIndex(xmlData, i + 1, closingChar);
|
|
1502
|
+
if (!result) return;
|
|
1503
|
+
let tagExp = result.data;
|
|
1504
|
+
const closeIndex = result.index;
|
|
1505
|
+
const separatorIndex = tagExp.search(/\s/);
|
|
1506
|
+
let tagName = tagExp;
|
|
1507
|
+
let attrExpPresent = true;
|
|
1508
|
+
if (separatorIndex !== -1) {
|
|
1509
|
+
tagName = tagExp.substring(0, separatorIndex);
|
|
1510
|
+
tagExp = tagExp.substring(separatorIndex + 1).trimStart();
|
|
1511
|
+
}
|
|
1512
|
+
const rawTagName = tagName;
|
|
1513
|
+
if (removeNSPrefix) {
|
|
1514
|
+
const colonIndex = tagName.indexOf(":");
|
|
1515
|
+
if (colonIndex !== -1) {
|
|
1516
|
+
tagName = tagName.substr(colonIndex + 1);
|
|
1517
|
+
attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return {
|
|
1521
|
+
tagName,
|
|
1522
|
+
tagExp,
|
|
1523
|
+
closeIndex,
|
|
1524
|
+
attrExpPresent,
|
|
1525
|
+
rawTagName
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
function readStopNodeData(xmlData, tagName, i) {
|
|
1529
|
+
const startIndex = i;
|
|
1530
|
+
let openTagCount = 1;
|
|
1531
|
+
for (; i < xmlData.length; i++) {
|
|
1532
|
+
if (xmlData[i] === "<") {
|
|
1533
|
+
if (xmlData[i + 1] === "/") {
|
|
1534
|
+
const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
|
|
1535
|
+
let closeTagName = xmlData.substring(i + 2, closeIndex).trim();
|
|
1536
|
+
if (closeTagName === tagName) {
|
|
1537
|
+
openTagCount--;
|
|
1538
|
+
if (openTagCount === 0) {
|
|
1539
|
+
return {
|
|
1540
|
+
tagContent: xmlData.substring(startIndex, i),
|
|
1541
|
+
i: closeIndex
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
i = closeIndex;
|
|
1546
|
+
} else if (xmlData[i + 1] === "?") {
|
|
1547
|
+
const closeIndex = findClosingIndex(xmlData, "?>", i + 1, "StopNode is not closed.");
|
|
1548
|
+
i = closeIndex;
|
|
1549
|
+
} else if (xmlData.substr(i + 1, 3) === "!--") {
|
|
1550
|
+
const closeIndex = findClosingIndex(xmlData, "-->", i + 3, "StopNode is not closed.");
|
|
1551
|
+
i = closeIndex;
|
|
1552
|
+
} else if (xmlData.substr(i + 1, 2) === "![") {
|
|
1553
|
+
const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
|
|
1554
|
+
i = closeIndex;
|
|
1555
|
+
} else {
|
|
1556
|
+
const tagData = readTagExp(xmlData, i, ">");
|
|
1557
|
+
if (tagData) {
|
|
1558
|
+
const openTagName = tagData && tagData.tagName;
|
|
1559
|
+
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length - 1] !== "/") {
|
|
1560
|
+
openTagCount++;
|
|
1561
|
+
}
|
|
1562
|
+
i = tagData.closeIndex;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
function parseValue(val, shouldParse, options) {
|
|
1569
|
+
if (shouldParse && typeof val === "string") {
|
|
1570
|
+
const newval = val.trim();
|
|
1571
|
+
if (newval === "true") return true;
|
|
1572
|
+
else if (newval === "false") return false;
|
|
1573
|
+
else return toNumber(val, options);
|
|
1574
|
+
} else {
|
|
1575
|
+
if (isExist(val)) {
|
|
1576
|
+
return val;
|
|
1577
|
+
} else {
|
|
1578
|
+
return "";
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/node2json.js
|
|
1584
|
+
var METADATA_SYMBOL2 = XmlNode.getMetaDataSymbol();
|
|
1585
|
+
function prettify(node, options) {
|
|
1586
|
+
return compress(node, options);
|
|
1587
|
+
}
|
|
1588
|
+
function compress(arr, options, jPath) {
|
|
1589
|
+
let text;
|
|
1590
|
+
const compressedObj = {};
|
|
1591
|
+
for (let i = 0; i < arr.length; i++) {
|
|
1592
|
+
const tagObj = arr[i];
|
|
1593
|
+
const property = propName(tagObj);
|
|
1594
|
+
let newJpath = "";
|
|
1595
|
+
if (jPath === void 0) newJpath = property;
|
|
1596
|
+
else newJpath = jPath + "." + property;
|
|
1597
|
+
if (property === options.textNodeName) {
|
|
1598
|
+
if (text === void 0) text = tagObj[property];
|
|
1599
|
+
else text += "" + tagObj[property];
|
|
1600
|
+
} else if (property === void 0) {
|
|
1601
|
+
continue;
|
|
1602
|
+
} else if (tagObj[property]) {
|
|
1603
|
+
let val = compress(tagObj[property], options, newJpath);
|
|
1604
|
+
const isLeaf = isLeafTag(val, options);
|
|
1605
|
+
if (tagObj[METADATA_SYMBOL2] !== void 0) {
|
|
1606
|
+
val[METADATA_SYMBOL2] = tagObj[METADATA_SYMBOL2];
|
|
1607
|
+
}
|
|
1608
|
+
if (tagObj[":@"]) {
|
|
1609
|
+
assignAttributes(val, tagObj[":@"], newJpath, options);
|
|
1610
|
+
} else if (Object.keys(val).length === 1 && val[options.textNodeName] !== void 0 && !options.alwaysCreateTextNode) {
|
|
1611
|
+
val = val[options.textNodeName];
|
|
1612
|
+
} else if (Object.keys(val).length === 0) {
|
|
1613
|
+
if (options.alwaysCreateTextNode) val[options.textNodeName] = "";
|
|
1614
|
+
else val = "";
|
|
1615
|
+
}
|
|
1616
|
+
if (compressedObj[property] !== void 0 && compressedObj.hasOwnProperty(property)) {
|
|
1617
|
+
if (!Array.isArray(compressedObj[property])) {
|
|
1618
|
+
compressedObj[property] = [compressedObj[property]];
|
|
1619
|
+
}
|
|
1620
|
+
compressedObj[property].push(val);
|
|
1621
|
+
} else {
|
|
1622
|
+
if (options.isArray(property, newJpath, isLeaf)) {
|
|
1623
|
+
compressedObj[property] = [val];
|
|
1624
|
+
} else {
|
|
1625
|
+
compressedObj[property] = val;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
if (typeof text === "string") {
|
|
1631
|
+
if (text.length > 0) compressedObj[options.textNodeName] = text;
|
|
1632
|
+
} else if (text !== void 0) compressedObj[options.textNodeName] = text;
|
|
1633
|
+
return compressedObj;
|
|
1634
|
+
}
|
|
1635
|
+
function propName(obj) {
|
|
1636
|
+
const keys = Object.keys(obj);
|
|
1637
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1638
|
+
const key = keys[i];
|
|
1639
|
+
if (key !== ":@") return key;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
function assignAttributes(obj, attrMap, jpath, options) {
|
|
1643
|
+
if (attrMap) {
|
|
1644
|
+
const keys = Object.keys(attrMap);
|
|
1645
|
+
const len = keys.length;
|
|
1646
|
+
for (let i = 0; i < len; i++) {
|
|
1647
|
+
const atrrName = keys[i];
|
|
1648
|
+
if (options.isArray(atrrName, jpath + "." + atrrName, true, true)) {
|
|
1649
|
+
obj[atrrName] = [attrMap[atrrName]];
|
|
1650
|
+
} else {
|
|
1651
|
+
obj[atrrName] = attrMap[atrrName];
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
function isLeafTag(obj, options) {
|
|
1657
|
+
const { textNodeName } = options;
|
|
1658
|
+
const propCount = Object.keys(obj).length;
|
|
1659
|
+
if (propCount === 0) {
|
|
1660
|
+
return true;
|
|
1661
|
+
}
|
|
1662
|
+
if (propCount === 1 && (obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0)) {
|
|
1663
|
+
return true;
|
|
1664
|
+
}
|
|
1665
|
+
return false;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
// node_modules/.pnpm/fast-xml-parser@5.3.3/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
|
|
1669
|
+
var XMLParser = class {
|
|
1670
|
+
constructor(options) {
|
|
1671
|
+
this.externalEntities = {};
|
|
1672
|
+
this.options = buildOptions(options);
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Parse XML dats to JS object
|
|
1676
|
+
* @param {string|Uint8Array} xmlData
|
|
1677
|
+
* @param {boolean|Object} validationOption
|
|
1678
|
+
*/
|
|
1679
|
+
parse(xmlData, validationOption) {
|
|
1680
|
+
if (typeof xmlData !== "string" && xmlData.toString) {
|
|
1681
|
+
xmlData = xmlData.toString();
|
|
1682
|
+
} else if (typeof xmlData !== "string") {
|
|
1683
|
+
throw new Error("XML data is accepted in String or Bytes[] form.");
|
|
1684
|
+
}
|
|
1685
|
+
if (validationOption) {
|
|
1686
|
+
if (validationOption === true) validationOption = {};
|
|
1687
|
+
const result = validate(xmlData, validationOption);
|
|
1688
|
+
if (result !== true) {
|
|
1689
|
+
throw Error(`${result.err.msg}:${result.err.line}:${result.err.col}`);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
const orderedObjParser = new OrderedObjParser(this.options);
|
|
1693
|
+
orderedObjParser.addExternalEntities(this.externalEntities);
|
|
1694
|
+
const orderedResult = orderedObjParser.parseXml(xmlData);
|
|
1695
|
+
if (this.options.preserveOrder || orderedResult === void 0) return orderedResult;
|
|
1696
|
+
else return prettify(orderedResult, this.options);
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Add Entity which is not by default supported by this library
|
|
1700
|
+
* @param {string} key
|
|
1701
|
+
* @param {string} value
|
|
1702
|
+
*/
|
|
1703
|
+
addEntity(key, value) {
|
|
1704
|
+
if (value.indexOf("&") !== -1) {
|
|
1705
|
+
throw new Error("Entity value can't have '&'");
|
|
1706
|
+
} else if (key.indexOf("&") !== -1 || key.indexOf(";") !== -1) {
|
|
1707
|
+
throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'");
|
|
1708
|
+
} else if (value === "&") {
|
|
1709
|
+
throw new Error("An entity with value '&' is not permitted");
|
|
1710
|
+
} else {
|
|
1711
|
+
this.externalEntities[key] = value;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Returns a Symbol that can be used to access the metadata
|
|
1716
|
+
* property on a node.
|
|
1717
|
+
*
|
|
1718
|
+
* If Symbol is not available in the environment, an ordinary property is used
|
|
1719
|
+
* and the name of the property is here returned.
|
|
1720
|
+
*
|
|
1721
|
+
* The XMLMetaData property is only present when `captureMetaData`
|
|
1722
|
+
* is true in the options.
|
|
1723
|
+
*/
|
|
1724
|
+
static getMetaDataSymbol() {
|
|
1725
|
+
return XmlNode.getMetaDataSymbol();
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
|
|
1729
|
+
// apps/cli/src/source.ts
|
|
1730
|
+
var MAXIMUM_API_BYTES = 1024 * 1024;
|
|
1731
|
+
var MAXIMUM_HTML_BYTES = 1024 * 1024;
|
|
1732
|
+
var MAXIMUM_RSS_BYTES = 2 * 1024 * 1024;
|
|
1733
|
+
var MAXIMUM_REDIRECTS = 3;
|
|
1734
|
+
var MAXIMUM_RSS_ITEMS = 100;
|
|
1735
|
+
var SourceCliError = class extends Error {
|
|
1736
|
+
constructor(code, message) {
|
|
1737
|
+
super(message);
|
|
1738
|
+
this.code = code;
|
|
1739
|
+
this.name = "SourceCliError";
|
|
1740
|
+
}
|
|
1741
|
+
code;
|
|
1742
|
+
};
|
|
1743
|
+
function asArray(value) {
|
|
1744
|
+
return Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
1745
|
+
}
|
|
1746
|
+
function bounded(value, maximum) {
|
|
1747
|
+
return value.trim().replaceAll(/\s+/gu, " ").slice(0, maximum).trim();
|
|
1748
|
+
}
|
|
1749
|
+
function contentHash(value) {
|
|
1750
|
+
return createHash("sha256").update(value).digest("hex");
|
|
1751
|
+
}
|
|
1752
|
+
function htmlDecode(value) {
|
|
1753
|
+
return value.replaceAll(/ /giu, " ").replaceAll(/&/giu, "&").replaceAll(/"/giu, '"').replaceAll(/'|'/giu, "'").replaceAll(/</giu, "<").replaceAll(/>/giu, ">").replaceAll(/&#(\d+);/gu, (_match, digits) => {
|
|
1754
|
+
const codePoint = Number(digits);
|
|
1755
|
+
return Number.isSafeInteger(codePoint) ? String.fromCodePoint(codePoint) : "";
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
function htmlText(value) {
|
|
1759
|
+
return bounded(
|
|
1760
|
+
htmlDecode(
|
|
1761
|
+
value.replaceAll(/<script\b[^>]*>[\s\S]*?<\/script\s*>/giu, " ").replaceAll(/<style\b[^>]*>[\s\S]*?<\/style\s*>/giu, " ").replaceAll(/<noscript\b[^>]*>[\s\S]*?<\/noscript\s*>/giu, " ").replaceAll(/<template\b[^>]*>[\s\S]*?<\/template\s*>/giu, " ").replaceAll(/<[^>]+>/gu, " ")
|
|
1762
|
+
),
|
|
1763
|
+
12e3
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
function isPrivateIpv4(address) {
|
|
1767
|
+
const values = address.split(".").map((value) => Number(value));
|
|
1768
|
+
if (values.length !== 4 || values.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {
|
|
1769
|
+
return true;
|
|
1770
|
+
}
|
|
1771
|
+
const [first, second] = values;
|
|
1772
|
+
return first === 0 || first === 10 || first === 127 || first >= 224 || first === 100 && second >= 64 && second <= 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 0 || first === 192 && second === 168 || first === 198 && (second === 18 || second === 19);
|
|
1773
|
+
}
|
|
1774
|
+
function isPrivateIpv6(address) {
|
|
1775
|
+
const normalized = address.toLowerCase();
|
|
1776
|
+
return normalized === "::" || normalized === "::1" || normalized.startsWith("::ffff:") || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb");
|
|
1777
|
+
}
|
|
1778
|
+
function isBlockedAddress(address, family) {
|
|
1779
|
+
if (family === 4) {
|
|
1780
|
+
return isPrivateIpv4(address);
|
|
1781
|
+
}
|
|
1782
|
+
if (family === 6) {
|
|
1783
|
+
return isPrivateIpv6(address);
|
|
1784
|
+
}
|
|
1785
|
+
return true;
|
|
1786
|
+
}
|
|
1787
|
+
function parseRemoteUrl(value) {
|
|
1788
|
+
let parsed;
|
|
1789
|
+
try {
|
|
1790
|
+
parsed = new URL(value);
|
|
1791
|
+
} catch {
|
|
1792
|
+
throw new SourceCliError("DXC_SOURCE_URL_INVALID", "\u6765\u6E90\u5730\u5740\u5FC5\u987B\u662F\u6709\u6548\u7684 HTTP(S) URL\u3002");
|
|
1793
|
+
}
|
|
1794
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username.length > 0 || parsed.password.length > 0 || parsed.hostname.length === 0) {
|
|
1795
|
+
throw new SourceCliError("DXC_SOURCE_URL_INVALID", "\u6765\u6E90\u5730\u5740\u53EA\u80FD\u662F\u65E0\u51ED\u636E\u7684 HTTP(S) URL\u3002");
|
|
1796
|
+
}
|
|
1797
|
+
return parsed;
|
|
1798
|
+
}
|
|
1799
|
+
function optionalString(value, maximum) {
|
|
1800
|
+
return typeof value === "string" ? bounded(value, maximum) || void 0 : void 0;
|
|
1801
|
+
}
|
|
1802
|
+
function parsePublishedAt(value) {
|
|
1803
|
+
if (typeof value !== "string") {
|
|
1804
|
+
return void 0;
|
|
1805
|
+
}
|
|
1806
|
+
const parsed = new Date(value);
|
|
1807
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed.toISOString();
|
|
1808
|
+
}
|
|
1809
|
+
function objectValue(value) {
|
|
1810
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1811
|
+
}
|
|
1812
|
+
function itemLink(value) {
|
|
1813
|
+
if (typeof value === "string") {
|
|
1814
|
+
return value;
|
|
1815
|
+
}
|
|
1816
|
+
const object = objectValue(value);
|
|
1817
|
+
return object === void 0 ? void 0 : optionalString(object["@_href"], 2e3);
|
|
1818
|
+
}
|
|
1819
|
+
function parseFeedItems(source, limit, baseUrl) {
|
|
1820
|
+
let document;
|
|
1821
|
+
try {
|
|
1822
|
+
const parsed = new XMLParser({
|
|
1823
|
+
attributeNamePrefix: "@_",
|
|
1824
|
+
ignoreAttributes: false,
|
|
1825
|
+
parseTagValue: true,
|
|
1826
|
+
processEntities: false,
|
|
1827
|
+
trimValues: true
|
|
1828
|
+
}).parse(source);
|
|
1829
|
+
document = objectValue(parsed) ?? {};
|
|
1830
|
+
} catch {
|
|
1831
|
+
throw new SourceCliError("DXC_SOURCE_CONTENT_INVALID", "RSS/Atom \u5185\u5BB9\u65E0\u6CD5\u89E3\u6790\u3002");
|
|
1832
|
+
}
|
|
1833
|
+
const rssChannel = objectValue(objectValue(document["rss"])?.["channel"]);
|
|
1834
|
+
const atomFeed = objectValue(document["feed"]);
|
|
1835
|
+
const rawItems = rssChannel === void 0 ? asArray(atomFeed?.["entry"]) : asArray(rssChannel["item"]);
|
|
1836
|
+
if (rawItems.length === 0) {
|
|
1837
|
+
throw new SourceCliError("DXC_SOURCE_CONTENT_INVALID", "\u6765\u6E90\u6CA1\u6709\u53EF\u8BC6\u522B\u7684 RSS/Atom \u6761\u76EE\u3002");
|
|
1838
|
+
}
|
|
1839
|
+
const items = rawItems.slice(0, limit).map((rawItem, index) => {
|
|
1840
|
+
const item = objectValue(rawItem) ?? {};
|
|
1841
|
+
const title = optionalString(item["title"], 500) ?? "\u65E0\u6807\u9898";
|
|
1842
|
+
const url = itemLink(item["link"]);
|
|
1843
|
+
const summary = optionalString(item["description"], 2e3) ?? optionalString(item["summary"], 2e3) ?? optionalString(item["content"], 2e3);
|
|
1844
|
+
const identifier = optionalString(item["guid"], 256) ?? optionalString(item["id"], 256) ?? url ?? contentHash(Buffer.from(`${title}:${index}`, "utf8"));
|
|
1845
|
+
let parsedUrl;
|
|
1846
|
+
if (url !== void 0) {
|
|
1847
|
+
try {
|
|
1848
|
+
parsedUrl = parseRemoteUrl(new URL(url, baseUrl).toString()).toString();
|
|
1849
|
+
} catch {
|
|
1850
|
+
parsedUrl = void 0;
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return {
|
|
1854
|
+
id: identifier,
|
|
1855
|
+
...parsePublishedAt(item["pubDate"]) === void 0 && parsePublishedAt(item["updated"]) === void 0 ? {} : { publishedAt: parsePublishedAt(item["pubDate"]) ?? parsePublishedAt(item["updated"]) },
|
|
1856
|
+
...summary === void 0 ? {} : { summary: htmlText(summary) || summary },
|
|
1857
|
+
title: htmlText(title) || title,
|
|
1858
|
+
...parsedUrl === void 0 ? {} : { url: parsedUrl }
|
|
1859
|
+
};
|
|
1860
|
+
});
|
|
1861
|
+
return {
|
|
1862
|
+
capture: {
|
|
1863
|
+
capturedAt: "",
|
|
1864
|
+
contentHash: "",
|
|
1865
|
+
dataTransit: "local-only",
|
|
1866
|
+
executionLocation: "local-device",
|
|
1867
|
+
extractor: "rss-atom@1",
|
|
1868
|
+
finalUrl: "https://placeholder.invalid/",
|
|
1869
|
+
mediaType: "application/xml",
|
|
1870
|
+
sourceUrl: "https://placeholder.invalid/"
|
|
1871
|
+
},
|
|
1872
|
+
items,
|
|
1873
|
+
kind: "rss"
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
function parseCanonicalUrl(source, finalUrl) {
|
|
1877
|
+
const match = /<link\b[^>]*\brel\s*=\s*["']?canonical["']?[^>]*\bhref\s*=\s*["']([^"']+)["'][^>]*>/iu.exec(
|
|
1878
|
+
source
|
|
1879
|
+
);
|
|
1880
|
+
if (match?.[1] === void 0) {
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
try {
|
|
1884
|
+
const canonical = parseRemoteUrl(new URL(htmlDecode(match[1]), finalUrl).toString());
|
|
1885
|
+
return canonical.origin === finalUrl.origin ? canonical.toString() : void 0;
|
|
1886
|
+
} catch {
|
|
1887
|
+
return void 0;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
function parseHtmlDocument(source, finalUrl) {
|
|
1891
|
+
const titleMatch = /<title\b[^>]*>([\s\S]*?)<\/title\s*>/iu.exec(source);
|
|
1892
|
+
const title = titleMatch?.[1] === void 0 ? "\u672A\u547D\u540D\u516C\u5F00\u9875\u9762" : htmlText(titleMatch[1]);
|
|
1893
|
+
const excerpt = htmlText(source);
|
|
1894
|
+
if (excerpt.length === 0) {
|
|
1895
|
+
throw new SourceCliError("DXC_SOURCE_CONTENT_INVALID", "\u516C\u5F00\u9875\u9762\u6CA1\u6709\u53EF\u63D0\u53D6\u7684\u6587\u672C\u5185\u5BB9\u3002");
|
|
1896
|
+
}
|
|
1897
|
+
const canonicalUrl = parseCanonicalUrl(source, finalUrl);
|
|
1898
|
+
return {
|
|
1899
|
+
capture: {
|
|
1900
|
+
capturedAt: "",
|
|
1901
|
+
contentHash: "",
|
|
1902
|
+
dataTransit: "local-only",
|
|
1903
|
+
executionLocation: "local-device",
|
|
1904
|
+
extractor: "public-html@1",
|
|
1905
|
+
finalUrl: "https://placeholder.invalid/",
|
|
1906
|
+
mediaType: "text/html",
|
|
1907
|
+
sourceUrl: "https://placeholder.invalid/"
|
|
1908
|
+
},
|
|
1909
|
+
document: {
|
|
1910
|
+
...canonicalUrl === void 0 ? {} : { canonicalUrl },
|
|
1911
|
+
excerpt,
|
|
1912
|
+
title: title || "\u672A\u547D\u540D\u516C\u5F00\u9875\u9762"
|
|
1913
|
+
},
|
|
1914
|
+
kind: "html"
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
function parseHeaderEnvironment(values) {
|
|
1918
|
+
return values.map((value) => {
|
|
1919
|
+
const [header, environment, ...rest] = value.split("=");
|
|
1920
|
+
if (header === void 0 || environment === void 0 || rest.length > 0 || !/^[A-Za-z0-9-]+$/u.test(header) || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(environment)) {
|
|
1921
|
+
throw new SourceCliError(
|
|
1922
|
+
"DXC_SOURCE_CONTENT_INVALID",
|
|
1923
|
+
"--header-env \u5FC5\u987B\u4F7F\u7528 Header=ENVIRONMENT \u7684\u5F62\u5F0F\u3002"
|
|
1924
|
+
);
|
|
1925
|
+
}
|
|
1926
|
+
return { header, environment };
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
async function readBody(response, maximumBytes) {
|
|
1930
|
+
if (response.body === null) {
|
|
1931
|
+
return Buffer.alloc(0);
|
|
1932
|
+
}
|
|
1933
|
+
const reader = response.body.getReader();
|
|
1934
|
+
const chunks = [];
|
|
1935
|
+
let total = 0;
|
|
1936
|
+
try {
|
|
1937
|
+
while (true) {
|
|
1938
|
+
const chunk = await reader.read();
|
|
1939
|
+
if (chunk.done) {
|
|
1940
|
+
return Buffer.concat(chunks);
|
|
1941
|
+
}
|
|
1942
|
+
total += chunk.value.byteLength;
|
|
1943
|
+
if (total > maximumBytes) {
|
|
1944
|
+
await reader.cancel();
|
|
1945
|
+
throw new SourceCliError(
|
|
1946
|
+
"DXC_SOURCE_RESPONSE_TOO_LARGE",
|
|
1947
|
+
`\u6765\u6E90\u54CD\u5E94\u8D85\u8FC7 ${maximumBytes} \u5B57\u8282\u4E0A\u9650\u3002`
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
chunks.push(chunk.value);
|
|
1951
|
+
}
|
|
1952
|
+
} finally {
|
|
1953
|
+
reader.releaseLock();
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
var SourceCli = class {
|
|
1957
|
+
#fetch;
|
|
1958
|
+
#lookup;
|
|
1959
|
+
#now;
|
|
1960
|
+
constructor(dependencies = {}) {
|
|
1961
|
+
this.#fetch = dependencies.fetch ?? fetch;
|
|
1962
|
+
this.#lookup = dependencies.lookup ?? systemLookup;
|
|
1963
|
+
this.#now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
1964
|
+
}
|
|
1965
|
+
async fetchRss(url, limit) {
|
|
1966
|
+
const source = await this.#retrieve(url, MAXIMUM_RSS_BYTES, {
|
|
1967
|
+
Accept: "application/atom+xml, application/rss+xml, application/xml, text/xml;q=0.9, */*;q=0.1"
|
|
1968
|
+
});
|
|
1969
|
+
const data = parseFeedItems(
|
|
1970
|
+
source.body.toString("utf8"),
|
|
1971
|
+
Math.min(limit, MAXIMUM_RSS_ITEMS),
|
|
1972
|
+
source.finalUrl
|
|
1973
|
+
);
|
|
1974
|
+
return this.#result(data, source);
|
|
1975
|
+
}
|
|
1976
|
+
async fetchApi(input) {
|
|
1977
|
+
const headers = { Accept: "application/json" };
|
|
1978
|
+
if (input.bearerEnvironment !== void 0) {
|
|
1979
|
+
const token = process.env[input.bearerEnvironment];
|
|
1980
|
+
if (token === void 0 || token.length === 0) {
|
|
1981
|
+
throw new SourceCliError(
|
|
1982
|
+
"DXC_SOURCE_AUTH_MISSING",
|
|
1983
|
+
`\u73AF\u5883\u53D8\u91CF ${input.bearerEnvironment} \u672A\u8BBE\u7F6E\uFF0C\u65E0\u6CD5\u8BFB\u53D6 API\u3002`
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
1987
|
+
}
|
|
1988
|
+
for (const binding of parseHeaderEnvironment(input.headerEnvironments)) {
|
|
1989
|
+
const value = process.env[binding.environment];
|
|
1990
|
+
if (value === void 0 || value.length === 0) {
|
|
1991
|
+
throw new SourceCliError(
|
|
1992
|
+
"DXC_SOURCE_AUTH_MISSING",
|
|
1993
|
+
`\u73AF\u5883\u53D8\u91CF ${binding.environment} \u672A\u8BBE\u7F6E\uFF0C\u65E0\u6CD5\u8BFB\u53D6 API\u3002`
|
|
1994
|
+
);
|
|
1995
|
+
}
|
|
1996
|
+
headers[binding.header] = value;
|
|
1997
|
+
}
|
|
1998
|
+
const source = await this.#retrieve(input.url, MAXIMUM_API_BYTES, headers);
|
|
1999
|
+
let payload;
|
|
2000
|
+
try {
|
|
2001
|
+
payload = JSON.parse(source.body.toString("utf8"));
|
|
2002
|
+
} catch {
|
|
2003
|
+
throw new SourceCliError("DXC_SOURCE_CONTENT_INVALID", "HTTP API \u6CA1\u6709\u8FD4\u56DE\u6709\u6548 JSON\u3002");
|
|
2004
|
+
}
|
|
2005
|
+
return this.#result(
|
|
2006
|
+
{
|
|
2007
|
+
capture: this.#capture(source, "http-api@1"),
|
|
2008
|
+
kind: "api",
|
|
2009
|
+
payload
|
|
2010
|
+
},
|
|
2011
|
+
source
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
async fetchHtml(url) {
|
|
2015
|
+
const source = await this.#retrieve(url, MAXIMUM_HTML_BYTES, {
|
|
2016
|
+
Accept: "text/html, application/xhtml+xml;q=0.9, */*;q=0.1"
|
|
2017
|
+
});
|
|
2018
|
+
if (source.mediaType !== "text/html" && source.mediaType !== "application/xhtml+xml") {
|
|
2019
|
+
throw new SourceCliError("DXC_SOURCE_CONTENT_INVALID", "\u516C\u5F00\u9875\u9762\u6CA1\u6709\u8FD4\u56DE HTML \u5185\u5BB9\u3002");
|
|
2020
|
+
}
|
|
2021
|
+
const data = parseHtmlDocument(source.body.toString("utf8"), source.finalUrl);
|
|
2022
|
+
return this.#result(data, source);
|
|
2023
|
+
}
|
|
2024
|
+
#capture(source, extractor) {
|
|
2025
|
+
return {
|
|
2026
|
+
capturedAt: this.#now().toISOString(),
|
|
2027
|
+
contentHash: contentHash(source.body),
|
|
2028
|
+
dataTransit: "local-only",
|
|
2029
|
+
executionLocation: "local-device",
|
|
2030
|
+
extractor,
|
|
2031
|
+
finalUrl: source.finalUrl.toString(),
|
|
2032
|
+
mediaType: source.mediaType || "application/octet-stream",
|
|
2033
|
+
sourceUrl: source.sourceUrl.toString()
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2036
|
+
#result(data, source) {
|
|
2037
|
+
const extractor = data.kind === "rss" ? "rss-atom@1" : data.kind === "api" ? "http-api@1" : "public-html@1";
|
|
2038
|
+
return sourceFetchResultSchema.parse({
|
|
2039
|
+
command: "source.fetch",
|
|
2040
|
+
data: { ...data, capture: this.#capture(source, extractor) },
|
|
2041
|
+
ok: true
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
async #assertPublicRemote(url) {
|
|
2045
|
+
if (url.hostname.toLowerCase() === "localhost") {
|
|
2046
|
+
throw new SourceCliError("DXC_SOURCE_URL_BLOCKED", "\u6765\u6E90\u5730\u5740\u4E0D\u80FD\u6307\u5411\u672C\u673A\u6216\u79C1\u7F51\u5730\u5740\u3002");
|
|
2047
|
+
}
|
|
2048
|
+
const literalAddress = url.hostname.replaceAll(/^\[|\]$/gu, "");
|
|
2049
|
+
const literalFamily = isIP(literalAddress);
|
|
2050
|
+
if (literalFamily !== 0 && isBlockedAddress(literalAddress, literalFamily)) {
|
|
2051
|
+
throw new SourceCliError(
|
|
2052
|
+
"DXC_SOURCE_URL_BLOCKED",
|
|
2053
|
+
"\u6765\u6E90\u5730\u5740\u4E0D\u80FD\u6307\u5411\u672C\u673A\u3001\u79C1\u7F51\u6216\u4E91\u5143\u6570\u636E\u5730\u5740\u3002"
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
const addresses = await this.#lookup(url.hostname, { all: true, verbatim: true }).catch(() => {
|
|
2057
|
+
throw new SourceCliError("DXC_SOURCE_FETCH_FAILED", "\u65E0\u6CD5\u89E3\u6790\u6765\u6E90\u57DF\u540D\u3002");
|
|
2058
|
+
});
|
|
2059
|
+
if (addresses.length === 0 || addresses.some((address) => isBlockedAddress(address.address, address.family))) {
|
|
2060
|
+
throw new SourceCliError(
|
|
2061
|
+
"DXC_SOURCE_URL_BLOCKED",
|
|
2062
|
+
"\u6765\u6E90\u5730\u5740\u4E0D\u80FD\u6307\u5411\u672C\u673A\u3001\u79C1\u7F51\u6216\u4E91\u5143\u6570\u636E\u5730\u5740\u3002"
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
async #retrieve(sourceUrl, maximumBytes, headers) {
|
|
2067
|
+
const originalUrl = parseRemoteUrl(sourceUrl);
|
|
2068
|
+
let currentUrl = originalUrl;
|
|
2069
|
+
for (let redirectCount = 0; redirectCount <= MAXIMUM_REDIRECTS; redirectCount += 1) {
|
|
2070
|
+
await this.#assertPublicRemote(currentUrl);
|
|
2071
|
+
let response;
|
|
2072
|
+
try {
|
|
2073
|
+
response = await this.#fetch(currentUrl, {
|
|
2074
|
+
headers: {
|
|
2075
|
+
...headers,
|
|
2076
|
+
"User-Agent": "DxC-LocalResearch/0.1 (+https://deployx.ai)"
|
|
2077
|
+
},
|
|
2078
|
+
redirect: "manual",
|
|
2079
|
+
signal: AbortSignal.timeout(1e4)
|
|
2080
|
+
});
|
|
2081
|
+
} catch (error) {
|
|
2082
|
+
if (error instanceof SourceCliError) {
|
|
2083
|
+
throw error;
|
|
2084
|
+
}
|
|
2085
|
+
throw new SourceCliError("DXC_SOURCE_FETCH_FAILED", "\u6765\u6E90\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
|
|
2086
|
+
}
|
|
2087
|
+
if (response.status >= 300 && response.status < 400) {
|
|
2088
|
+
const location = response.headers.get("location");
|
|
2089
|
+
if (location === null) {
|
|
2090
|
+
throw new SourceCliError("DXC_SOURCE_FETCH_FAILED", "\u6765\u6E90\u91CD\u5B9A\u5411\u6CA1\u6709\u63D0\u4F9B\u76EE\u6807\u5730\u5740\u3002");
|
|
2091
|
+
}
|
|
2092
|
+
if (redirectCount === MAXIMUM_REDIRECTS) {
|
|
2093
|
+
throw new SourceCliError("DXC_SOURCE_REDIRECT_LIMIT", "\u6765\u6E90\u91CD\u5B9A\u5411\u6B21\u6570\u8D85\u8FC7\u4E0A\u9650\u3002");
|
|
2094
|
+
}
|
|
2095
|
+
currentUrl = parseRemoteUrl(new URL(location, currentUrl).toString());
|
|
2096
|
+
continue;
|
|
2097
|
+
}
|
|
2098
|
+
if (!response.ok) {
|
|
2099
|
+
throw new SourceCliError(
|
|
2100
|
+
"DXC_SOURCE_FETCH_FAILED",
|
|
2101
|
+
`\u6765\u6E90\u8BF7\u6C42\u5931\u8D25\uFF0CHTTP \u72B6\u6001\u4E3A ${response.status}\u3002`
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2104
|
+
return {
|
|
2105
|
+
body: await readBody(response, maximumBytes),
|
|
2106
|
+
finalUrl: currentUrl,
|
|
2107
|
+
mediaType: response.headers.get("content-type")?.split(";")[0]?.trim() ?? "application/octet-stream",
|
|
2108
|
+
sourceUrl: originalUrl
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
throw new SourceCliError("DXC_SOURCE_REDIRECT_LIMIT", "\u6765\u6E90\u91CD\u5B9A\u5411\u6B21\u6570\u8D85\u8FC7\u4E0A\u9650\u3002");
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
export {
|
|
2116
|
+
SourceCliError,
|
|
2117
|
+
SourceCli
|
|
2118
|
+
};
|