@grainulation/mill 1.0.0 → 1.0.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 (41) hide show
  1. package/CODE_OF_CONDUCT.md +25 -0
  2. package/CONTRIBUTING.md +101 -0
  3. package/README.md +90 -42
  4. package/bin/mill.js +233 -67
  5. package/lib/exporters/csv.js +35 -30
  6. package/lib/exporters/json-ld.js +19 -13
  7. package/lib/exporters/markdown.js +83 -44
  8. package/lib/exporters/pdf.js +15 -15
  9. package/lib/formats/bibtex.js +41 -34
  10. package/lib/formats/changelog.js +27 -26
  11. package/lib/formats/confluence-adf.js +312 -0
  12. package/lib/formats/csv.js +41 -37
  13. package/lib/formats/dot.js +45 -34
  14. package/lib/formats/evidence-matrix.js +17 -16
  15. package/lib/formats/executive-summary.js +89 -41
  16. package/lib/formats/github-issues.js +40 -33
  17. package/lib/formats/graphml.js +45 -32
  18. package/lib/formats/html-report.js +110 -63
  19. package/lib/formats/jira-csv.js +30 -29
  20. package/lib/formats/json-ld.js +6 -6
  21. package/lib/formats/markdown.js +53 -36
  22. package/lib/formats/ndjson.js +6 -6
  23. package/lib/formats/obsidian.js +43 -35
  24. package/lib/formats/opml.js +38 -28
  25. package/lib/formats/ris.js +29 -23
  26. package/lib/formats/rss.js +31 -28
  27. package/lib/formats/sankey.js +16 -15
  28. package/lib/formats/slide-deck.js +145 -57
  29. package/lib/formats/sql.js +57 -53
  30. package/lib/formats/static-site.js +64 -52
  31. package/lib/formats/treemap.js +16 -15
  32. package/lib/formats/typescript-defs.js +79 -76
  33. package/lib/formats/yaml.js +58 -40
  34. package/lib/formats.js +16 -16
  35. package/lib/index.js +5 -5
  36. package/lib/json-ld-common.js +37 -31
  37. package/lib/publishers/clipboard.js +21 -19
  38. package/lib/publishers/static.js +27 -12
  39. package/lib/serve-mcp.js +158 -83
  40. package/lib/server.js +252 -142
  41. package/package.json +7 -3
@@ -3,13 +3,15 @@
3
3
  *
4
4
  * Single-page HTML showing only active risks, top recommendations,
5
5
  * and confidence-weighted findings. Filters out resolved/low-confidence noise.
6
+ * Accessible: semantic landmarks, table captions/scope, skip link.
6
7
  * Zero dependencies — node built-in only.
7
8
  */
8
9
 
9
- export const name = 'executive-summary';
10
- export const extension = '.html';
11
- export const mimeType = 'text/html; charset=utf-8';
12
- export const description = 'Compact executive summary: active risks, recommendations, evidence coverage';
10
+ export const name = "executive-summary";
11
+ export const extension = ".html";
12
+ export const mimeType = "text/html; charset=utf-8";
13
+ export const description =
14
+ "Compact executive summary: active risks, recommendations, evidence coverage";
13
15
 
