Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- @cursorless-dev/code-owners
* @cursorless-dev/code-owners
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ foo bar baz: "foo bar baz"
```yaml
repos:
- repo: https://github.com/cursorless-dev/talon-tools
rev: v0.9.0
rev: v0.10.0
hooks:
- id: talon-fmt
- id: snippet-fmt
Expand Down
4 changes: 2 additions & 2 deletions dist/lib.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/lib.js.map

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions dist/node/cli.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Readable } from "node:stream";
import type { CLI, Logger } from "../types.js";
import { type ExitCode } from "../util/constants.js";
export declare function main(cli: CLI): Promise<void>;
interface FormatFilesArgs {
cli: CLI;
Expand All @@ -8,7 +9,7 @@ interface FormatFilesArgs {
debug: boolean;
filePaths: string[];
}
export declare function formatFiles({ cli, logger, check, debug, filePaths, }: FormatFilesArgs): Promise<number>;
export declare function formatFiles({ cli, logger, check, debug, filePaths, }: FormatFilesArgs): Promise<[number, boolean]>;
interface FormatFileArgs {
cli: CLI;
logger: Logger;
Expand All @@ -24,5 +25,5 @@ interface MainFormatStdinArgs {
check: boolean;
debug: boolean;
}
export declare function mainFormatStdin({ cli, logger, stdin, check, debug, }: MainFormatStdinArgs): Promise<number>;
export declare function mainFormatStdin({ cli, logger, stdin, check, debug, }: MainFormatStdinArgs): Promise<ExitCode>;
export {};
2 changes: 1 addition & 1 deletion dist/node/isMissingFileError.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export declare function isMissingFileError(error: unknown): boolean;
export declare function isMissingFileError(error: unknown): error is NodeJS.ErrnoException;
18 changes: 9 additions & 9 deletions dist/snippetFormatter.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/snippetFormatter.js.map

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions dist/talonFormatter.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/talonFormatter.js.map

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions dist/treeSitterFormatter.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { FormatterOptions, SyntaxNode } from "./types.js";
type Options = FormatterOptions<"endOfLine" | "indentTabs" | "indentSize" | "insertFinalNewline">;
export type Options = FormatterOptions<"endOfLine" | "indentTabs" | "indentSize" | "insertFinalNewline">;
export declare function treeSitterFormatter(node: SyntaxNode, options?: Options, debug?: boolean): string;
export {};
20 changes: 10 additions & 10 deletions dist/treeSitterFormatter.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/treeSitterFormatter.js.map

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions dist/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface EditorConfigOptions extends KnownProps {
column_width?: number | "unset";
preserve_multiline?: boolean | "unset";
}
interface Point {
export interface Point {
row: number;
column: number;
}
Expand All @@ -56,7 +56,9 @@ export interface SyntaxNode {
type: string;
startPosition: Point;
endPosition: Point;
hasError: boolean;
isError: boolean;
isMissing: boolean;
parent: SyntaxNode | null;
children: SyntaxNode[];
}
export {};
7 changes: 7 additions & 0 deletions dist/util/SyntaxError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Point } from "../types.js";
export declare class SyntaxError extends Error {
private location?;
constructor(location?: Point | undefined);
getLocation(): string | undefined;
}
export declare function isSyntaxError(error: unknown): error is SyntaxError;
5 changes: 5 additions & 0 deletions dist/util/SyntaxTreeError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { SyntaxNode } from "../types.js";
import { SyntaxError } from "./SyntaxError.js";
export declare class SyntaxTreeError extends SyntaxError {
constructor(rootNode: SyntaxNode);
}
1 change: 1 addition & 0 deletions dist/util/constants.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export declare const EXIT_OK = 0;
export declare const EXIT_FAIL = 1;
export declare const EXIT_ERROR = 2;
export type ExitCode = typeof EXIT_OK | typeof EXIT_FAIL | typeof EXIT_ERROR;
export declare const DEFAULT_INDENT_WIDTH = 4;
export declare const DEFAULT_MAX_LINE_LENGTH = 80;
export declare const DEFAULT_INSERT_FINAL_NEWLINE = true;
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cursorless/talon-tools",
"version": "0.9.0",
"version": "0.10.0",
"description": "Linting and formatting tools for Talon and Cursorless",
"author": "Cursorless Dev",
"license": "MIT",
Expand Down
91 changes: 61 additions & 30 deletions src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@ import * as path from "node:path";
import * as process from "node:process";
import type { Readable } from "node:stream";
import type { CLI, Logger, ParsedArgs } from "../types.js";
import { EXIT_ERROR, EXIT_FAIL, EXIT_OK } from "../util/constants.js";
import { FilePatternError } from "./FilePatternError.js";
import {
EXIT_ERROR,
EXIT_FAIL,
EXIT_OK,
type ExitCode,
} from "../util/constants.js";
import { getErrorMessage } from "../util/getErrorMessage.js";
import { isMissingFileError } from "./isMissingFileError.js";
import { setExitCode } from "./setExitCode.js";
import { isSyntaxError } from "../util/SyntaxError.js";
import { createLogger } from "./createLogger.js";
import { FilePatternError } from "./FilePatternError.js";
import { getOptionsFromConfig } from "./getOptionsFromConfig.js";
import { isMissingFileError } from "./isMissingFileError.js";
import { normalizeToPosix } from "./normalizeToPosix.js";
import { parseArgs } from "./parseArgs.js";
import { parseFilePatterns } from "./parseFilePatterns.js";
import { printHelp } from "./printHelp.js";
import { printVersion } from "./printVersion.js";
import { setExitCode } from "./setExitCode.js";

export async function main(cli: CLI): Promise<void> {
let logger = createLogger();
Expand Down Expand Up @@ -47,7 +53,7 @@ async function mainUnsafe({
cli,
args,
logger,
}: MainUnsafeArgs): Promise<number> {
}: MainUnsafeArgs): Promise<ExitCode> {
if (args.help) {
printHelp(cli);
return EXIT_OK;
Expand Down Expand Up @@ -101,13 +107,13 @@ async function mainFormatFiles({
check,
debug,
filePatterns,
}: MainFormatFilesArgs): Promise<number> {
}: MainFormatFilesArgs): Promise<ExitCode> {
if (check) {
logger.log("Checking formatting...");
}

const filePaths = await parseFilePatterns(cli, filePatterns);
const changedFileCount = await formatFiles({
const [changedFileCount, hasError] = await formatFiles({
cli,
logger,
check,
Expand All @@ -120,11 +126,18 @@ async function mainFormatFiles({
logger.warn(
`Code style issues found in ${changedFileCount} file(s).`,
);
return EXIT_FAIL;
if (!hasError) {
return EXIT_FAIL;
}
}

logger.log("All matched files use correct code style!");
return EXIT_OK;
if (!hasError) {
logger.log("All matched files use correct code style!");
}
}

if (hasError) {
return EXIT_ERROR;
}

return EXIT_OK;
Expand All @@ -144,24 +157,37 @@ export async function formatFiles({
check,
debug,
filePaths,
}: FormatFilesArgs): Promise<number> {
}: FormatFilesArgs): Promise<[number, boolean]> {
let changedFileCount = 0;
let hasError = false;

for (const fileName of filePaths) {
if (
await formatFile({
for (const filePath of filePaths) {
try {
const fileWasChanged = await formatFile({
cli,
logger,
check,
debug,
filePath: fileName,
})
) {
changedFileCount++;
filePath,
});
if (fileWasChanged) {
changedFileCount++;
}
} catch (error) {
if (isSyntaxError(error)) {
logger.error(
`${getDisplayPath(filePath)}${error.getLocation()}: ${error.message}`,
);
} else {
logger.error(
`${getDisplayPath(filePath)}: ${getErrorMessage(error)}`,
);
}
hasError = true;
}
}

return changedFileCount;
return [changedFileCount, hasError];
}

interface FormatFileArgs {
Expand Down Expand Up @@ -200,12 +226,7 @@ export async function formatFile({
return false;
}

throw new Error(
`Failed to format '${filePath}': ${getErrorMessage(error)}`,
{
cause: error,
},
);
throw error;
}
}

Expand All @@ -227,13 +248,23 @@ export async function mainFormatStdin({
stdin,
check,
debug,
}: MainFormatStdinArgs): Promise<number> {
}: MainFormatStdinArgs): Promise<ExitCode> {
const input = await getStdin({ stdin });
const fileEnding = cli.getStdinFileEnding(input);
const fileName = `stdin.${fileEnding}`;
const filePath = path.resolve(fileName);
const options = await getOptionsFromConfig(filePath);
const formatted = await cli.format(input, options, filePath, debug);
const fauxFileName = `stdin.${fileEnding}`;
const fauxFilePath = path.resolve(fauxFileName);
const options = await getOptionsFromConfig(fauxFilePath);
let formatted: string;

try {
formatted = await cli.format(input, options, fauxFilePath, debug);
} catch (error) {
if (isSyntaxError(error)) {
logger.error(`stdin${error.getLocation()}: ${error.message}`);
return EXIT_ERROR;
}
throw error;
}

if (check) {
if (input !== formatted) {
Expand Down
4 changes: 3 additions & 1 deletion src/node/isMissingFileError.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export function isMissingFileError(error: unknown) {
export function isMissingFileError(
error: unknown,
): error is NodeJS.ErrnoException {
return error instanceof Error && "code" in error && error.code === "ENOENT";
}
5 changes: 5 additions & 0 deletions src/talon/talonFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createDebugLogger } from "../util/createDebugLogger.js";
import { getColumnWidth } from "../util/getColumnWidth.js";
import { getEndOfLine } from "../util/getEndOfLine.js";
import { getIndentation } from "../util/getIndentation.js";
import { SyntaxTreeError } from "../util/SyntaxTreeError.js";
import { convertQuotes } from "./convertQuotes.js";

export type Options = FormatterOptions<
Expand All @@ -24,6 +25,10 @@ export function talonFormatter(
options: Options = {},
debug: boolean = false,
): string {
if (node.hasError) {
throw new SyntaxTreeError(node);
}

const columnWidth = getColumnWidth(node.text) ?? options.columnWidth;
const indentation = getIndentation(options.indentTabs, options.indentSize);
const eol = getEndOfLine(options.endOfLine);
Expand Down
4 changes: 2 additions & 2 deletions src/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ suite("CLI", () => {
await fs.writeFile(unchangedFileName, "unchanged", "utf8");
await fs.writeFile(changedFileName, "changed", "utf8");

const changedFileCount = await formatFiles({
const [changedFileCount] = await formatFiles({
cli,
logger,
check: false,
Expand Down Expand Up @@ -280,7 +280,7 @@ suite("CLI", () => {
debug: false,
filePath: fileName,
}),
/Failed to format '.*example\.txt': boom/,
/boom/,
);
} finally {
await cleanupTempFile(fileName);
Expand Down
15 changes: 15 additions & 0 deletions src/test/talonFormatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@ suite("Talon formatter", () => {
assert.equal(actual, "aaa: bbb\n");
});

test("Syntax tree error", async () => {
const content = [
"^test [<user.ini>]$:",
'if ini: insert("{ini}")',
].join("\n");
await assert.rejects(
() => talonFormatter(content),
(error) => {
assert.ok(error instanceof Error);
assert.equal(error.name, "SyntaxTreeError");
return true;
},
);
});

test("Debug logs unknown syntax node types", async () => {
const rootNode = createNode("mystery", "value");
const output = await captureStreamWrite(process.stderr, () =>
Expand Down
3 changes: 3 additions & 0 deletions src/test/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export function createNode(type: string, text: string): SyntaxNode {
startPosition: { row: 0, column: 0 },
endPosition: { row: 0, column: text.length },
parent: null,
hasError: false,
isError: false,
isMissing: false,
children: [],
};
}
Expand Down
Loading