single-file-core 1.3.21 → 1.3.23
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.
|
@@ -394,7 +394,7 @@ function getProcessorHelperClass(utilInstance) {
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
setMetaCSP(metaElement) {
|
|
397
|
-
metaElement.content = "default-src 'none'; connect-src 'self'
|
|
397
|
+
metaElement.content = "default-src 'none'; connect-src 'self' data: blob:; font-src 'self' data: blob:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline' data: blob:; frame-src 'self' data: blob:; media-src 'self' data: blob:; script-src 'self' 'unsafe-inline' data: blob:; object-src 'self' data: blob:;";
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
removeUnusedStylesheets() {
|
package/package.json
CHANGED
|
@@ -70,6 +70,7 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
|
|
|
70
70
|
const REGEXP_MATCH_ROOT_INDEX = /^([0-9_]+\/)?index\.html$/;
|
|
71
71
|
const REGEXP_MATCH_INDEX = /index\.html$/;
|
|
72
72
|
const REGEXP_MATCH_FRAMES = /frames\//;
|
|
73
|
+
const REGEXP_MATCH_MANIFEST = /manifest\.json$/;
|
|
73
74
|
const CHARSET_UTF8 = ";charset=utf-8";
|
|
74
75
|
const REGEXP_ESCAPE = /([{}()^$&.*?/+|[\\\\]|\]|-)/g;
|
|
75
76
|
|
|
@@ -105,11 +106,6 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
|
|
|
105
106
|
} else if (filename.match(REGEXP_MATCH_SCRIPT)) {
|
|
106
107
|
mimeType = "text/javascript" + CHARSET_UTF8;
|
|
107
108
|
}
|
|
108
|
-
if (textContent !== undefined) {
|
|
109
|
-
content = noBlobURL ? await getDataURI(textContent, mimeType) : URL.createObjectURL(new Blob([textContent], { type: mimeType }));
|
|
110
|
-
} else {
|
|
111
|
-
content = "data:text/plain,";
|
|
112
|
-
}
|
|
113
109
|
}
|
|
114
110
|
} else {
|
|
115
111
|
resources.push(resourceInfo);
|
|
@@ -127,7 +123,13 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
|
|
|
127
123
|
}
|
|
128
124
|
}
|
|
129
125
|
const name = entry.filename.match(/^([0-9_]+\/)?(.*)$/)[2];
|
|
126
|
+
let prefixPath = "";
|
|
127
|
+
const prefixPathMatch = filename.match(/(.*\/)[^/]+$/);
|
|
128
|
+
if (prefixPathMatch && prefixPathMatch[1]) {
|
|
129
|
+
prefixPath = prefixPathMatch[1];
|
|
130
|
+
}
|
|
130
131
|
Object.assign(resourceInfo, {
|
|
132
|
+
prefixPath,
|
|
131
133
|
filename: entry.filename,
|
|
132
134
|
name,
|
|
133
135
|
url: entry.comment,
|
|
@@ -142,43 +144,57 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
|
|
|
142
144
|
textResources.sort(sortByFilenameLengthInc);
|
|
143
145
|
resources = resources.sort(sortByFilenameLengthDec).concat(...textResources).concat(...indexPages);
|
|
144
146
|
for (const resource of resources) {
|
|
145
|
-
|
|
147
|
+
const { filename, prefixPath } = resource;
|
|
148
|
+
let { textContent } = resource;
|
|
146
149
|
if (textContent !== undefined) {
|
|
147
|
-
let prefixPath = "";
|
|
148
|
-
const prefixPathMatch = filename.match(/(.*\/)[^/]+$/);
|
|
149
|
-
if (prefixPathMatch && prefixPathMatch[1]) {
|
|
150
|
-
prefixPath = prefixPathMatch[1];
|
|
151
|
-
}
|
|
152
150
|
if (filename.match(REGEXP_MATCH_ROOT_INDEX)) {
|
|
153
151
|
origDocContent = textContent;
|
|
154
152
|
}
|
|
155
153
|
if (!filename.match(REGEXP_MATCH_SCRIPT)) {
|
|
156
|
-
const resourceFilename = filename;
|
|
157
154
|
resources.forEach(innerResource => {
|
|
158
155
|
const { filename, parentResources, content } = innerResource;
|
|
156
|
+
if (filename.startsWith(prefixPath) && filename != resource.filename) {
|
|
157
|
+
const relativeFilename = filename.substring(prefixPath.length);
|
|
158
|
+
if (!relativeFilename.match(REGEXP_MATCH_MANIFEST)) {
|
|
159
|
+
if (textContent.includes(relativeFilename)) {
|
|
160
|
+
parentResources.push(resource.filename);
|
|
161
|
+
if (innerResource.textContent === undefined) {
|
|
162
|
+
textContent = replaceAll(textContent, relativeFilename, content);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
resource.textContent = textContent;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
for (const resource of resources) {
|
|
173
|
+
let { textContent, prefixPath, filename } = resource;
|
|
174
|
+
if (textContent !== undefined) {
|
|
175
|
+
if (!filename.match(REGEXP_MATCH_SCRIPT)) {
|
|
176
|
+
const resourceFilename = filename;
|
|
177
|
+
for (const innerResource of resources) {
|
|
178
|
+
const { filename } = innerResource;
|
|
159
179
|
if (filename.startsWith(prefixPath) && filename != resourceFilename) {
|
|
160
180
|
const relativeFilename = filename.substring(prefixPath.length);
|
|
161
|
-
if (!relativeFilename.match(
|
|
181
|
+
if (!relativeFilename.match(REGEXP_MATCH_MANIFEST)) {
|
|
162
182
|
const position = textContent.indexOf(relativeFilename);
|
|
163
183
|
if (position != -1) {
|
|
164
|
-
|
|
165
|
-
textContent = replaceAll(textContent, relativeFilename, content);
|
|
184
|
+
innerResource.content = await getContent(innerResource);
|
|
185
|
+
textContent = replaceAll(textContent, relativeFilename, innerResource.content);
|
|
166
186
|
}
|
|
167
187
|
}
|
|
168
188
|
}
|
|
169
|
-
}
|
|
189
|
+
}
|
|
170
190
|
resource.textContent = textContent;
|
|
191
|
+
resource.content = await getContent(resource);
|
|
171
192
|
}
|
|
172
193
|
if (filename.match(REGEXP_MATCH_INDEX)) {
|
|
173
194
|
if (shadowRootScriptURL) {
|
|
174
195
|
resource.textContent = textContent.replace(/<script data-template-shadow-root.*<\/script>/g, "<script data-template-shadow-root src=" + shadowRootScriptURL + "></" + "script>");
|
|
175
196
|
}
|
|
176
197
|
}
|
|
177
|
-
if (filename.match(REGEXP_MATCH_INDEX) || filename.match(REGEXP_MATCH_FRAMES) || noBlobURL) {
|
|
178
|
-
resource.content = await getDataURI(textContent, mimeType);
|
|
179
|
-
} else {
|
|
180
|
-
resource.content = URL.createObjectURL(new Blob([textContent], { type: mimeType }));
|
|
181
|
-
}
|
|
182
198
|
if (filename.match(REGEXP_MATCH_ROOT_INDEX)) {
|
|
183
199
|
docContent = textContent;
|
|
184
200
|
url = resource.url;
|
|
@@ -187,6 +203,10 @@ async function extract(content, { password, prompt = () => { }, shadowRootScript
|
|
|
187
203
|
}
|
|
188
204
|
return { docContent, origDocContent, resources, url };
|
|
189
205
|
|
|
206
|
+
async function getContent(resource) {
|
|
207
|
+
return resource.filename.match(REGEXP_MATCH_FRAMES) || noBlobURL ? await getDataURI(resource.textContent, resource.mimeType) : URL.createObjectURL(new Blob([resource.textContent], { type: resource.mimeType }));
|
|
208
|
+
}
|
|
209
|
+
|
|
190
210
|
async function getDataURI(textContent, mimeType) {
|
|
191
211
|
const reader = new FileReader();
|
|
192
212
|
reader.readAsDataURL(new Blob([textContent], { type: mimeType }));
|
|
@@ -52,13 +52,13 @@ const EMBEDDED_IMAGE_DATA_TAGS = [
|
|
|
52
52
|
...EXTRA_DATA_TAGS,
|
|
53
53
|
];
|
|
54
54
|
const EXTRA_DATA_REGEXPS = [
|
|
55
|
-
[/<\/noscript>/i],
|
|
56
|
-
[/<\/script>/i],
|
|
57
|
-
[/<\/xmp>/i],
|
|
58
|
-
[/<\/plaintext>/i]
|
|
55
|
+
[/<noscript/i, /<\/noscript>/i],
|
|
56
|
+
[/<script/i, /<\/script>/i],
|
|
57
|
+
[/<xmp/i, /<\/xmp>/i],
|
|
58
|
+
[/<plaintext/i, /<\/plaintext>/i]
|
|
59
59
|
];
|
|
60
60
|
const EMBEDDED_IMAGE_DATA_REGEXPS = [
|
|
61
|
-
/-->/i,
|
|
61
|
+
[/<!--/i, /-->/i],
|
|
62
62
|
...EXTRA_DATA_REGEXPS,
|
|
63
63
|
];
|
|
64
64
|
const CRC32_TABLE = new Uint32Array(256).map((_, indexTable) => {
|
|
@@ -96,7 +96,7 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
96
96
|
await writeData(zipDataWriter.writable, options.embeddedImage.slice(0, PNG_SIGNATURE_LENGTH + PNG_IHDR_LENGTH));
|
|
97
97
|
if (options.selfExtractingArchive) {
|
|
98
98
|
const embeddedImageText = embeddedImageData.reduce((text, charCode) => text + String.fromCharCode(charCode), "");
|
|
99
|
-
const tagIndex = EMBEDDED_IMAGE_DATA_REGEXPS.findIndex(
|
|
99
|
+
const tagIndex = EMBEDDED_IMAGE_DATA_REGEXPS.findIndex(tests => !embeddedImageText.match(tests[1]));
|
|
100
100
|
let startTag;
|
|
101
101
|
[startTag, endTag] = tagIndex == -1 ? ["", ""] : EMBEDDED_IMAGE_DATA_TAGS[tagIndex];
|
|
102
102
|
const html = getHTMLStartData(pageData, options) + startTag;
|
|
@@ -128,8 +128,8 @@ async function process(pageData, options, lastModDate = new Date()) {
|
|
|
128
128
|
if (!options.extractDataFromPageTags) {
|
|
129
129
|
let textContent = "";
|
|
130
130
|
data.slice(startOffset).forEach(charCode => textContent += String.fromCharCode(charCode));
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
131
|
+
const matchCommentTags = textContent.match(/<!--/i) || textContent.match(/-->/i);
|
|
132
|
+
if (matchCommentTags) {
|
|
133
133
|
return findExtraDataTags(textContent, pageData, options, lastModDate);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -296,7 +296,7 @@ function getHTMLStartData(pageData, options) {
|
|
|
296
296
|
pageContent += "<meta name=viewport content=" + JSON.stringify(pageData.viewport) + ">";
|
|
297
297
|
}
|
|
298
298
|
if (options.insertMetaCSP) {
|
|
299
|
-
pageContent += "<meta http-equiv=content-security-policy content=\"default-src 'none'; connect-src 'self'
|
|
299
|
+
pageContent += "<meta http-equiv=content-security-policy content=\"default-src 'none'; connect-src 'self' data: blob:; font-src 'self' data: blob:; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline' data: blob:; frame-src 'self' data: blob:; media-src 'self' data: blob:; script-src 'self' 'unsafe-inline' data: blob:; object-src 'self' data: blob:\">";
|
|
300
300
|
}
|
|
301
301
|
pageContent += "<style>@keyframes display-wait-message{0%{opacity:0}100%{opacity:1}};body{color:transparent};div{color:initial}</style>";
|
|
302
302
|
pageContent += "<body hidden>";
|
|
@@ -308,8 +308,9 @@ function getPageTitle(pageData) {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
function findExtraDataTags(textContent, pageData, options, lastModDate, indexExtractDataFromPageTags = 0) {
|
|
311
|
-
const
|
|
312
|
-
|
|
311
|
+
const regExpsTag = EXTRA_DATA_REGEXPS[indexExtractDataFromPageTags];
|
|
312
|
+
const matchTag = textContent.match(regExpsTag[0]) || textContent.match(regExpsTag[1]);
|
|
313
|
+
if (matchTag) {
|
|
313
314
|
if (indexExtractDataFromPageTags < EXTRA_DATA_TAGS.length - 1) {
|
|
314
315
|
return findExtraDataTags(textContent, pageData, options, lastModDate, indexExtractDataFromPageTags + 1);
|
|
315
316
|
} else {
|