nnw-theme 2.0.2 → 2.0.3

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.
Files changed (2) hide show
  1. package/dist/render.js +34 -3
  2. package/package.json +3 -3
package/dist/render.js CHANGED
@@ -2,11 +2,11 @@ import { createHash } from "node:crypto";
2
2
  import { mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { decodeHTML } from "entities";
5
+ import { Parser } from "htmlparser2";
5
6
  import { renderingInputs } from "./netnewswire.js";
6
7
  import { fixturePath, readFixture, repositoryFixtures, ThemeError, themeStem, } from "./project.js";
7
8
  import { formatG, pyStr } from "./pyformat.js";
8
9
  const MACRO_RE = /\[\[([a-zA-Z0-9_-]+)\]\]/g;
9
- const SCRIPT_RE = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
10
10
  // A whole <img> or <source> tag; quoted attribute values may contain ">".
11
11
  const MEDIA_TAG_RE = /<(img|source)\b((?:[^>"']|"[^"]*"|'[^']*')*)>/gi;
12
12
  const ATTRIBUTE_RE = /([^\s"'=<>/]+)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'=<>`]+))?/g;
@@ -301,6 +301,37 @@ function injectScripts(page, inputs, platform) {
301
301
  const end = page.lastIndexOf("</body>");
302
302
  return `${page.slice(0, end)}${bundle}\n${page.slice(end)}`;
303
303
  }
304
+ /**
305
+ * Remove every <script> element as WebKit's tokenizer finds them, including end
306
+ * tags like "</script >" and a script left open to the end of the document.
307
+ */
308
+ export function removeScripts(html) {
309
+ const ranges = [];
310
+ let start = -1;
311
+ const parser = new Parser({
312
+ onopentag(name) {
313
+ if (name === "script")
314
+ start = parser.startIndex;
315
+ },
316
+ onclosetag(name, isImplied) {
317
+ if (name !== "script" || start < 0)
318
+ return;
319
+ const end = isImplied
320
+ ? html.length
321
+ : html.indexOf(">", parser.endIndex) + 1 || html.length;
322
+ ranges.push([start, end]);
323
+ start = -1;
324
+ },
325
+ });
326
+ parser.end(html);
327
+ let result = "";
328
+ let offset = 0;
329
+ for (const [from, to] of ranges) {
330
+ result += html.slice(offset, from);
331
+ offset = to;
332
+ }
333
+ return result + html.slice(offset);
334
+ }
304
335
  function isFile(path) {
305
336
  try {
306
337
  return statSync(path).isFile();
@@ -319,7 +350,7 @@ export function renderPage(theme, fixture, target, snapshot = renderingInputs().
319
350
  if (!required.every(isFile)) {
320
351
  throw new ThemeError("bundled NetNewsWire rendering inputs are incomplete");
321
352
  }
322
- const skeleton = read(pagePath).replace(SCRIPT_RE, "");
353
+ const skeleton = removeScripts(read(pagePath));
323
354
  const stylesheet = read(join(theme, "stylesheet.css"));
324
355
  // styleSubstitutions() is empty on macOS, so the macro must stay literal there.
325
356
  const styleSubstitutions = {};
@@ -331,7 +362,7 @@ export function renderPage(theme, fixture, target, snapshot = renderingInputs().
331
362
  const template = read(join(theme, "template.html"));
332
363
  let body = substitute(template, fixtureMapping(fixture, target));
333
364
  if (!target.themeScripts)
334
- body = body.replace(SCRIPT_RE, "");
365
+ body = removeScripts(body);
335
366
  let page = substitute(skeleton, {
336
367
  title: fixture.title ?? "Theme preview",
337
368
  style,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nnw-theme",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Create, preview, check, and publish a NetNewsWire theme.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Dave Marquard",
@@ -44,8 +44,8 @@
44
44
  "entities": "8.1.0",
45
45
  "fflate": "0.8.3",
46
46
  "htmlparser2": "12.0.0",
47
- "playwright-core": "1.64.0-alpha-2026-09-14",
48
- "smol-toml": "1.8.0"
47
+ "playwright-core": "1.64.0",
48
+ "smol-toml": "1.9.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@biomejs/biome": "2.5.14",