lewtun HF Staff commited on
Commit
77bdec5
·
1 Parent(s): 7f920f1

Wrap code

Browse files
Files changed (1) hide show
  1. app/scripts/export-txt.mjs +89 -1
app/scripts/export-txt.mjs CHANGED
@@ -64,6 +64,15 @@ function parseArgs(argv) {
64
  return out;
65
  }
66
 
 
 
 
 
 
 
 
 
 
67
  function slugify(text) {
68
  return String(text || '')
69
  .normalize('NFKD')
@@ -106,6 +115,82 @@ function headingToMarkdown(level, text) {
106
  return `${hashes} ${text}`;
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  /**
110
  * Extract and convert article content to TXT format
111
  */
@@ -503,10 +588,13 @@ async function main() {
503
 
504
  console.log('> Extracting article content…');
505
  const txtContent = await extractArticleContent(page);
 
 
 
506
 
507
  // Write output
508
  const outPath = resolve(cwd, 'dist', `${outFileBase}.txt`);
509
- await fs.writeFile(outPath, txtContent, 'utf-8');
510
  console.log(`✅ TXT exported: ${outPath}`);
511
 
512
  // Copy to public folder
 
64
  return out;
65
  }
66
 
67
+ function parseBoolean(value, defaultValue) {
68
+ if (value === undefined) return defaultValue;
69
+ if (value === true) return true;
70
+ const v = String(value).trim().toLowerCase();
71
+ if (['1', 'true', 'yes', 'y', 'on'].includes(v)) return true;
72
+ if (['0', 'false', 'no', 'n', 'off'].includes(v)) return false;
73
+ return defaultValue;
74
+ }
75
+
76
  function slugify(text) {
77
  return String(text || '')
78
  .normalize('NFKD')
 
115
  return `${hashes} ${text}`;
116
  }
117
 
118
+ function wrapLineWithIndent(line, maxWidth) {
119
+ if (line.length <= maxWidth) return [line];
120
+
121
+ const indentMatch = line.match(/^\s*/);
122
+ const indent = indentMatch ? indentMatch[0] : '';
123
+ const indentLen = indent.length;
124
+ const available = Math.max(10, maxWidth - indentLen);
125
+
126
+ let rest = line.slice(indentLen);
127
+ const out = [];
128
+
129
+ while (rest.length > available) {
130
+ let breakPos = -1;
131
+ for (let i = available; i >= 1; i--) {
132
+ if (/\s/.test(rest[i - 1])) {
133
+ breakPos = i;
134
+ break;
135
+ }
136
+ }
137
+ if (breakPos === -1) breakPos = available;
138
+
139
+ const chunk = rest.slice(0, breakPos).replace(/\s+$/g, '');
140
+ out.push(indent + chunk);
141
+ rest = rest.slice(breakPos).replace(/^\s+/g, '');
142
+ }
143
+
144
+ out.push(indent + rest);
145
+ return out;
146
+ }
147
+
148
+ function wrapCodeTextAccountingForTags(codeText, maxWidth) {
149
+ const width = Number(maxWidth);
150
+ if (!Number.isFinite(width) || width <= 0) return String(codeText || '');
151
+
152
+ const baseLines = String(codeText || '').split('\n');
153
+ const wrappedLines = [];
154
+ for (const line of baseLines) wrappedLines.push(...wrapLineWithIndent(line, width));
155
+
156
+ if (wrappedLines.length === 0) return '';
157
+
158
+ // If the whole block is a single line, account for both "<c>" and "</c>" on that line.
159
+ if (wrappedLines.length === 1) {
160
+ const maxInner = width - '<c>'.length - '</c>'.length;
161
+ if (wrappedLines[0].length > maxInner && maxInner > 0) {
162
+ return wrapLineWithIndent(wrappedLines[0], maxInner).join('\n');
163
+ }
164
+ return wrappedLines[0];
165
+ }
166
+
167
+ // Otherwise, "<c>" applies to the first line and "</c>" to the last line only.
168
+ const firstMaxInner = width - '<c>'.length;
169
+ if (firstMaxInner > 0 && wrappedLines[0].length > firstMaxInner) {
170
+ const rewrappedFirst = wrapLineWithIndent(wrappedLines[0], firstMaxInner);
171
+ wrappedLines.splice(0, 1, ...rewrappedFirst);
172
+ }
173
+
174
+ const lastMaxInner = width - '</c>'.length;
175
+ const lastIdx = wrappedLines.length - 1;
176
+ if (lastMaxInner > 0 && wrappedLines[lastIdx].length > lastMaxInner) {
177
+ const rewrappedLast = wrapLineWithIndent(wrappedLines[lastIdx], lastMaxInner);
178
+ wrappedLines.splice(lastIdx, 1, ...rewrappedLast);
179
+ }
180
+
181
+ return wrappedLines.join('\n');
182
+ }
183
+
184
+ function wrapCodeBlocksInTxt(txt, maxWidth = 80) {
185
+ const width = Number(maxWidth);
186
+ if (!Number.isFinite(width) || width <= 0) return txt;
187
+
188
+ return String(txt || '').replace(/<c>([\s\S]*?)<\/c>/g, (_m, inner) => {
189
+ const wrappedInner = wrapCodeTextAccountingForTags(inner, width);
190
+ return `<c>${wrappedInner}</c>`;
191
+ });
192
+ }
193
+
194
  /**
195
  * Extract and convert article content to TXT format
196
  */
 
588
 
589
  console.log('> Extracting article content…');
590
  const txtContent = await extractArticleContent(page);
591
+ const shouldWrapCode = parseBoolean(args['wrap-code'], true);
592
+ const codeWidth = Number(args['code-width'] ?? 80);
593
+ const finalTxtContent = shouldWrapCode ? wrapCodeBlocksInTxt(txtContent, codeWidth) : txtContent;
594
 
595
  // Write output
596
  const outPath = resolve(cwd, 'dist', `${outFileBase}.txt`);
597
+ await fs.writeFile(outPath, finalTxtContent, 'utf-8');
598
  console.log(`✅ TXT exported: ${outPath}`);
599
 
600
  // Copy to public folder