-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathextract-group-mapping-from-proto-services.ts
112 lines (105 loc) · 3.78 KB
/
extract-group-mapping-from-proto-services.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { stringify } from "https://deno.land/[email protected]/encoding/yaml.ts";
import { walk } from "https://deno.land/[email protected]/fs/walk.ts";
import { Command } from "https://deno.land/x/[email protected]/command/mod.ts";
import * as ast from "https://deno.land/x/[email protected]/core/ast/index.ts";
import { parse } from "https://deno.land/x/[email protected]/core/parser/proto.ts";
import {
filterNodesByType,
findNodeByType,
} from "https://deno.land/x/[email protected]/core/schema/ast-util.ts";
import {
evalConstant,
} from "https://deno.land/x/[email protected]/core/schema/eval-ast-constant.ts";
import {
stringifyFullIdent,
stringifyOptionName,
} from "https://deno.land/x/[email protected]/core/schema/stringify-ast-frag.ts";
export interface Table {
[key: string]: string[];
}
if (import.meta.main) {
interface Options {
invert?: boolean;
yaml?: boolean;
}
const command = new Command();
command
.name("riiid-extract-keycloak-groups")
.arguments("<dir:string>")
.option("-i, --invert", "invert result")
.option("-y, --yaml", "print as yaml")
.action(async (options: Options, dir: string) => {
const table: Table = {};
const entries = walk(dir, { includeDirs: false, exts: [".proto"] });
for await (const { path } of entries) {
const code = await Deno.readTextFile(path);
const parseResult = parse(code);
Object.assign(
table,
getMethodNameToKeycloakGroupTable(parseResult.ast),
);
}
const t = options.invert ? invert(table) : table;
if (options.yaml) console.log(stringify(t, { lineWidth: Infinity }));
else console.log(JSON.stringify(t, null, 2));
})
.parse(Deno.args);
}
function joinTypePath(...fragments: string[]): string {
return fragments.filter((fragment) => fragment).join(".");
}
export function getMethodNameToKeycloakGroupTable(ast: ast.Proto): Table {
const result: Table = {};
const packagePath = getPackage(ast.statements);
for (const service of filterNodesByType(ast.statements, "service")) {
const serviceName = service.serviceName.text;
const serviceBodyStatements = service.serviceBody.statements;
for (const rpc of filterNodesByType(serviceBodyStatements, "rpc")) {
const rpcName = rpc.rpcName.text;
const rpcPath = joinTypePath(packagePath, serviceName) + "/" + rpcName;
if (rpc.semiOrRpcBody.type === "rpc-body") {
const options = getOptions(rpc.semiOrRpcBody.statements);
const keycloakGroupOptionValue = options["(inside.keycloak_group)"];
if (typeof keycloakGroupOptionValue === "string") {
result[rpcPath] = keycloakGroupOptionValue.split(",").map(
(keycloakGroup) => keycloakGroup.trim(),
);
continue;
}
}
result[rpcPath] = [];
}
}
return result;
}
function getPackage(statements: ast.Statement[]): string {
const packageStatement = findNodeByType(statements, "package");
if (!packageStatement) return "";
return stringifyFullIdent(packageStatement.fullIdent);
}
type OptionValue = boolean | number | string;
interface Options {
[optionName: string]: OptionValue;
}
function getOptions(nodes?: ast.Node[]): Options {
if (!nodes) return {};
const optionStatements = filterNodesByType(nodes, "option");
const result: Options = {};
for (const statement of optionStatements) {
const optionName = stringifyOptionName(statement.optionName);
const optionValue = evalConstant(statement.constant);
result[optionName] = optionValue;
}
return result;
}
export function invert(table: Table): Table {
const result: Table = {};
for (const [key, value] of Object.entries(table)) {
const arr = value.length ? value : [""];
for (const k of arr) {
result[k] = result[k] || [];
result[k].push(key);
}
}
return result;
}