dsh-plugin-lookatstudy 0.22.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/index.mjs +96 -13
  2. package/package.json +1 -1
package/lib/index.mjs CHANGED
@@ -4967,22 +4967,105 @@ function decodeHexString(s) {
4967
4967
  for (const b of bytes) if (b >= 32 && b < 127) out += String.fromCharCode(b);
4968
4968
  return out;
4969
4969
  }
4970
- /** Pull text out of one decoded content stream. */
4970
+ /** Pull text out of one decoded content stream. Linear hand-rolled scan —
4971
+ * the original regex alternation backtracked catastrophically on real
4972
+ * papers' content streams (an unclosed `[` made the lazy TJ arm rescan
4973
+ * megabytes; found 2026-09-14 when the livetest refresh wedged the host for
4974
+ * 10+ CPU-minutes on a real arXiv PDF while even a watchdog timer could not
4975
+ * fire — the loop blocked the event loop synchronously). */
4976
+ function readLiteral(src, i) {
4977
+ let depth = 1;
4978
+ let j = i + 1;
4979
+ let raw = "";
4980
+ while (j < src.length) {
4981
+ const c = src[j];
4982
+ if (c === "\\") {
4983
+ raw += src.slice(j, j + 2);
4984
+ j += 2;
4985
+ continue;
4986
+ }
4987
+ if (c === "(") {
4988
+ depth++;
4989
+ raw += c;
4990
+ j++;
4991
+ continue;
4992
+ }
4993
+ if (c === ")") {
4994
+ depth--;
4995
+ if (depth === 0) {
4996
+ j++;
4997
+ break;
4998
+ }
4999
+ raw += c;
5000
+ j++;
5001
+ continue;
5002
+ }
5003
+ raw += c;
5004
+ j++;
5005
+ }
5006
+ return {
5007
+ text: decodePdfString(raw),
5008
+ next: j
5009
+ };
5010
+ }
5011
+ function readHex(src, i) {
5012
+ const close = src.indexOf(">", i);
5013
+ if (close === -1) return {
5014
+ text: decodeHexString(src.slice(i + 1)),
5015
+ next: src.length
5016
+ };
5017
+ return {
5018
+ text: decodeHexString(src.slice(i + 1, close)),
5019
+ next: close + 1
5020
+ };
5021
+ }
5022
+ function skipWs(src, i) {
5023
+ while (i < src.length && /\s/.test(src[i])) i++;
5024
+ return i;
5025
+ }
5026
+ function readWord(src, i) {
5027
+ let j = i;
5028
+ while (j < src.length && /[A-Za-z0-9*'"]/.test(src[j])) j++;
5029
+ return src.slice(i, j);
5030
+ }
4971
5031
  function textFromContentStream(content) {
4972
5032
  if (!/BT[\s\S]*?ET/.test(content)) return "";
4973
5033
  let out = "";
4974
- const re = /\(((?:\\.|[^\\()])*)\)\s*(Tj|'|")|<([0-9a-fA-F\s]+)>\s*(Tj|'|")|\[((?:\(.*?\)|<[0-9a-fA-F\s]+>|[^\]])*?)\]\s*TJ/g;
4975
- let m;
4976
- while ((m = re.exec(content)) !== null) if (m[1] !== void 0) {
4977
- out += decodePdfString(m[1]);
4978
- if (m[2] === "'" || m[2] === "\"") out += "\n";
4979
- } else if (m[3] !== void 0) {
4980
- out += decodeHexString(m[3]);
4981
- if (m[4] === "'" || m[4] === "\"") out += "\n";
4982
- } else if (m[5] !== void 0) {
4983
- const partRe = /\(((?:\\.|[^\\()])*)\)|<([0-9a-fA-F\s]+)>/g;
4984
- let pm;
4985
- while ((pm = partRe.exec(m[5])) !== null) out += pm[1] !== void 0 ? decodePdfString(pm[1]) : decodeHexString(pm[2] ?? "");
5034
+ let i = 0;
5035
+ const n = content.length;
5036
+ while (i < n) {
5037
+ const c = content[i];
5038
+ if (c === "[") {
5039
+ const parts = [];
5040
+ let j = i + 1;
5041
+ while (j < n && content[j] !== "]") {
5042
+ const d = content[j];
5043
+ if (d === "(") {
5044
+ const r = readLiteral(content, j);
5045
+ parts.push(r.text);
5046
+ j = r.next;
5047
+ } else if (d === "<") {
5048
+ const r = readHex(content, j);
5049
+ parts.push(r.text);
5050
+ j = r.next;
5051
+ } else j++;
5052
+ }
5053
+ if (j >= n) break;
5054
+ if (readWord(content, skipWs(content, j + 1)) === "TJ") out += parts.join("");
5055
+ i = j + 1;
5056
+ continue;
5057
+ }
5058
+ if (c === "(" || c === "<") {
5059
+ const r = c === "(" ? readLiteral(content, i) : readHex(content, i);
5060
+ const op = readWord(content, skipWs(content, r.next));
5061
+ if (op === "Tj" || op === "'" || op === "\"") {
5062
+ out += r.text;
5063
+ if (op !== "Tj") out += "\n";
5064
+ }
5065
+ i = r.next;
5066
+ continue;
5067
+ }
5068
+ i++;
4986
5069
  }
4987
5070
  return out;
4988
5071
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-lookatstudy",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "packageManager": "pnpm@11.7.0",
5
5
  "description": "Turn any markdown, local folder, or GitHub learning repo into a guided course inside DeepSeek Harness: gated skill-tree progression, BKT mastery tracking, SM-2 spaced repetition.",
6
6
  "type": "module",