{"format":1,"manifest":{"name":"lint-runner","publisher":"vyloxi","version":"1.0.0","displayName":"Lint Runner","description":"Runs ESLint, Ruff or Stylelint on the open file and paints the problems as underlines with the message on hover.","engines":{"ferrum":"^0.1.1"},"categories":["Linters"],"icon":"icon.png","repository":"https://github.com/voukengdongmofrankysteve/ferrum-market","license":"MIT","main":"extension.js","activationEvents":["onStartup"],"permissions":["terminal","workspace.read","workspace.write"],"contributes":{"commands":[{"command":"lintRunner.run","title":"Check This File","category":"Lint Runner"},{"command":"lintRunner.list","title":"List Problems...","category":"Lint Runner"},{"command":"lintRunner.next","title":"Go to the Next Problem","category":"Lint Runner"},{"command":"lintRunner.clear","title":"Clear Problems","category":"Lint Runner"}],"keybindings":[{"command":"lintRunner.next","key":"Alt+F8"}],"configuration":{"title":"Lint Runner","properties":{"lintRunner.linter":{"type":"string","enum":["auto","eslint","ruff","stylelint"],"default":"auto","description":"Which linter to use. Auto picks by file type: ESLint for JavaScript and TypeScript, Ruff for Python, Stylelint for CSS."},"lintRunner.onSave":{"type":"boolean","default":false,"description":"Check the file every time you save."}}}}},"files":{"icon.png":{"encoding":"base64","content":"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"},"extension.js":{"encoding":"utf8","content":"// Lint Runner: runs ESLint, Ruff or Stylelint on the open file and paints the problems in the editor as colored underlines\n// with the message on hover, a count in the status bar and a list you can jump through. Needs the linter installed in your project.\n// The linter writes its JSON report to .ferrum/lint, which this extension reads.\n\nconst DIR = '.ferrum/lint';\n\nconst LINTERS = {\n  eslint: { name: 'ESLint', exts: 'js jsx mjs cjs ts tsx vue svelte', report: DIR + '/eslint.json', command: (f, r) => `npx eslint -f json -o \"${r}\" \"${f}\"` },\n  ruff: { name: 'Ruff', exts: 'py pyi', report: DIR + '/ruff.json', command: (f, r) => `ruff check --output-format=json --output-file \"${r}\" \"${f}\"` },\n  stylelint: { name: 'Stylelint', exts: 'css scss less', report: DIR + '/stylelint.json', command: (f, r) => `npx stylelint -f json -o \"${r}\" \"${f}\"` },\n};\n\nfunction linterFor(path, forced) {\n  if (forced && forced !== 'auto' && LINTERS[forced]) return forced;\n  const ext = String(path || '').split('.').pop().toLowerCase();\n  return Object.keys(LINTERS).find((k) => LINTERS[k].exts.split(' ').includes(ext)) || null;\n}\n\n/** Turns a linter report into problems: { line, col, endLine, endCol, severity: 'error'|'warning', message, rule }. Lines and columns start at 0. */\nfunction parse(linter, text) {\n  let data;\n  try { data = JSON.parse(text); } catch { return null; }\n  if (!Array.isArray(data)) return null;\n  const out = [];\n  if (linter === 'eslint') {\n    for (const f of data) for (const m of f.messages || []) out.push({ line: (m.line || 1) - 1, col: (m.column || 1) - 1, endLine: (m.endLine || m.line || 1) - 1, endCol: (m.endColumn || m.column || 1) - 1, severity: m.severity === 2 ? 'error' : 'warning', message: m.message, rule: m.ruleId || '' });\n  } else if (linter === 'ruff') {\n    for (const m of data) out.push({ line: (m.location?.row || 1) - 1, col: (m.location?.column || 1) - 1, endLine: (m.end_location?.row || m.location?.row || 1) - 1, endCol: (m.end_location?.column || m.location?.column || 1) - 1, severity: /^(E9|F)/.test(m.code || '') ? 'error' : 'warning', message: m.message, rule: m.code || '' });\n  } else if (linter === 'stylelint') {\n    for (const f of data) for (const m of f.warnings || []) out.push({ line: (m.line || 1) - 1, col: (m.column || 1) - 1, endLine: (m.endLine || m.line || 1) - 1, endCol: (m.endColumn || m.column || 1) - 1, severity: m.severity === 'error' ? 'error' : 'warning', message: String(m.text || '').replace(/\\s*\\([^)]*\\)$/, ''), rule: m.rule || '' });\n  }\n  return out.sort((a, b) => a.line - b.line || a.col - b.col);\n}\n\nconst unsafePath = (p) => /[\"\\n\\r$`]/.test(p);\nconst relative = (root, p) => (root && p.startsWith(root) ? p.slice(root.length).replace(/^[\\\\/]+/, '') : p);\n\nexports._test = { linterFor, parse, LINTERS, relative };\n\nexports.activate = function (context) {\n  let problems = [];\n  let types = null;\n  const reg = (id, fn) => context.subscriptions.push(ferrum.commands.register(id, fn));\n  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));\n\n  types = {\n    error: ferrum.editor.createDecorationType({ textDecoration: 'underline wavy', backgroundColor: 'rgba(239, 68, 68, 0.14)', gutterText: '●', gutterColor: '#ef4444' }),\n    warning: ferrum.editor.createDecorationType({ textDecoration: 'underline wavy', backgroundColor: 'rgba(245, 158, 11, 0.14)', gutterText: '●', gutterColor: '#f59e0b' }),\n  };\n  context.subscriptions.push(types.error, types.warning);\n\n  async function paint(path) {\n    const mk = (sev) => problems.filter((p) => p.severity === sev).map((p) => ({\n      start: { line: p.line, col: p.col },\n      end: { line: p.endLine, col: Math.max(p.endCol, p.endLine === p.line ? p.col + 1 : 0) },\n      hoverMessage: p.message + (p.rule ? '  (' + p.rule + ')' : ''),\n    }));\n    await ferrum.editor.setDecorations(types.error, mk('error'), path);\n    await ferrum.editor.setDecorations(types.warning, mk('warning'), path);\n    const e = problems.filter((p) => p.severity === 'error').length;\n    const w = problems.length - e;\n    ferrum.window.setStatusBar('lintRunner.status', { text: problems.length ? 'Lint: ' + e + ' error' + (e === 1 ? '' : 's') + ', ' + w + ' warning' + (w === 1 ? '' : 's') : 'Lint: clean', tooltip: 'Click to list the problems', command: 'lintRunner.list' });\n  }\n\n  async function lint(quiet) {\n    const doc = await ferrum.editor.active();\n    if (!doc || !doc.path) return quiet ? undefined : ferrum.window.showMessage('Open and save a file first.', 'warn');\n    if (!ferrum.workspace.root) return quiet ? undefined : ferrum.window.showMessage('Open a folder first.', 'warn');\n    const key = linterFor(doc.path, ferrum.settings.get('lintRunner.linter'));\n    if (!key) return quiet ? undefined : ferrum.window.showMessage('No linter is set up for this kind of file. Supported: ESLint (JavaScript, TypeScript, Vue, Svelte), Ruff (Python), Stylelint (CSS, SCSS).', 'warn');\n    if (unsafePath(doc.path)) return ferrum.window.showMessage('The path of this file has characters I will not put in a command.', 'warn');\n    if (doc.dirty) await ferrum.commands.execute('file.save');\n    const l = LINTERS[key];\n    const rel = relative(ferrum.workspace.root, doc.path);\n    await ferrum.workspace.writeFile(l.report, '');\n    await ferrum.terminal.run(l.command(rel, l.report));\n    const t0 = Date.now();\n    let parsed = null;\n    while (Date.now() - t0 < 45000) {\n      await sleep(600);\n      let text = '';\n      try { text = await ferrum.workspace.readFile(l.report); } catch { text = ''; }\n      if (text.trim()) { parsed = parse(key, text); if (parsed) break; }\n    }\n    if (!parsed) return ferrum.window.showMessage(l.name + ' did not produce a report. Is it installed in this project? See the terminal.', 'warn');\n    problems = parsed;\n    await paint(doc.path);\n    if (!quiet) ferrum.window.showMessage(problems.length ? l.name + ': ' + problems.length + ' problem' + (problems.length === 1 ? '' : 's') + '.' : l.name + ': no problems.');\n  }\n\n  reg('lintRunner.run', () => lint(false));\n  reg('lintRunner.list', async () => {\n    if (!problems.length) return ferrum.window.showMessage('No problems. Run \"Lint: Check This File\" first.');\n    const pick = await ferrum.window.showQuickPick(problems.map((p) => ({ label: p.message, detail: 'Line ' + (p.line + 1) + ', column ' + (p.col + 1) + (p.rule ? '  ·  ' + p.rule : ''), description: p.severity, p })), { placeholder: problems.length + ' problems. Pick one to go there.' });\n    if (pick) await ferrum.editor.setSelection({ line: pick.p.line, col: pick.p.col }, { line: pick.p.endLine, col: pick.p.endCol });\n  });\n  reg('lintRunner.next', async () => {\n    if (!problems.length) return ferrum.window.showMessage('No problems recorded. Run \"Lint: Check This File\" first.');\n    const doc = await ferrum.editor.active();\n    const at = doc ? doc.selection.start : { line: -1, col: -1 };\n    const next = problems.find((p) => p.line > at.line || (p.line === at.line && p.col > at.col)) || problems[0];\n    await ferrum.editor.setSelection({ line: next.line, col: next.col }, { line: next.endLine, col: next.endCol });\n  });\n  reg('lintRunner.clear', async () => {\n    problems = [];\n    await paint();\n    ferrum.window.setStatusBar('lintRunner.status', { text: '' });\n  });\n\n  context.subscriptions.push(\n    ferrum.events.on('save', () => { if (ferrum.settings.get('lintRunner.onSave') === true) lint(true).catch(() => {}); }),\n    ferrum.events.on('activeChanged', () => { problems = []; paint().catch(() => {}); }),\n  );\n};\n\nexports.deactivate = function () {};\n"},"README.md":{"encoding":"utf8","content":"# Lint Runner\n\nRun your project's own linter on the open file and see the problems **in the editor**: red wavy underlines for errors, amber for warnings, a dot in the gutter, the message on hover, a count in the status bar, a list to jump through (**Alt+F8** goes to the next one).\n\n| Linter | For | Needs |\n| --- | --- | --- |\n| ESLint | JavaScript, TypeScript, Vue, Svelte | ESLint in your project (`npx eslint`) |\n| Ruff | Python | `ruff` on your PATH |\n| Stylelint | CSS, SCSS, Less | Stylelint in your project |\n\n## How it works, honestly\n\nThe extension cannot read the terminal. It types the linter command in the terminal (you see it) with an option that makes the linter write its **JSON report to `.ferrum/lint/`**, then reads that file and paints the result. If the linter is missing or crashes, no report arrives and you are told to look at the terminal. Turn on `lintRunner.onSave` to check on every save.\n\nUses the **decorations** API (Ferrum 0.3.1 and later).\n\n## Permissions\n\n**terminal** to run the linter, **workspace.read** and **workspace.write** for the report file.\n"}}}