14
16
  /**
15
17
  * Convert a compilation object to an executive summary HTML page.
@@ -21,48 +23,65 @@ export function convert(compilation) {
21
23
  const claims = compilation.claims || [];
22
24
  const certificate = compilation.certificate || {};
23
25
 
24
- const title = meta.sprint || meta.question || 'Executive Summary';
26
+ const title = meta.sprint || meta.question || "Executive Summary";
25
27
 
26
28
  // Active risks sorted by confidence desc
27
29
  const risks = claims
28
- .filter(c => c.type === 'risk' && c.status === 'active')
30
+ .filter((c) => c.type === "risk" && c.status === "active")
29
31
  .sort((a, b) => (b.confidence || 0) - (a.confidence || 0));
30
32
 
31
33
  // Active recommendations sorted by confidence desc
32
34
  const recs = claims
33
- .filter(c => c.type === 'recommendation' && c.status === 'active')
35
+ .filter((c) => c.type === "recommendation" && c.status === "active")
34
36
  .sort((a, b) => (b.confidence || 0) - (a.confidence || 0));
35
37
 
36
38
  // Evidence coverage — count by tier
37
- const tierOrder = ['production', 'tested', 'documented', 'web', 'stated'];
39
+ const tierOrder = ["production", "tested", "documented", "web", "stated"];
38
40
  const tierCounts = {};
39
41
  for (const c of claims) {
40
- if (c.status === 'reverted') continue;
41
- const tier = typeof c.evidence === 'string' ? c.evidence : (c.evidence?.tier || c.evidence_tier || 'unknown');
42
+ if (c.status === "reverted") continue;
43
+ const tier =
44
+ typeof c.evidence === "string"
45
+ ? c.evidence
46
+ : c.evidence?.tier || c.evidence_tier || "unknown";
42
47
  tierCounts[tier] = (tierCounts[tier] || 0) + 1;
43
48
  }
44
49
 
45
- const riskRows = risks.map(c => {
46
- const conf = c.confidence != null ? Math.round(c.confidence * 100) + '%' : '--';
47
- const tier = typeof c.evidence === 'string' ? c.evidence : (c.evidence?.tier || '');
48
- return `<tr><td class="mono">${esc(c.id)}</td><td>${esc(c.content || c.text || '')}</td><td class="center">${esc(tier)}</td><td class="center">${conf}</td></tr>`;
49
- }).join('\n');
50
-
51
- const recRows = recs.map(c => {
52
- const conf = c.confidence != null ? Math.round(c.confidence * 100) + '%' : '--';
53
- const tier = typeof c.evidence === 'string' ? c.evidence : (c.evidence?.tier || '');
54
- return `<tr><td class="mono">${esc(c.id)}</td><td>${esc(c.content || c.text || '')}</td><td class="center">${esc(tier)}</td><td class="center">${conf}</td></tr>`;
55
- }).join('\n');
50
+ const riskRows = risks
51
+ .map((c) => {
52
+ const conf =
53
+ c.confidence != null ? Math.round(c.confidence * 100) + "%" : "--";
54
+ const tier =
55
+ typeof c.evidence === "string" ? c.evidence : c.evidence?.tier || "";
56
+ return `<tr><td class="mono">${esc(c.id)}</td><td>${esc(c.content || c.text || "")}</td><td class="center">${esc(tier)}</td><td class="center">${conf}</td></tr>`;
57
+ })
58
+ .join("\n");
59
+
60
+ const recRows = recs
61
+ .map((c) => {
62
+ const conf =
63
+ c.confidence != null ? Math.round(c.confidence * 100) + "%" : "--";
64
+ const tier =
65
+ typeof c.evidence === "string" ? c.evidence : c.evidence?.tier || "";
66
+ return `<tr><td class="mono">${esc(c.id)}</td><td>${esc(c.content || c.text || "")}</td><td class="center">${esc(tier)}</td><td class="center">${conf}</td></tr>`;
67
+ })
68
+ .join("\n");
56
69
 
57
70
  const evidenceRows = tierOrder
58
- .filter(t => tierCounts[t])
59
- .map(t => `<tr><td>${capitalize(t)}</td><td class="center">${tierCounts[t]}</td></tr>`)
60
- .join('\n');
71
+ .filter((t) => tierCounts[t])
72
+ .map(
73
+ (t) =>
74
+ `<tr><td>${capitalize(t)}</td><td class="center">${tierCounts[t]}</td></tr>`,
75
+ )
76
+ .join("\n");
61
77
  // Include unknown tiers
62
78
  const extraTiers = Object.keys(tierCounts)
63
- .filter(t => !tierOrder.includes(t))
64
- .map(t => `<tr><td>${capitalize(t)}</td><td class="center">${tierCounts[t]}</td></tr>`)
65
- .join('\n');
79
+ .filter((t) => !tierOrder.includes(t))
80
+ .map(
81
+ (t) =>
82
+ `<tr><td>${capitalize(t)}</td><td class="center">${tierCounts[t]}</td></tr>`,
83
+ )
84
+ .join("\n");
66
85
 
67
86
  return `<!DOCTYPE html>
68
87
  <html lang="en">
@@ -74,11 +93,14 @@ export function convert(compilation) {
74
93
  :root { --bg:#0a0e1a; --surface:#111827; --border:#1e293b; --text:#e2e8f0; --muted:#94a3b8; }
75
94
  * { margin:0; padding:0; box-sizing:border-box; }
76
95
  body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; line-height:1.6; padding:2rem; max-width:900px; margin:0 auto; }
96
+ a.skip-link { position:absolute; top:-40px; left:0; background:var(--surface); color:var(--text); padding:0.5rem 1rem; z-index:100; border-radius:0 0 4px 0; }
97
+ a.skip-link:focus { top:0; }
77
98
  h1 { font-size:1.6rem; margin-bottom:0.25rem; }
78
99
  .subtitle { color:var(--muted); font-size:0.9rem; margin-bottom:2rem; }
79
100
  h2 { font-size:1.1rem; margin:1.5rem 0 0.75rem; padding-bottom:0.4rem; border-bottom:1px solid var(--border); }
80
101
  h2 .count { color:var(--muted); font-weight:400; }
81
102
  table { width:100%; border-collapse:collapse; margin-bottom:1rem; }
103
+ caption { text-align:left; font-size:0.75rem; color:var(--muted); padding-bottom:0.25rem; caption-side:top; }
82
104
  th { text-align:left; font-size:0.75rem; text-transform:uppercase; color:var(--muted); padding:0.5rem; border-bottom:1px solid var(--border); }
83
105
  td { padding:0.5rem; border-bottom:1px solid var(--border); font-size:0.88rem; vertical-align:top; }
84
106
  .center { text-align:center; }
@@ -90,39 +112,65 @@ export function convert(compilation) {
90
112
  </style>
91
113
  </head>
92
114
  <body>
93
- <h1>${esc(title)}</h1>
94
- <p class="subtitle">${meta.question ? esc(meta.question) : ''}${meta.question && certificate.compiled_at ? ' | ' : ''}${certificate.compiled_at ? 'Compiled: ' + esc(certificate.compiled_at) : ''}</p>
95
-
115
+ <a class="skip-link" href="#main-content">Skip to content</a>
116
+ <header role="banner">
117
+ <h1>${esc(title)}</h1>
118
+ <p class="subtitle">${meta.question ? esc(meta.question) : ""}${meta.question && certificate.compiled_at ? " | " : ""}${certificate.compiled_at ? "Compiled: " + esc(certificate.compiled_at) : ""}</p>
119
+ </header>
120
+
121
+ <main id="main-content">
122
+ <section aria-label="Key risks">
96
123
  <h2>Key Risks <span class="count">(${risks.length})</span></h2>
97
- ${risks.length > 0 ? `
124
+ ${
125
+ risks.length > 0
126
+ ? `
98
127
  <table class="risk-table">
99
- <thead><tr><th>ID</th><th>Description</th><th>Evidence</th><th>Confidence</th></tr></thead>
128
+ <caption>Active risks sorted by confidence</caption>
129
+ <thead><tr><th scope="col">ID</th><th scope="col">Description</th><th scope="col">Evidence</th><th scope="col">Confidence</th></tr></thead>
100
130
  <tbody>${riskRows}</tbody>
101
- </table>` : '<p class="empty">No active risks.</p>'}
131
+ </table>`
132
+ : '<p class="empty">No active risks.</p>'
133
+ }
134
+ </section>
102
135
 
136
+ <section aria-label="Recommendations">
103
137
  <h2>Recommendations <span class="count">(${recs.length})</span></h2>
104
- ${recs.length > 0 ? `
138
+ ${
139
+ recs.length > 0
140
+ ? `
105
141
  <table class="rec-table">
106
- <thead><tr><th>ID</th><th>Description</th><th>Evidence</th><th>Confidence</th></tr></thead>
142
+ <caption>Active recommendations sorted by confidence</caption>
143
+ <thead><tr><th scope="col">ID</th><th scope="col">Description</th><th scope="col">Evidence</th><th scope="col">Confidence</th></tr></thead>
107
144
  <tbody>${recRows}</tbody>
108
- </table>` : '<p class="empty">No active recommendations.</p>'}
145
+ </table>`
146
+ : '<p class="empty">No active recommendations.</p>'
147
+ }
148
+ </section>
109
149
 
150
+ <section aria-label="Evidence coverage">
110
151
  <h2>Evidence Coverage</h2>
111
152
  <table>
112
- <thead><tr><th>Tier</th><th>Claims</th></tr></thead>
153
+ <caption>Claims count per evidence tier</caption>
154
+ <thead><tr><th scope="col">Tier</th><th scope="col">Claims</th></tr></thead>
113
155
  <tbody>${evidenceRows}${extraTiers}</tbody>
114
156
  </table>
157
+ </section>
158
+ </main>
115
159
 
116
- <footer>
117
- Certificate: ${certificate.claim_count || claims.length} claims | sha256:${(certificate.sha256 || 'unknown').slice(0, 16)}
160
+ <footer role="contentinfo">
161
+ Certificate: ${certificate.claim_count || claims.length} claims | sha256:${(certificate.sha256 || "unknown").slice(0, 16)}
118
162
  </footer>
119
163
  </body>
120
164
  </html>`;
121
165
  }
122
166
 
123
167
  function esc(str) {
124
- if (str == null) return '';
125
- return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
168
+ if (str == null) return "";
169
+ return String(str)
170
+ .replace(/&/g, "&amp;")
171
+ .replace(/</g, "&lt;")
172
+ .replace(/>/g, "&gt;")
173
+ .replace(/"/g, "&quot;");
126
174
  }
127
175
 
128
176
  function capitalize(str) {
@@ -6,10 +6,11 @@
6
6
  * Zero dependencies — node built-in only.
7
7
  */
