mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-08 06:40:39 +08:00
static analysis
This commit is contained in:
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
@ -0,0 +1,138 @@
|
||||
// @ts-ignore
|
||||
import { Pattern } from './types/Pattern'; // @ts-ignore
|
||||
import { Match } from './types/Match'; // @ts-ignore
|
||||
import * as symbols from './internals/symbols'; // @ts-ignore
|
||||
import { matchPattern } from './internals/helpers'; // @ts-ignore
|
||||
|
||||
type MatchState<output> =
|
||||
| { matched: true; value: output }
|
||||
| { matched: false; value: undefined };
|
||||
|
||||
const unmatched: MatchState<never> = {
|
||||
matched: false,
|
||||
value: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* `match` creates a **pattern matching expression**.
|
||||
* * Use `.with(pattern, handler)` to pattern match on the input.
|
||||
* * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.
|
||||
*
|
||||
* [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)
|
||||
*
|
||||
* @example
|
||||
* declare let input: "A" | "B";
|
||||
*
|
||||
* return match(input)
|
||||
* .with("A", () => "It's an A!")
|
||||
* .with("B", () => "It's a B!")
|
||||
* .exhaustive();
|
||||
*
|
||||
*/
|
||||
export function match<const input, output = symbols.unset>(
|
||||
value: input
|
||||
): Match<input, output> {
|
||||
return new MatchExpression(value, unmatched) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a match expression. It follows the
|
||||
* builder pattern, we chain methods to add features to the expression
|
||||
* until we call `.exhaustive`, `.otherwise` or the unsafe `.run`
|
||||
* method to execute it.
|
||||
*
|
||||
* The types of this class aren't public, the public type definition
|
||||
* can be found in src/types/Match.ts.
|
||||
*/
|
||||
class MatchExpression<input, output> {
|
||||
constructor(private input: input, private state: MatchState<output>) {}
|
||||
|
||||
with(...args: any[]): MatchExpression<input, output> {
|
||||
if (this.state.matched) return this;
|
||||
|
||||
const handler: (selection: unknown, value: input) => output =
|
||||
args[args.length - 1];
|
||||
|
||||
const patterns: Pattern<input>[] = [args[0]];
|
||||
let predicate: ((value: input) => unknown) | undefined = undefined;
|
||||
|
||||
if (args.length === 3 && typeof args[1] === 'function') {
|
||||
// case with guard as second argument
|
||||
patterns.push(args[0]);
|
||||
predicate = args[1];
|
||||
} else if (args.length > 2) {
|
||||
// case with several patterns
|
||||
patterns.push(...args.slice(1, args.length - 1));
|
||||
}
|
||||
|
||||
let hasSelections = false;
|
||||
let selected: Record<string, unknown> = {};
|
||||
const select = (key: string, value: unknown) => {
|
||||
hasSelections = true;
|
||||
selected[key] = value;
|
||||
};
|
||||
|
||||
const matched =
|
||||
patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&
|
||||
(predicate ? Boolean(predicate(this.input)) : true);
|
||||
|
||||
const selections = hasSelections
|
||||
? symbols.anonymousSelectKey in selected
|
||||
? selected[symbols.anonymousSelectKey]
|
||||
: selected
|
||||
: this.input;
|
||||
|
||||
const state = matched
|
||||
? {
|
||||
matched: true as const,
|
||||
value: handler(selections, this.input),
|
||||
}
|
||||
: unmatched;
|
||||
|
||||
return new MatchExpression(this.input, state);
|
||||
}
|
||||
|
||||
when(
|
||||
predicate: (value: input) => unknown,
|
||||
handler: (selection: input, value: input) => output
|
||||
): MatchExpression<input, output> {
|
||||
if (this.state.matched) return this;
|
||||
|
||||
const matched = Boolean(predicate(this.input));
|
||||
|
||||
return new MatchExpression<input, output>(
|
||||
this.input,
|
||||
matched
|
||||
? { matched: true, value: handler(this.input, this.input) }
|
||||
: unmatched
|
||||
);
|
||||
}
|
||||
|
||||
otherwise(handler: (value: input) => output): output {
|
||||
if (this.state.matched) return this.state.value;
|
||||
return handler(this.input);
|
||||
}
|
||||
|
||||
exhaustive(): output {
|
||||
return this.run();
|
||||
}
|
||||
|
||||
run(): output {
|
||||
if (this.state.matched) return this.state.value;
|
||||
|
||||
let displayedValue;
|
||||
try {
|
||||
displayedValue = JSON.stringify(this.input);
|
||||
} catch (e) {
|
||||
displayedValue = this.input;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Pattern matching error: no pattern matches value ${displayedValue}`
|
||||
);
|
||||
}
|
||||
|
||||
returnType() {
|
||||
return this;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user