diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..82df6db --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,56 @@ +name: Deploy + +on: + workflow_run: + workflows: [Test] + types: [completed] + branches: [main] + +permissions: + id-token: write + contents: write + +jobs: + publish-npm: + name: Publish to NPM + runs-on: ubuntu-latest + environment: production + if: ${{ github.event.workflow_run.conclusion == 'success' }} + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ github.event.workflow_run.head_sha }} + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install dependencies + run: npm --color ci + + - name: Build + run: npm --color run build + + - name: Read version from package.json + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=v$VERSION" >> $GITHUB_ENV + + - name: Check whether this version is already published + run: | + if git ls-remote --exit-code --tags origin "refs/tags/${{ env.version }}" > /dev/null; then + echo "Version ${{ env.version }} is already tagged." + exit 1 + fi + + - name: Publish to NPM + run: npx -y npm@11.6.2 publish --access public + + - name: Create Git tag + run: | + git tag ${{ env.version }} + git push origin ${{ env.version }} diff --git a/dist/snippetFormatter.js b/dist/snippetFormatter.js index 2ddc19f..2d78251 100644 --- a/dist/snippetFormatter.js +++ b/dist/snippetFormatter.js @@ -10,6 +10,6 @@ ${r.join(` `),process.stdout.write(` `),process.stdout.write(`Options: `);for(let e of G)process.stdout.write(` ${e} -`)}var q={name:"@cursorless/talon-tools",version:"0.10.1",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function B(){process.stdout.write(`${q.version} +`)}var q={name:"@cursorless/talon-tools",version:"0.10.2",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function B(){process.stdout.write(`${q.version} `)}function T(t){Reflect.set(process,"exitCode",t)}async function Y(t){let e=$();try{let r=z(c.argv.slice(2));e=$(r.quiet);let n=await Fe({cli:t,args:r,logger:e});T(n)}catch(r){if(r instanceof m)for(let n of r.messages)e.error(n);else e.error(_(r));T(2)}}async function Fe({cli:t,args:e,logger:r}){if(e.help)return H(t),0;if(e.version)return B(),0;if(e.filePatterns.length>0)return Se({cli:t,logger:r,check:e.check,debug:e.debug,filePatterns:e.filePatterns});if(!c.stdin.isTTY)return Pe({cli:t,logger:r,stdin:c.stdin,check:e.check,debug:e.debug});throw new Error("No input files specified. Use --help for usage information.")}async function Se({cli:t,logger:e,check:r,debug:n,filePatterns:i}){r&&e.log("Checking formatting...");let o=await X(t,i),[s,a]=await Le({cli:t,logger:e,check:r,debug:n,filePaths:o});if(r){if(s>0&&(e.warn(`Code style issues found in ${s} file(s).`),!a))return 1;a||e.log("All matched files use correct code style!")}return a?2:0}async function Le({cli:t,logger:e,check:r,debug:n,filePaths:i}){let o=0,s=!1;for(let a of i)try{await _e({cli:t,logger:e,check:r,debug:n,filePath:a})&&o++}catch(l){O(l)?e.error(l.getFileMessage(A(a))):e.error(`${A(a)}: ${_(l)}`),s=!0}return[o,s]}async function _e({cli:t,logger:e,check:r,debug:n,filePath:i}){try{let o=await v(i),s=await F.readFile(i,"utf8"),a=await t.format(s,o,i,n);return a===s?!1:(e.log(A(i)),r||await F.writeFile(i,a,"utf8"),!0)}catch(o){if(E(o))return!1;throw o}}function A(t){return w(S.relative(c.cwd(),t))}async function Pe({cli:t,logger:e,stdin:r,check:n,debug:i}){let o=await we({stdin:r}),a=`stdin.${t.getStdinFileEnding(o)}`,l=S.resolve(a),h=await v(l),f;try{f=await t.format(o,h,l,i)}catch(p){if(O(p))return e.error(p.getFileMessage("stdin")),2;throw p}return n?o!==f?(e.warn("Code style issues found in stdin."),1):0:(c.stdout.write(f),0)}var Q="snippet";Y({binName:"snippet-fmt",fileEndings:[Q],getStdinFileEnding(){return Q},format:async(t,e)=>{let r=j(t,e);return Promise.resolve(r)}}); //# sourceMappingURL=snippetFormatter.js.map diff --git a/dist/snippetFormatter.js.map b/dist/snippetFormatter.js.map index 4b9af88..2f2c7d1 100644 --- a/dist/snippetFormatter.js.map +++ b/dist/snippetFormatter.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/snippet/parseSnippetFile.ts", "../src/util/constants.ts", "../src/util/getEndOfLine.ts", "../src/snippet/serializeSnippetFile.ts", "../src/snippet/snippetFormatter.ts", "../src/node/cli.ts", "../src/util/getErrorMessage.ts", "../src/util/SyntaxError.ts", "../src/node/createLogger.ts", "../src/node/FilePatternError.ts", "../src/node/getOptionsFromConfig.ts", "../src/node/isMissingFileError.ts", "../src/node/normalizeToPosix.ts", "../src/node/getDefaultArguments.ts", "../src/node/parseArgs.ts", "../src/node/parseFilePatterns.ts", "../src/node/lstatSafe.ts", "../src/types.ts", "../src/node/printHelp.ts", "../package.json", "../src/node/printVersion.ts", "../src/node/setExitCode.ts", "../src/node/snippetFormatter.ts"], - "sourcesContent": ["import type { Snippet, SnippetFile, SnippetVariable } from \"./snippetTypes.js\";\n\nexport function parseSnippetFile(content: string): SnippetFile {\n const documentContents = content.split(/^---$/m);\n const file: SnippetFile = { snippets: [] };\n\n for (const text of documentContents) {\n const match = text.match(/^-$/m);\n const contextText = match != null ? text.slice(0, match.index) : text;\n const bodyText =\n match != null ? text.slice(match.index! + match[0].length) : null;\n const body = bodyText ? parseBody(bodyText) : null;\n let context = parseContext(contextText);\n\n // Snippet with body\n if (body != null) {\n if (context == null) {\n context = { variables: [] };\n }\n const { variables, ...rest } = context;\n file.snippets.push({ ...rest, body, variables });\n }\n // Header without body\n else if (context != null) {\n if (file.header != null || file.snippets.length !== 0) {\n throw Error(\"Header snippet must be first in file\");\n }\n file.header = context;\n }\n }\n\n return file;\n}\n\ntype Context = Omit;\n\nfunction parseContext(text: string): Context | undefined {\n const document: Context = { variables: [] };\n const pairs = parseContextPairs(text);\n\n if (Object.keys(pairs).length === 0) {\n return undefined;\n }\n\n const variables: Record = {};\n\n for (const [key, value] of Object.entries(pairs)) {\n switch (key) {\n case \"name\":\n document.name = value;\n break;\n case \"description\":\n document.description = value;\n break;\n case \"phrase\":\n document.phrases = parseVectorValue(value);\n break;\n case \"insertionScope\":\n document.insertionScopes = parseVectorValue(value);\n break;\n case \"language\":\n document.languages = parseVectorValue(value);\n break;\n default:\n if (!key.startsWith(\"$\")) {\n throw Error(`Invalid key '${key}'`);\n }\n variables[key] = value;\n }\n }\n\n document.variables = parseVariables(variables);\n\n return document;\n}\n\nfunction parseContextPairs(text: string): Record {\n const lines = text\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter(Boolean);\n const pairs: Record = {};\n\n for (const line of lines) {\n const parts = line.split(\":\");\n if (parts.length !== 2) {\n throw Error(`Invalid line '${line}'`);\n }\n const key = parts[0].trim();\n const value = parts[1].trim();\n if (key.length === 0 || value.length === 0) {\n throw Error(`Invalid line '${line}'`);\n }\n if (pairs[key] != null) {\n throw Error(`Duplicate key '${key}' in '${text}'`);\n }\n pairs[key] = value;\n }\n\n return pairs;\n}\n\nfunction parseVariables(variables: Record): SnippetVariable[] {\n const variablesMap: Record = {};\n\n const getVariable = (name: string): SnippetVariable => {\n if (variablesMap[name] == null) {\n variablesMap[name] = { name };\n }\n return variablesMap[name];\n };\n\n for (const [key, value] of Object.entries(variables)) {\n const parts = key.split(\".\");\n if (parts.length !== 2) {\n throw Error(`Invalid variable key '${key}'`);\n }\n const name = parts[0].slice(1);\n const field = parts[1];\n switch (field) {\n case \"insertionFormatter\":\n getVariable(name).insertionFormatters = parseVectorValue(value);\n break;\n case \"wrapperPhrase\":\n getVariable(name).wrapperPhrases = parseVectorValue(value);\n break;\n case \"wrapperScope\":\n getVariable(name).wrapperScope = value;\n break;\n default:\n throw Error(`Invalid variable key '${key}'`);\n }\n }\n\n return Object.values(variablesMap);\n}\n\nfunction parseBody(text: string): string[] | undefined {\n // Find first line that is not empty. Preserve indentation.\n const matchLeading = text.match(/^[ \\t]*\\S/m);\n if (matchLeading?.index == null) {\n return undefined;\n }\n return text\n .slice(matchLeading.index)\n .trimEnd()\n .split(/\\r?\\n/)\n .map((l) => l.trimEnd());\n}\n\nfunction parseVectorValue(value: string): string[] {\n return value.split(\"|\").map((v) => v.trim());\n}\n", "// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import type { FormatterOptions } from \"../types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"../util/constants.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport type {\n Snippet,\n SnippetFile,\n SnippetHeader,\n SnippetVariable,\n} from \"./snippetTypes.js\";\n\nexport type Options = FormatterOptions<\"endOfLine\" | \"insertFinalNewline\">;\n\nexport function serializeSnippetFile(\n snippetFile: SnippetFile,\n options: Options = {},\n): string {\n const eol = getEndOfLine(options.endOfLine);\n const serializer = new SnippetSerializer(\n eol,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n );\n return serializer.getText(snippetFile);\n}\n\nclass SnippetSerializer {\n constructor(\n private eol: string,\n private insertFinalNewline: boolean,\n ) {}\n\n getText(snippetFile: SnippetFile): string {\n const docDelimiter = \"---\";\n const documents: string[] = [];\n\n if (snippetFile.header != null) {\n documents.push(this.getDocumentText(snippetFile.header));\n }\n\n documents.push(\n ...snippetFile.snippets.map(this.getDocumentText.bind(this)),\n );\n\n const result = documents\n .filter((d) => d.length > 0)\n .join(`${this.eol}${docDelimiter}${this.eol}${this.eol}`);\n\n if (result.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return result + `${this.eol}${docDelimiter}${this.eol}`;\n }\n\n return result + `${this.eol}${docDelimiter}`;\n }\n\n private getDocumentText(document: SnippetHeader | Snippet): string {\n const lines: string[] = [\n getOptionalPairString(\"name\", document.name),\n getOptionalPairString(\"description\", document.description),\n getOptionalPairString(\"language\", document.languages),\n getOptionalPairString(\"phrase\", document.phrases),\n getOptionalPairString(\"insertionScope\", document.insertionScopes),\n ].filter(Boolean);\n\n if (document.variables.length > 0) {\n if (lines.length > 0) {\n lines.push(\"\");\n }\n lines.push(...getSortedVariables(document.variables));\n }\n\n if (\"body\" in document) {\n lines.push(\"-\", ...document.body);\n }\n\n return lines.join(this.eol);\n }\n}\n\nfunction getSortedVariables(variables: SnippetVariable[]): string[] {\n const result = variables.slice();\n result.sort(compareVariables);\n return result\n .flatMap((variable) => [\n getOptionalPairString(\n `$${variable.name}.insertionFormatter`,\n variable.insertionFormatters,\n ),\n getOptionalPairString(\n `$${variable.name}.wrapperPhrase`,\n variable.wrapperPhrases,\n ),\n getOptionalPairString(\n `$${variable.name}.wrapperScope`,\n variable.wrapperScope,\n ),\n ])\n .filter((v) => v.length > 0);\n}\n\nfunction getOptionalPairString(\n key: string,\n value: string | string[] | undefined,\n): string {\n if (value == null) {\n return \"\";\n }\n if (Array.isArray(value)) {\n return `${key}: ${value.join(\" | \")}`;\n }\n return `${key}: ${value}`;\n}\n\nfunction compareVariables(a: SnippetVariable, b: SnippetVariable): number {\n if (a.name === \"0\") {\n return 1;\n }\n if (b.name === \"0\") {\n return -1;\n }\n return a.name.localeCompare(b.name);\n}\n", "import { parseSnippetFile } from \"./parseSnippetFile.js\";\nimport { serializeSnippetFile } from \"./serializeSnippetFile.js\";\nimport type { Options } from \"./serializeSnippetFile.js\";\n\nexport function snippetFormatter(text: string, options?: Options): string {\n const snippetFile = parseSnippetFile(text);\n return serializeSnippetFile(snippetFile, options);\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.1\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { snippetFormatter } from \"../snippet/snippetFormatter.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEnding = \"snippet\";\n\nvoid main({\n binName: \"snippet-fmt\",\n fileEndings: [fileEnding],\n\n getStdinFileEnding() {\n return fileEnding;\n },\n\n format: async (text, options) => {\n const updated = snippetFormatter(text, options);\n return Promise.resolve(updated);\n },\n});\n"], + "sourcesContent": ["import type { Snippet, SnippetFile, SnippetVariable } from \"./snippetTypes.js\";\n\nexport function parseSnippetFile(content: string): SnippetFile {\n const documentContents = content.split(/^---$/m);\n const file: SnippetFile = { snippets: [] };\n\n for (const text of documentContents) {\n const match = text.match(/^-$/m);\n const contextText = match != null ? text.slice(0, match.index) : text;\n const bodyText =\n match != null ? text.slice(match.index! + match[0].length) : null;\n const body = bodyText ? parseBody(bodyText) : null;\n let context = parseContext(contextText);\n\n // Snippet with body\n if (body != null) {\n if (context == null) {\n context = { variables: [] };\n }\n const { variables, ...rest } = context;\n file.snippets.push({ ...rest, body, variables });\n }\n // Header without body\n else if (context != null) {\n if (file.header != null || file.snippets.length !== 0) {\n throw Error(\"Header snippet must be first in file\");\n }\n file.header = context;\n }\n }\n\n return file;\n}\n\ntype Context = Omit;\n\nfunction parseContext(text: string): Context | undefined {\n const document: Context = { variables: [] };\n const pairs = parseContextPairs(text);\n\n if (Object.keys(pairs).length === 0) {\n return undefined;\n }\n\n const variables: Record = {};\n\n for (const [key, value] of Object.entries(pairs)) {\n switch (key) {\n case \"name\":\n document.name = value;\n break;\n case \"description\":\n document.description = value;\n break;\n case \"phrase\":\n document.phrases = parseVectorValue(value);\n break;\n case \"insertionScope\":\n document.insertionScopes = parseVectorValue(value);\n break;\n case \"language\":\n document.languages = parseVectorValue(value);\n break;\n default:\n if (!key.startsWith(\"$\")) {\n throw Error(`Invalid key '${key}'`);\n }\n variables[key] = value;\n }\n }\n\n document.variables = parseVariables(variables);\n\n return document;\n}\n\nfunction parseContextPairs(text: string): Record {\n const lines = text\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter(Boolean);\n const pairs: Record = {};\n\n for (const line of lines) {\n const parts = line.split(\":\");\n if (parts.length !== 2) {\n throw Error(`Invalid line '${line}'`);\n }\n const key = parts[0].trim();\n const value = parts[1].trim();\n if (key.length === 0 || value.length === 0) {\n throw Error(`Invalid line '${line}'`);\n }\n if (pairs[key] != null) {\n throw Error(`Duplicate key '${key}' in '${text}'`);\n }\n pairs[key] = value;\n }\n\n return pairs;\n}\n\nfunction parseVariables(variables: Record): SnippetVariable[] {\n const variablesMap: Record = {};\n\n const getVariable = (name: string): SnippetVariable => {\n if (variablesMap[name] == null) {\n variablesMap[name] = { name };\n }\n return variablesMap[name];\n };\n\n for (const [key, value] of Object.entries(variables)) {\n const parts = key.split(\".\");\n if (parts.length !== 2) {\n throw Error(`Invalid variable key '${key}'`);\n }\n const name = parts[0].slice(1);\n const field = parts[1];\n switch (field) {\n case \"insertionFormatter\":\n getVariable(name).insertionFormatters = parseVectorValue(value);\n break;\n case \"wrapperPhrase\":\n getVariable(name).wrapperPhrases = parseVectorValue(value);\n break;\n case \"wrapperScope\":\n getVariable(name).wrapperScope = value;\n break;\n default:\n throw Error(`Invalid variable key '${key}'`);\n }\n }\n\n return Object.values(variablesMap);\n}\n\nfunction parseBody(text: string): string[] | undefined {\n // Find first line that is not empty. Preserve indentation.\n const matchLeading = text.match(/^[ \\t]*\\S/m);\n if (matchLeading?.index == null) {\n return undefined;\n }\n return text\n .slice(matchLeading.index)\n .trimEnd()\n .split(/\\r?\\n/)\n .map((l) => l.trimEnd());\n}\n\nfunction parseVectorValue(value: string): string[] {\n return value.split(\"|\").map((v) => v.trim());\n}\n", "// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import type { FormatterOptions } from \"../types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"../util/constants.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport type {\n Snippet,\n SnippetFile,\n SnippetHeader,\n SnippetVariable,\n} from \"./snippetTypes.js\";\n\nexport type Options = FormatterOptions<\"endOfLine\" | \"insertFinalNewline\">;\n\nexport function serializeSnippetFile(\n snippetFile: SnippetFile,\n options: Options = {},\n): string {\n const eol = getEndOfLine(options.endOfLine);\n const serializer = new SnippetSerializer(\n eol,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n );\n return serializer.getText(snippetFile);\n}\n\nclass SnippetSerializer {\n constructor(\n private eol: string,\n private insertFinalNewline: boolean,\n ) {}\n\n getText(snippetFile: SnippetFile): string {\n const docDelimiter = \"---\";\n const documents: string[] = [];\n\n if (snippetFile.header != null) {\n documents.push(this.getDocumentText(snippetFile.header));\n }\n\n documents.push(\n ...snippetFile.snippets.map(this.getDocumentText.bind(this)),\n );\n\n const result = documents\n .filter((d) => d.length > 0)\n .join(`${this.eol}${docDelimiter}${this.eol}${this.eol}`);\n\n if (result.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return result + `${this.eol}${docDelimiter}${this.eol}`;\n }\n\n return result + `${this.eol}${docDelimiter}`;\n }\n\n private getDocumentText(document: SnippetHeader | Snippet): string {\n const lines: string[] = [\n getOptionalPairString(\"name\", document.name),\n getOptionalPairString(\"description\", document.description),\n getOptionalPairString(\"language\", document.languages),\n getOptionalPairString(\"phrase\", document.phrases),\n getOptionalPairString(\"insertionScope\", document.insertionScopes),\n ].filter(Boolean);\n\n if (document.variables.length > 0) {\n if (lines.length > 0) {\n lines.push(\"\");\n }\n lines.push(...getSortedVariables(document.variables));\n }\n\n if (\"body\" in document) {\n lines.push(\"-\", ...document.body);\n }\n\n return lines.join(this.eol);\n }\n}\n\nfunction getSortedVariables(variables: SnippetVariable[]): string[] {\n const result = variables.slice();\n result.sort(compareVariables);\n return result\n .flatMap((variable) => [\n getOptionalPairString(\n `$${variable.name}.insertionFormatter`,\n variable.insertionFormatters,\n ),\n getOptionalPairString(\n `$${variable.name}.wrapperPhrase`,\n variable.wrapperPhrases,\n ),\n getOptionalPairString(\n `$${variable.name}.wrapperScope`,\n variable.wrapperScope,\n ),\n ])\n .filter((v) => v.length > 0);\n}\n\nfunction getOptionalPairString(\n key: string,\n value: string | string[] | undefined,\n): string {\n if (value == null) {\n return \"\";\n }\n if (Array.isArray(value)) {\n return `${key}: ${value.join(\" | \")}`;\n }\n return `${key}: ${value}`;\n}\n\nfunction compareVariables(a: SnippetVariable, b: SnippetVariable): number {\n if (a.name === \"0\") {\n return 1;\n }\n if (b.name === \"0\") {\n return -1;\n }\n return a.name.localeCompare(b.name);\n}\n", "import { parseSnippetFile } from \"./parseSnippetFile.js\";\nimport { serializeSnippetFile } from \"./serializeSnippetFile.js\";\nimport type { Options } from \"./serializeSnippetFile.js\";\n\nexport function snippetFormatter(text: string, options?: Options): string {\n const snippetFile = parseSnippetFile(text);\n return serializeSnippetFile(snippetFile, options);\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.2\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { snippetFormatter } from \"../snippet/snippetFormatter.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEnding = \"snippet\";\n\nvoid main({\n binName: \"snippet-fmt\",\n fileEndings: [fileEnding],\n\n getStdinFileEnding() {\n return fileEnding;\n },\n\n format: async (text, options) => {\n const updated = snippetFormatter(text, options);\n return Promise.resolve(updated);\n },\n});\n"], "mappings": "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", "names": ["parseSnippetFile", "content", "documentContents", "file", "text", "match", "contextText", "bodyText", "body", "parseBody", "context", "parseContext", "variables", "rest", "document", "pairs", "parseContextPairs", "key", "value", "parseVectorValue", "parseVariables", "lines", "l", "line", "parts", "variablesMap", "getVariable", "name", "matchLeading", "v", "IGNORE_FOLDERS", "GLOB_IGNORE_PATTERNS", "pattern", "getEndOfLine", "eof", "serializeSnippetFile", "snippetFile", "options", "eol", "getEndOfLine", "SnippetSerializer", "insertFinalNewline", "documents", "result", "d", "document", "lines", "getOptionalPairString", "getSortedVariables", "variables", "compareVariables", "variable", "v", "key", "value", "a", "b", "snippetFormatter", "text", "options", "snippetFile", "parseSnippetFile", "serializeSnippetFile", "getStdin", "fs", "path", "process", "getErrorMessage", "error", "shortMessage", "SyntaxError", "point", "location", "getLocation", "getMessage", "file", "isSyntaxError", "error", "process", "ANSI_RESET", "ANSI_YELLOW", "ANSI_RED", "WARN_PREFIX", "ERROR_PREFIX", "createLogger", "quiet", "createLoggerFromStreams", "stdout", "stderr", "colorize", "shouldUseColor", "message", "color", "_color", "log", "warn", "shouldUseColor", "stream", "FilePatternError", "messages", "editorconfig", "getOptionsFromConfig", "filePath", "config", "options", "isMissingFileError", "error", "path", "normalizeToPosix", "filepath", "getDefaultArguments", "parseArgs", "argv", "result", "getDefaultArguments", "i", "arg", "parseKnownArgument", "fastGlob", "path", "fs", "lstatSafe", "filePath", "error", "isMissingFileError", "parseFilePatterns", "cli", "filePatterns", "seen", "globFileEndingPattern", "getGlobFileEndingsPattern", "errorMessages", "globOptions", "GLOB_IGNORE_PATTERNS", "pattern", "absolutePath", "stat", "lstatSafe", "files", "fastGlob", "file", "glob", "normalizeToPosix", "hasSupportedFileEnding", "FilePatternError", "a", "b", "fileEndings", "extension", "KNOWN_ARGUMENTS", "printHelp", "cli", "option", "KNOWN_ARGUMENTS", "package_default", "printVersion", "package_default", "setExitCode", "code", "main", "cli", "logger", "createLogger", "args", "parseArgs", "exitCode", "mainUnsafe", "setExitCode", "error", "FilePatternError", "message", "getErrorMessage", "printHelp", "printVersion", "mainFormatFiles", "mainFormatStdin", "check", "debug", "filePatterns", "filePaths", "parseFilePatterns", "changedFileCount", "hasError", "formatFiles", "filePath", "formatFile", "isSyntaxError", "getDisplayPath", "options", "getOptionsFromConfig", "content", "formatted", "isMissingFileError", "normalizeToPosix", "stdin", "input", "getStdin", "fauxFileName", "fauxFilePath", "fileEnding", "main", "text", "options", "updated", "snippetFormatter"] } diff --git a/dist/talonFormatter.js b/dist/talonFormatter.js index 6201279..cb7c261 100644 --- a/dist/talonFormatter.js +++ b/dist/talonFormatter.js @@ -10,6 +10,6 @@ ${r.join(` `),process.stdout.write(` `),process.stdout.write(`Options: `);for(let e of ae)process.stdout.write(` ${e} -`)}var ce={name:"@cursorless/talon-tools",version:"0.10.1",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function pe(){process.stdout.write(`${ce.version} +`)}var ce={name:"@cursorless/talon-tools",version:"0.10.2",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function pe(){process.stdout.write(`${ce.version} `)}function D(t){Reflect.set(process,"exitCode",t)}async function de(t){let e=R();try{let r=re(p.argv.slice(2));e=R(r.quiet);let n=await ze({cli:t,args:r,logger:e});D(n)}catch(r){if(r instanceof m)for(let n of r.messages)e.error(n);else e.error(j(r));D(2)}}async function ze({cli:t,args:e,logger:r}){if(e.help)return le(t),0;if(e.version)return pe(),0;if(e.filePatterns.length>0)return Ve({cli:t,logger:r,check:e.check,debug:e.debug,filePatterns:e.filePatterns});if(!p.stdin.isTTY)return He({cli:t,logger:r,stdin:p.stdin,check:e.check,debug:e.debug});throw new Error("No input files specified. Use --help for usage information.")}async function Ve({cli:t,logger:e,check:r,debug:n,filePatterns:s}){r&&e.log("Checking formatting...");let o=await se(t,s),[i,a]=await Ge({cli:t,logger:e,check:r,debug:n,filePaths:o});if(r){if(i>0&&(e.warn(`Code style issues found in ${i} file(s).`),!a))return 1;a||e.log("All matched files use correct code style!")}return a?2:0}async function Ge({cli:t,logger:e,check:r,debug:n,filePaths:s}){let o=0,i=!1;for(let a of s)try{await Ke({cli:t,logger:e,check:r,debug:n,filePath:a})&&o++}catch(l){k(l)?e.error(l.getFileMessage(M(a))):e.error(`${M(a)}: ${j(l)}`),i=!0}return[o,i]}async function Ke({cli:t,logger:e,check:r,debug:n,filePath:s}){try{let o=await W(s),i=await T.readFile(s,"utf8"),a=await t.format(i,o,s,n);return a===i?!1:(e.log(M(s)),r||await T.writeFile(s,a,"utf8"),!0)}catch(o){if(S(o))return!1;throw o}}function M(t){return F($.relative(p.cwd(),t))}async function He({cli:t,logger:e,stdin:r,check:n,debug:s}){let o=await Ue({stdin:r}),a=`stdin.${t.getStdinFileEnding(o)}`,l=$.resolve(a),f=await W(l),d;try{d=await t.format(o,f,l,s)}catch(c){if(k(c))return e.error(c.getFileMessage("stdin")),2;throw c}return n?o!==d?(e.warn("Code style issues found in stdin."),1):0:(p.stdout.write(d),0)}var ge="talon",ue="talon-list";de({binName:"talon-fmt",fileEndings:[ge,ue],getStdinFileEnding(t){return me(t)?ue:ge},format:async(t,e,r,n)=>{if(Xe(t,r)){let o=C(t,e);return Promise.resolve(o)}let s=await Y(t,"tree-sitter-talon");return A(s,e,n)}});function Xe(t,e){return e.endsWith(".talon")?!1:e.endsWith(".talon-list")?!0:me(t)}function me(t){return t.trimStart().startsWith("list:")} //# sourceMappingURL=talonFormatter.js.map diff --git a/dist/talonFormatter.js.map b/dist/talonFormatter.js.map index 3d3dc15..5dd198e 100644 --- a/dist/talonFormatter.js.map +++ b/dist/talonFormatter.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/util/constants.ts", "../src/util/getEndOfLine.ts", "../src/util/createDebugLogger.ts", "../src/util/getColumnWidth.ts", "../src/util/getIndentation.ts", "../src/util/SyntaxError.ts", "../src/util/SyntaxTreeError.ts", "../src/talon/convertQuotes.ts", "../src/talon/talonFormatter.ts", "../src/talon/parseTalonList.ts", "../src/talon/talonListFormatter.ts", "../src/node/parseText.ts", "../src/node/cli.ts", "../src/util/getErrorMessage.ts", "../src/node/createLogger.ts", "../src/node/FilePatternError.ts", "../src/node/getOptionsFromConfig.ts", "../src/node/isMissingFileError.ts", "../src/node/normalizeToPosix.ts", "../src/node/getDefaultArguments.ts", "../src/node/parseArgs.ts", "../src/node/parseFilePatterns.ts", "../src/node/lstatSafe.ts", "../src/types.ts", "../src/node/printHelp.ts", "../package.json", "../src/node/printVersion.ts", "../src/node/setExitCode.ts", "../src/node/talonFormatter.ts"], - "sourcesContent": ["// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import type { DebugLogger } from \"../types.js\";\n\nexport function createDebugLogger(debug: boolean): DebugLogger {\n return {\n debug(message: string) {\n if (debug) {\n console.warn(`[debug] ${message}`);\n }\n },\n };\n}\n", "export function getColumnWidth(text: string): number | undefined {\n const match = text.match(/# fmt: columnWidth=(\\d+)/);\n\n if (match != null) {\n return parseInt(match[1], 10);\n }\n\n return undefined;\n}\n", "import { DEFAULT_INDENT_WIDTH } from \"./constants.js\";\n\nexport function getIndentation(\n indentTabs: boolean | undefined,\n indentSize: number | undefined,\n): string {\n return indentTabs ? \"\\t\" : \" \".repeat(indentSize ?? DEFAULT_INDENT_WIDTH);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import type { SyntaxNode } from \"../types.js\";\nimport { SyntaxError } from \"./SyntaxError.js\";\n\nexport class SyntaxTreeError extends SyntaxError {\n constructor(rootNode: SyntaxNode) {\n super(findFirstProblemNode(rootNode)?.startPosition);\n this.name = \"SyntaxTreeError\";\n }\n}\n\nfunction findFirstProblemNode(node: SyntaxNode): SyntaxNode | null {\n if (node.isError || node.isMissing) {\n return node;\n }\n for (const child of node.children) {\n if (!child.hasError) {\n continue;\n }\n const errorNode = findFirstProblemNode(child);\n if (errorNode != null) {\n return errorNode;\n }\n }\n return null;\n}\n", "export function convertQuotes(text: string): string {\n // Convert single quotes to double quotes\n if (\n text.length > 0 &&\n text[0] === \"'\" &&\n text[text.length - 1] === \"'\" &&\n !text.includes('\"')\n ) {\n const innerText = text.slice(1, -1).replaceAll(\"\\\\'\", \"'\");\n return `\"${innerText}\"`;\n }\n\n return text;\n}\n", "import type { DebugLogger, FormatterOptions, SyntaxNode } from \"../types.js\";\nimport {\n DEFAULT_INSERT_FINAL_NEWLINE,\n DEFAULT_MAX_LINE_LENGTH,\n} from \"../util/constants.js\";\nimport { createDebugLogger } from \"../util/createDebugLogger.js\";\nimport { getColumnWidth } from \"../util/getColumnWidth.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport { getIndentation } from \"../util/getIndentation.js\";\nimport { SyntaxTreeError } from \"../util/SyntaxTreeError.js\";\nimport { convertQuotes } from \"./convertQuotes.js\";\n\nexport type Options = FormatterOptions<\n | \"endOfLine\"\n | \"indentTabs\"\n | \"indentSize\"\n | \"maxLineLength\"\n | \"columnWidth\"\n | \"insertFinalNewline\"\n | \"preserveMultiline\"\n>;\n\nexport function talonFormatter(\n node: SyntaxNode,\n options: Options = {},\n debug: boolean = false,\n): string {\n if (node.hasError) {\n throw new SyntaxTreeError(node);\n }\n\n const columnWidth = getColumnWidth(node.text) ?? options.columnWidth;\n const indentation = getIndentation(options.indentTabs, options.indentSize);\n const eol = getEndOfLine(options.endOfLine);\n const formatter = new TalonFormatter(\n indentation,\n eol,\n options.maxLineLength ?? DEFAULT_MAX_LINE_LENGTH,\n columnWidth,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n options.preserveMultiline ?? false,\n debug,\n );\n return formatter.getText(node);\n}\n\nclass TalonFormatter {\n private lines: string[] = [];\n private lastRow = 0;\n private logger: DebugLogger;\n\n constructor(\n private indent: string,\n private eol: string,\n private maxLineLength: number,\n private columnWidth: number | undefined,\n private insertFinalNewline: boolean,\n private preserveMultiline: boolean,\n debug: boolean,\n ) {\n this.logger = createDebugLogger(debug);\n }\n\n getText(node: SyntaxNode): string {\n this.addNode(node);\n\n const result = this.lines.join(this.eol).trimEnd();\n\n if (result.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return result + this.eol;\n }\n\n return result;\n }\n\n private addNL(): void {\n if (this.lines[this.lines.length - 1] !== \"\") {\n this.lines.push(\"\");\n }\n }\n\n private addNode(node: SyntaxNode, isIndented = false): void {\n if (node.startPosition.row > this.lastRow + 1) {\n this.addNL();\n }\n this.lastRow = node.endPosition.row;\n this.addNodeHelper(node, isIndented);\n this.lastRow = node.endPosition.row;\n }\n\n private addNodeHelper(node: SyntaxNode, isIndented = false): void {\n switch (node.type) {\n case \"source_file\":\n for (const n of node.children) {\n this.addNode(n);\n }\n break;\n\n case \"matches\": {\n // There are match nodes or there is a comment before\n if (node.children.length > 1 || !isFirstChild(node)) {\n for (const n of node.children) {\n this.addNode(n);\n }\n this.addNL();\n }\n break;\n }\n\n case \"declarations\":\n for (const n of node.children) {\n this.addNode(n);\n }\n break;\n\n case \"block\":\n for (const n of node.children) {\n this.addNode(n, true);\n }\n break;\n\n case \"command_declaration\":\n case \"key_binding_declaration\":\n case \"parrot_declaration\":\n case \"noise_declaration\":\n case \"face_declaration\":\n case \"gamepad_declaration\":\n case \"deck_declaration\":\n this.addLeftRightNode(node, false);\n break;\n\n case \"settings_declaration\":\n if (\n this.lines.length > 0 &&\n !this.lines[this.lines.length - 1].startsWith(\"#\")\n ) {\n this.addNL();\n }\n this.addLeftRightNode(node, true);\n this.addNL();\n break;\n\n case \"comment\": {\n // When using crlf eol comments have a trailing `\\r`\n const text = node.text.trimEnd();\n const nodeText =\n isIndented || node.startPosition.column > 0\n ? `${this.indent}${text}`\n : text;\n this.lines.push(nodeText);\n break;\n }\n\n default: {\n const nodeText = this.getNodeText(node);\n this.lines.push(\n isIndented ? `${this.indent}${nodeText}` : nodeText,\n );\n }\n }\n }\n\n private getNodeText(node: SyntaxNode): string {\n switch (node.type) {\n case \"source_file\":\n case \"matches\":\n case \"declarations\":\n case \"block\":\n case \"command_declaration\":\n case \"key_binding_declaration\":\n case \"parrot_declaration\":\n case \"noise_declaration\":\n case \"face_declaration\":\n case \"gamepad_declaration\":\n case \"deck_declaration\":\n case \"settings_declaration\":\n case \"comment\":\n throw new Error(\n `Node type '${node.type}' should be handled in addNode, not getNodeText`,\n );\n\n case \"parenthesized_rule\":\n return this.pairWithChildren(\n node,\n node.parent != null && rangeEqual(node, node.parent),\n );\n\n case \"optional\":\n return this.pairWithChildren(node);\n\n case \"expression_statement\":\n case \"assignment_statement\":\n case \"seq\":\n case \"choice\":\n return node.children.map((n) => this.getNodeText(n)).join(\" \");\n\n case \"rule\":\n case \"action\":\n case \"key_action\":\n case \"sleep_action\":\n case \"argument_list\":\n case \"key_binding\":\n case \"face_binding\":\n case \"gamepad_binding\":\n case \"parrot_binding\":\n case \"noise_binding\":\n case \"deck_binding\":\n case \"tag_import_declaration\":\n case \"match\":\n return node.children.map((n) => this.getNodeText(n)).join(\"\");\n\n case \"string\":\n return formatString(node);\n\n case \"match_modifier\":\n case \":\":\n case \",\":\n return `${node.text} `;\n\n case \"implicit_string\":\n return node.text.trim();\n\n case \"tag_binding\":\n case \"settings_binding\":\n case \"capture\":\n case \"list\":\n case \"key(\":\n case \"sleep(\":\n case \"gamepad(\":\n case \"face(\":\n case \"parrot(\":\n case \"noise(\":\n case \"identifier\":\n case \"variable\":\n case \"word\":\n case \"binary_operator\":\n case \"integer\":\n case \"float\":\n case \"start_anchor\":\n case \"end_anchor\":\n case \"repeat\":\n case \"deck(\":\n case \"repeat1\":\n case \"(\":\n case \")\":\n case \"=\":\n case \"-\":\n case \"|\":\n return node.text;\n\n default:\n this.logger.debug(`Unknown syntax node type '${node.type}'`);\n return node.text;\n }\n }\n\n private pairWithChildren(\n node: SyntaxNode,\n unwrap: boolean = false,\n ): string {\n const { children } = node;\n const middle = children\n .slice(1, -1)\n .map((n) => this.getNodeText(n))\n .join(\" \");\n if (unwrap) {\n return middle;\n }\n const pre = children[0].text;\n const post = children[children.length - 1].text;\n return `${pre}${middle}${post}`;\n }\n\n private addLeftRightNode(node: SyntaxNode, forceMultiline: boolean): void {\n const [leftNode, _colonNode, ...rightNodes] = node.children;\n const left = this.getNodeText(leftNode);\n\n if (!forceMultiline && rightNodes.length === 1) {\n if (\n !this.preserveMultiline ||\n isLeftRightSingleLine(leftNode, rightNodes)\n ) {\n const rightNode = rightNodes[0];\n if (rightNode.children.length === 1) {\n const right = this.getNodeText(rightNode.children[0]);\n const leftWithPadding =\n this.columnWidth != null\n ? `${left}: `.padEnd(this.columnWidth)\n : `${left}: `;\n if (\n leftWithPadding.length + right.length <=\n this.maxLineLength\n ) {\n this.lines.push(leftWithPadding + right);\n return;\n }\n }\n }\n }\n\n this.lines.push(`${left}:`);\n\n for (const n of rightNodes) {\n this.addNode(n, true);\n }\n }\n}\n\nfunction isLeftRightSingleLine(\n left: SyntaxNode,\n rights: SyntaxNode[],\n): boolean {\n return left.endPosition.row === rights[rights.length - 1].startPosition.row;\n}\n\nfunction rangeEqual(a: SyntaxNode, b: SyntaxNode): boolean {\n return (\n a.startPosition.row === b.startPosition.row &&\n a.startPosition.column === b.startPosition.column &&\n a.endPosition.row === b.endPosition.row &&\n a.endPosition.column === b.endPosition.column\n );\n}\n\nfunction isFirstChild(node: SyntaxNode): boolean {\n return node.id === node.parent?.children?.[0]?.id;\n}\n\nfunction formatString(node: SyntaxNode): string {\n // Convert single quotes to double quotes\n const text = convertQuotes(node.text);\n\n // A single string literal is allowed as syntactic sugar for the insert\n // action, but not in combination with other sibling statements.\n if (\n node.parent?.type === \"expression_statement\" &&\n node.parent.parent?.type === \"block\" &&\n rangeEqual(node, node.parent) &&\n node.parent.parent.children.length > 1\n ) {\n return `insert(${text})`;\n }\n\n return text;\n}\n", "interface TalonListHeader {\n type: \"header\";\n key: string;\n value: string;\n}\n\ninterface TalonListItem {\n type: \"item\";\n key: string;\n value?: string;\n}\n\ninterface EmptyLine {\n type: \"empty\";\n}\n\ninterface CommentLine {\n type: \"comment\";\n text: string;\n}\n\nexport interface TalonList {\n headers: (TalonListHeader | CommentLine)[];\n items: (TalonListItem | CommentLine | EmptyLine)[];\n}\n\nexport function parseTalonList(text: string): TalonList {\n const lines = text.split(/\\r?\\n/).map((l) => l.trim());\n const separatorIndex = lines.indexOf(\"-\");\n\n if (separatorIndex === -1) {\n throw Error(\"Separator not found in talon list\");\n }\n\n const headerLines = lines.slice(0, separatorIndex);\n const bodyLines = trim(lines.slice(separatorIndex + 1));\n\n const result: TalonList = {\n headers: [],\n items: [],\n };\n\n for (const line of headerLines) {\n if (line.length === 0) {\n continue;\n }\n if (line.startsWith(\"#\")) {\n result.headers.push({ type: \"comment\", text: line });\n continue;\n }\n const [key, value] = splitLine(line);\n if (value == null) {\n throw Error(\"Header value missing\");\n }\n result.headers.push({ type: \"header\", key, value });\n }\n\n for (const line of bodyLines) {\n if (line.length === 0) {\n result.items.push({ type: \"empty\" });\n continue;\n }\n if (line.startsWith(\"#\")) {\n result.items.push({ type: \"comment\", text: line });\n continue;\n }\n const [key, value] = splitLine(line);\n result.items.push({ type: \"item\", key, value });\n }\n\n return result;\n}\n\nfunction splitLine(line: string): [string, string | undefined] {\n const index = line.indexOf(\":\");\n if (index === -1) {\n return [line, undefined];\n }\n return [\n line.substring(0, index).trimEnd(),\n line.substring(index + 1).trimStart(),\n ];\n}\n\nfunction trim(list: string[]): string[] {\n const startIndex = list.findIndex((l) => l.length > 0);\n if (startIndex < 0) {\n return [];\n }\n const endIndex = list.findLastIndex((l) => l.length > 0);\n return list.slice(startIndex, endIndex + 1);\n}\n", "import type { FormatterOptions } from \"../types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"../util/constants.js\";\nimport { getColumnWidth } from \"../util/getColumnWidth.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport { convertQuotes } from \"./convertQuotes.js\";\nimport { parseTalonList } from \"./parseTalonList.js\";\n\ntype Options = FormatterOptions<\n \"endOfLine\" | \"columnWidth\" | \"insertFinalNewline\"\n>;\n\nexport function talonListFormatter(\n text: string,\n options: Options = {},\n): string {\n const columnWidth = getColumnWidth(text) ?? options.columnWidth;\n const eol = getEndOfLine(options.endOfLine);\n const talonList = parseTalonList(text);\n talonList.headers.sort((a, _b) =>\n a.type === \"header\" && a.key === \"list\" ? -1 : 0,\n );\n const lines: string[] = [];\n\n for (const header of talonList.headers) {\n if (header.type === \"comment\") {\n lines.push(header.text);\n continue;\n }\n lines.push(`${header.key}: ${header.value}`);\n }\n\n lines.push(\"-\", \"\");\n\n for (const item of talonList.items) {\n if (item.type === \"empty\") {\n lines.push(\"\");\n continue;\n }\n if (item.type === \"comment\") {\n lines.push(item.text);\n continue;\n }\n if (item.value != null) {\n const keyWithColon =\n columnWidth != null\n ? `${item.key}: `.padEnd(columnWidth)\n : `${item.key}: `;\n const value = convertQuotes(item.value);\n lines.push(`${keyWithColon}${value}`);\n } else {\n lines.push(item.key);\n }\n }\n\n if (lines.length === 0) {\n return \"\";\n }\n\n if (options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE) {\n lines.push(\"\");\n }\n\n return lines.join(eol);\n}\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Language, Parser } from \"web-tree-sitter\";\nimport type { SyntaxNode } from \"../types.js\";\n\ntype ParserName = \"tree-sitter-talon\" | \"tree-sitter-query\";\n\nlet initPromise: Promise | undefined;\nconst languageCache = new Map>();\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nfunction initTreeSitter() {\n initPromise ??= Parser.init();\n return initPromise;\n}\n\nfunction loadLanguage(parserName: ParserName) {\n let promise = languageCache.get(parserName);\n\n if (promise == null) {\n const wasmFilePath = getWasmFilePath(parserName);\n promise = Language.load(wasmFilePath);\n languageCache.set(parserName, promise);\n }\n\n return promise;\n}\n\nfunction getWasmFilePath(parserName: ParserName) {\n const fileName = `${parserName}.wasm`;\n const wasmFilePath = [\n path.join(\n moduleDir,\n \"../../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n path.join(\n moduleDir,\n \"../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n ].find((candidate) => fs.existsSync(candidate));\n\n if (wasmFilePath == null) {\n throw new Error(`Could not find ${fileName}`);\n }\n\n return wasmFilePath;\n}\n\nexport async function parseText(\n text: string,\n parserName: ParserName,\n): Promise {\n await initTreeSitter();\n\n const language = await loadLanguage(parserName);\n\n const parser = new Parser();\n parser.setLanguage(language);\n\n const tree = parser.parse(text);\n\n if (tree == null) {\n throw new Error(\"Failed to parse text\");\n }\n\n return tree.rootNode;\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.1\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { talonListFormatter } from \"../lib.js\";\nimport { talonFormatter } from \"../talon/talonFormatter.js\";\nimport { parseText } from \"./parseText.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEndingTalon = \"talon\";\nconst fileEndingTalonList = \"talon-list\";\n\nvoid main({\n binName: \"talon-fmt\",\n fileEndings: [fileEndingTalon, fileEndingTalonList],\n\n getStdinFileEnding(text) {\n return textIsList(text) ? fileEndingTalonList : fileEndingTalon;\n },\n\n format: async (text, options, filePath, debug) => {\n if (isListFile(text, filePath)) {\n const updated = talonListFormatter(text, options);\n return Promise.resolve(updated);\n }\n\n const node = await parseText(text, \"tree-sitter-talon\");\n return talonFormatter(node, options, debug);\n },\n});\n\nfunction isListFile(text: string, filePath: string): boolean {\n if (filePath.endsWith(\".talon\")) {\n return false;\n }\n if (filePath.endsWith(\".talon-list\")) {\n return true;\n }\n return textIsList(text);\n}\n\nfunction textIsList(text: string): boolean {\n return text.trimStart().startsWith(\"list:\");\n}\n"], + "sourcesContent": ["// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import type { DebugLogger } from \"../types.js\";\n\nexport function createDebugLogger(debug: boolean): DebugLogger {\n return {\n debug(message: string) {\n if (debug) {\n console.warn(`[debug] ${message}`);\n }\n },\n };\n}\n", "export function getColumnWidth(text: string): number | undefined {\n const match = text.match(/# fmt: columnWidth=(\\d+)/);\n\n if (match != null) {\n return parseInt(match[1], 10);\n }\n\n return undefined;\n}\n", "import { DEFAULT_INDENT_WIDTH } from \"./constants.js\";\n\nexport function getIndentation(\n indentTabs: boolean | undefined,\n indentSize: number | undefined,\n): string {\n return indentTabs ? \"\\t\" : \" \".repeat(indentSize ?? DEFAULT_INDENT_WIDTH);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import type { SyntaxNode } from \"../types.js\";\nimport { SyntaxError } from \"./SyntaxError.js\";\n\nexport class SyntaxTreeError extends SyntaxError {\n constructor(rootNode: SyntaxNode) {\n super(findFirstProblemNode(rootNode)?.startPosition);\n this.name = \"SyntaxTreeError\";\n }\n}\n\nfunction findFirstProblemNode(node: SyntaxNode): SyntaxNode | null {\n if (node.isError || node.isMissing) {\n return node;\n }\n for (const child of node.children) {\n if (!child.hasError) {\n continue;\n }\n const errorNode = findFirstProblemNode(child);\n if (errorNode != null) {\n return errorNode;\n }\n }\n return null;\n}\n", "export function convertQuotes(text: string): string {\n // Convert single quotes to double quotes\n if (\n text.length > 0 &&\n text[0] === \"'\" &&\n text[text.length - 1] === \"'\" &&\n !text.includes('\"')\n ) {\n const innerText = text.slice(1, -1).replaceAll(\"\\\\'\", \"'\");\n return `\"${innerText}\"`;\n }\n\n return text;\n}\n", "import type { DebugLogger, FormatterOptions, SyntaxNode } from \"../types.js\";\nimport {\n DEFAULT_INSERT_FINAL_NEWLINE,\n DEFAULT_MAX_LINE_LENGTH,\n} from \"../util/constants.js\";\nimport { createDebugLogger } from \"../util/createDebugLogger.js\";\nimport { getColumnWidth } from \"../util/getColumnWidth.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport { getIndentation } from \"../util/getIndentation.js\";\nimport { SyntaxTreeError } from \"../util/SyntaxTreeError.js\";\nimport { convertQuotes } from \"./convertQuotes.js\";\n\nexport type Options = FormatterOptions<\n | \"endOfLine\"\n | \"indentTabs\"\n | \"indentSize\"\n | \"maxLineLength\"\n | \"columnWidth\"\n | \"insertFinalNewline\"\n | \"preserveMultiline\"\n>;\n\nexport function talonFormatter(\n node: SyntaxNode,\n options: Options = {},\n debug: boolean = false,\n): string {\n if (node.hasError) {\n throw new SyntaxTreeError(node);\n }\n\n const columnWidth = getColumnWidth(node.text) ?? options.columnWidth;\n const indentation = getIndentation(options.indentTabs, options.indentSize);\n const eol = getEndOfLine(options.endOfLine);\n const formatter = new TalonFormatter(\n indentation,\n eol,\n options.maxLineLength ?? DEFAULT_MAX_LINE_LENGTH,\n columnWidth,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n options.preserveMultiline ?? false,\n debug,\n );\n return formatter.getText(node);\n}\n\nclass TalonFormatter {\n private lines: string[] = [];\n private lastRow = 0;\n private logger: DebugLogger;\n\n constructor(\n private indent: string,\n private eol: string,\n private maxLineLength: number,\n private columnWidth: number | undefined,\n private insertFinalNewline: boolean,\n private preserveMultiline: boolean,\n debug: boolean,\n ) {\n this.logger = createDebugLogger(debug);\n }\n\n getText(node: SyntaxNode): string {\n this.addNode(node);\n\n const result = this.lines.join(this.eol).trimEnd();\n\n if (result.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return result + this.eol;\n }\n\n return result;\n }\n\n private addNL(): void {\n if (this.lines[this.lines.length - 1] !== \"\") {\n this.lines.push(\"\");\n }\n }\n\n private addNode(node: SyntaxNode, isIndented = false): void {\n if (node.startPosition.row > this.lastRow + 1) {\n this.addNL();\n }\n this.lastRow = node.endPosition.row;\n this.addNodeHelper(node, isIndented);\n this.lastRow = node.endPosition.row;\n }\n\n private addNodeHelper(node: SyntaxNode, isIndented = false): void {\n switch (node.type) {\n case \"source_file\":\n for (const n of node.children) {\n this.addNode(n);\n }\n break;\n\n case \"matches\": {\n // There are match nodes or there is a comment before\n if (node.children.length > 1 || !isFirstChild(node)) {\n for (const n of node.children) {\n this.addNode(n);\n }\n this.addNL();\n }\n break;\n }\n\n case \"declarations\":\n for (const n of node.children) {\n this.addNode(n);\n }\n break;\n\n case \"block\":\n for (const n of node.children) {\n this.addNode(n, true);\n }\n break;\n\n case \"command_declaration\":\n case \"key_binding_declaration\":\n case \"parrot_declaration\":\n case \"noise_declaration\":\n case \"face_declaration\":\n case \"gamepad_declaration\":\n case \"deck_declaration\":\n this.addLeftRightNode(node, false);\n break;\n\n case \"settings_declaration\":\n if (\n this.lines.length > 0 &&\n !this.lines[this.lines.length - 1].startsWith(\"#\")\n ) {\n this.addNL();\n }\n this.addLeftRightNode(node, true);\n this.addNL();\n break;\n\n case \"comment\": {\n // When using crlf eol comments have a trailing `\\r`\n const text = node.text.trimEnd();\n const nodeText =\n isIndented || node.startPosition.column > 0\n ? `${this.indent}${text}`\n : text;\n this.lines.push(nodeText);\n break;\n }\n\n default: {\n const nodeText = this.getNodeText(node);\n this.lines.push(\n isIndented ? `${this.indent}${nodeText}` : nodeText,\n );\n }\n }\n }\n\n private getNodeText(node: SyntaxNode): string {\n switch (node.type) {\n case \"source_file\":\n case \"matches\":\n case \"declarations\":\n case \"block\":\n case \"command_declaration\":\n case \"key_binding_declaration\":\n case \"parrot_declaration\":\n case \"noise_declaration\":\n case \"face_declaration\":\n case \"gamepad_declaration\":\n case \"deck_declaration\":\n case \"settings_declaration\":\n case \"comment\":\n throw new Error(\n `Node type '${node.type}' should be handled in addNode, not getNodeText`,\n );\n\n case \"parenthesized_rule\":\n return this.pairWithChildren(\n node,\n node.parent != null && rangeEqual(node, node.parent),\n );\n\n case \"optional\":\n return this.pairWithChildren(node);\n\n case \"expression_statement\":\n case \"assignment_statement\":\n case \"seq\":\n case \"choice\":\n return node.children.map((n) => this.getNodeText(n)).join(\" \");\n\n case \"rule\":\n case \"action\":\n case \"key_action\":\n case \"sleep_action\":\n case \"argument_list\":\n case \"key_binding\":\n case \"face_binding\":\n case \"gamepad_binding\":\n case \"parrot_binding\":\n case \"noise_binding\":\n case \"deck_binding\":\n case \"tag_import_declaration\":\n case \"match\":\n return node.children.map((n) => this.getNodeText(n)).join(\"\");\n\n case \"string\":\n return formatString(node);\n\n case \"match_modifier\":\n case \":\":\n case \",\":\n return `${node.text} `;\n\n case \"implicit_string\":\n return node.text.trim();\n\n case \"tag_binding\":\n case \"settings_binding\":\n case \"capture\":\n case \"list\":\n case \"key(\":\n case \"sleep(\":\n case \"gamepad(\":\n case \"face(\":\n case \"parrot(\":\n case \"noise(\":\n case \"identifier\":\n case \"variable\":\n case \"word\":\n case \"binary_operator\":\n case \"integer\":\n case \"float\":\n case \"start_anchor\":\n case \"end_anchor\":\n case \"repeat\":\n case \"deck(\":\n case \"repeat1\":\n case \"(\":\n case \")\":\n case \"=\":\n case \"-\":\n case \"|\":\n return node.text;\n\n default:\n this.logger.debug(`Unknown syntax node type '${node.type}'`);\n return node.text;\n }\n }\n\n private pairWithChildren(\n node: SyntaxNode,\n unwrap: boolean = false,\n ): string {\n const { children } = node;\n const middle = children\n .slice(1, -1)\n .map((n) => this.getNodeText(n))\n .join(\" \");\n if (unwrap) {\n return middle;\n }\n const pre = children[0].text;\n const post = children[children.length - 1].text;\n return `${pre}${middle}${post}`;\n }\n\n private addLeftRightNode(node: SyntaxNode, forceMultiline: boolean): void {\n const [leftNode, _colonNode, ...rightNodes] = node.children;\n const left = this.getNodeText(leftNode);\n\n if (!forceMultiline && rightNodes.length === 1) {\n if (\n !this.preserveMultiline ||\n isLeftRightSingleLine(leftNode, rightNodes)\n ) {\n const rightNode = rightNodes[0];\n if (rightNode.children.length === 1) {\n const right = this.getNodeText(rightNode.children[0]);\n const leftWithPadding =\n this.columnWidth != null\n ? `${left}: `.padEnd(this.columnWidth)\n : `${left}: `;\n if (\n leftWithPadding.length + right.length <=\n this.maxLineLength\n ) {\n this.lines.push(leftWithPadding + right);\n return;\n }\n }\n }\n }\n\n this.lines.push(`${left}:`);\n\n for (const n of rightNodes) {\n this.addNode(n, true);\n }\n }\n}\n\nfunction isLeftRightSingleLine(\n left: SyntaxNode,\n rights: SyntaxNode[],\n): boolean {\n return left.endPosition.row === rights[rights.length - 1].startPosition.row;\n}\n\nfunction rangeEqual(a: SyntaxNode, b: SyntaxNode): boolean {\n return (\n a.startPosition.row === b.startPosition.row &&\n a.startPosition.column === b.startPosition.column &&\n a.endPosition.row === b.endPosition.row &&\n a.endPosition.column === b.endPosition.column\n );\n}\n\nfunction isFirstChild(node: SyntaxNode): boolean {\n return node.id === node.parent?.children?.[0]?.id;\n}\n\nfunction formatString(node: SyntaxNode): string {\n // Convert single quotes to double quotes\n const text = convertQuotes(node.text);\n\n // A single string literal is allowed as syntactic sugar for the insert\n // action, but not in combination with other sibling statements.\n if (\n node.parent?.type === \"expression_statement\" &&\n node.parent.parent?.type === \"block\" &&\n rangeEqual(node, node.parent) &&\n node.parent.parent.children.length > 1\n ) {\n return `insert(${text})`;\n }\n\n return text;\n}\n", "interface TalonListHeader {\n type: \"header\";\n key: string;\n value: string;\n}\n\ninterface TalonListItem {\n type: \"item\";\n key: string;\n value?: string;\n}\n\ninterface EmptyLine {\n type: \"empty\";\n}\n\ninterface CommentLine {\n type: \"comment\";\n text: string;\n}\n\nexport interface TalonList {\n headers: (TalonListHeader | CommentLine)[];\n items: (TalonListItem | CommentLine | EmptyLine)[];\n}\n\nexport function parseTalonList(text: string): TalonList {\n const lines = text.split(/\\r?\\n/).map((l) => l.trim());\n const separatorIndex = lines.indexOf(\"-\");\n\n if (separatorIndex === -1) {\n throw Error(\"Separator not found in talon list\");\n }\n\n const headerLines = lines.slice(0, separatorIndex);\n const bodyLines = trim(lines.slice(separatorIndex + 1));\n\n const result: TalonList = {\n headers: [],\n items: [],\n };\n\n for (const line of headerLines) {\n if (line.length === 0) {\n continue;\n }\n if (line.startsWith(\"#\")) {\n result.headers.push({ type: \"comment\", text: line });\n continue;\n }\n const [key, value] = splitLine(line);\n if (value == null) {\n throw Error(\"Header value missing\");\n }\n result.headers.push({ type: \"header\", key, value });\n }\n\n for (const line of bodyLines) {\n if (line.length === 0) {\n result.items.push({ type: \"empty\" });\n continue;\n }\n if (line.startsWith(\"#\")) {\n result.items.push({ type: \"comment\", text: line });\n continue;\n }\n const [key, value] = splitLine(line);\n result.items.push({ type: \"item\", key, value });\n }\n\n return result;\n}\n\nfunction splitLine(line: string): [string, string | undefined] {\n const index = line.indexOf(\":\");\n if (index === -1) {\n return [line, undefined];\n }\n return [\n line.substring(0, index).trimEnd(),\n line.substring(index + 1).trimStart(),\n ];\n}\n\nfunction trim(list: string[]): string[] {\n const startIndex = list.findIndex((l) => l.length > 0);\n if (startIndex < 0) {\n return [];\n }\n const endIndex = list.findLastIndex((l) => l.length > 0);\n return list.slice(startIndex, endIndex + 1);\n}\n", "import type { FormatterOptions } from \"../types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"../util/constants.js\";\nimport { getColumnWidth } from \"../util/getColumnWidth.js\";\nimport { getEndOfLine } from \"../util/getEndOfLine.js\";\nimport { convertQuotes } from \"./convertQuotes.js\";\nimport { parseTalonList } from \"./parseTalonList.js\";\n\ntype Options = FormatterOptions<\n \"endOfLine\" | \"columnWidth\" | \"insertFinalNewline\"\n>;\n\nexport function talonListFormatter(\n text: string,\n options: Options = {},\n): string {\n const columnWidth = getColumnWidth(text) ?? options.columnWidth;\n const eol = getEndOfLine(options.endOfLine);\n const talonList = parseTalonList(text);\n talonList.headers.sort((a, _b) =>\n a.type === \"header\" && a.key === \"list\" ? -1 : 0,\n );\n const lines: string[] = [];\n\n for (const header of talonList.headers) {\n if (header.type === \"comment\") {\n lines.push(header.text);\n continue;\n }\n lines.push(`${header.key}: ${header.value}`);\n }\n\n lines.push(\"-\", \"\");\n\n for (const item of talonList.items) {\n if (item.type === \"empty\") {\n lines.push(\"\");\n continue;\n }\n if (item.type === \"comment\") {\n lines.push(item.text);\n continue;\n }\n if (item.value != null) {\n const keyWithColon =\n columnWidth != null\n ? `${item.key}: `.padEnd(columnWidth)\n : `${item.key}: `;\n const value = convertQuotes(item.value);\n lines.push(`${keyWithColon}${value}`);\n } else {\n lines.push(item.key);\n }\n }\n\n if (lines.length === 0) {\n return \"\";\n }\n\n if (options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE) {\n lines.push(\"\");\n }\n\n return lines.join(eol);\n}\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Language, Parser } from \"web-tree-sitter\";\nimport type { SyntaxNode } from \"../types.js\";\n\ntype ParserName = \"tree-sitter-talon\" | \"tree-sitter-query\";\n\nlet initPromise: Promise | undefined;\nconst languageCache = new Map>();\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nfunction initTreeSitter() {\n initPromise ??= Parser.init();\n return initPromise;\n}\n\nfunction loadLanguage(parserName: ParserName) {\n let promise = languageCache.get(parserName);\n\n if (promise == null) {\n const wasmFilePath = getWasmFilePath(parserName);\n promise = Language.load(wasmFilePath);\n languageCache.set(parserName, promise);\n }\n\n return promise;\n}\n\nfunction getWasmFilePath(parserName: ParserName) {\n const fileName = `${parserName}.wasm`;\n const wasmFilePath = [\n path.join(\n moduleDir,\n \"../../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n path.join(\n moduleDir,\n \"../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n ].find((candidate) => fs.existsSync(candidate));\n\n if (wasmFilePath == null) {\n throw new Error(`Could not find ${fileName}`);\n }\n\n return wasmFilePath;\n}\n\nexport async function parseText(\n text: string,\n parserName: ParserName,\n): Promise {\n await initTreeSitter();\n\n const language = await loadLanguage(parserName);\n\n const parser = new Parser();\n parser.setLanguage(language);\n\n const tree = parser.parse(text);\n\n if (tree == null) {\n throw new Error(\"Failed to parse text\");\n }\n\n return tree.rootNode;\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.2\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { talonListFormatter } from \"../lib.js\";\nimport { talonFormatter } from \"../talon/talonFormatter.js\";\nimport { parseText } from \"./parseText.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEndingTalon = \"talon\";\nconst fileEndingTalonList = \"talon-list\";\n\nvoid main({\n binName: \"talon-fmt\",\n fileEndings: [fileEndingTalon, fileEndingTalonList],\n\n getStdinFileEnding(text) {\n return textIsList(text) ? fileEndingTalonList : fileEndingTalon;\n },\n\n format: async (text, options, filePath, debug) => {\n if (isListFile(text, filePath)) {\n const updated = talonListFormatter(text, options);\n return Promise.resolve(updated);\n }\n\n const node = await parseText(text, \"tree-sitter-talon\");\n return talonFormatter(node, options, debug);\n },\n});\n\nfunction isListFile(text: string, filePath: string): boolean {\n if (filePath.endsWith(\".talon\")) {\n return false;\n }\n if (filePath.endsWith(\".talon-list\")) {\n return true;\n }\n return textIsList(text);\n}\n\nfunction textIsList(text: string): boolean {\n return text.trimStart().startsWith(\"list:\");\n}\n"], "mappings": "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", "names": ["IGNORE_FOLDERS", "GLOB_IGNORE_PATTERNS", "pattern", "getEndOfLine", "eof", "createDebugLogger", "debug", "message", "getColumnWidth", "text", "match", "getIndentation", "indentTabs", "indentSize", "shortMessage", "SyntaxError", "point", "location", "getLocation", "getMessage", "file", "isSyntaxError", "error", "SyntaxTreeError", "SyntaxError", "rootNode", "findFirstProblemNode", "node", "child", "errorNode", "convertQuotes", "text", "talonFormatter", "node", "options", "debug", "SyntaxTreeError", "columnWidth", "getColumnWidth", "indentation", "getIndentation", "eol", "getEndOfLine", "TalonFormatter", "indent", "maxLineLength", "insertFinalNewline", "preserveMultiline", "createDebugLogger", "result", "isIndented", "isFirstChild", "text", "nodeText", "rangeEqual", "n", "formatString", "unwrap", "children", "middle", "pre", "post", "forceMultiline", "leftNode", "_colonNode", "rightNodes", "left", "isLeftRightSingleLine", "rightNode", "right", "leftWithPadding", "rights", "a", "b", "convertQuotes", "parseTalonList", "text", "lines", "l", "separatorIndex", "headerLines", "bodyLines", "trim", "result", "line", "key", "value", "splitLine", "index", "list", "startIndex", "endIndex", "talonListFormatter", "text", "options", "columnWidth", "getColumnWidth", "eol", "getEndOfLine", "talonList", "parseTalonList", "a", "_b", "lines", "header", "item", "keyWithColon", "value", "convertQuotes", "fs", "path", "fileURLToPath", "Language", "Parser", "initPromise", "languageCache", "moduleDir", "initTreeSitter", "loadLanguage", "parserName", "promise", "wasmFilePath", "getWasmFilePath", "fileName", "candidate", "parseText", "text", "language", "parser", "tree", "getStdin", "fs", "path", "process", "getErrorMessage", "error", "process", "ANSI_RESET", "ANSI_YELLOW", "ANSI_RED", "WARN_PREFIX", "ERROR_PREFIX", "createLogger", "quiet", "createLoggerFromStreams", "stdout", "stderr", "colorize", "shouldUseColor", "message", "color", "_color", "log", "warn", "shouldUseColor", "stream", "FilePatternError", "messages", "editorconfig", "getOptionsFromConfig", "filePath", "config", "options", "isMissingFileError", "error", "path", "normalizeToPosix", "filepath", "getDefaultArguments", "parseArgs", "argv", "result", "getDefaultArguments", "i", "arg", "parseKnownArgument", "fastGlob", "path", "fs", "lstatSafe", "filePath", "error", "isMissingFileError", "parseFilePatterns", "cli", "filePatterns", "seen", "globFileEndingPattern", "getGlobFileEndingsPattern", "errorMessages", "globOptions", "GLOB_IGNORE_PATTERNS", "pattern", "absolutePath", "stat", "lstatSafe", "files", "fastGlob", "file", "glob", "normalizeToPosix", "hasSupportedFileEnding", "FilePatternError", "a", "b", "fileEndings", "extension", "KNOWN_ARGUMENTS", "printHelp", "cli", "option", "KNOWN_ARGUMENTS", "package_default", "printVersion", "package_default", "setExitCode", "code", "main", "cli", "logger", "createLogger", "args", "parseArgs", "exitCode", "mainUnsafe", "setExitCode", "error", "FilePatternError", "message", "getErrorMessage", "printHelp", "printVersion", "mainFormatFiles", "mainFormatStdin", "check", "debug", "filePatterns", "filePaths", "parseFilePatterns", "changedFileCount", "hasError", "formatFiles", "filePath", "formatFile", "isSyntaxError", "getDisplayPath", "options", "getOptionsFromConfig", "content", "formatted", "isMissingFileError", "normalizeToPosix", "stdin", "input", "getStdin", "fauxFileName", "fauxFilePath", "fileEndingTalon", "fileEndingTalonList", "main", "text", "textIsList", "options", "filePath", "debug", "isListFile", "updated", "talonListFormatter", "node", "parseText", "talonFormatter"] } diff --git a/dist/treeSitterFormatter.js b/dist/treeSitterFormatter.js index dafe0dd..d935f09 100644 --- a/dist/treeSitterFormatter.js +++ b/dist/treeSitterFormatter.js @@ -10,6 +10,6 @@ ${r.join(` `),process.stdout.write(` `),process.stdout.write(`Options: `);for(let e of Z)process.stdout.write(` ${e} -`)}var te={name:"@cursorless/talon-tools",version:"0.10.1",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function re(){process.stdout.write(`${te.version} +`)}var te={name:"@cursorless/talon-tools",version:"0.10.2",description:"Linting and formatting tools for Talon and Cursorless",author:"Cursorless Dev",license:"MIT",type:"module",files:["dist","!dist/test","!dist/build.*"],types:"./dist/lib.d.ts",exports:{".":{types:"./dist/lib.d.ts",default:"./dist/lib.js"},"./node":{types:"./dist/node/libNode.d.ts",default:"./dist/libNode.js"}},bin:{"snippet-fmt":"dist/snippetFormatter.js","talon-fmt":"dist/talonFormatter.js","tree-sitter-fmt":"dist/treeSitterFormatter.js"},repository:{type:"git",url:"git+https://github.com/cursorless-dev/talon-tools.git"},funding:"https://github.com/sponsors/cursorless-dev",sponsor:{url:"https://github.com/sponsors/cursorless-dev"},scripts:{build:"npm run clean && tsc -p . && tsx ./src/build.ts",clean:"rm -rf dist/*",lint:"npm run lint:ts &&npm run lint:fmt","lint:ts":"tsc -p . --noEmit && eslint src","lint:fmt":"prettier --check .",fix:"npm run fix:ts && npm run fix:fmt","fix:ts":"eslint src --fix","fix:fmt":"prettier --write --list-different .",test:"tsx src/test/runAllTests.ts","test:subset":"tsx src/test/runAllTests.ts --subset"},dependencies:{"@cursorless/tree-sitter-wasms":"^0.7.0",editorconfig:"^3.0.2","fast-glob":"^3.3.3","get-stdin":"^10.0.0","web-tree-sitter":"^0.26.7"},devDependencies:{"@eslint/js":"^9.39.4","@types/mocha":"^10.0.10","@types/node":"^24.12.0",esbuild:"^0.27.4","eslint-config-prettier":"^10.1.8","eslint-plugin-import":"^2.32.0",eslint:"^9.39.4",jiti:"^2.6.1",mocha:"^11.7.5",prettier:"^3.8.1",tsx:"^4.21.0","typescript-eslint":"^8.57.1",typescript:"^5.9.3"}};function re(){process.stdout.write(`${te.version} `)}function v(t){Reflect.set(process,"exitCode",t)}async function ie(t){let e=S();try{let r=J(f.argv.slice(2));e=S(r.quiet);let n=await $e({cli:t,args:r,logger:e});v(n)}catch(r){if(r instanceof u)for(let n of r.messages)e.error(n);else e.error(T(r));v(2)}}async function $e({cli:t,args:e,logger:r}){if(e.help)return ee(t),0;if(e.version)return re(),0;if(e.filePatterns.length>0)return ve({cli:t,logger:r,check:e.check,debug:e.debug,filePatterns:e.filePatterns});if(!f.stdin.isTTY)return Ce({cli:t,logger:r,stdin:f.stdin,check:e.check,debug:e.debug});throw new Error("No input files specified. Use --help for usage information.")}async function ve({cli:t,logger:e,check:r,debug:n,filePatterns:i}){r&&e.log("Checking formatting...");let a=await Q(t,i),[o,s]=await Ae({cli:t,logger:e,check:r,debug:n,filePaths:a});if(r){if(o>0&&(e.warn(`Code style issues found in ${o} file(s).`),!s))return 1;s||e.log("All matched files use correct code style!")}return s?2:0}async function Ae({cli:t,logger:e,check:r,debug:n,filePaths:i}){let a=0,o=!1;for(let s of i)try{await Oe({cli:t,logger:e,check:r,debug:n,filePath:s})&&a++}catch(l){F(l)?e.error(l.getFileMessage(A(s))):e.error(`${A(s)}: ${T(l)}`),o=!0}return[a,o]}async function Oe({cli:t,logger:e,check:r,debug:n,filePath:i}){try{let a=await $(i),o=await L.readFile(i,"utf8"),s=await t.format(o,a,i,n);return s===o?!1:(e.log(A(i)),r||await L.writeFile(i,s,"utf8"),!0)}catch(a){if(w(a))return!1;throw a}}function A(t){return E(N.relative(f.cwd(),t))}async function Ce({cli:t,logger:e,stdin:r,check:n,debug:i}){let a=await Se({stdin:r}),s=`stdin.${t.getStdinFileEnding(a)}`,l=N.resolve(s),P=await $(l),g;try{g=await t.format(a,P,l,i)}catch(c){if(F(c))return e.error(c.getFileMessage("stdin")),2;throw c}return n?a!==g?(e.warn("Code style issues found in stdin."),1):0:(f.stdout.write(g),0)}var oe="scm";ie({binName:"tree-sitter-fmt",fileEndings:[oe],getStdinFileEnding(){return oe},format:async(t,e,r,n)=>{let i=await X(t,"tree-sitter-query");return D(i,e,n)}}); //# sourceMappingURL=treeSitterFormatter.js.map diff --git a/dist/treeSitterFormatter.js.map b/dist/treeSitterFormatter.js.map index 5c02a47..4845293 100644 --- a/dist/treeSitterFormatter.js.map +++ b/dist/treeSitterFormatter.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/util/constants.ts", "../src/util/createDebugLogger.ts", "../src/util/getEndOfLine.ts", "../src/util/getIndentation.ts", "../src/util/SyntaxError.ts", "../src/util/SyntaxTreeError.ts", "../src/treeSitterFormatter.ts", "../src/node/parseText.ts", "../src/node/cli.ts", "../src/util/getErrorMessage.ts", "../src/node/createLogger.ts", "../src/node/FilePatternError.ts", "../src/node/getOptionsFromConfig.ts", "../src/node/isMissingFileError.ts", "../src/node/normalizeToPosix.ts", "../src/node/getDefaultArguments.ts", "../src/node/parseArgs.ts", "../src/node/parseFilePatterns.ts", "../src/node/lstatSafe.ts", "../src/types.ts", "../src/node/printHelp.ts", "../package.json", "../src/node/printVersion.ts", "../src/node/setExitCode.ts", "../src/node/treeSitterFormatter.ts"], - "sourcesContent": ["// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { DebugLogger } from \"../types.js\";\n\nexport function createDebugLogger(debug: boolean): DebugLogger {\n return {\n debug(message: string) {\n if (debug) {\n console.warn(`[debug] ${message}`);\n }\n },\n };\n}\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import { DEFAULT_INDENT_WIDTH } from \"./constants.js\";\n\nexport function getIndentation(\n indentTabs: boolean | undefined,\n indentSize: number | undefined,\n): string {\n return indentTabs ? \"\\t\" : \" \".repeat(indentSize ?? DEFAULT_INDENT_WIDTH);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import type { SyntaxNode } from \"../types.js\";\nimport { SyntaxError } from \"./SyntaxError.js\";\n\nexport class SyntaxTreeError extends SyntaxError {\n constructor(rootNode: SyntaxNode) {\n super(findFirstProblemNode(rootNode)?.startPosition);\n this.name = \"SyntaxTreeError\";\n }\n}\n\nfunction findFirstProblemNode(node: SyntaxNode): SyntaxNode | null {\n if (node.isError || node.isMissing) {\n return node;\n }\n for (const child of node.children) {\n if (!child.hasError) {\n continue;\n }\n const errorNode = findFirstProblemNode(child);\n if (errorNode != null) {\n return errorNode;\n }\n }\n return null;\n}\n", "import type { DebugLogger, FormatterOptions, SyntaxNode } from \"./types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"./util/constants.js\";\nimport { createDebugLogger } from \"./util/createDebugLogger.js\";\nimport { getEndOfLine } from \"./util/getEndOfLine.js\";\nimport { getIndentation } from \"./util/getIndentation.js\";\nimport { SyntaxTreeError } from \"./util/SyntaxTreeError.js\";\n\nexport type Options = FormatterOptions<\n \"endOfLine\" | \"indentTabs\" | \"indentSize\" | \"insertFinalNewline\"\n>;\n\nexport function treeSitterFormatter(\n node: SyntaxNode,\n options: Options = {},\n debug: boolean = false,\n): string {\n if (node.hasError) {\n throw new SyntaxTreeError(node);\n }\n\n const indentation = getIndentation(options.indentTabs, options.indentSize);\n const eol = getEndOfLine(options.endOfLine);\n const formatter = new TreeSitterFormatter(\n indentation,\n eol,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n debug,\n );\n return formatter.getText(node);\n}\n\nclass TreeSitterFormatter {\n private lastRow = 0;\n private logger: DebugLogger;\n\n constructor(\n private indentation: string,\n private eol: string,\n private insertFinalNewline: boolean,\n debug: boolean,\n ) {\n this.logger = createDebugLogger(debug);\n }\n\n getText(node: SyntaxNode): string {\n const nodeText = this.getNodeText(node, 0);\n\n if (nodeText.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return nodeText + this.eol;\n }\n\n return nodeText;\n }\n\n private getNodeText(node: SyntaxNode, numIndents: number): string {\n const nl = node.startPosition.row > this.lastRow + 1 ? this.eol : \"\";\n this.lastRow = node.endPosition.row;\n const text = this.getNodeTextInternal(node, numIndents);\n this.lastRow = node.endPosition.row;\n return `${nl}${text}`;\n }\n\n private getNamedNodeText(node: SyntaxNode, numIndents: number): string {\n const index = node.children.findIndex((n) => n.type === \")\");\n const first = node.children\n .slice(0, 2)\n .map((n) => n.text)\n .join(\"\");\n const last = node.children\n .slice(index)\n .map((n) => this.getNodeText(n, 0))\n .join(\"\");\n const interior = node.children\n .slice(2, index)\n .map((n) => this.getNodeText(n, numIndents + 1));\n // Inline node\n if (interior.length === 0) {\n return `${this.getIndent(numIndents)}${first}${last}`;\n }\n // Multiline node\n return [\n `${this.getIndent(numIndents)}${first}`,\n ...interior,\n `${this.getIndent(numIndents)}${last}`,\n ].join(this.eol);\n }\n\n private getListText(node: SyntaxNode, numIndents: number): string {\n const index = node.children.findIndex((n) => n.type === \"]\");\n const first = node.children[0].text;\n const last = node.children\n .slice(index)\n .map((n) => n.text)\n .join(\" \");\n const parts = [\n `${this.getIndent(numIndents)}${first}`,\n ...node.children\n .slice(1, index)\n .map((n) => this.getNodeText(n, numIndents + 1)),\n `${this.getIndent(numIndents)}${last}`,\n ];\n return parts.join(this.eol);\n }\n\n private getPredicateText(node: SyntaxNode, numIndents: number): string {\n const first = node.children[0].text;\n const last = node.children[node.children.length - 1].text;\n const parts = [\n node.children\n .slice(1, 4)\n .map((n) => n.text)\n .join(\"\"),\n ...node.children[node.children.length - 2].children.map(\n (n) => n.text,\n ),\n ];\n // Inline predicate\n if (node.startPosition.row === node.endPosition.row) {\n const text = `${first}${parts.join(\" \")}${last}`;\n return `${this.getIndent(numIndents)}${text}`;\n }\n // Multiline predicate\n return [\n `${this.getIndent(numIndents)}${first}${parts[0]}`,\n ...parts\n .slice(1)\n .map((s) => `${this.getIndent(numIndents + 1)}${s}`),\n `${this.getIndent(numIndents)}${last}`,\n ].join(this.eol);\n }\n\n private getFieldDefinitionText(\n node: SyntaxNode,\n numIndents: number,\n ): string {\n // Field definition directly in document root\n if (numIndents === 0) {\n return [\"(_\", this.getFieldDefinitionText(node, 1), \")\"].join(\n this.eol,\n );\n }\n // [lhs, \":\", rhs]\n return [\n this.getIndent(numIndents),\n node.children[0].text,\n node.children[1].text,\n \" \",\n this.getNodeText(node.children[2], numIndents).trimStart(),\n ].join(\"\");\n }\n\n private getNodeTextInternal(node: SyntaxNode, numIndents: number): string {\n switch (node.type) {\n case \"program\":\n return this.joinLines(node.children, 0);\n\n case \"grouping\":\n return this.joinLines(node.children, numIndents + 1);\n\n case \"list\":\n return this.getListText(node, numIndents);\n\n case \"named_node\":\n return this.getNamedNodeText(node, numIndents);\n\n case \"predicate\":\n return this.getPredicateText(node, numIndents);\n\n case \"field_definition\":\n return this.getFieldDefinitionText(node, numIndents);\n\n case \"anonymous_node\":\n return (\n this.getIndent(numIndents) +\n node.children\n .map((n) => this.getNodeText(n, numIndents + 1))\n .join(\"\")\n );\n\n case \"comment\":\n return `${this.getIndent(numIndents)}${node.text.trimEnd()}`;\n\n case \".\":\n case \"negated_field\":\n return `${this.getIndent(numIndents)}${node.text}`;\n\n case \"(\":\n case \")\":\n return `${this.getIndent(numIndents - 1)}${node.text}`;\n\n case \"capture\":\n return ` ${node.text}`;\n\n case \"#\":\n case \"_\":\n case \"predicate_type\":\n case \"identifier\":\n case \"quantifier\":\n case \"string\":\n return node.text;\n\n case \"parameters\": {\n const text = node.children.map((n) => n.text).join(\" \");\n return ` ${text}`;\n }\n\n default:\n this.logger.debug(`Unknown syntax node type '${node.type}'`);\n return node.text;\n }\n }\n\n private joinLines(nodes: SyntaxNode[], numIndents: number): string {\n if (nodes.length === 0) {\n return \"\";\n }\n const lastIsQuantifier = nodes[nodes.length - 1].type === \"quantifier\";\n const nodesToUse = lastIsQuantifier ? nodes.slice(0, -1) : nodes;\n const text = nodesToUse\n .map((n) => this.getNodeText(n, numIndents))\n .join(this.eol);\n return lastIsQuantifier\n ? `${text}${nodes[nodes.length - 1].text}`\n : text;\n }\n\n private getIndent(length: number): string {\n return length < 1\n ? \"\"\n : new Array(length).fill(this.indentation).join(\"\");\n }\n}\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Language, Parser } from \"web-tree-sitter\";\nimport type { SyntaxNode } from \"../types.js\";\n\ntype ParserName = \"tree-sitter-talon\" | \"tree-sitter-query\";\n\nlet initPromise: Promise | undefined;\nconst languageCache = new Map>();\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nfunction initTreeSitter() {\n initPromise ??= Parser.init();\n return initPromise;\n}\n\nfunction loadLanguage(parserName: ParserName) {\n let promise = languageCache.get(parserName);\n\n if (promise == null) {\n const wasmFilePath = getWasmFilePath(parserName);\n promise = Language.load(wasmFilePath);\n languageCache.set(parserName, promise);\n }\n\n return promise;\n}\n\nfunction getWasmFilePath(parserName: ParserName) {\n const fileName = `${parserName}.wasm`;\n const wasmFilePath = [\n path.join(\n moduleDir,\n \"../../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n path.join(\n moduleDir,\n \"../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n ].find((candidate) => fs.existsSync(candidate));\n\n if (wasmFilePath == null) {\n throw new Error(`Could not find ${fileName}`);\n }\n\n return wasmFilePath;\n}\n\nexport async function parseText(\n text: string,\n parserName: ParserName,\n): Promise {\n await initTreeSitter();\n\n const language = await loadLanguage(parserName);\n\n const parser = new Parser();\n parser.setLanguage(language);\n\n const tree = parser.parse(text);\n\n if (tree == null) {\n throw new Error(\"Failed to parse text\");\n }\n\n return tree.rootNode;\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.1\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { treeSitterFormatter } from \"../treeSitterFormatter.js\";\nimport { parseText } from \"./parseText.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEnding = \"scm\";\n\nvoid main({\n binName: \"tree-sitter-fmt\",\n fileEndings: [fileEnding],\n\n getStdinFileEnding() {\n return fileEnding;\n },\n\n format: async (text, options, _filePath, debug) => {\n const node = await parseText(text, \"tree-sitter-query\");\n return treeSitterFormatter(node, options, debug);\n },\n});\n"], + "sourcesContent": ["// Exit code 0: Success\nexport const EXIT_OK = 0;\n// Exit code 1: Check failed\nexport const EXIT_FAIL = 1;\n// Exit code 2: Unexpected error\nexport const EXIT_ERROR = 2;\n\nexport type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;\n\nexport const DEFAULT_INDENT_WIDTH = 4;\nexport const DEFAULT_MAX_LINE_LENGTH = 80;\nexport const DEFAULT_INSERT_FINAL_NEWLINE = true;\n\nexport const IGNORE_FOLDERS = [\n \".git\",\n \".svn\",\n \".hg\",\n \"node_modules\",\n \"__pycache__\",\n];\n\nexport const GLOB_IGNORE_PATTERNS = IGNORE_FOLDERS.map(\n (pattern) => `**/${pattern}/**`,\n);\n", "import type { DebugLogger } from \"../types.js\";\n\nexport function createDebugLogger(debug: boolean): DebugLogger {\n return {\n debug(message: string) {\n if (debug) {\n console.warn(`[debug] ${message}`);\n }\n },\n };\n}\n", "import type { EndOfLine } from \"../types.js\";\n\nexport function getEndOfLine(eof?: EndOfLine): string {\n return eof === \"crlf\" ? \"\\r\\n\" : \"\\n\";\n}\n", "import { DEFAULT_INDENT_WIDTH } from \"./constants.js\";\n\nexport function getIndentation(\n indentTabs: boolean | undefined,\n indentSize: number | undefined,\n): string {\n return indentTabs ? \"\\t\" : \" \".repeat(indentSize ?? DEFAULT_INDENT_WIDTH);\n}\n", "import type { Point } from \"../types.js\";\n\nconst shortMessage = \"Syntax error\";\n\nexport class SyntaxError extends Error {\n private readonly location: string | undefined;\n\n constructor(private point?: Point) {\n const location = getLocation(point);\n super(getMessage(location));\n this.name = \"SyntaxError\";\n this.location = location;\n }\n\n getFileMessage(file: string): string {\n return this.location != null\n ? `${file}(${this.location}): ${shortMessage}`\n : `${file}: ${shortMessage}`;\n }\n}\n\nexport function isSyntaxError(error: unknown): error is SyntaxError {\n return error instanceof SyntaxError;\n}\n\nfunction getMessage(location: string | undefined): string {\n return location != null ? `${shortMessage} at ${location}.` : shortMessage;\n}\n\nfunction getLocation(point: Point | undefined): string | undefined {\n return point != null ? `${point.row + 1}:${point.column + 1}` : undefined;\n}\n", "import type { SyntaxNode } from \"../types.js\";\nimport { SyntaxError } from \"./SyntaxError.js\";\n\nexport class SyntaxTreeError extends SyntaxError {\n constructor(rootNode: SyntaxNode) {\n super(findFirstProblemNode(rootNode)?.startPosition);\n this.name = \"SyntaxTreeError\";\n }\n}\n\nfunction findFirstProblemNode(node: SyntaxNode): SyntaxNode | null {\n if (node.isError || node.isMissing) {\n return node;\n }\n for (const child of node.children) {\n if (!child.hasError) {\n continue;\n }\n const errorNode = findFirstProblemNode(child);\n if (errorNode != null) {\n return errorNode;\n }\n }\n return null;\n}\n", "import type { DebugLogger, FormatterOptions, SyntaxNode } from \"./types.js\";\nimport { DEFAULT_INSERT_FINAL_NEWLINE } from \"./util/constants.js\";\nimport { createDebugLogger } from \"./util/createDebugLogger.js\";\nimport { getEndOfLine } from \"./util/getEndOfLine.js\";\nimport { getIndentation } from \"./util/getIndentation.js\";\nimport { SyntaxTreeError } from \"./util/SyntaxTreeError.js\";\n\nexport type Options = FormatterOptions<\n \"endOfLine\" | \"indentTabs\" | \"indentSize\" | \"insertFinalNewline\"\n>;\n\nexport function treeSitterFormatter(\n node: SyntaxNode,\n options: Options = {},\n debug: boolean = false,\n): string {\n if (node.hasError) {\n throw new SyntaxTreeError(node);\n }\n\n const indentation = getIndentation(options.indentTabs, options.indentSize);\n const eol = getEndOfLine(options.endOfLine);\n const formatter = new TreeSitterFormatter(\n indentation,\n eol,\n options.insertFinalNewline ?? DEFAULT_INSERT_FINAL_NEWLINE,\n debug,\n );\n return formatter.getText(node);\n}\n\nclass TreeSitterFormatter {\n private lastRow = 0;\n private logger: DebugLogger;\n\n constructor(\n private indentation: string,\n private eol: string,\n private insertFinalNewline: boolean,\n debug: boolean,\n ) {\n this.logger = createDebugLogger(debug);\n }\n\n getText(node: SyntaxNode): string {\n const nodeText = this.getNodeText(node, 0);\n\n if (nodeText.length === 0) {\n return \"\";\n }\n\n if (this.insertFinalNewline) {\n return nodeText + this.eol;\n }\n\n return nodeText;\n }\n\n private getNodeText(node: SyntaxNode, numIndents: number): string {\n const nl = node.startPosition.row > this.lastRow + 1 ? this.eol : \"\";\n this.lastRow = node.endPosition.row;\n const text = this.getNodeTextInternal(node, numIndents);\n this.lastRow = node.endPosition.row;\n return `${nl}${text}`;\n }\n\n private getNamedNodeText(node: SyntaxNode, numIndents: number): string {\n const index = node.children.findIndex((n) => n.type === \")\");\n const first = node.children\n .slice(0, 2)\n .map((n) => n.text)\n .join(\"\");\n const last = node.children\n .slice(index)\n .map((n) => this.getNodeText(n, 0))\n .join(\"\");\n const interior = node.children\n .slice(2, index)\n .map((n) => this.getNodeText(n, numIndents + 1));\n // Inline node\n if (interior.length === 0) {\n return `${this.getIndent(numIndents)}${first}${last}`;\n }\n // Multiline node\n return [\n `${this.getIndent(numIndents)}${first}`,\n ...interior,\n `${this.getIndent(numIndents)}${last}`,\n ].join(this.eol);\n }\n\n private getListText(node: SyntaxNode, numIndents: number): string {\n const index = node.children.findIndex((n) => n.type === \"]\");\n const first = node.children[0].text;\n const last = node.children\n .slice(index)\n .map((n) => n.text)\n .join(\" \");\n const parts = [\n `${this.getIndent(numIndents)}${first}`,\n ...node.children\n .slice(1, index)\n .map((n) => this.getNodeText(n, numIndents + 1)),\n `${this.getIndent(numIndents)}${last}`,\n ];\n return parts.join(this.eol);\n }\n\n private getPredicateText(node: SyntaxNode, numIndents: number): string {\n const first = node.children[0].text;\n const last = node.children[node.children.length - 1].text;\n const parts = [\n node.children\n .slice(1, 4)\n .map((n) => n.text)\n .join(\"\"),\n ...node.children[node.children.length - 2].children.map(\n (n) => n.text,\n ),\n ];\n // Inline predicate\n if (node.startPosition.row === node.endPosition.row) {\n const text = `${first}${parts.join(\" \")}${last}`;\n return `${this.getIndent(numIndents)}${text}`;\n }\n // Multiline predicate\n return [\n `${this.getIndent(numIndents)}${first}${parts[0]}`,\n ...parts\n .slice(1)\n .map((s) => `${this.getIndent(numIndents + 1)}${s}`),\n `${this.getIndent(numIndents)}${last}`,\n ].join(this.eol);\n }\n\n private getFieldDefinitionText(\n node: SyntaxNode,\n numIndents: number,\n ): string {\n // Field definition directly in document root\n if (numIndents === 0) {\n return [\"(_\", this.getFieldDefinitionText(node, 1), \")\"].join(\n this.eol,\n );\n }\n // [lhs, \":\", rhs]\n return [\n this.getIndent(numIndents),\n node.children[0].text,\n node.children[1].text,\n \" \",\n this.getNodeText(node.children[2], numIndents).trimStart(),\n ].join(\"\");\n }\n\n private getNodeTextInternal(node: SyntaxNode, numIndents: number): string {\n switch (node.type) {\n case \"program\":\n return this.joinLines(node.children, 0);\n\n case \"grouping\":\n return this.joinLines(node.children, numIndents + 1);\n\n case \"list\":\n return this.getListText(node, numIndents);\n\n case \"named_node\":\n return this.getNamedNodeText(node, numIndents);\n\n case \"predicate\":\n return this.getPredicateText(node, numIndents);\n\n case \"field_definition\":\n return this.getFieldDefinitionText(node, numIndents);\n\n case \"anonymous_node\":\n return (\n this.getIndent(numIndents) +\n node.children\n .map((n) => this.getNodeText(n, numIndents + 1))\n .join(\"\")\n );\n\n case \"comment\":\n return `${this.getIndent(numIndents)}${node.text.trimEnd()}`;\n\n case \".\":\n case \"negated_field\":\n return `${this.getIndent(numIndents)}${node.text}`;\n\n case \"(\":\n case \")\":\n return `${this.getIndent(numIndents - 1)}${node.text}`;\n\n case \"capture\":\n return ` ${node.text}`;\n\n case \"#\":\n case \"_\":\n case \"predicate_type\":\n case \"identifier\":\n case \"quantifier\":\n case \"string\":\n return node.text;\n\n case \"parameters\": {\n const text = node.children.map((n) => n.text).join(\" \");\n return ` ${text}`;\n }\n\n default:\n this.logger.debug(`Unknown syntax node type '${node.type}'`);\n return node.text;\n }\n }\n\n private joinLines(nodes: SyntaxNode[], numIndents: number): string {\n if (nodes.length === 0) {\n return \"\";\n }\n const lastIsQuantifier = nodes[nodes.length - 1].type === \"quantifier\";\n const nodesToUse = lastIsQuantifier ? nodes.slice(0, -1) : nodes;\n const text = nodesToUse\n .map((n) => this.getNodeText(n, numIndents))\n .join(this.eol);\n return lastIsQuantifier\n ? `${text}${nodes[nodes.length - 1].text}`\n : text;\n }\n\n private getIndent(length: number): string {\n return length < 1\n ? \"\"\n : new Array(length).fill(this.indentation).join(\"\");\n }\n}\n", "import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Language, Parser } from \"web-tree-sitter\";\nimport type { SyntaxNode } from \"../types.js\";\n\ntype ParserName = \"tree-sitter-talon\" | \"tree-sitter-query\";\n\nlet initPromise: Promise | undefined;\nconst languageCache = new Map>();\nconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nfunction initTreeSitter() {\n initPromise ??= Parser.init();\n return initPromise;\n}\n\nfunction loadLanguage(parserName: ParserName) {\n let promise = languageCache.get(parserName);\n\n if (promise == null) {\n const wasmFilePath = getWasmFilePath(parserName);\n promise = Language.load(wasmFilePath);\n languageCache.set(parserName, promise);\n }\n\n return promise;\n}\n\nfunction getWasmFilePath(parserName: ParserName) {\n const fileName = `${parserName}.wasm`;\n const wasmFilePath = [\n path.join(\n moduleDir,\n \"../../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n path.join(\n moduleDir,\n \"../node_modules/@cursorless/tree-sitter-wasms/out\",\n fileName,\n ),\n ].find((candidate) => fs.existsSync(candidate));\n\n if (wasmFilePath == null) {\n throw new Error(`Could not find ${fileName}`);\n }\n\n return wasmFilePath;\n}\n\nexport async function parseText(\n text: string,\n parserName: ParserName,\n): Promise {\n await initTreeSitter();\n\n const language = await loadLanguage(parserName);\n\n const parser = new Parser();\n parser.setLanguage(language);\n\n const tree = parser.parse(text);\n\n if (tree == null) {\n throw new Error(\"Failed to parse text\");\n }\n\n return tree.rootNode;\n}\n", "import getStdin from \"get-stdin\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as process from \"node:process\";\nimport type { Readable } from \"node:stream\";\nimport type { CLI, Logger, ParsedArgs } from \"../types.js\";\nimport {\n EXIT_ERROR,\n EXIT_FAIL,\n EXIT_OK,\n type ExitCode,\n} from \"../util/constants.js\";\nimport { getErrorMessage } from \"../util/getErrorMessage.js\";\nimport { isSyntaxError } from \"../util/SyntaxError.js\";\nimport { createLogger } from \"./createLogger.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { getOptionsFromConfig } from \"./getOptionsFromConfig.js\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\nimport { parseArgs } from \"./parseArgs.js\";\nimport { parseFilePatterns } from \"./parseFilePatterns.js\";\nimport { printHelp } from \"./printHelp.js\";\nimport { printVersion } from \"./printVersion.js\";\nimport { setExitCode } from \"./setExitCode.js\";\n\nexport async function main(cli: CLI): Promise {\n let logger = createLogger();\n\n try {\n const args = parseArgs(process.argv.slice(2));\n logger = createLogger(args.quiet);\n const exitCode = await mainUnsafe({ cli, args, logger });\n setExitCode(exitCode);\n } catch (error) {\n if (error instanceof FilePatternError) {\n for (const message of error.messages) {\n logger.error(message);\n }\n } else {\n logger.error(getErrorMessage(error));\n }\n setExitCode(EXIT_ERROR);\n }\n}\n\ninterface MainUnsafeArgs {\n cli: CLI;\n args: ParsedArgs;\n logger: Logger;\n}\n\nasync function mainUnsafe({\n cli,\n args,\n logger,\n}: MainUnsafeArgs): Promise {\n if (args.help) {\n printHelp(cli);\n return EXIT_OK;\n }\n\n if (args.version) {\n printVersion();\n return EXIT_OK;\n }\n\n const hasFilePatterns = args.filePatterns.length > 0;\n\n if (hasFilePatterns) {\n return mainFormatFiles({\n cli,\n logger,\n check: args.check,\n debug: args.debug,\n filePatterns: args.filePatterns,\n });\n }\n\n // If no file patterns are provided, check if there's input from stdin.\n // If stdin TTY it's an interactive terminal, so we shouldn't read from it.\n if (!process.stdin.isTTY) {\n return mainFormatStdin({\n cli,\n logger,\n stdin: process.stdin,\n check: args.check,\n debug: args.debug,\n });\n }\n\n throw new Error(\n \"No input files specified. Use --help for usage information.\",\n );\n}\n\ninterface MainFormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePatterns: string[];\n}\n\nasync function mainFormatFiles({\n cli,\n logger,\n check,\n debug,\n filePatterns,\n}: MainFormatFilesArgs): Promise {\n if (check) {\n logger.log(\"Checking formatting...\");\n }\n\n const filePaths = await parseFilePatterns(cli, filePatterns);\n const [changedFileCount, hasError] = await formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n });\n\n if (check) {\n if (changedFileCount > 0) {\n logger.warn(\n `Code style issues found in ${changedFileCount} file(s).`,\n );\n if (!hasError) {\n return EXIT_FAIL;\n }\n }\n\n if (!hasError) {\n logger.log(\"All matched files use correct code style!\");\n }\n }\n\n if (hasError) {\n return EXIT_ERROR;\n }\n\n return EXIT_OK;\n}\n\ninterface FormatFilesArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePaths: string[];\n}\n\nexport async function formatFiles({\n cli,\n logger,\n check,\n debug,\n filePaths,\n}: FormatFilesArgs): Promise<[number, boolean]> {\n let changedFileCount = 0;\n let hasError = false;\n\n for (const filePath of filePaths) {\n try {\n const fileWasChanged = await formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n });\n if (fileWasChanged) {\n changedFileCount++;\n }\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(getDisplayPath(filePath)));\n } else {\n logger.error(\n `${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,\n );\n }\n hasError = true;\n }\n }\n\n return [changedFileCount, hasError];\n}\n\ninterface FormatFileArgs {\n cli: CLI;\n logger: Logger;\n check: boolean;\n debug: boolean;\n filePath: string;\n}\n\nexport async function formatFile({\n cli,\n logger,\n check,\n debug,\n filePath,\n}: FormatFileArgs): Promise {\n try {\n const options = await getOptionsFromConfig(filePath);\n const content = await fs.readFile(filePath, \"utf8\");\n const formatted = await cli.format(content, options, filePath, debug);\n\n if (formatted === content) {\n return false;\n }\n\n logger.log(getDisplayPath(filePath));\n\n if (!check) {\n await fs.writeFile(filePath, formatted, \"utf8\");\n }\n\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nfunction getDisplayPath(filePath: string): string {\n return normalizeToPosix(path.relative(process.cwd(), filePath));\n}\n\ninterface MainFormatStdinArgs {\n cli: CLI;\n logger: Logger;\n stdin: Readable;\n check: boolean;\n debug: boolean;\n}\n\nexport async function mainFormatStdin({\n cli,\n logger,\n stdin,\n check,\n debug,\n}: MainFormatStdinArgs): Promise {\n const input = await getStdin({ stdin });\n const fileEnding = cli.getStdinFileEnding(input);\n const fauxFileName = `stdin.${fileEnding}`;\n const fauxFilePath = path.resolve(fauxFileName);\n const options = await getOptionsFromConfig(fauxFilePath);\n let formatted: string;\n\n try {\n formatted = await cli.format(input, options, fauxFilePath, debug);\n } catch (error) {\n if (isSyntaxError(error)) {\n logger.error(error.getFileMessage(\"stdin\"));\n return EXIT_ERROR;\n }\n throw error;\n }\n\n if (check) {\n if (input !== formatted) {\n logger.warn(\"Code style issues found in stdin.\");\n return EXIT_FAIL;\n }\n\n return EXIT_OK;\n }\n\n process.stdout.write(formatted);\n\n return EXIT_OK;\n}\n", "export function getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import * as process from \"node:process\";\nimport type { WriteStream } from \"node:tty\";\nimport type { Logger, LoggerEntry, TestLogger } from \"../types.js\";\n\ntype LogCallback = (message: string) => void;\ntype ColorizeCallback = (message: string, color: string) => string;\ntype LoggerStream = Pick & Partial;\n\nconst ANSI_RESET = \"\\u001b[0m\";\nconst ANSI_YELLOW = \"\\u001b[33m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst WARN_PREFIX = \"[warn]\";\nconst ERROR_PREFIX = \"[error]\";\n\nexport function createLogger(quiet: boolean = false): Logger {\n return createLoggerFromStreams(process.stdout, process.stderr, quiet);\n}\n\nexport function createLoggerFromStreams(\n stdout: LoggerStream,\n stderr: LoggerStream,\n quiet: boolean = false,\n): Logger {\n const colorize: ColorizeCallback = shouldUseColor(stderr)\n ? (message, color) => `${color}${message}${ANSI_RESET}`\n : (message, _color) => message;\n\n let log: LogCallback;\n let warn: LogCallback;\n\n if (quiet) {\n log = () => {};\n warn = () => {};\n } else {\n log = (message: string) => {\n stdout.write(`${message}\\n`);\n };\n warn = (message: string) => {\n stderr.write(`${colorize(WARN_PREFIX, ANSI_YELLOW)} ${message}\\n`);\n };\n }\n\n return {\n log,\n warn,\n error(message: string) {\n stderr.write(`${colorize(ERROR_PREFIX, ANSI_RED)} ${message}\\n`);\n },\n };\n}\n\nexport function createTestLogger(): TestLogger {\n const entries: LoggerEntry[] = [];\n\n return {\n log(message: string) {\n entries.push({ level: \"log\", message });\n },\n warn(message: string) {\n entries.push({ level: \"warn\", message });\n },\n error(message: string) {\n entries.push({ level: \"error\", message });\n },\n getEntries() {\n return entries;\n },\n };\n}\n\nfunction shouldUseColor(stream: LoggerStream): boolean {\n if (\"NO_COLOR\" in process.env) {\n return false;\n }\n\n return stream.isTTY === true;\n}\n", "export class FilePatternError extends Error {\n name = \"FilePatternError\";\n\n constructor(public messages: string[]) {\n super(\n `One or more file pattern errors occurred:\\n${messages.join(\"\\n\")}`,\n );\n }\n}\n", "import * as editorconfig from \"editorconfig\";\nimport type { EditorConfigOptions, Options } from \"../types.js\";\n\nexport async function getOptionsFromConfig(filePath: string): Promise {\n const config = (await editorconfig.parse(filePath)) as EditorConfigOptions;\n\n const options: Options = {};\n\n if (config.indent_style === \"tab\") {\n options.indentTabs = true;\n } else if (config.indent_style === \"space\") {\n options.indentTabs = false;\n }\n\n if (typeof config.indent_size === \"number\") {\n options.indentSize = config.indent_size;\n } else if (\n config.indent_size === \"tab\" &&\n typeof config.tab_width === \"number\"\n ) {\n options.indentSize = config.tab_width;\n }\n\n if (typeof config.max_line_length === \"number\") {\n options.maxLineLength = config.max_line_length;\n }\n\n if (typeof config.column_width === \"number\") {\n options.columnWidth = config.column_width;\n }\n\n if (typeof config.insert_final_newline === \"boolean\") {\n options.insertFinalNewline = config.insert_final_newline;\n }\n\n if (typeof config.preserve_multiline === \"boolean\") {\n options.preserveMultiline = config.preserve_multiline;\n }\n\n if (config.end_of_line != null && config.end_of_line !== \"unset\") {\n options.endOfLine = config.end_of_line;\n }\n\n return options;\n}\n", "export function isMissingFileError(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n", "import * as path from \"node:path\";\n\n/**\n * Replace `\\` with `/` on Windows\n * @param {string} filepath\n * @returns {string}\n */\nexport const normalizeToPosix =\n path.sep === \"\\\\\"\n ? (filepath: string) => filepath.replaceAll(\"\\\\\", \"/\")\n : (filepath: string) => filepath;\n", "import type { ParsedArgs } from \"../types.js\";\n\nexport function getDefaultArguments(): ParsedArgs {\n return {\n filePatterns: [],\n help: false,\n version: false,\n quiet: false,\n debug: false,\n check: false,\n };\n}\n", "import type { KnownArgument, ParsedArgs } from \"../types.js\";\nimport { getDefaultArguments } from \"./getDefaultArguments.js\";\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const result = getDefaultArguments();\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n // All following arguments are treated as file patterns, even if they start with \"--\"\n result.filePatterns.push(...argv.slice(i + 1));\n break;\n }\n\n if (parseKnownArgument(result, arg as KnownArgument)) {\n continue;\n }\n\n if (arg.startsWith(\"--\")) {\n throw new Error(`Unknown argument: ${arg}`);\n }\n\n result.filePatterns.push(arg);\n }\n\n return result;\n}\n\nfunction parseKnownArgument(result: ParsedArgs, arg: KnownArgument): boolean {\n switch (arg) {\n case \"--help\":\n result.help = true;\n return true;\n case \"--version\":\n result.version = true;\n return true;\n case \"--quiet\":\n result.quiet = true;\n return true;\n case \"--check\":\n result.check = true;\n return true;\n case \"--debug\":\n result.debug = true;\n return true;\n default:\n return false;\n }\n}\n", "import type { Options } from \"fast-glob\";\nimport fastGlob from \"fast-glob\";\nimport * as path from \"node:path\";\nimport type { CLI } from \"../types.js\";\nimport { GLOB_IGNORE_PATTERNS } from \"../util/constants.js\";\nimport { FilePatternError } from \"./FilePatternError.js\";\nimport { lstatSafe } from \"./lstatSafe.js\";\nimport { normalizeToPosix } from \"./normalizeToPosix.js\";\n\nexport async function parseFilePatterns(\n cli: CLI,\n filePatterns: string[],\n): Promise {\n const seen: Set = new Set();\n const globFileEndingPattern = getGlobFileEndingsPattern(cli.fileEndings);\n const errorMessages: string[] = [];\n\n const globOptions: Options = {\n dot: true,\n followSymbolicLinks: false,\n ignore: GLOB_IGNORE_PATTERNS,\n };\n\n for (const pattern of filePatterns) {\n const absolutePath = path.resolve(pattern);\n const stat = await lstatSafe(absolutePath);\n\n if (stat != null) {\n if (stat.isSymbolicLink()) {\n errorMessages.push(\n `Specified pattern is a symbolic link: ${pattern}`,\n );\n continue;\n }\n\n if (stat.isFile()) {\n seen.add(absolutePath);\n continue;\n }\n\n if (stat.isDirectory()) {\n const files = await fastGlob(`**/*.${globFileEndingPattern}`, {\n ...globOptions,\n cwd: absolutePath,\n });\n if (files.length === 0) {\n errorMessages.push(\n `No matching files were found in the directory: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(absolutePath, file));\n }\n continue;\n }\n }\n\n const glob = normalizeToPosix(pattern);\n const files = (await fastGlob(glob, globOptions)).filter((file) =>\n hasSupportedFileEnding(file, cli.fileEndings),\n );\n if (files.length === 0) {\n errorMessages.push(\n `No files matching the pattern were found: ${pattern}`,\n );\n }\n for (const file of files) {\n seen.add(path.resolve(file));\n }\n }\n\n if (errorMessages.length > 0) {\n throw new FilePatternError(errorMessages);\n }\n\n return Array.from(seen).sort((a, b) => a.localeCompare(b));\n}\n\nfunction getGlobFileEndingsPattern(fileEndings: readonly string[]): string {\n return fileEndings.length === 1\n ? fileEndings[0]\n : `{${fileEndings.join(\",\")}}`;\n}\n\nfunction hasSupportedFileEnding(\n file: string,\n fileEndings: readonly string[],\n): boolean {\n const extension = path.extname(file).slice(1);\n return fileEndings.includes(extension);\n}\n", "import type { Stats } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport { isMissingFileError } from \"./isMissingFileError.js\";\n\nexport async function lstatSafe(filePath: string): Promise {\n try {\n return await fs.lstat(filePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined;\n }\n\n throw error;\n }\n}\n", "import type { KnownProps } from \"editorconfig\";\n\nexport const KNOWN_ARGUMENTS = [\n \"--help\",\n \"--version\",\n \"--quiet\",\n \"--check\",\n \"--debug\",\n] as const;\n\nexport type KnownArgument = (typeof KNOWN_ARGUMENTS)[number];\n\nexport interface CLI {\n binName: \"snippet-fmt\" | \"talon-fmt\" | \"tree-sitter-fmt\";\n fileEndings: readonly string[];\n\n getStdinFileEnding(text: string): string;\n format(\n text: string,\n options: Options,\n filePath: string,\n debug: boolean,\n ): Promise;\n}\n\nexport type EndOfLine = \"lf\" | \"crlf\";\n\nexport interface Options {\n endOfLine?: EndOfLine;\n indentTabs?: boolean;\n indentSize?: number;\n maxLineLength?: number;\n columnWidth?: number;\n insertFinalNewline?: boolean;\n preserveMultiline?: boolean;\n}\n\nexport type FormatterOptions = Pick;\n\nexport interface ParsedArgs {\n filePatterns: string[];\n help: boolean;\n version: boolean;\n check: boolean;\n quiet: boolean;\n debug: boolean;\n}\n\nexport interface LoggerEntry {\n level: \"log\" | \"warn\" | \"error\";\n message: string;\n}\n\nexport interface Logger {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport interface TestLogger extends Logger {\n getEntries(): readonly LoggerEntry[];\n}\n\nexport interface DebugLogger {\n debug(message: string): void;\n}\n\n/* eslint-disable @typescript-eslint/naming-convention */\nexport interface EditorConfigOptions extends KnownProps {\n max_line_length?: number | \"unset\";\n column_width?: number | \"unset\";\n preserve_multiline?: boolean | \"unset\";\n}\n\nexport interface Point {\n row: number;\n column: number;\n}\n\n/**\n * Internal representation of the Tree sitter node. Used so that our api doesn't\n * need to export or expose clients to Tree sitter types. Also makes it simple\n * to write tests internally.\n */\nexport interface SyntaxNode {\n id: number;\n text: string;\n type: string;\n startPosition: Point;\n endPosition: Point;\n hasError: boolean;\n isError: boolean;\n isMissing: boolean;\n parent: SyntaxNode | null;\n children: SyntaxNode[];\n}\n", "import type { CLI } from \"../types.js\";\nimport { KNOWN_ARGUMENTS } from \"../types.js\";\n\nexport function printHelp(cli: CLI) {\n process.stdout.write(\n `Usage: ${cli.binName} [options] [file/dir/glob ...]\\n`,\n );\n process.stdout.write(\"\\n\");\n process.stdout.write(\"Options:\\n\");\n\n for (const option of KNOWN_ARGUMENTS) {\n process.stdout.write(` ${option}\\n`);\n }\n}\n", "{\n \"name\": \"@cursorless/talon-tools\",\n \"version\": \"0.10.2\",\n \"description\": \"Linting and formatting tools for Talon and Cursorless\",\n \"author\": \"Cursorless Dev\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"!dist/test\",\n \"!dist/build.*\"\n ],\n \"types\": \"./dist/lib.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/lib.d.ts\",\n \"default\": \"./dist/lib.js\"\n },\n \"./node\": {\n \"types\": \"./dist/node/libNode.d.ts\",\n \"default\": \"./dist/libNode.js\"\n }\n },\n \"bin\": {\n \"snippet-fmt\": \"dist/snippetFormatter.js\",\n \"talon-fmt\": \"dist/talonFormatter.js\",\n \"tree-sitter-fmt\": \"dist/treeSitterFormatter.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cursorless-dev/talon-tools.git\"\n },\n \"funding\": \"https://github.com/sponsors/cursorless-dev\",\n \"sponsor\": {\n \"url\": \"https://github.com/sponsors/cursorless-dev\"\n },\n \"scripts\": {\n \"build\": \"npm run clean && tsc -p . && tsx ./src/build.ts\",\n \"clean\": \"rm -rf dist/*\",\n \"lint\": \"npm run lint:ts &&npm run lint:fmt\",\n \"lint:ts\": \"tsc -p . --noEmit && eslint src\",\n \"lint:fmt\": \"prettier --check .\",\n \"fix\": \"npm run fix:ts && npm run fix:fmt\",\n \"fix:ts\": \"eslint src --fix\",\n \"fix:fmt\": \"prettier --write --list-different .\",\n \"test\": \"tsx src/test/runAllTests.ts\",\n \"test:subset\": \"tsx src/test/runAllTests.ts --subset\"\n },\n \"dependencies\": {\n \"@cursorless/tree-sitter-wasms\": \"^0.7.0\",\n \"editorconfig\": \"^3.0.2\",\n \"fast-glob\": \"^3.3.3\",\n \"get-stdin\": \"^10.0.0\",\n \"web-tree-sitter\": \"^0.26.7\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.4\",\n \"@types/mocha\": \"^10.0.10\",\n \"@types/node\": \"^24.12.0\",\n \"esbuild\": \"^0.27.4\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-import\": \"^2.32.0\",\n \"eslint\": \"^9.39.4\",\n \"jiti\": \"^2.6.1\",\n \"mocha\": \"^11.7.5\",\n \"prettier\": \"^3.8.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript-eslint\": \"^8.57.1\",\n \"typescript\": \"^5.9.3\"\n }\n}\n", "import packageJson from \"../../package.json\" with { type: \"json\" };\n\nexport function printVersion() {\n process.stdout.write(`${packageJson.version}\\n`);\n}\n", "export function setExitCode(code: number): void {\n Reflect.set(process, \"exitCode\", code);\n}\n", "#!/usr/bin/env node\n\nimport { treeSitterFormatter } from \"../treeSitterFormatter.js\";\nimport { parseText } from \"./parseText.js\";\nimport { main } from \"./cli.js\";\n\nconst fileEnding = \"scm\";\n\nvoid main({\n binName: \"tree-sitter-fmt\",\n fileEndings: [fileEnding],\n\n getStdinFileEnding() {\n return fileEnding;\n },\n\n format: async (text, options, _filePath, debug) => {\n const node = await parseText(text, \"tree-sitter-query\");\n return treeSitterFormatter(node, options, debug);\n },\n});\n"], "mappings": "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", "names": ["IGNORE_FOLDERS", "GLOB_IGNORE_PATTERNS", "pattern", "createDebugLogger", "debug", "message", "getEndOfLine", "eof", "getIndentation", "indentTabs", "indentSize", "shortMessage", "SyntaxError", "point", "location", "getLocation", "getMessage", "file", "isSyntaxError", "error", "SyntaxTreeError", "SyntaxError", "rootNode", "findFirstProblemNode", "node", "child", "errorNode", "treeSitterFormatter", "node", "options", "debug", "SyntaxTreeError", "indentation", "getIndentation", "eol", "getEndOfLine", "TreeSitterFormatter", "insertFinalNewline", "createDebugLogger", "nodeText", "numIndents", "nl", "text", "index", "n", "first", "last", "interior", "parts", "s", "nodes", "lastIsQuantifier", "length", "fs", "path", "fileURLToPath", "Language", "Parser", "initPromise", "languageCache", "moduleDir", "initTreeSitter", "loadLanguage", "parserName", "promise", "wasmFilePath", "getWasmFilePath", "fileName", "candidate", "parseText", "text", "language", "parser", "tree", "getStdin", "fs", "path", "process", "getErrorMessage", "error", "process", "ANSI_RESET", "ANSI_YELLOW", "ANSI_RED", "WARN_PREFIX", "ERROR_PREFIX", "createLogger", "quiet", "createLoggerFromStreams", "stdout", "stderr", "colorize", "shouldUseColor", "message", "color", "_color", "log", "warn", "shouldUseColor", "stream", "FilePatternError", "messages", "editorconfig", "getOptionsFromConfig", "filePath", "config", "options", "isMissingFileError", "error", "path", "normalizeToPosix", "filepath", "getDefaultArguments", "parseArgs", "argv", "result", "getDefaultArguments", "i", "arg", "parseKnownArgument", "fastGlob", "path", "fs", "lstatSafe", "filePath", "error", "isMissingFileError", "parseFilePatterns", "cli", "filePatterns", "seen", "globFileEndingPattern", "getGlobFileEndingsPattern", "errorMessages", "globOptions", "GLOB_IGNORE_PATTERNS", "pattern", "absolutePath", "stat", "lstatSafe", "files", "fastGlob", "file", "glob", "normalizeToPosix", "hasSupportedFileEnding", "FilePatternError", "a", "b", "fileEndings", "extension", "KNOWN_ARGUMENTS", "printHelp", "cli", "option", "KNOWN_ARGUMENTS", "package_default", "printVersion", "package_default", "setExitCode", "code", "main", "cli", "logger", "createLogger", "args", "parseArgs", "exitCode", "mainUnsafe", "setExitCode", "error", "FilePatternError", "message", "getErrorMessage", "printHelp", "printVersion", "mainFormatFiles", "mainFormatStdin", "check", "debug", "filePatterns", "filePaths", "parseFilePatterns", "changedFileCount", "hasError", "formatFiles", "filePath", "formatFile", "isSyntaxError", "getDisplayPath", "options", "getOptionsFromConfig", "content", "formatted", "isMissingFileError", "normalizeToPosix", "stdin", "input", "getStdin", "fauxFileName", "fauxFilePath", "fileEnding", "main", "text", "options", "_filePath", "debug", "node", "parseText", "treeSitterFormatter"] } diff --git a/package-lock.json b/package-lock.json index 363da99..4de3c3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cursorless/talon-tools", - "version": "0.10.1", + "version": "0.10.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cursorless/talon-tools", - "version": "0.10.1", + "version": "0.10.2", "license": "MIT", "dependencies": { "@cursorless/tree-sitter-wasms": "^0.7.0", diff --git a/package.json b/package.json index 2819fe2..44bddd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cursorless/talon-tools", - "version": "0.10.1", + "version": "0.10.2", "description": "Linting and formatting tools for Talon and Cursorless", "author": "Cursorless Dev", "license": "MIT",