8
8
 
9
- export const name = 'github-issues';
10
- export const extension = '.md';
11
- export const mimeType = 'text/markdown; charset=utf-8';
12
- export const description = 'Claims as GitHub issue templates (one markdown file, horizontal-rule separated)';
9
+ export const name = "github-issues";
10
+ export const extension = ".md";
11
+ export const mimeType = "text/markdown; charset=utf-8";
12
+ export const description =
13
+ "Claims as GitHub issue templates (one markdown file, horizontal-rule separated)";
13
14
 
14
15
  /**
15
16
  * Convert a compilation object to GitHub issue markdown.
@@ -19,71 +20,77 @@ export const description = 'Claims as GitHub issue templates (one markdown file,
19
20
  export function convert(compilation) {
20
21
  const meta = compilation.meta || {};
21
22
  const claims = compilation.claims || [];
22
- const sprint = meta.sprint || 'unknown';
23
+ const sprint = meta.sprint || "unknown";
23
24
 
24
25
  const lines = [];
25
26
 
26
27
  lines.push(`# GitHub Issues: ${sprint}`);
27
- lines.push('');
28
- lines.push('> Bulk-create with the `gh` CLI:');
29
- lines.push('> ```');
30
- lines.push('> # Split this file by "---" and create each section as an issue:');
31
- lines.push(`> # gh issue create --title "TITLE" --body "BODY" --label "TYPE"`);
32
- lines.push('> ```');
33
- lines.push('');
28
+ lines.push("");
29
+ lines.push("> Bulk-create with the `gh` CLI:");
30
+ lines.push("> ```");
31
+ lines.push(
32
+ '> # Split this file by "---" and create each section as an issue:',
33
+ );
34
+ lines.push(
35
+ `> # gh issue create --title "TITLE" --body "BODY" --label "TYPE"`,
36
+ );
37
+ lines.push("> ```");
38
+ lines.push("");
34
39
 
35
40
  if (claims.length === 0) {
36
- lines.push('_No claims to export._');
37
- return lines.join('\n') + '\n';
41
+ lines.push("_No claims to export._");
42
+ return lines.join("\n") + "\n";
38
43
  }
39
44
 
40
45
  for (let i = 0; i < claims.length; i++) {
41
46
  if (i > 0) {
42
- lines.push('');
47
+ lines.push("");
43
48
  }
44
- lines.push('---');
45
- lines.push('');
49
+ lines.push("---");
50
+ lines.push("");
46
51
  lines.push(...formatClaim(claims[i]));
47
52
  }
48
53
 
49
- lines.push('');
50
- return lines.join('\n') + '\n';
54
+ lines.push("");
55
+ return lines.join("\n") + "\n";
51
56
  }
52
57
 
53
58
  function formatClaim(claim) {
54
- const id = claim.id || '???';
55
- const content = claim.content || claim.text || '';
56
- const type = claim.type || 'unknown';
59
+ const id = claim.id || "???";
60
+ const content = claim.content || claim.text || "";
61
+ const type = claim.type || "unknown";
57
62
  const evidence = getEvidence(claim);
58
- const status = claim.status || 'unknown';
63
+ const status = claim.status || "unknown";
59
64
  const tags = Array.isArray(claim.tags) ? claim.tags : [];
60
65
  const summary = truncate(content, 80);
61
66
 
62
67
  const lines = [];
63
68
 
64
69
  lines.push(`## ${id}: ${summary}`);
65
- lines.push('');
66
- lines.push(`**Type:** ${type} | **Evidence:** ${evidence} | **Status:** ${status}`);
67
- lines.push('');
70
+ lines.push("");
71
+ lines.push(
72
+ `**Type:** ${type} | **Evidence:** ${evidence} | **Status:** ${status}`,
73
+ );
74
+ lines.push("");
68
75
  lines.push(content);
69
76
 
70
77
  if (tags.length > 0) {
71
- lines.push('');
72
- lines.push(`**Tags:** ${tags.join(', ')}`);
78
+ lines.push("");
79
+ lines.push(`**Tags:** ${tags.join(", ")}`);
73
80
  }
74
81
 
75
82
  return lines;
76
83
  }
77
84
 
78
85
  function getEvidence(claim) {
79
- if (typeof claim.evidence === 'string') return claim.evidence;
80
- if (typeof claim.evidence === 'object' && claim.evidence !== null) {
81
- return claim.evidence.tier || claim.evidence_tier || 'stated';
86
+ if (typeof claim.evidence === "string") return claim.evidence;
87
+ if (typeof claim.evidence === "object" && claim.evidence !== null) {
88
+ return claim.evidence.tier || claim.evidence_tier || "stated";
82
89
  }
83
- return claim.evidence_tier || 'stated';
90
+ return claim.evidence_tier || "stated";
84
91
  }
85
92
 
86
93
  function truncate(str, max) {
87
94
  if (str.length <= max) return str;
88
- return str.slice(0, max - 3) + '...';
95
+ return str.slice(0, max - 3) + "...";
89
96
  }
@@ -6,10 +6,11 @@
6
6
  * Zero dependencies — node built-in only.
7
7
  */
