@swiftuijs/twill-linter 0.1.0 → 0.1.2
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 +4 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Twill linter
|
|
1
|
+
# <img src="https://twill.evecalm.com/logo.png" alt="Twill hummingbird" align="right" width="40" height="40" /> Twill linter
|
|
2
2
|
|
|
3
|
-
An ESLint 9/10 flat-config plugin for `.twill` and `.twillx
|
|
3
|
+
An ESLint 9/10 flat-config plugin for Twill, a TypeScript-based language with Swift-inspired syntax extensions. Lint `.twill` and `.twillx` with typescript-eslint rules, original-source diagnostics and conservative fixes.
|
|
4
4
|
|
|
5
5
|
Install in your application:
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ pnpm exec eslint src --fix
|
|
|
26
26
|
|
|
27
27
|
`recommended` supplies standard JS and typescript-eslint recommended rules. `recommendedTypeChecked` additionally supplies typed rules; Twill files need a nearby tsconfig and are checked against Twill's virtual TypeScript program. Native TS files use typescript-eslint's project service normally. Add ordinary framework/environment globals as with any ESLint project.
|
|
28
28
|
|
|
29
|
-
`recommendedTypeChecked` also enables `@typescript-eslint/switch-exhaustiveness-check`. A switch over a discriminated union must explicitly cover each variant, even when it has a `default` branch. Adding a variant then exposes missing handlers in both Twill and native TS files. This check is opt-in linting, not a new compiler guarantee; run ESLint in CI to enforce it. Ordinary `recommended` does not require type information. See [practical patterns](https://
|
|
29
|
+
`recommendedTypeChecked` also enables `@typescript-eslint/switch-exhaustiveness-check`. A switch over a discriminated union must explicitly cover each variant, even when it has a `default` branch. Adding a variant then exposes missing handlers in both Twill and native TS files. This check is opt-in linting, not a new compiler guarantee; run ESLint in CI to enforce it. Ordinary `recommended` does not require type information. See [practical patterns](https://twill.evecalm.com/patterns) for an example.
|
|
30
30
|
|
|
31
31
|
The processor honors the project Twill/JSX settings. Generated-only diagnostics are suppressed. Fixes and suggestions are offered only when their ranges and replaced text map exactly to original source; fixes requiring compiler-generated syntax are withheld. `disposeProjects()` releases the cached typed projects when embedding the plugin in a long-lived process. The typed cache checks existing project/configuration file mtimes; restart linting after adding/deleting files to refresh discovered roots.
|
|
32
32
|
|
|
@@ -40,4 +40,4 @@ Custom rule overrides should also match the virtual TS/TSX files, as with other
|
|
|
40
40
|
|
|
41
41
|
Framework ESLint plugins can attach their ordinary TS/TSX rules to these virtual files. Keep ESLint formatting rules disabled and let Prettier handle layout; rewrites spanning generated syntax cannot always be mapped back safely.
|
|
42
42
|
|
|
43
|
-
[Documentation](https://
|
|
43
|
+
[Documentation](https://twill.evecalm.com/tooling) · [Issues](https://github.com/swiftuijs/twill/issues) · MIT licensed · Built by [forth.ink](https://forth.ink).
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { dirname } from "node:path";
|
|
|
9
9
|
import { statSync } from "node:fs";
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "@swiftuijs/twill-linter",
|
|
12
|
-
version: "0.1.
|
|
12
|
+
version: "0.1.2",
|
|
13
13
|
type: "module",
|
|
14
14
|
license: "MIT",
|
|
15
15
|
repository: {
|
|
@@ -59,7 +59,7 @@ var package_default = {
|
|
|
59
59
|
"name": "forth.ink",
|
|
60
60
|
"url": "https://forth.ink"
|
|
61
61
|
},
|
|
62
|
-
homepage: "https://
|
|
62
|
+
homepage: "https://twill.evecalm.com/",
|
|
63
63
|
bugs: { "url": "https://github.com/swiftuijs/twill/issues" },
|
|
64
64
|
keywords: [
|
|
65
65
|
"twill",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["files","metadata"],"sources":["../package.json","../src/positions.ts","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@swiftuijs/twill-linter\",\n \"version\": \"0.1.0\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/swiftuijs/twill.git\",\n \"directory\": \"packages/linter\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"vite build\",\n \"typecheck\": \"tsc --noEmit -p tsconfig.json\",\n \"test:unit\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:package\": \"node tests/consumer.mjs\",\n \"prepack\": \"pnpm run build\",\n \"test\": \"pnpm run test:unit\"\n },\n \"dependencies\": {\n \"@swiftuijs/twill\": \"workspace:*\",\n \"@typescript-eslint/parser\": \"^8.71.0\",\n \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n \"@eslint/js\": \"catalog:\",\n \"typescript\": \"catalog:\"\n },\n \"devDependencies\": {\n \"vite\": \"catalog:\",\n \"vite-plugin-dts\": \"^5.1.2\",\n \"@types/node\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"eslint\": \"catalog:\",\n \"vitest\": \"catalog:\",\n \"@vitest/coverage-v8\": \"catalog:\"\n },\n \"engines\": {\n \"node\": \"^20.19.0 || >=22.12.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"peerDependencies\": {\n \"eslint\": \"^9.0.0 || ^10.0.0\"\n },\n \"author\": {\n \"name\": \"forth.ink\",\n \"url\": \"https://forth.ink\"\n },\n \"homepage\": \"https://swiftuijs.github.io/twill/\",\n \"bugs\": {\n \"url\": \"https://github.com/swiftuijs/twill/issues\"\n },\n \"keywords\": [\n \"twill\",\n \"eslint\",\n \"eslint-plugin\",\n \"typescript\",\n \"linter\"\n ],\n \"description\": \"ESLint flat configurations for Twill with TypeScript rules, original-source diagnostics and safe fixes.\"\n}\n","/** Source-map lines use LF; ESLint positions also count CR and Unicode separators. */\nexport class SourcePositions {\n private native = [0];\n private mapped = [0];\n\n constructor(text: string) {\n const breaks = /\\r\\n|[\\n\\r\\u2028\\u2029]/g;\n while (breaks.exec(text)) this.native.push(breaks.lastIndex);\n for (let index = 0; index < text.length; index++)\n if (text[index] === '\\n') this.mapped.push(index + 1);\n }\n\n private position(starts: number[], offset: number) {\n let low = 0;\n let high = starts.length;\n while (low + 1 < high) {\n const middle = (low + high) >>> 1;\n if (starts[middle]! <= offset) low = middle;\n else high = middle;\n }\n return { line: low, character: offset - starts[low]! };\n }\n\n getLineAndCharacterOfPosition(offset: number) {\n return this.position(this.native, offset);\n }\n\n getPositionOfLineAndCharacter(line: number, column: number) {\n return this.native[line]! + column;\n }\n\n mapPosition(offset: number) {\n const position = this.position(this.mapped, offset);\n return { line: position.line + 1, column: position.character };\n }\n\n mapOffset(line: number, column: number) {\n return this.mapped[line - 1]! + column;\n }\n}\n","import {\n transform,\n originalPosition,\n generatedPosition,\n type TransformResult,\n} from '@swiftuijs/twill';\nimport { TwillProject, virtualFilename, sourceFilename } from '@swiftuijs/twill/project';\nimport * as parser from '@typescript-eslint/parser';\nimport typescriptPlugin from '@typescript-eslint/eslint-plugin';\nimport js from '@eslint/js';\nimport ts from 'typescript';\nimport { loadConfig } from '@swiftuijs/twill/config';\nimport { dirname, resolve } from 'node:path';\nimport { statSync } from 'node:fs';\nimport type { ESLint, Linter, Rule } from 'eslint';\nimport metadata from '../package.json' with { type: 'json' };\nimport { SourcePositions } from './positions.js';\n\ntype State = {\n source: string;\n filename: string;\n result?: TransformResult;\n error?: any;\n original: SourcePositions;\n generated?: SourcePositions;\n project?: TwillProject;\n};\nconst pending = new Map<string, State>();\nconst projects = new Map<string, { project: TwillProject; times: Map<string, number> }>();\nconst normalize = (filename: string) => filename.replaceAll('\\\\', '/');\nconst stamp = (filename: string) => {\n try {\n return statSync(filename).mtimeMs;\n } catch {\n return -1;\n }\n};\n\nfunction projectFor(filename: string) {\n const config = ts.findConfigFile(dirname(filename), ts.sys.fileExists);\n if (!config) throw new Error('Typed Twill linting requires a tsconfig.json.');\n let cached = projects.get(config);\n if (\n cached &&\n cached.project.configFiles.some((file) => cached!.times.get(file) !== stamp(file))\n ) {\n cached.project.dispose();\n projects.delete(config);\n cached = undefined;\n }\n if (!cached) {\n cached = { project: new TwillProject(config), times: new Map() };\n for (const file of cached.project.configFiles) cached.times.set(file, stamp(file));\n if (projects.size >= 8) {\n const oldest = projects.keys().next().value!;\n projects.get(oldest)!.project.dispose();\n projects.delete(oldest);\n }\n projects.set(config, cached);\n }\n for (const file of cached.project.sourceFiles()) {\n const time = stamp(file);\n if (cached.times.has(file) && cached.times.get(file) !== time) cached.project.refresh(file);\n cached.times.set(file, time);\n }\n return cached.project;\n}\n\nfunction originalOffset(state: State, offset: number) {\n const position = state.generated!.mapPosition(offset);\n const point = originalPosition(state.result!, position.line, position.column);\n return point.line == null || point.column == null\n ? undefined\n : state.original.mapOffset(point.line, point.column);\n}\nfunction fix(state: State, value: Rule.Fix | undefined): Rule.Fix | undefined {\n if (!value) return undefined;\n const [start, end] = value.range;\n const offset = originalOffset(state, start);\n if (offset === undefined) return undefined;\n const position = state.original.mapPosition(offset);\n const generated = generatedPosition(state.result!, position.line, position.column);\n if (\n generated.line == null ||\n generated.column == null ||\n state.generated!.mapOffset(generated.line, generated.column) !== start ||\n state.source.slice(offset, offset + end - start) !== state.result!.code.slice(start, end)\n )\n return undefined;\n return { range: [offset, offset + end - start], text: value.text };\n}\n\nconst processor: Linter.Processor = {\n supportsAutofix: true,\n preprocess(source, filename) {\n filename = normalize(filename);\n const state: State = {\n source,\n filename,\n original: new SourcePositions(source),\n };\n pending.set(filename, state);\n try {\n // A project supplies the same inherited JSX settings as builds/checking.\n const config = ts.findConfigFile(dirname(filename), ts.sys.fileExists);\n state.result = transform(source, {\n ...loadConfig(config ? dirname(config) : dirname(filename)),\n filename,\n });\n state.generated = new SourcePositions(state.result.code);\n return [\n {\n text: state.result.code,\n filename: filename.endsWith('.twillx') ? 'source.tsx' : 'source.ts',\n },\n ];\n } catch (error) {\n state.error = error;\n return [];\n }\n },\n postprocess(lists, filename) {\n filename = normalize(filename);\n const state = pending.get(filename)!;\n pending.delete(filename);\n state.project?.update(filename);\n if (state.error)\n return [\n {\n ruleId: null,\n severity: 2,\n fatal: true,\n message: state.error.message,\n line: state.error.line ?? 1,\n column: (state.error.column ?? 0) + 1,\n },\n ];\n return lists.flat().flatMap((message) => {\n if (!message.line || !message.column) return [message];\n const generated = state.generated!;\n const start = generated.getPositionOfLineAndCharacter(message.line - 1, message.column - 1);\n let offset = originalOffset(state, start);\n let expressionSwitch = false;\n if (\n message.ruleId === '@typescript-eslint/switch-exhaustiveness-check' &&\n state.project &&\n (offset === undefined || state.result!.code[start] !== state.source[offset])\n ) {\n // Expression subjects use a generated once-evaluated local. Report the\n // missing union arm on the source-backed switch keyword instead.\n const file = state.project.service.getProgram()?.getSourceFile(virtualFilename(filename));\n const visit = (node: ts.Node) => {\n if (ts.isSwitchStatement(node) && node.expression.getStart() === start) {\n const sourceStart = originalOffset(state, node.getStart());\n if (\n sourceStart !== undefined &&\n state.source.slice(sourceStart, sourceStart + 6) === 'switch'\n ) {\n offset = sourceStart;\n expressionSwitch = true;\n }\n } else if (start >= node.getFullStart() && start < node.end) ts.forEachChild(node, visit);\n };\n if (file) visit(file);\n }\n if (\n offset === undefined ||\n (!expressionSwitch &&\n start < state.result!.code.length &&\n state.result!.code[start] !== state.source[offset])\n )\n return [];\n const position = state.original.getLineAndCharacterOfPosition(offset);\n const endOffset = expressionSwitch\n ? offset + 6\n : message.endLine && message.endColumn\n ? originalOffset(\n state,\n generated.getPositionOfLineAndCharacter(message.endLine - 1, message.endColumn - 1),\n )\n : undefined;\n const end =\n endOffset === undefined\n ? undefined\n : state.original.getLineAndCharacterOfPosition(endOffset);\n return [\n {\n ...message,\n line: position.line + 1,\n column: position.character + 1,\n endLine: end && end.line + 1,\n endColumn: end && end.character + 1,\n fix: fix(state, message.fix),\n suggestions: message.suggestions?.flatMap((suggestion) => {\n const mapped = fix(state, suggestion.fix);\n return mapped ? [{ ...suggestion, fix: mapped }] : [];\n }),\n },\n ];\n });\n },\n};\n\nconst virtualParser = {\n meta: { name: '@swiftuijs/twill-linter/parser', version: metadata.version },\n parseForESLint(code: string, options: any) {\n const original = normalize(options.filePath ?? '').replace(/\\/(?:\\d+_)?source\\.tsx?$/, '');\n const state = pending.get(original);\n if (!state) return parser.parseForESLint(code, options);\n const typed = options.projectService || options.project || options.programs;\n if (!typed) return parser.parseForESLint(code, options);\n const project = projectFor(original);\n project.update(original, state.source);\n state.project = project;\n return parser.parseForESLint(code, {\n ...options,\n filePath: virtualFilename(original),\n projectService: false,\n project: undefined,\n programs: [project.service.getProgram()!],\n });\n },\n};\n\nconst plugin: ESLint.Plugin & { configs: Record<string, Linter.Config[]> } = {\n meta: { name: '@swiftuijs/twill-linter', version: metadata.version },\n processors: { twill: processor },\n configs: {} as Record<string, Linter.Config[]>,\n};\nconst files = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];\nfunction configuration(typed: boolean): Linter.Config[] {\n const recommended = typescriptPlugin.configs[\n typed ? 'flat/recommended-type-checked' : 'flat/recommended'\n ] as Linter.Config[];\n return [\n js.configs.recommended,\n { files: ['**/*.twill', '**/*.twillx'], plugins: { twill: plugin }, processor: 'twill/twill' },\n ...recommended.map((config) => ({\n ...config,\n files,\n languageOptions: {\n ...config.languageOptions,\n parser: virtualParser,\n ...(typed ? { parserOptions: { projectService: true } } : {}),\n },\n })),\n ...(typed\n ? [\n {\n files,\n rules: {\n '@typescript-eslint/switch-exhaustiveness-check': [\n 'error',\n { considerDefaultExhaustiveForUnions: false },\n ] satisfies Linter.RuleEntry,\n },\n },\n ]\n : []),\n ];\n}\nplugin.configs.recommended = configuration(false);\nplugin.configs.recommendedTypeChecked = configuration(true);\nexport const configs: Record<string, Linter.Config[]> = plugin.configs;\nexport const processors: Record<string, Linter.Processor> = { twill: processor };\nexport function disposeProjects() {\n for (const { project } of projects.values()) project.dispose();\n projects.clear();\n pending.clear();\n}\nexport default plugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA,IAAa,kBAAb,MAA6B;CAC3B,SAAiB,CAAC,CAAC;CACnB,SAAiB,CAAC,CAAC;CAEnB,YAAY,MAAc;EACxB,MAAM,SAAS;EACf,OAAO,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,OAAO,SAAS;EAC3D,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SACvC,IAAI,KAAK,WAAW,MAAM,KAAK,OAAO,KAAK,QAAQ,CAAC;CACxD;CAEA,SAAiB,QAAkB,QAAgB;EACjD,IAAI,MAAM;EACV,IAAI,OAAO,OAAO;EAClB,OAAO,MAAM,IAAI,MAAM;GACrB,MAAM,SAAU,MAAM,SAAU;GAChC,IAAI,OAAO,WAAY,QAAQ,MAAM;QAChC,OAAO;EACd;EACA,OAAO;GAAE,MAAM;GAAK,WAAW,SAAS,OAAO;EAAM;CACvD;CAEA,8BAA8B,QAAgB;EAC5C,OAAO,KAAK,SAAS,KAAK,QAAQ,MAAM;CAC1C;CAEA,8BAA8B,MAAc,QAAgB;EAC1D,OAAO,KAAK,OAAO,QAAS;CAC9B;CAEA,YAAY,QAAgB;EAC1B,MAAM,WAAW,KAAK,SAAS,KAAK,QAAQ,MAAM;EAClD,OAAO;GAAE,MAAM,SAAS,OAAO;GAAG,QAAQ,SAAS;EAAU;CAC/D;CAEA,UAAU,MAAc,QAAgB;EACtC,OAAO,KAAK,OAAO,OAAO,KAAM;CAClC;AACF;;;ACZA,IAAM,0BAAU,IAAI,IAAmB;AACvC,IAAM,2BAAW,IAAI,IAAmE;AACxF,IAAM,aAAa,aAAqB,SAAS,WAAW,MAAM,GAAG;AACrE,IAAM,SAAS,aAAqB;CAClC,IAAI;EACF,OAAO,SAAS,QAAQ,CAAC,CAAC;CAC5B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,UAAkB;CACpC,MAAM,SAAS,GAAG,eAAe,QAAQ,QAAQ,GAAG,GAAG,IAAI,UAAU;CACrE,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,+CAA+C;CAC5E,IAAI,SAAS,SAAS,IAAI,MAAM;CAChC,IACE,UACA,OAAO,QAAQ,YAAY,MAAM,SAAS,OAAQ,MAAM,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,GACjF;EACA,OAAO,QAAQ,QAAQ;EACvB,SAAS,OAAO,MAAM;EACtB,SAAS,KAAA;CACX;CACA,IAAI,CAAC,QAAQ;EACX,SAAS;GAAE,SAAS,IAAI,aAAa,MAAM;GAAG,uBAAO,IAAI,IAAI;EAAE;EAC/D,KAAK,MAAM,QAAQ,OAAO,QAAQ,aAAa,OAAO,MAAM,IAAI,MAAM,MAAM,IAAI,CAAC;EACjF,IAAI,SAAS,QAAQ,GAAG;GACtB,MAAM,SAAS,SAAS,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;GACtC,SAAS,IAAI,MAAM,CAAC,CAAE,QAAQ,QAAQ;GACtC,SAAS,OAAO,MAAM;EACxB;EACA,SAAS,IAAI,QAAQ,MAAM;CAC7B;CACA,KAAK,MAAM,QAAQ,OAAO,QAAQ,YAAY,GAAG;EAC/C,MAAM,OAAO,MAAM,IAAI;EACvB,IAAI,OAAO,MAAM,IAAI,IAAI,KAAK,OAAO,MAAM,IAAI,IAAI,MAAM,MAAM,OAAO,QAAQ,QAAQ,IAAI;EAC1F,OAAO,MAAM,IAAI,MAAM,IAAI;CAC7B;CACA,OAAO,OAAO;AAChB;AAEA,SAAS,eAAe,OAAc,QAAgB;CACpD,MAAM,WAAW,MAAM,UAAW,YAAY,MAAM;CACpD,MAAM,QAAQ,iBAAiB,MAAM,QAAS,SAAS,MAAM,SAAS,MAAM;CAC5E,OAAO,MAAM,QAAQ,QAAQ,MAAM,UAAU,OACzC,KAAA,IACA,MAAM,SAAS,UAAU,MAAM,MAAM,MAAM,MAAM;AACvD;AACA,SAAS,IAAI,OAAc,OAAmD;CAC5E,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,MAAM,CAAC,OAAO,OAAO,MAAM;CAC3B,MAAM,SAAS,eAAe,OAAO,KAAK;CAC1C,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;CACjC,MAAM,WAAW,MAAM,SAAS,YAAY,MAAM;CAClD,MAAM,YAAY,kBAAkB,MAAM,QAAS,SAAS,MAAM,SAAS,MAAM;CACjF,IACE,UAAU,QAAQ,QAClB,UAAU,UAAU,QACpB,MAAM,UAAW,UAAU,UAAU,MAAM,UAAU,MAAM,MAAM,SACjE,MAAM,OAAO,MAAM,QAAQ,SAAS,MAAM,KAAK,MAAM,MAAM,OAAQ,KAAK,MAAM,OAAO,GAAG,GAExF,OAAO,KAAA;CACT,OAAO;EAAE,OAAO,CAAC,QAAQ,SAAS,MAAM,KAAK;EAAG,MAAM,MAAM;CAAK;AACnE;AAEA,IAAM,YAA8B;CAClC,iBAAiB;CACjB,WAAW,QAAQ,UAAU;EAC3B,WAAW,UAAU,QAAQ;EAC7B,MAAM,QAAe;GACnB;GACA;GACA,UAAU,IAAI,gBAAgB,MAAM;EACtC;EACA,QAAQ,IAAI,UAAU,KAAK;EAC3B,IAAI;GAEF,MAAM,SAAS,GAAG,eAAe,QAAQ,QAAQ,GAAG,GAAG,IAAI,UAAU;GACrE,MAAM,SAAS,UAAU,QAAQ;IAC/B,GAAG,WAAW,SAAS,QAAQ,MAAM,IAAI,QAAQ,QAAQ,CAAC;IAC1D;GACF,CAAC;GACD,MAAM,YAAY,IAAI,gBAAgB,MAAM,OAAO,IAAI;GACvD,OAAO,CACL;IACE,MAAM,MAAM,OAAO;IACnB,UAAU,SAAS,SAAS,SAAS,IAAI,eAAe;GAC1D,CACF;EACF,SAAS,OAAO;GACd,MAAM,QAAQ;GACd,OAAO,CAAC;EACV;CACF;CACA,YAAY,OAAO,UAAU;EAC3B,WAAW,UAAU,QAAQ;EAC7B,MAAM,QAAQ,QAAQ,IAAI,QAAQ;EAClC,QAAQ,OAAO,QAAQ;EACvB,MAAM,SAAS,OAAO,QAAQ;EAC9B,IAAI,MAAM,OACR,OAAO,CACL;GACE,QAAQ;GACR,UAAU;GACV,OAAO;GACP,SAAS,MAAM,MAAM;GACrB,MAAM,MAAM,MAAM,QAAQ;GAC1B,SAAS,MAAM,MAAM,UAAU,KAAK;EACtC,CACF;EACF,OAAO,MAAM,KAAK,CAAC,CAAC,SAAS,YAAY;GACvC,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,QAAQ,OAAO,CAAC,OAAO;GACrD,MAAM,YAAY,MAAM;GACxB,MAAM,QAAQ,UAAU,8BAA8B,QAAQ,OAAO,GAAG,QAAQ,SAAS,CAAC;GAC1F,IAAI,SAAS,eAAe,OAAO,KAAK;GACxC,IAAI,mBAAmB;GACvB,IACE,QAAQ,WAAW,oDACnB,MAAM,YACL,WAAW,KAAA,KAAa,MAAM,OAAQ,KAAK,WAAW,MAAM,OAAO,UACpE;IAGA,MAAM,OAAO,MAAM,QAAQ,QAAQ,WAAW,CAAC,EAAE,cAAc,gBAAgB,QAAQ,CAAC;IACxF,MAAM,SAAS,SAAkB;KAC/B,IAAI,GAAG,kBAAkB,IAAI,KAAK,KAAK,WAAW,SAAS,MAAM,OAAO;MACtE,MAAM,cAAc,eAAe,OAAO,KAAK,SAAS,CAAC;MACzD,IACE,gBAAgB,KAAA,KAChB,MAAM,OAAO,MAAM,aAAa,cAAc,CAAC,MAAM,UACrD;OACA,SAAS;OACT,mBAAmB;MACrB;KACF,OAAO,IAAI,SAAS,KAAK,aAAa,KAAK,QAAQ,KAAK,KAAK,GAAG,aAAa,MAAM,KAAK;IAC1F;IACA,IAAI,MAAM,MAAM,IAAI;GACtB;GACA,IACE,WAAW,KAAA,KACV,CAAC,oBACA,QAAQ,MAAM,OAAQ,KAAK,UAC3B,MAAM,OAAQ,KAAK,WAAW,MAAM,OAAO,SAE7C,OAAO,CAAC;GACV,MAAM,WAAW,MAAM,SAAS,8BAA8B,MAAM;GACpE,MAAM,YAAY,mBACd,SAAS,IACT,QAAQ,WAAW,QAAQ,YACzB,eACE,OACA,UAAU,8BAA8B,QAAQ,UAAU,GAAG,QAAQ,YAAY,CAAC,CACpF,IACA,KAAA;GACN,MAAM,MACJ,cAAc,KAAA,IACV,KAAA,IACA,MAAM,SAAS,8BAA8B,SAAS;GAC5D,OAAO,CACL;IACE,GAAG;IACH,MAAM,SAAS,OAAO;IACtB,QAAQ,SAAS,YAAY;IAC7B,SAAS,OAAO,IAAI,OAAO;IAC3B,WAAW,OAAO,IAAI,YAAY;IAClC,KAAK,IAAI,OAAO,QAAQ,GAAG;IAC3B,aAAa,QAAQ,aAAa,SAAS,eAAe;KACxD,MAAM,SAAS,IAAI,OAAO,WAAW,GAAG;KACxC,OAAO,SAAS,CAAC;MAAE,GAAG;MAAY,KAAK;KAAO,CAAC,IAAI,CAAC;IACtD,CAAC;GACH,CACF;EACF,CAAC;CACH;AACF;AAEA,IAAM,gBAAgB;CACpB,MAAM;EAAE,MAAM;EAAkC,SAASC,gBAAS;CAAQ;CAC1E,eAAe,MAAc,SAAc;EACzC,MAAM,WAAW,UAAU,QAAQ,YAAY,EAAE,CAAC,CAAC,QAAQ,4BAA4B,EAAE;EACzF,MAAM,QAAQ,QAAQ,IAAI,QAAQ;EAClC,IAAI,CAAC,OAAO,OAAO,OAAO,eAAe,MAAM,OAAO;EAEtD,IAAI,EADU,QAAQ,kBAAkB,QAAQ,WAAW,QAAQ,WACvD,OAAO,OAAO,eAAe,MAAM,OAAO;EACtD,MAAM,UAAU,WAAW,QAAQ;EACnC,QAAQ,OAAO,UAAU,MAAM,MAAM;EACrC,MAAM,UAAU;EAChB,OAAO,OAAO,eAAe,MAAM;GACjC,GAAG;GACH,UAAU,gBAAgB,QAAQ;GAClC,gBAAgB;GAChB,SAAS,KAAA;GACT,UAAU,CAAC,QAAQ,QAAQ,WAAW,CAAE;EAC1C,CAAC;CACH;AACF;AAEA,IAAM,SAAuE;CAC3E,MAAM;EAAE,MAAM;EAA2B,SAASA,gBAAS;CAAQ;CACnE,YAAY,EAAE,OAAO,UAAU;CAC/B,SAAS,CAAC;AACZ;AACA,IAAM,QAAQ;CAAC;CAAW;CAAY;CAAY;AAAU;AAC5D,SAAS,cAAc,OAAiC;CACtD,MAAM,cAAc,iBAAiB,QACnC,QAAQ,kCAAkC;CAE5C,OAAO;EACL,GAAG,QAAQ;EACX;GAAE,OAAO,CAAC,cAAc,aAAa;GAAG,SAAS,EAAE,OAAO,OAAO;GAAG,WAAW;EAAc;EAC7F,GAAG,YAAY,KAAK,YAAY;GAC9B,GAAG;GACH;GACA,iBAAiB;IACf,GAAG,OAAO;IACV,QAAQ;IACR,GAAI,QAAQ,EAAE,eAAe,EAAE,gBAAgB,KAAK,EAAE,IAAI,CAAC;GAC7D;EACF,EAAE;EACF,GAAI,QACA,CACE;GACE;GACA,OAAO,EACL,kDAAkD,CAChD,SACA,EAAE,oCAAoC,MAAM,CAC9C,EACF;EACF,CACF,IACA,CAAC;CACP;AACF;AACA,OAAO,QAAQ,cAAc,cAAc,KAAK;AAChD,OAAO,QAAQ,yBAAyB,cAAc,IAAI;AAC1D,IAAa,UAA2C,OAAO;AAC/D,IAAa,aAA+C,EAAE,OAAO,UAAU;AAC/E,SAAgB,kBAAkB;CAChC,KAAK,MAAM,EAAE,aAAa,SAAS,OAAO,GAAG,QAAQ,QAAQ;CAC7D,SAAS,MAAM;CACf,QAAQ,MAAM;AAChB"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["files","metadata"],"sources":["../package.json","../src/positions.ts","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@swiftuijs/twill-linter\",\n \"version\": \"0.1.2\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/swiftuijs/twill.git\",\n \"directory\": \"packages/linter\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"vite build\",\n \"typecheck\": \"tsc --noEmit -p tsconfig.json\",\n \"test:unit\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:package\": \"node tests/consumer.mjs\",\n \"prepack\": \"pnpm run build\",\n \"test\": \"pnpm run test:unit\"\n },\n \"dependencies\": {\n \"@swiftuijs/twill\": \"workspace:*\",\n \"@typescript-eslint/parser\": \"^8.71.0\",\n \"@typescript-eslint/eslint-plugin\": \"^8.71.0\",\n \"@eslint/js\": \"catalog:\",\n \"typescript\": \"catalog:\"\n },\n \"devDependencies\": {\n \"vite\": \"catalog:\",\n \"vite-plugin-dts\": \"^5.1.2\",\n \"@types/node\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"eslint\": \"catalog:\",\n \"vitest\": \"catalog:\",\n \"@vitest/coverage-v8\": \"catalog:\"\n },\n \"engines\": {\n \"node\": \"^20.19.0 || >=22.12.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"peerDependencies\": {\n \"eslint\": \"^9.0.0 || ^10.0.0\"\n },\n \"author\": {\n \"name\": \"forth.ink\",\n \"url\": \"https://forth.ink\"\n },\n \"homepage\": \"https://twill.evecalm.com/\",\n \"bugs\": {\n \"url\": \"https://github.com/swiftuijs/twill/issues\"\n },\n \"keywords\": [\n \"twill\",\n \"eslint\",\n \"eslint-plugin\",\n \"typescript\",\n \"linter\"\n ],\n \"description\": \"ESLint flat configurations for Twill with TypeScript rules, original-source diagnostics and safe fixes.\"\n}\n","/** Source-map lines use LF; ESLint positions also count CR and Unicode separators. */\nexport class SourcePositions {\n private native = [0];\n private mapped = [0];\n\n constructor(text: string) {\n const breaks = /\\r\\n|[\\n\\r\\u2028\\u2029]/g;\n while (breaks.exec(text)) this.native.push(breaks.lastIndex);\n for (let index = 0; index < text.length; index++)\n if (text[index] === '\\n') this.mapped.push(index + 1);\n }\n\n private position(starts: number[], offset: number) {\n let low = 0;\n let high = starts.length;\n while (low + 1 < high) {\n const middle = (low + high) >>> 1;\n if (starts[middle]! <= offset) low = middle;\n else high = middle;\n }\n return { line: low, character: offset - starts[low]! };\n }\n\n getLineAndCharacterOfPosition(offset: number) {\n return this.position(this.native, offset);\n }\n\n getPositionOfLineAndCharacter(line: number, column: number) {\n return this.native[line]! + column;\n }\n\n mapPosition(offset: number) {\n const position = this.position(this.mapped, offset);\n return { line: position.line + 1, column: position.character };\n }\n\n mapOffset(line: number, column: number) {\n return this.mapped[line - 1]! + column;\n }\n}\n","import {\n transform,\n originalPosition,\n generatedPosition,\n type TransformResult,\n} from '@swiftuijs/twill';\nimport { TwillProject, virtualFilename, sourceFilename } from '@swiftuijs/twill/project';\nimport * as parser from '@typescript-eslint/parser';\nimport typescriptPlugin from '@typescript-eslint/eslint-plugin';\nimport js from '@eslint/js';\nimport ts from 'typescript';\nimport { loadConfig } from '@swiftuijs/twill/config';\nimport { dirname, resolve } from 'node:path';\nimport { statSync } from 'node:fs';\nimport type { ESLint, Linter, Rule } from 'eslint';\nimport metadata from '../package.json' with { type: 'json' };\nimport { SourcePositions } from './positions.js';\n\ntype State = {\n source: string;\n filename: string;\n result?: TransformResult;\n error?: any;\n original: SourcePositions;\n generated?: SourcePositions;\n project?: TwillProject;\n};\nconst pending = new Map<string, State>();\nconst projects = new Map<string, { project: TwillProject; times: Map<string, number> }>();\nconst normalize = (filename: string) => filename.replaceAll('\\\\', '/');\nconst stamp = (filename: string) => {\n try {\n return statSync(filename).mtimeMs;\n } catch {\n return -1;\n }\n};\n\nfunction projectFor(filename: string) {\n const config = ts.findConfigFile(dirname(filename), ts.sys.fileExists);\n if (!config) throw new Error('Typed Twill linting requires a tsconfig.json.');\n let cached = projects.get(config);\n if (\n cached &&\n cached.project.configFiles.some((file) => cached!.times.get(file) !== stamp(file))\n ) {\n cached.project.dispose();\n projects.delete(config);\n cached = undefined;\n }\n if (!cached) {\n cached = { project: new TwillProject(config), times: new Map() };\n for (const file of cached.project.configFiles) cached.times.set(file, stamp(file));\n if (projects.size >= 8) {\n const oldest = projects.keys().next().value!;\n projects.get(oldest)!.project.dispose();\n projects.delete(oldest);\n }\n projects.set(config, cached);\n }\n for (const file of cached.project.sourceFiles()) {\n const time = stamp(file);\n if (cached.times.has(file) && cached.times.get(file) !== time) cached.project.refresh(file);\n cached.times.set(file, time);\n }\n return cached.project;\n}\n\nfunction originalOffset(state: State, offset: number) {\n const position = state.generated!.mapPosition(offset);\n const point = originalPosition(state.result!, position.line, position.column);\n return point.line == null || point.column == null\n ? undefined\n : state.original.mapOffset(point.line, point.column);\n}\nfunction fix(state: State, value: Rule.Fix | undefined): Rule.Fix | undefined {\n if (!value) return undefined;\n const [start, end] = value.range;\n const offset = originalOffset(state, start);\n if (offset === undefined) return undefined;\n const position = state.original.mapPosition(offset);\n const generated = generatedPosition(state.result!, position.line, position.column);\n if (\n generated.line == null ||\n generated.column == null ||\n state.generated!.mapOffset(generated.line, generated.column) !== start ||\n state.source.slice(offset, offset + end - start) !== state.result!.code.slice(start, end)\n )\n return undefined;\n return { range: [offset, offset + end - start], text: value.text };\n}\n\nconst processor: Linter.Processor = {\n supportsAutofix: true,\n preprocess(source, filename) {\n filename = normalize(filename);\n const state: State = {\n source,\n filename,\n original: new SourcePositions(source),\n };\n pending.set(filename, state);\n try {\n // A project supplies the same inherited JSX settings as builds/checking.\n const config = ts.findConfigFile(dirname(filename), ts.sys.fileExists);\n state.result = transform(source, {\n ...loadConfig(config ? dirname(config) : dirname(filename)),\n filename,\n });\n state.generated = new SourcePositions(state.result.code);\n return [\n {\n text: state.result.code,\n filename: filename.endsWith('.twillx') ? 'source.tsx' : 'source.ts',\n },\n ];\n } catch (error) {\n state.error = error;\n return [];\n }\n },\n postprocess(lists, filename) {\n filename = normalize(filename);\n const state = pending.get(filename)!;\n pending.delete(filename);\n state.project?.update(filename);\n if (state.error)\n return [\n {\n ruleId: null,\n severity: 2,\n fatal: true,\n message: state.error.message,\n line: state.error.line ?? 1,\n column: (state.error.column ?? 0) + 1,\n },\n ];\n return lists.flat().flatMap((message) => {\n if (!message.line || !message.column) return [message];\n const generated = state.generated!;\n const start = generated.getPositionOfLineAndCharacter(message.line - 1, message.column - 1);\n let offset = originalOffset(state, start);\n let expressionSwitch = false;\n if (\n message.ruleId === '@typescript-eslint/switch-exhaustiveness-check' &&\n state.project &&\n (offset === undefined || state.result!.code[start] !== state.source[offset])\n ) {\n // Expression subjects use a generated once-evaluated local. Report the\n // missing union arm on the source-backed switch keyword instead.\n const file = state.project.service.getProgram()?.getSourceFile(virtualFilename(filename));\n const visit = (node: ts.Node) => {\n if (ts.isSwitchStatement(node) && node.expression.getStart() === start) {\n const sourceStart = originalOffset(state, node.getStart());\n if (\n sourceStart !== undefined &&\n state.source.slice(sourceStart, sourceStart + 6) === 'switch'\n ) {\n offset = sourceStart;\n expressionSwitch = true;\n }\n } else if (start >= node.getFullStart() && start < node.end) ts.forEachChild(node, visit);\n };\n if (file) visit(file);\n }\n if (\n offset === undefined ||\n (!expressionSwitch &&\n start < state.result!.code.length &&\n state.result!.code[start] !== state.source[offset])\n )\n return [];\n const position = state.original.getLineAndCharacterOfPosition(offset);\n const endOffset = expressionSwitch\n ? offset + 6\n : message.endLine && message.endColumn\n ? originalOffset(\n state,\n generated.getPositionOfLineAndCharacter(message.endLine - 1, message.endColumn - 1),\n )\n : undefined;\n const end =\n endOffset === undefined\n ? undefined\n : state.original.getLineAndCharacterOfPosition(endOffset);\n return [\n {\n ...message,\n line: position.line + 1,\n column: position.character + 1,\n endLine: end && end.line + 1,\n endColumn: end && end.character + 1,\n fix: fix(state, message.fix),\n suggestions: message.suggestions?.flatMap((suggestion) => {\n const mapped = fix(state, suggestion.fix);\n return mapped ? [{ ...suggestion, fix: mapped }] : [];\n }),\n },\n ];\n });\n },\n};\n\nconst virtualParser = {\n meta: { name: '@swiftuijs/twill-linter/parser', version: metadata.version },\n parseForESLint(code: string, options: any) {\n const original = normalize(options.filePath ?? '').replace(/\\/(?:\\d+_)?source\\.tsx?$/, '');\n const state = pending.get(original);\n if (!state) return parser.parseForESLint(code, options);\n const typed = options.projectService || options.project || options.programs;\n if (!typed) return parser.parseForESLint(code, options);\n const project = projectFor(original);\n project.update(original, state.source);\n state.project = project;\n return parser.parseForESLint(code, {\n ...options,\n filePath: virtualFilename(original),\n projectService: false,\n project: undefined,\n programs: [project.service.getProgram()!],\n });\n },\n};\n\nconst plugin: ESLint.Plugin & { configs: Record<string, Linter.Config[]> } = {\n meta: { name: '@swiftuijs/twill-linter', version: metadata.version },\n processors: { twill: processor },\n configs: {} as Record<string, Linter.Config[]>,\n};\nconst files = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];\nfunction configuration(typed: boolean): Linter.Config[] {\n const recommended = typescriptPlugin.configs[\n typed ? 'flat/recommended-type-checked' : 'flat/recommended'\n ] as Linter.Config[];\n return [\n js.configs.recommended,\n { files: ['**/*.twill', '**/*.twillx'], plugins: { twill: plugin }, processor: 'twill/twill' },\n ...recommended.map((config) => ({\n ...config,\n files,\n languageOptions: {\n ...config.languageOptions,\n parser: virtualParser,\n ...(typed ? { parserOptions: { projectService: true } } : {}),\n },\n })),\n ...(typed\n ? [\n {\n files,\n rules: {\n '@typescript-eslint/switch-exhaustiveness-check': [\n 'error',\n { considerDefaultExhaustiveForUnions: false },\n ] satisfies Linter.RuleEntry,\n },\n },\n ]\n : []),\n ];\n}\nplugin.configs.recommended = configuration(false);\nplugin.configs.recommendedTypeChecked = configuration(true);\nexport const configs: Record<string, Linter.Config[]> = plugin.configs;\nexport const processors: Record<string, Linter.Processor> = { twill: processor };\nexport function disposeProjects() {\n for (const { project } of projects.values()) project.dispose();\n projects.clear();\n pending.clear();\n}\nexport default plugin;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swiftuijs/twill-linter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@typescript-eslint/eslint-plugin": "^8.71.0",
|
|
25
25
|
"@eslint/js": "^9.39.5",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
|
-
"@swiftuijs/twill": "0.1.
|
|
27
|
+
"@swiftuijs/twill": "0.1.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"vite": "^8.3.2",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"name": "forth.ink",
|
|
49
49
|
"url": "https://forth.ink"
|
|
50
50
|
},
|
|
51
|
-
"homepage": "https://
|
|
51
|
+
"homepage": "https://twill.evecalm.com/",
|
|
52
52
|
"bugs": {
|
|
53
53
|
"url": "https://github.com/swiftuijs/twill/issues"
|
|
54
54
|
},
|