Skip to content

Commit

Permalink
Latest
Browse files Browse the repository at this point in the history
  • Loading branch information
lydell committed Oct 30, 2023
1 parent 3a60e38 commit ac26b8d
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 66 deletions.
8 changes: 4 additions & 4 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
Expand Up @@ -25,7 +25,7 @@
],
"dependencies": {
"node-pty": "^1.0.0",
"tiny-decoders": "^7.0.1"
"tiny-decoders": "^23.0.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "6.7.2",
Expand Down
94 changes: 40 additions & 54 deletions run-pty.js
Original file line number Diff line number Diff line change
Expand Up @@ -1077,74 +1077,62 @@ const partitionArgs = (args) => {
* @returns {Array<CommandDescription>}
*/
const parseInputFile = (string) => {
const result = Codec.parse(Codec.array(commandDescriptionCodec), string);
const result = Codec.JSON.parse(Codec.array(commandDescriptionCodec), string);
switch (result.tag) {
case "Valid":
return result.value;
case "DecoderError":
throw new Error(Codec.formatAll(result.errors));
throw new Error(Codec.format(result.error));
}
};

const statusCodec = Codec.map(
Codec.orNull(Codec.tuple([Codec.string, Codec.string])),
Codec.nullOr(Codec.tuple([Codec.string, Codec.string])),
{
decoder: (value) => value ?? undefined,
encoder: (value) => value ?? null,
},
);

const statusesCodec = Codec.flatMap(Codec.record(statusCodec), {
decoder: (record) => {
/** @type {Array<[RegExp, Codec.Infer<typeof statusCodec>]>} */
const result = [];
for (const [key, value] of Object.entries(record)) {
try {
result.push([RegExp(key, "u"), value]);
} catch (error) {
return {
tag: "DecoderError",
error: {
tag: "custom",
message: error instanceof Error ? error.message : String(error),
got: key,
path: [key],
},
};
}
}
return { tag: "Valid", value: result };
},
encoder: (items) =>
Object.fromEntries(items.map(([key, value]) => [key.source, value])),
});

/**
* @type {Codec.Codec<CommandDescription>}
*/
const commandDescriptionCodec = Codec.map(
Codec.fields(
{
command: nonEmptyArray(Codec.string),
title: Codec.optional(Codec.string),
cwd: Codec.optional(Codec.string),
status: Codec.optional(
Codec.flatMap(Codec.record(statusCodec), {
decoder: (record) => {
/** @type {Array<[RegExp, Codec.Infer<typeof statusCodec>]>} */
const result = [];
/** @type {Array<Codec.DecoderError>} */
const errors = [];
for (const [key, value] of Object.entries(record)) {
try {
result.push([RegExp(key, "u"), value]);
} catch (error) {
errors.push({
tag: "custom",
message:
error instanceof Error ? error.message : String(error),
got: key,
path: [key],
});
}
}
const [firstError, ...restErrors] = errors;
return firstError === undefined
? { tag: "Valid", value: result }
: {
tag: "DecoderError",
errors: [firstError, ...restErrors],
};
},
/**
* @param {Array<[RegExp, Codec.Infer<typeof statusCodec>]>} items
* @returns {Record<string, Codec.Infer<typeof statusCodec>>}
*/
encoder: (items) =>
Object.fromEntries(
items.map(([key, value]) => [key.source, value]),
),
}),
),
defaultStatus: Codec.optional(statusCodec),
killAllSequence: Codec.optional(Codec.string),
title: Codec.field(Codec.string, { optional: true }),
cwd: Codec.field(Codec.string, { optional: true }),
status: Codec.field(statusesCodec, { optional: true }),
defaultStatus: Codec.field(statusCodec, { optional: true }),
killAllSequence: Codec.field(Codec.string, { optional: true }),
},
{ disallowExtraFields: true },
{ allowExtraFields: false },
),
{
decoder: ({
Expand All @@ -1170,14 +1158,12 @@ function nonEmptyArray(decoder) {
arr.length === 0
? {
tag: "DecoderError",
errors: [
{
tag: "custom",
message: "Expected a non-empty array",
got: arr,
path: [],
},
],
error: {
tag: "custom",
message: "Expected a non-empty array",
got: arr,
path: [],
},
}
: { tag: "Valid", value: arr },
encoder: (value) => value,
Expand Down
18 changes: 11 additions & 7 deletions test/run-pty.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1189,19 +1189,17 @@ describe("parse json", () => {
expect(testJsonError("empty.json")).toMatchInlineSnapshot(`
Failed to read command descriptions file as JSON:
At root:
Unexpected end of JSON input
Got: ""
SyntaxError: Unexpected end of JSON input
`);
});

test("invalid json syntax", () => {
expect(testJsonError("invalid-json-syntax.json")).toMatchInlineSnapshot(`
Failed to read command descriptions file as JSON:
At root:
Unexpected token ']', ..."kend"] },
SyntaxError: Unexpected token ']', ..."kend"] },
]
" is not valid JSON
Got: "[\\n { \\"command\\": [\\"npm\\", \\"run\\", \\"frontend…ommand\\": [\\"npm\\", \\"run\\", \\"backend\\"] },\\n]\\n"
`);
});

Expand Down Expand Up @@ -1260,9 +1258,15 @@ describe("parse json", () => {
expect(testJsonError("key-typo.json")).toMatchInlineSnapshot(`
Failed to read command descriptions file as JSON:
At root[0]:
Expected only these fields: "command", "title", "cwd", "status", "defaultStatus", "killAllSequence"
Found extra fields:
"titel"␊
Expected only these fields:
"command",
"title",
"cwd",
"status",
"defaultStatus",
"killAllSequence"
Found extra fields:
"titel"
`);
});

Expand Down

0 comments on commit ac26b8d

Please sign in to comment.