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
12 changes: 11 additions & 1 deletion build/utils.mts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,17 @@ export const exec = catchWrap(execute, 99);
export const quote = (paths: string | string[]) =>
[paths]
.flat()
.map((path) => `'${path.replaceAll("'", "'\\''")}'`)
.map((path) => {
// Quoting settles what the shell does with a name and nothing about
// what the tool then makes of it: `'--write.md'` arrives at prettier as
// `--write.md`, which it reads as an option. It answered that one by
// printing an error and exiting 0 -- a check that passed having checked
// nothing. A leading `./` says the argument is a path and costs a
// relative name two characters.
const safe = path.startsWith('-') ? `./${path}` : path;

return `'${safe.replaceAll("'", "'\\''")}'`;
})
.join(' ');

/**
Expand Down
11 changes: 11 additions & 0 deletions build/utils.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ describe('quote', () => {
deepStrictEqual(quote("it's.md"), "'it'\\''s.md'");
});

test('keeps a name that looks like an option from being read as one', () => {
// Quoting alone leaves `--write.md` arriving at the tool as `--write.md`.
deepStrictEqual(quote('--write.md'), "'./--write.md'");
deepStrictEqual(quote('-'), "'./-'");
});

test('leaves an ordinary path alone', () => {
deepStrictEqual(quote('doc/adr/0001-a.md'), "'doc/adr/0001-a.md'");
deepStrictEqual(quote('/abs/path.jar'), "'/abs/path.jar'");
});

test('survives a round trip through the shell it is written for', async () => {
// The escaping is only worth anything if the shell `exec` uses agrees
// with it, so this asks that shell rather than a model of it.
Expand Down
Loading