lintpage 0.2.1 → 0.3.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.
- package/README.md +62 -43
- package/dist/cli.cjs +3 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +3 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/{reporter-BSqL5Cvj.mjs → formatter-BhulhYos.mjs} +3 -3
- package/dist/formatter-BhulhYos.mjs.map +1 -0
- package/dist/{reporter-XFqRSceN.cjs → formatter-CJEdbkqw.cjs} +3 -3
- package/dist/formatter-CJEdbkqw.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -8
- package/dist/index.d.mts +1 -8
- package/dist/index.mjs +1 -1
- package/package.json +2 -3
- package/dist/reporter-BSqL5Cvj.mjs.map +0 -1
- package/dist/reporter-XFqRSceN.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import e from"chalk";const t={CRITICAL:e.red.bold(`✗`),WARNING:e.yellow(`⚠`),INFO:e.blue(`ℹ`)},n={CRITICAL:e.red.bold(`CRITICAL`),WARNING:e.yellow(`WARNING`),INFO:e.blue(`INFO`)};function r(e){let t={};for(let n of e)(t[n.category]??=[]).push(n);return t}function i(i,a){let o=[],s=i.overallStatus===`PASS`?e.green:e.red;if(o.push(``),o.push(`${e.bold(`LintPage`)} audit for ${e.underline(i.url)}`),o.push(`Score: ${s.bold(String(i.score))}/100 Status: ${s.bold(i.overallStatus)}`),o.push(``),i.results.length===0)return o.push(e.green(` No issues found!`)),o.push(``),o.join(`
|
|
2
2
|
`);if(a){let t=i.results.filter(e=>e.severity===`CRITICAL`).length,n=i.results.filter(e=>e.severity===`WARNING`).length,r=i.results.filter(e=>e.severity===`INFO`).length;return o.push(` ${e.red.bold(`${t} critical`)} ${e.yellow(`${n} warnings`)} ${e.blue(`${r} info`)}`),o.push(``),o.join(`
|
|
3
3
|
`)}for(let[t,n]of Object.entries(i.categoryScores)){let r=n.max>0?Math.round(n.score/n.max*100):100,i=r>=80?e.green:r>=50?e.yellow:e.red;o.push(` ${e.bold(t.padEnd(16))} ${i(`${n.score}/${n.max}`)} ${e.dim(`(${r}%)`)}`)}o.push(``);let c=r(i.results);for(let[r,i]of Object.entries(c)){o.push(e.bold.underline(` ${r}`));for(let r of i)o.push(` ${t[r.severity]} ${n[r.severity].padEnd(20)} ${r.message}`),r.fix&&o.push(` ${e.dim(r.fix)}`);o.push(``)}return o.join(`
|
|
4
|
-
`)}function a(e){return JSON.stringify(e,null,2)}const o={CRITICAL:`error`,WARNING:`warning`,INFO:`notice`};function s(e){let t=[];for(let n of e.results){let e=o[n.severity],r
|
|
5
|
-
`)}function
|
|
6
|
-
//# sourceMappingURL=
|
|
4
|
+
`)}function a(e){return JSON.stringify(e,null,2)}const o={CRITICAL:`error`,WARNING:`warning`,INFO:`notice`};function s(e){return e.replace(/%/g,`%25`).replace(/\r/g,`%0D`).replace(/\n/g,`%0A`).replace(/:/g,`%3A`).replace(/,/g,`%2C`)}function c(e){let t=[];for(let n of e.results){let e=o[n.severity],r=s(`[${n.ruleId}] ${n.ruleName}`),i=s(n.message);t.push(`::${e} title=${r}::${i}`)}let n=s(`${e.overallStatus===`PASS`?`✅`:`❌`} ${e.url} — Score: ${e.score}/100 (${e.overallStatus})`);return t.push(`::notice title=LintPage Score::${n}`),t.join(`
|
|
5
|
+
`)}function l(e,t,n){switch(t){case`json`:return a(e);case`github`:return c(e);default:return i(e,n)}}export{i,c as n,a as r,l as t};
|
|
6
|
+
//# sourceMappingURL=formatter-BhulhYos.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter-BhulhYos.mjs","names":[],"sources":["../src/formatter.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { PageResult, RuleResult, Severity } from '@lintpage/core';\n\nexport type Format = 'text' | 'json' | 'github';\n\n// ── Text formatter ─────────────────────────────────────────────\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('✗'),\n WARNING: chalk.yellow('⚠'),\n INFO: chalk.blue('ℹ'),\n};\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('CRITICAL'),\n WARNING: chalk.yellow('WARNING'),\n INFO: chalk.blue('INFO'),\n};\n\nfunction groupByCategory(results: RuleResult[]): Record<string, RuleResult[]> {\n const groups: Record<string, RuleResult[]> = {};\n for (const r of results) {\n (groups[r.category] ??= []).push(r);\n }\n return groups;\n}\n\nexport function formatText(result: PageResult, quiet: boolean): string {\n const lines: string[] = [];\n\n const statusColor = result.overallStatus === 'PASS' ? chalk.green : chalk.red;\n lines.push('');\n lines.push(\n `${chalk.bold('LintPage')} audit for ${chalk.underline(result.url)}`\n );\n lines.push(\n `Score: ${statusColor.bold(String(result.score))}/100 Status: ${statusColor.bold(result.overallStatus)}`\n );\n lines.push('');\n\n if (result.results.length === 0) {\n lines.push(chalk.green(' No issues found!'));\n lines.push('');\n return lines.join('\\n');\n }\n\n if (quiet) {\n const critical = result.results.filter((r) => r.severity === 'CRITICAL').length;\n const warnings = result.results.filter((r) => r.severity === 'WARNING').length;\n const info = result.results.filter((r) => r.severity === 'INFO').length;\n lines.push(\n ` ${chalk.red.bold(`${critical} critical`)} ${chalk.yellow(`${warnings} warnings`)} ${chalk.blue(`${info} info`)}`\n );\n lines.push('');\n return lines.join('\\n');\n }\n\n // Category scores\n for (const [category, scores] of Object.entries(result.categoryScores)) {\n const pct = scores.max > 0 ? Math.round((scores.score / scores.max) * 100) : 100;\n const color = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.red;\n lines.push(\n ` ${chalk.bold(category.padEnd(16))} ${color(`${scores.score}/${scores.max}`)} ${chalk.dim(`(${pct}%)`)}`\n );\n }\n lines.push('');\n\n // Issues grouped by category\n const grouped = groupByCategory(result.results);\n for (const [category, issues] of Object.entries(grouped)) {\n lines.push(chalk.bold.underline(` ${category}`));\n for (const issue of issues) {\n lines.push(\n ` ${SEVERITY_ICON[issue.severity]} ${SEVERITY_LABEL[issue.severity].padEnd(20)} ${issue.message}`\n );\n if (issue.fix) {\n lines.push(` ${chalk.dim(issue.fix)}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── JSON formatter ─────────────────────────────────────────────\n\nexport function formatJson(result: PageResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ── GitHub Actions formatter ───────────────────────────────────\n\nconst GH_LEVEL: Record<Severity, string> = {\n CRITICAL: 'error',\n WARNING: 'warning',\n INFO: 'notice',\n};\n\n/**\n * Sanitize a string for use in GitHub Actions workflow commands.\n * Escapes characters that could break or inject annotations.\n * @see https://github.com/actions/toolkit/blob/main/packages/core/src/command.ts\n */\nfunction sanitizeAnnotation(str: string): string {\n return str\n .replace(/%/g, '%25')\n .replace(/\\r/g, '%0D')\n .replace(/\\n/g, '%0A')\n .replace(/:/g, '%3A')\n .replace(/,/g, '%2C');\n}\n\nexport function formatGithub(result: PageResult): string {\n const lines: string[] = [];\n\n for (const issue of result.results) {\n const level = GH_LEVEL[issue.severity];\n const title = sanitizeAnnotation(`[${issue.ruleId}] ${issue.ruleName}`);\n const message = sanitizeAnnotation(issue.message);\n // GitHub annotation format: ::level title=TITLE::MESSAGE\n lines.push(`::${level} title=${title}::${message}`);\n }\n\n // Summary annotation\n const statusEmoji = result.overallStatus === 'PASS' ? '✅' : '❌';\n const summaryMessage = sanitizeAnnotation(\n `${statusEmoji} ${result.url} — Score: ${result.score}/100 (${result.overallStatus})`\n );\n lines.push(\n `::notice title=LintPage Score::${summaryMessage}`\n );\n\n return lines.join('\\n');\n}\n\n// ── Dispatcher ─────────────────────────────────────────────────\n\nexport function format(\n result: PageResult,\n fmt: Format,\n quiet: boolean\n): string {\n switch (fmt) {\n case 'json':\n return formatJson(result);\n case 'github':\n return formatGithub(result);\n case 'text':\n default:\n return formatText(result, quiet);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`chalk`);c=s(c);const l={CRITICAL:c.default.red.bold(`✗`),WARNING:c.default.yellow(`⚠`),INFO:c.default.blue(`ℹ`)},u={CRITICAL:c.default.red.bold(`CRITICAL`),WARNING:c.default.yellow(`WARNING`),INFO:c.default.blue(`INFO`)};function d(e){let t={};for(let n of e)(t[n.category]??=[]).push(n);return t}function f(e,t){let n=[],r=e.overallStatus===`PASS`?c.default.green:c.default.red;if(n.push(``),n.push(`${c.default.bold(`LintPage`)} audit for ${c.default.underline(e.url)}`),n.push(`Score: ${r.bold(String(e.score))}/100 Status: ${r.bold(e.overallStatus)}`),n.push(``),e.results.length===0)return n.push(c.default.green(` No issues found!`)),n.push(``),n.join(`
|
|
2
2
|
`);if(t){let t=e.results.filter(e=>e.severity===`CRITICAL`).length,r=e.results.filter(e=>e.severity===`WARNING`).length,i=e.results.filter(e=>e.severity===`INFO`).length;return n.push(` ${c.default.red.bold(`${t} critical`)} ${c.default.yellow(`${r} warnings`)} ${c.default.blue(`${i} info`)}`),n.push(``),n.join(`
|
|
3
3
|
`)}for(let[t,r]of Object.entries(e.categoryScores)){let e=r.max>0?Math.round(r.score/r.max*100):100,i=e>=80?c.default.green:e>=50?c.default.yellow:c.default.red;n.push(` ${c.default.bold(t.padEnd(16))} ${i(`${r.score}/${r.max}`)} ${c.default.dim(`(${e}%)`)}`)}n.push(``);let i=d(e.results);for(let[e,t]of Object.entries(i)){n.push(c.default.bold.underline(` ${e}`));for(let e of t)n.push(` ${l[e.severity]} ${u[e.severity].padEnd(20)} ${e.message}`),e.fix&&n.push(` ${c.default.dim(e.fix)}`);n.push(``)}return n.join(`
|
|
4
|
-
`)}function p(e){return JSON.stringify(e,null,2)}const m={CRITICAL:`error`,WARNING:`warning`,INFO:`notice`};function h(e){let t=[];for(let n of e.results){let e=m[n.severity],r
|
|
5
|
-
`)}function
|
|
6
|
-
//# sourceMappingURL=
|
|
4
|
+
`)}function p(e){return JSON.stringify(e,null,2)}const m={CRITICAL:`error`,WARNING:`warning`,INFO:`notice`};function h(e){return e.replace(/%/g,`%25`).replace(/\r/g,`%0D`).replace(/\n/g,`%0A`).replace(/:/g,`%3A`).replace(/,/g,`%2C`)}function g(e){let t=[];for(let n of e.results){let e=m[n.severity],r=h(`[${n.ruleId}] ${n.ruleName}`),i=h(n.message);t.push(`::${e} title=${r}::${i}`)}let n=h(`${e.overallStatus===`PASS`?`✅`:`❌`} ${e.url} — Score: ${e.score}/100 (${e.overallStatus})`);return t.push(`::notice title=LintPage Score::${n}`),t.join(`
|
|
5
|
+
`)}function _(e,t,n){switch(t){case`json`:return p(e);case`github`:return g(e);default:return f(e,n)}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return _}});
|
|
6
|
+
//# sourceMappingURL=formatter-CJEdbkqw.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter-CJEdbkqw.cjs","names":[],"sources":["../src/formatter.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { PageResult, RuleResult, Severity } from '@lintpage/core';\n\nexport type Format = 'text' | 'json' | 'github';\n\n// ── Text formatter ─────────────────────────────────────────────\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('✗'),\n WARNING: chalk.yellow('⚠'),\n INFO: chalk.blue('ℹ'),\n};\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('CRITICAL'),\n WARNING: chalk.yellow('WARNING'),\n INFO: chalk.blue('INFO'),\n};\n\nfunction groupByCategory(results: RuleResult[]): Record<string, RuleResult[]> {\n const groups: Record<string, RuleResult[]> = {};\n for (const r of results) {\n (groups[r.category] ??= []).push(r);\n }\n return groups;\n}\n\nexport function formatText(result: PageResult, quiet: boolean): string {\n const lines: string[] = [];\n\n const statusColor = result.overallStatus === 'PASS' ? chalk.green : chalk.red;\n lines.push('');\n lines.push(\n `${chalk.bold('LintPage')} audit for ${chalk.underline(result.url)}`\n );\n lines.push(\n `Score: ${statusColor.bold(String(result.score))}/100 Status: ${statusColor.bold(result.overallStatus)}`\n );\n lines.push('');\n\n if (result.results.length === 0) {\n lines.push(chalk.green(' No issues found!'));\n lines.push('');\n return lines.join('\\n');\n }\n\n if (quiet) {\n const critical = result.results.filter((r) => r.severity === 'CRITICAL').length;\n const warnings = result.results.filter((r) => r.severity === 'WARNING').length;\n const info = result.results.filter((r) => r.severity === 'INFO').length;\n lines.push(\n ` ${chalk.red.bold(`${critical} critical`)} ${chalk.yellow(`${warnings} warnings`)} ${chalk.blue(`${info} info`)}`\n );\n lines.push('');\n return lines.join('\\n');\n }\n\n // Category scores\n for (const [category, scores] of Object.entries(result.categoryScores)) {\n const pct = scores.max > 0 ? Math.round((scores.score / scores.max) * 100) : 100;\n const color = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.red;\n lines.push(\n ` ${chalk.bold(category.padEnd(16))} ${color(`${scores.score}/${scores.max}`)} ${chalk.dim(`(${pct}%)`)}`\n );\n }\n lines.push('');\n\n // Issues grouped by category\n const grouped = groupByCategory(result.results);\n for (const [category, issues] of Object.entries(grouped)) {\n lines.push(chalk.bold.underline(` ${category}`));\n for (const issue of issues) {\n lines.push(\n ` ${SEVERITY_ICON[issue.severity]} ${SEVERITY_LABEL[issue.severity].padEnd(20)} ${issue.message}`\n );\n if (issue.fix) {\n lines.push(` ${chalk.dim(issue.fix)}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── JSON formatter ─────────────────────────────────────────────\n\nexport function formatJson(result: PageResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ── GitHub Actions formatter ───────────────────────────────────\n\nconst GH_LEVEL: Record<Severity, string> = {\n CRITICAL: 'error',\n WARNING: 'warning',\n INFO: 'notice',\n};\n\n/**\n * Sanitize a string for use in GitHub Actions workflow commands.\n * Escapes characters that could break or inject annotations.\n * @see https://github.com/actions/toolkit/blob/main/packages/core/src/command.ts\n */\nfunction sanitizeAnnotation(str: string): string {\n return str\n .replace(/%/g, '%25')\n .replace(/\\r/g, '%0D')\n .replace(/\\n/g, '%0A')\n .replace(/:/g, '%3A')\n .replace(/,/g, '%2C');\n}\n\nexport function formatGithub(result: PageResult): string {\n const lines: string[] = [];\n\n for (const issue of result.results) {\n const level = GH_LEVEL[issue.severity];\n const title = sanitizeAnnotation(`[${issue.ruleId}] ${issue.ruleName}`);\n const message = sanitizeAnnotation(issue.message);\n // GitHub annotation format: ::level title=TITLE::MESSAGE\n lines.push(`::${level} title=${title}::${message}`);\n }\n\n // Summary annotation\n const statusEmoji = result.overallStatus === 'PASS' ? '✅' : '❌';\n const summaryMessage = sanitizeAnnotation(\n `${statusEmoji} ${result.url} — Score: ${result.score}/100 (${result.overallStatus})`\n );\n lines.push(\n `::notice title=LintPage Score::${summaryMessage}`\n );\n\n return lines.join('\\n');\n}\n\n// ── Dispatcher ─────────────────────────────────────────────────\n\nexport function format(\n result: PageResult,\n fmt: Format,\n quiet: boolean\n): string {\n switch (fmt) {\n case 'json':\n return formatJson(result);\n case 'github':\n return formatGithub(result);\n case 'text':\n default:\n return formatText(result, quiet);\n }\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./formatter-CJEdbkqw.cjs`);exports.format=e.t,exports.formatGithub=e.n,exports.formatJson=e.r,exports.formatText=e.i;
|
package/dist/index.d.cts
CHANGED
|
@@ -32,12 +32,5 @@ declare function formatJson(result: PageResult): string;
|
|
|
32
32
|
declare function formatGithub(result: PageResult): string;
|
|
33
33
|
declare function format(result: PageResult, fmt: Format, quiet: boolean): string;
|
|
34
34
|
//#endregion
|
|
35
|
-
|
|
36
|
-
interface ReportOptions {
|
|
37
|
-
apiUrl: string;
|
|
38
|
-
token: string;
|
|
39
|
-
}
|
|
40
|
-
declare function reportResults(result: PageResult, options: ReportOptions): Promise<void>;
|
|
41
|
-
//#endregion
|
|
42
|
-
export { type Format, type ReportOptions, format, formatGithub, formatJson, formatText, reportResults };
|
|
35
|
+
export { type Format, format, formatGithub, formatJson, formatText };
|
|
43
36
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -32,12 +32,5 @@ declare function formatJson(result: PageResult): string;
|
|
|
32
32
|
declare function formatGithub(result: PageResult): string;
|
|
33
33
|
declare function format(result: PageResult, fmt: Format, quiet: boolean): string;
|
|
34
34
|
//#endregion
|
|
35
|
-
|
|
36
|
-
interface ReportOptions {
|
|
37
|
-
apiUrl: string;
|
|
38
|
-
token: string;
|
|
39
|
-
}
|
|
40
|
-
declare function reportResults(result: PageResult, options: ReportOptions): Promise<void>;
|
|
41
|
-
//#endregion
|
|
42
|
-
export { type Format, type ReportOptions, format, formatGithub, formatJson, formatText, reportResults };
|
|
35
|
+
export { type Format, format, formatGithub, formatJson, formatText };
|
|
43
36
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e,n as t,r as n,t as r}from"./formatter-BhulhYos.mjs";export{r as format,t as formatGithub,n as formatJson,e as formatText};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lintpage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "CLI for LintPage — audit website SEO, accessibility, and performance",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"cac": "^6.7.14",
|
|
35
35
|
"chalk": "^5.4.1",
|
|
36
|
-
"jsdom": "^26.1.0"
|
|
37
|
-
"jose": "^6.0.11"
|
|
36
|
+
"jsdom": "^26.1.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@lintpage/core": "workspace:*",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reporter-BSqL5Cvj.mjs","names":[],"sources":["../src/formatter.ts","../src/reporter.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { PageResult, RuleResult, Severity } from '@lintpage/core';\n\nexport type Format = 'text' | 'json' | 'github';\n\n// ── Text formatter ─────────────────────────────────────────────\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('✗'),\n WARNING: chalk.yellow('⚠'),\n INFO: chalk.blue('ℹ'),\n};\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('CRITICAL'),\n WARNING: chalk.yellow('WARNING'),\n INFO: chalk.blue('INFO'),\n};\n\nfunction groupByCategory(results: RuleResult[]): Record<string, RuleResult[]> {\n const groups: Record<string, RuleResult[]> = {};\n for (const r of results) {\n (groups[r.category] ??= []).push(r);\n }\n return groups;\n}\n\nexport function formatText(result: PageResult, quiet: boolean): string {\n const lines: string[] = [];\n\n const statusColor = result.overallStatus === 'PASS' ? chalk.green : chalk.red;\n lines.push('');\n lines.push(\n `${chalk.bold('LintPage')} audit for ${chalk.underline(result.url)}`\n );\n lines.push(\n `Score: ${statusColor.bold(String(result.score))}/100 Status: ${statusColor.bold(result.overallStatus)}`\n );\n lines.push('');\n\n if (result.results.length === 0) {\n lines.push(chalk.green(' No issues found!'));\n lines.push('');\n return lines.join('\\n');\n }\n\n if (quiet) {\n const critical = result.results.filter((r) => r.severity === 'CRITICAL').length;\n const warnings = result.results.filter((r) => r.severity === 'WARNING').length;\n const info = result.results.filter((r) => r.severity === 'INFO').length;\n lines.push(\n ` ${chalk.red.bold(`${critical} critical`)} ${chalk.yellow(`${warnings} warnings`)} ${chalk.blue(`${info} info`)}`\n );\n lines.push('');\n return lines.join('\\n');\n }\n\n // Category scores\n for (const [category, scores] of Object.entries(result.categoryScores)) {\n const pct = scores.max > 0 ? Math.round((scores.score / scores.max) * 100) : 100;\n const color = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.red;\n lines.push(\n ` ${chalk.bold(category.padEnd(16))} ${color(`${scores.score}/${scores.max}`)} ${chalk.dim(`(${pct}%)`)}`\n );\n }\n lines.push('');\n\n // Issues grouped by category\n const grouped = groupByCategory(result.results);\n for (const [category, issues] of Object.entries(grouped)) {\n lines.push(chalk.bold.underline(` ${category}`));\n for (const issue of issues) {\n lines.push(\n ` ${SEVERITY_ICON[issue.severity]} ${SEVERITY_LABEL[issue.severity].padEnd(20)} ${issue.message}`\n );\n if (issue.fix) {\n lines.push(` ${chalk.dim(issue.fix)}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── JSON formatter ─────────────────────────────────────────────\n\nexport function formatJson(result: PageResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ── GitHub Actions formatter ───────────────────────────────────\n\nconst GH_LEVEL: Record<Severity, string> = {\n CRITICAL: 'error',\n WARNING: 'warning',\n INFO: 'notice',\n};\n\nexport function formatGithub(result: PageResult): string {\n const lines: string[] = [];\n\n for (const issue of result.results) {\n const level = GH_LEVEL[issue.severity];\n const title = `[${issue.ruleId}] ${issue.ruleName}`;\n // GitHub annotation format: ::level title=TITLE::MESSAGE\n lines.push(`::${level} title=${title}::${issue.message}`);\n }\n\n // Summary annotation\n const statusEmoji = result.overallStatus === 'PASS' ? '✅' : '❌';\n lines.push(\n `::notice title=LintPage Score::${statusEmoji} ${result.url} — Score: ${result.score}/100 (${result.overallStatus})`\n );\n\n return lines.join('\\n');\n}\n\n// ── Dispatcher ─────────────────────────────────────────────────\n\nexport function format(\n result: PageResult,\n fmt: Format,\n quiet: boolean\n): string {\n switch (fmt) {\n case 'json':\n return formatJson(result);\n case 'github':\n return formatGithub(result);\n case 'text':\n default:\n return formatText(result, quiet);\n }\n}\n","import type { PageResult } from '@lintpage/core';\n\nexport interface ReportOptions {\n apiUrl: string;\n token: string;\n}\n\nexport async function reportResults(\n result: PageResult,\n options: ReportOptions\n): Promise<void> {\n const url = options.apiUrl.replace(/\\/$/, '') + '/api/reports';\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${options.token}`,\n },\n body: JSON.stringify(result),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new Error(\n `Failed to report results: ${response.status} ${response.statusText}${body ? ` — ${body}` : ''}`\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reporter-XFqRSceN.cjs","names":[],"sources":["../src/formatter.ts","../src/reporter.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { PageResult, RuleResult, Severity } from '@lintpage/core';\n\nexport type Format = 'text' | 'json' | 'github';\n\n// ── Text formatter ─────────────────────────────────────────────\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('✗'),\n WARNING: chalk.yellow('⚠'),\n INFO: chalk.blue('ℹ'),\n};\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n CRITICAL: chalk.red.bold('CRITICAL'),\n WARNING: chalk.yellow('WARNING'),\n INFO: chalk.blue('INFO'),\n};\n\nfunction groupByCategory(results: RuleResult[]): Record<string, RuleResult[]> {\n const groups: Record<string, RuleResult[]> = {};\n for (const r of results) {\n (groups[r.category] ??= []).push(r);\n }\n return groups;\n}\n\nexport function formatText(result: PageResult, quiet: boolean): string {\n const lines: string[] = [];\n\n const statusColor = result.overallStatus === 'PASS' ? chalk.green : chalk.red;\n lines.push('');\n lines.push(\n `${chalk.bold('LintPage')} audit for ${chalk.underline(result.url)}`\n );\n lines.push(\n `Score: ${statusColor.bold(String(result.score))}/100 Status: ${statusColor.bold(result.overallStatus)}`\n );\n lines.push('');\n\n if (result.results.length === 0) {\n lines.push(chalk.green(' No issues found!'));\n lines.push('');\n return lines.join('\\n');\n }\n\n if (quiet) {\n const critical = result.results.filter((r) => r.severity === 'CRITICAL').length;\n const warnings = result.results.filter((r) => r.severity === 'WARNING').length;\n const info = result.results.filter((r) => r.severity === 'INFO').length;\n lines.push(\n ` ${chalk.red.bold(`${critical} critical`)} ${chalk.yellow(`${warnings} warnings`)} ${chalk.blue(`${info} info`)}`\n );\n lines.push('');\n return lines.join('\\n');\n }\n\n // Category scores\n for (const [category, scores] of Object.entries(result.categoryScores)) {\n const pct = scores.max > 0 ? Math.round((scores.score / scores.max) * 100) : 100;\n const color = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.red;\n lines.push(\n ` ${chalk.bold(category.padEnd(16))} ${color(`${scores.score}/${scores.max}`)} ${chalk.dim(`(${pct}%)`)}`\n );\n }\n lines.push('');\n\n // Issues grouped by category\n const grouped = groupByCategory(result.results);\n for (const [category, issues] of Object.entries(grouped)) {\n lines.push(chalk.bold.underline(` ${category}`));\n for (const issue of issues) {\n lines.push(\n ` ${SEVERITY_ICON[issue.severity]} ${SEVERITY_LABEL[issue.severity].padEnd(20)} ${issue.message}`\n );\n if (issue.fix) {\n lines.push(` ${chalk.dim(issue.fix)}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── JSON formatter ─────────────────────────────────────────────\n\nexport function formatJson(result: PageResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ── GitHub Actions formatter ───────────────────────────────────\n\nconst GH_LEVEL: Record<Severity, string> = {\n CRITICAL: 'error',\n WARNING: 'warning',\n INFO: 'notice',\n};\n\nexport function formatGithub(result: PageResult): string {\n const lines: string[] = [];\n\n for (const issue of result.results) {\n const level = GH_LEVEL[issue.severity];\n const title = `[${issue.ruleId}] ${issue.ruleName}`;\n // GitHub annotation format: ::level title=TITLE::MESSAGE\n lines.push(`::${level} title=${title}::${issue.message}`);\n }\n\n // Summary annotation\n const statusEmoji = result.overallStatus === 'PASS' ? '✅' : '❌';\n lines.push(\n `::notice title=LintPage Score::${statusEmoji} ${result.url} — Score: ${result.score}/100 (${result.overallStatus})`\n );\n\n return lines.join('\\n');\n}\n\n// ── Dispatcher ─────────────────────────────────────────────────\n\nexport function format(\n result: PageResult,\n fmt: Format,\n quiet: boolean\n): string {\n switch (fmt) {\n case 'json':\n return formatJson(result);\n case 'github':\n return formatGithub(result);\n case 'text':\n default:\n return formatText(result, quiet);\n }\n}\n","import type { PageResult } from '@lintpage/core';\n\nexport interface ReportOptions {\n apiUrl: string;\n token: string;\n}\n\nexport async function reportResults(\n result: PageResult,\n options: ReportOptions\n): Promise<void> {\n const url = options.apiUrl.replace(/\\/$/, '') + '/api/reports';\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${options.token}`,\n },\n body: JSON.stringify(result),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new Error(\n `Failed to report results: ${response.status} ${response.statusText}${body ? ` — ${body}` : ''}`\n );\n }\n}\n"],"mappings":"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"}
|