8
8
 
9
- export const name = 'graphml';
10
- export const extension = '.graphml';
11
- export const mimeType = 'application/graphml+xml; charset=utf-8';
12
- export const description = 'Claims as GraphML graph (nodes per claim, edges for shared tags)';
9
+ export const name = "graphml";
10
+ export const extension = ".graphml";
11
+ export const mimeType = "application/graphml+xml; charset=utf-8";
12
+ export const description =
13
+ "Claims as GraphML graph (nodes per claim, edges for shared tags)";
13
14
 
14
15
  /**
15
16
  * Convert a compilation object to GraphML XML.
@@ -22,32 +23,42 @@ export function convert(compilation) {
22
23
  const lines = [];
23
24
  lines.push('<?xml version="1.0" encoding="utf-8"?>');
24
25
  lines.push('<graphml xmlns="http://graphml.graphstruct.org/graphml">');
25
- lines.push(' <key id="type" for="node" attr.name="type" attr.type="string"/>');
26
- lines.push(' <key id="evidence" for="node" attr.name="evidence" attr.type="string"/>');
27
- lines.push(' <key id="content" for="node" attr.name="content" attr.type="string"/>');
28
- lines.push(' <key id="status" for="node" attr.name="status" attr.type="string"/>');
29
- lines.push(' <key id="confidence" for="node" attr.name="confidence" attr.type="double"/>');
26
+ lines.push(
27
+ ' <key id="type" for="node" attr.name="type" attr.type="string"/>',
28
+ );
29
+ lines.push(
30
+ ' <key id="evidence" for="node" attr.name="evidence" attr.type="string"/>',
31
+ );
32
+ lines.push(
33
+ ' <key id="content" for="node" attr.name="content" attr.type="string"/>',
34
+ );
35
+ lines.push(
36
+ ' <key id="status" for="node" attr.name="status" attr.type="string"/>',
37
+ );
38
+ lines.push(
39
+ ' <key id="confidence" for="node" attr.name="confidence" attr.type="double"/>',
40
+ );
30
41
  lines.push(' <key id="tag" for="edge" attr.name="tag" attr.type="string"/>');
31
42
  lines.push(' <graph id="G" edgedefault="undirected">');
32
43
 
33
44
  // Nodes
34
45
  for (const claim of claims) {
35
- const id = esc(claim.id || '');
36
- const type = esc(claim.type || '');
46
+ const id = esc(claim.id || "");
47
+ const type = esc(claim.type || "");
37
48
  const evidence = esc(getEvidence(claim));
38
- const content = esc(claim.content || claim.text || '');
39
- const status = esc(claim.status || '');
40
- const confidence = claim.confidence != null ? claim.confidence : '';
49
+ const content = esc(claim.content || claim.text || "");
50
+ const status = esc(claim.status || "");
51
+ const confidence = claim.confidence != null ? claim.confidence : "";
41
52
 
42
53
  lines.push(` <node id="${id}">`);
43
54
  lines.push(` <data key="type">${type}</data>`);
44
55
  lines.push(` <data key="evidence">${evidence}</data>`);
45
56
  lines.push(` <data key="content">${content}</data>`);
46
57
  lines.push(` <data key="status">${status}</data>`);
47
- if (confidence !== '') {
58
+ if (confidence !== "") {
48
59
  lines.push(` <data key="confidence">${confidence}</data>`);
49
60
  }
50
- lines.push(' </node>');
61
+ lines.push(" </node>");
51
62
  }
52
63
 
53
64
  // Edges: connect claims that share at least one tag
@@ -55,15 +66,17 @@ export function convert(compilation) {
55
66
  let edgeId = 0;
56
67
  for (const edge of edges) {
57
68
  edgeId++;
58
- lines.push(` <edge id="e${edgeId}" source="${esc(edge.source)}" target="${esc(edge.target)}">`);
69
+ lines.push(
70
+ ` <edge id="e${edgeId}" source="${esc(edge.source)}" target="${esc(edge.target)}">`,
71
+ );
59
72
  lines.push(` <data key="tag">${esc(edge.tag)}</data>`);
60
- lines.push(' </edge>');
73
+ lines.push(" </edge>");
61
74
  }
62
75
 
63
- lines.push(' </graph>');
64
- lines.push('</graphml>');
76
+ lines.push(" </graph>");
77
+ lines.push("</graphml>");
65
78
 
66
- return lines.join('\n') + '\n';
79
+ return lines.join("\n") + "\n";
67
80
  }
68
81
 
69
82
  /**
@@ -77,7 +90,7 @@ function buildTagEdges(claims) {
77
90
  const tags = Array.isArray(claim.tags) ? claim.tags : [];
78
91
  for (const tag of tags) {
79
92
  if (!tagMap[tag]) tagMap[tag] = [];
80
- tagMap[tag].push(claim.id || '');
93
+ tagMap[tag].push(claim.id || "");
81
94
  }
82
95
  }
83
96
 
@@ -100,19 +113,19 @@ function buildTagEdges(claims) {
100
113
  }
101
114
 
102
115
  function getEvidence(claim) {
103
- if (typeof claim.evidence === 'string') return claim.evidence;
104
- if (typeof claim.evidence === 'object' && claim.evidence !== null) {
105
- return claim.evidence.tier || claim.evidence_tier || '';
116
+ if (typeof claim.evidence === "string") return claim.evidence;
117
+ if (typeof claim.evidence === "object" && claim.evidence !== null) {
118
+ return claim.evidence.tier || claim.evidence_tier || "";
106
119
  }
107
- return claim.evidence_tier || '';
120
+ return claim.evidence_tier || "";
108
121
  }
109
122
 
110
123
  function esc(str) {
111
- if (str == null) return '';
124
+ if (str == null) return "";
112
125
  return String(str)
113
- .replace(/&/g, '&amp;')
114
- .replace(/</g, '&lt;')
115
- .replace(/>/g, '&gt;')
116
- .replace(/"/g, '&quot;')
117
- .replace(/'/g, '&apos;');
126
+ .replace(/&/g, "&amp;")
127
+ .replace(/</g, "&lt;")
128
+ .replace(/>/g, "&gt;")
129
+ .replace(/"/g, "&quot;")
130
+ .replace(/'/g, "&apos;");
118
131
  }