@zachacious/protoc-gen-connect-vue 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generator.js +77 -78
- package/package.json +1 -1
- package/templates/api.ts.mustache +13 -31
- package/templates/rpc.ts.mustache +20 -21
package/dist/generator.js
CHANGED
|
@@ -336793,69 +336793,58 @@ var mustache_default = mustache;
|
|
|
336793
336793
|
|
|
336794
336794
|
// src/generator.ts
|
|
336795
336795
|
var METHOD_KIND_UNARY = 1;
|
|
336796
|
-
var
|
|
336797
|
-
"google.protobuf.Empty"
|
|
336798
|
-
"google.protobuf.Timestamp"
|
|
336799
|
-
"google.protobuf.Duration"
|
|
336800
|
-
|
|
336796
|
+
var KNOWN_WKT = [
|
|
336797
|
+
"google.protobuf.Empty",
|
|
336798
|
+
"google.protobuf.Timestamp",
|
|
336799
|
+
"google.protobuf.Duration"
|
|
336800
|
+
];
|
|
336801
336801
|
var currentDir = new URL(".", import.meta.url).pathname;
|
|
336802
336802
|
var templateDir = path.join(currentDir, "..", "templates");
|
|
336803
|
-
var
|
|
336804
|
-
|
|
336805
|
-
|
|
336806
|
-
|
|
336807
|
-
|
|
336808
|
-
|
|
336809
|
-
|
|
336810
|
-
|
|
336811
|
-
|
|
336812
|
-
const
|
|
336813
|
-
|
|
336814
|
-
|
|
336815
|
-
"cursor",
|
|
336816
|
-
"limit",
|
|
336817
|
-
"pagesize",
|
|
336818
|
-
"pagenumber"
|
|
336819
|
-
];
|
|
336820
|
-
for (const field of message.fields) {
|
|
336821
|
-
if (pagingKeys.includes(field.name.toLowerCase()))
|
|
336822
|
-
return true;
|
|
336823
|
-
if (field.fieldKind === "message" && isPaginatedDeep(field.message, visited))
|
|
336824
|
-
return true;
|
|
336803
|
+
var templates = {
|
|
336804
|
+
client: fs.readFileSync(path.join(templateDir, "client.ts.mustache"), "utf-8"),
|
|
336805
|
+
api: fs.readFileSync(path.join(templateDir, "api.ts.mustache"), "utf-8"),
|
|
336806
|
+
rpc: fs.readFileSync(path.join(templateDir, "rpc.ts.mustache"), "utf-8"),
|
|
336807
|
+
index: fs.readFileSync(path.join(templateDir, "index.ts.mustache"), "utf-8")
|
|
336808
|
+
};
|
|
336809
|
+
function findPath(msg, targets, depth = 0) {
|
|
336810
|
+
if (depth > 4)
|
|
336811
|
+
return null;
|
|
336812
|
+
for (const f of msg.fields) {
|
|
336813
|
+
if (targets.includes(f.name.toLowerCase()))
|
|
336814
|
+
return [f.name];
|
|
336825
336815
|
}
|
|
336826
|
-
|
|
336827
|
-
|
|
336828
|
-
|
|
336829
|
-
|
|
336816
|
+
for (const f of msg.fields) {
|
|
336817
|
+
if (f.fieldKind === "message") {
|
|
336818
|
+
const p = findPath(f.message, targets, depth + 1);
|
|
336819
|
+
if (p)
|
|
336820
|
+
return [f.name, ...p];
|
|
336821
|
+
}
|
|
336822
|
+
}
|
|
336823
|
+
return null;
|
|
336830
336824
|
}
|
|
336831
336825
|
function processService(service) {
|
|
336832
|
-
const rpcs = [];
|
|
336833
|
-
const wktImports = new Set;
|
|
336834
336826
|
const importMap = new Map;
|
|
336835
|
-
const
|
|
336836
|
-
|
|
336837
|
-
|
|
336838
|
-
|
|
336839
|
-
|
|
336840
|
-
if (KNOWN_TYPES[fullTypeName]) {
|
|
336841
|
-
wktImports.add(KNOWN_TYPES[fullTypeName]);
|
|
336842
|
-
allMessages.set(KNOWN_TYPES[fullTypeName], "@bufbuild/protobuf/wkt");
|
|
336827
|
+
const wktImports = new Set;
|
|
336828
|
+
const allMessages = new Set;
|
|
336829
|
+
function track(msg) {
|
|
336830
|
+
if (KNOWN_WKT.includes(msg.typeName)) {
|
|
336831
|
+
wktImports.add(msg.name);
|
|
336843
336832
|
return;
|
|
336844
336833
|
}
|
|
336845
|
-
|
|
336846
|
-
|
|
336847
|
-
|
|
336848
|
-
|
|
336849
|
-
|
|
336850
|
-
|
|
336851
|
-
|
|
336852
|
-
|
|
336853
|
-
}
|
|
336834
|
+
if (allMessages.has(msg.name))
|
|
336835
|
+
return;
|
|
336836
|
+
allMessages.add(msg.name);
|
|
336837
|
+
const importPath = `./gen/${msg.file.name.replace(".proto", "_pb")}`;
|
|
336838
|
+
if (!importMap.has(importPath))
|
|
336839
|
+
importMap.set(importPath, new Set);
|
|
336840
|
+
importMap.get(importPath).add(msg.name);
|
|
336841
|
+
msg.fields.forEach((f) => f.fieldKind === "message" && track(f.message));
|
|
336854
336842
|
}
|
|
336855
|
-
|
|
336856
|
-
|
|
336857
|
-
|
|
336858
|
-
const
|
|
336843
|
+
const rpcs = service.methods.map((m) => {
|
|
336844
|
+
track(m.input);
|
|
336845
|
+
track(m.output);
|
|
336846
|
+
const isUnary = m.methodKind === METHOD_KIND_UNARY;
|
|
336847
|
+
const verbs = [
|
|
336859
336848
|
"Create",
|
|
336860
336849
|
"Update",
|
|
336861
336850
|
"Delete",
|
|
@@ -336865,27 +336854,37 @@ function processService(service) {
|
|
|
336865
336854
|
"Set",
|
|
336866
336855
|
"Add"
|
|
336867
336856
|
];
|
|
336868
|
-
const
|
|
336869
|
-
|
|
336870
|
-
|
|
336871
|
-
|
|
336872
|
-
|
|
336873
|
-
|
|
336874
|
-
|
|
336875
|
-
|
|
336876
|
-
|
|
336877
|
-
|
|
336878
|
-
|
|
336879
|
-
|
|
336880
|
-
|
|
336881
|
-
|
|
336882
|
-
|
|
336883
|
-
|
|
336857
|
+
const isMutation = verbs.some((v) => m.name.startsWith(v));
|
|
336858
|
+
const reqPath = findPath(m.input, [
|
|
336859
|
+
"page",
|
|
336860
|
+
"offset",
|
|
336861
|
+
"pagetoken",
|
|
336862
|
+
"cursor",
|
|
336863
|
+
"pagenumber"
|
|
336864
|
+
]);
|
|
336865
|
+
const resPath = findPath(m.output, [
|
|
336866
|
+
"nextpagetoken",
|
|
336867
|
+
"nextpage",
|
|
336868
|
+
"hasmore",
|
|
336869
|
+
"nextcursor"
|
|
336870
|
+
]);
|
|
336871
|
+
return {
|
|
336872
|
+
functionName: m.name.charAt(0).toLowerCase() + m.name.slice(1),
|
|
336873
|
+
hookName: `use${m.name}`,
|
|
336874
|
+
resource: m.name.replace(/^(Get|ListAll|List|Create|Update|Delete|Remove|Patch|Post|Set|Add)/, ""),
|
|
336875
|
+
inputType: m.input.name,
|
|
336876
|
+
outputType: m.output.name,
|
|
336877
|
+
isQuery: isUnary && !isMutation,
|
|
336878
|
+
isPaginated: isUnary && !isMutation && !!reqPath && !!resPath,
|
|
336879
|
+
reqPath: reqPath?.join("."),
|
|
336880
|
+
resPath: resPath?.join(".")
|
|
336881
|
+
};
|
|
336882
|
+
});
|
|
336884
336883
|
return {
|
|
336885
336884
|
serviceName: service.name,
|
|
336886
336885
|
protoPbFile: service.file.name.replace(".proto", "_pb"),
|
|
336887
336886
|
rpcs,
|
|
336888
|
-
messageNames: Array.from(allMessages
|
|
336887
|
+
messageNames: Array.from(allMessages),
|
|
336889
336888
|
wktImports: Array.from(wktImports),
|
|
336890
336889
|
externalImports: Array.from(importMap.entries()).map(([path2, types2]) => ({
|
|
336891
336890
|
path: path2,
|
|
@@ -336895,15 +336894,15 @@ function processService(service) {
|
|
|
336895
336894
|
}
|
|
336896
336895
|
var plugin = createEcmaScriptPlugin({
|
|
336897
336896
|
name: "protoc-gen-connect-vue",
|
|
336898
|
-
version: "v1.0.
|
|
336897
|
+
version: "v1.0.7",
|
|
336899
336898
|
generateTs: (schema) => {
|
|
336900
|
-
const
|
|
336901
|
-
if (!
|
|
336899
|
+
const service = schema.files.flatMap((f) => f.services)[0];
|
|
336900
|
+
if (!service)
|
|
336902
336901
|
return;
|
|
336903
|
-
const
|
|
336904
|
-
schema.generateFile("client.ts").print(mustache_default.render(
|
|
336905
|
-
schema.generateFile("api.ts").print(mustache_default.render(
|
|
336906
|
-
schema.generateFile("index.ts").print(mustache_default.render(
|
|
336902
|
+
const data = processService(service);
|
|
336903
|
+
schema.generateFile("client.ts").print(mustache_default.render(templates.client, data));
|
|
336904
|
+
schema.generateFile("api.ts").print(mustache_default.render(templates.api, data, { rpc: templates.rpc }));
|
|
336905
|
+
schema.generateFile("index.ts").print(mustache_default.render(templates.index, {}));
|
|
336907
336906
|
}
|
|
336908
336907
|
});
|
|
336909
336908
|
runNodeJs(plugin);
|
package/package.json
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { computed, unref } from "vue";
|
|
2
2
|
import {
|
|
3
|
-
useQuery,
|
|
4
|
-
useMutation,
|
|
5
|
-
useInfiniteQuery,
|
|
6
|
-
useQueryClient,
|
|
7
|
-
useIsFetching,
|
|
8
|
-
useIsMutating
|
|
3
|
+
useQuery, useMutation, useInfiniteQuery, useQueryClient, useIsFetching, useIsMutating
|
|
9
4
|
} from "@tanstack/vue-query";
|
|
10
5
|
import { ConnectError } from "@connectrpc/connect";
|
|
11
|
-
import { create
|
|
6
|
+
import { create } from "@bufbuild/protobuf";
|
|
12
7
|
import { useGrpcClient } from "./client";
|
|
13
8
|
|
|
14
9
|
{{#wktImports}}
|
|
@@ -24,18 +19,15 @@ import type { {{#types}}{{.}}, {{/types}} } from "{{{path}}}";
|
|
|
24
19
|
export type APIResponse<T> = { error: string | null; data: T | null; };
|
|
25
20
|
|
|
26
21
|
async function callConnect<ReqT, ResT, DataT>(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
method: (req: ReqT) => Promise<ResT>,
|
|
23
|
+
req: ReqT,
|
|
24
|
+
extractor: (res: ResT) => DataT
|
|
30
25
|
): Promise<APIResponse<DataT>> {
|
|
31
26
|
try {
|
|
32
|
-
const res = await
|
|
33
|
-
return { error: null, data:
|
|
27
|
+
const res = await method(req);
|
|
28
|
+
return { error: null, data: extractor(res) };
|
|
34
29
|
} catch (err) {
|
|
35
|
-
return {
|
|
36
|
-
error: err instanceof ConnectError ? err.message : "Unknown error",
|
|
37
|
-
data: null
|
|
38
|
-
};
|
|
30
|
+
return { error: err instanceof ConnectError ? err.message : "Unknown error", data: null };
|
|
39
31
|
}
|
|
40
32
|
}
|
|
41
33
|
|
|
@@ -47,29 +39,19 @@ export const queryKeys = {
|
|
|
47
39
|
|
|
48
40
|
export const createEmpty = {
|
|
49
41
|
{{#messageNames}}
|
|
50
|
-
{{.}}: (data?:
|
|
42
|
+
{{.}}: (data?: any) => create({{.}}Schema, data) as {{.}},
|
|
51
43
|
{{/messageNames}}
|
|
52
44
|
};
|
|
53
45
|
|
|
54
46
|
export const useApi = () => {
|
|
55
47
|
const { client } = useGrpcClient();
|
|
56
48
|
const queryClient = useQueryClient();
|
|
49
|
+
const isGlobalLoading = computed(() => useIsFetching().value > 0 || useIsMutating().value > 0);
|
|
57
50
|
|
|
58
|
-
|
|
59
|
-
const isMutating = useIsMutating();
|
|
60
|
-
const isGlobalLoading = computed(() => isFetching.value > 0 || isMutating.value > 0);
|
|
61
|
-
|
|
62
|
-
{{#rpcs}}
|
|
63
|
-
{{> rpc}}
|
|
64
|
-
{{/rpcs}}
|
|
51
|
+
{{#rpcs}}{{> rpc}}{{/rpcs}}
|
|
65
52
|
|
|
66
53
|
return {
|
|
67
|
-
{{#rpcs}}
|
|
68
|
-
|
|
69
|
-
{{hookName}},
|
|
70
|
-
{{/rpcs}}
|
|
71
|
-
isGlobalLoading,
|
|
72
|
-
queryKeys,
|
|
73
|
-
createEmpty
|
|
54
|
+
{{#rpcs}}{{functionName}}, {{hookName}}, {{/rpcs}}
|
|
55
|
+
isGlobalLoading, queryKeys, createEmpty
|
|
74
56
|
};
|
|
75
57
|
};
|
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Used for manual actions. Invalidates the cache for this resource on success.
|
|
2
|
+
* Async Wrapper: {{functionName}}
|
|
4
3
|
*/
|
|
5
4
|
const {{functionName}} = async (req: {{inputType}}): Promise<APIResponse<{{outputType}}>> => {
|
|
6
5
|
const res = await callConnect(client.value.{{functionName}}.bind(client.value), req, (res) => res);
|
|
7
|
-
if (!res.error) {
|
|
8
|
-
queryClient.invalidateQueries({ queryKey: ["{{resource}}"] });
|
|
9
|
-
}
|
|
6
|
+
if (!res.error) queryClient.invalidateQueries({ queryKey: ["{{resource}}"] });
|
|
10
7
|
return res;
|
|
11
8
|
};
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
|
-
*
|
|
15
|
-
* Provides reactive data binding with caching.
|
|
11
|
+
* Hook: {{hookName}}
|
|
16
12
|
*/
|
|
17
13
|
const {{hookName}} = (
|
|
18
|
-
{{#isQuery}}
|
|
19
|
-
|
|
20
|
-
options: any = {}
|
|
21
|
-
{{/isQuery}}
|
|
22
|
-
{{^isQuery}}
|
|
23
|
-
options: any = {}
|
|
24
|
-
{{/isQuery}}
|
|
14
|
+
{{#isQuery}}input: any, options: any = {}{{/isQuery}}
|
|
15
|
+
{{^isQuery}}options: any = {}{{/isQuery}}
|
|
25
16
|
) => {
|
|
26
17
|
{{#isPaginated}}
|
|
27
18
|
return useInfiniteQuery({
|
|
28
19
|
queryKey: queryKeys.{{functionName}}(input),
|
|
29
20
|
queryFn: async ({ pageParam }) => {
|
|
30
|
-
const req =
|
|
21
|
+
const req = JSON.parse(JSON.stringify(unref(input)));
|
|
22
|
+
const path = "{{reqPath}}".split('.');
|
|
23
|
+
let curr = req;
|
|
24
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
25
|
+
curr[path[i]] = curr[path[i]] || {};
|
|
26
|
+
curr = curr[path[i]];
|
|
27
|
+
}
|
|
28
|
+
curr[path[path.length - 1]] = pageParam;
|
|
31
29
|
return client.value.{{functionName}}(req);
|
|
32
30
|
},
|
|
33
|
-
initialPageParam: 1,
|
|
34
|
-
getNextPageParam: (lastPage: any) =>
|
|
31
|
+
initialPageParam: options.initialPageParam ?? 1,
|
|
32
|
+
getNextPageParam: (lastPage: any) => {
|
|
33
|
+
const path = "{{resPath}}".split('.');
|
|
34
|
+
return path.reduce((o, i) => o?.[i], lastPage) || undefined;
|
|
35
|
+
},
|
|
35
36
|
...options,
|
|
36
37
|
});
|
|
37
38
|
{{/isPaginated}}
|
|
38
|
-
|
|
39
39
|
{{^isPaginated}}
|
|
40
40
|
{{#isQuery}}
|
|
41
41
|
return useQuery({
|
|
@@ -44,13 +44,12 @@ const {{hookName}} = (
|
|
|
44
44
|
...options,
|
|
45
45
|
});
|
|
46
46
|
{{/isQuery}}
|
|
47
|
-
|
|
48
47
|
{{^isQuery}}
|
|
49
48
|
return useMutation({
|
|
50
49
|
mutationFn: (req: {{inputType}}) => client.value.{{functionName}}(req),
|
|
51
|
-
onSuccess: async (
|
|
50
|
+
onSuccess: async (d, v, c) => {
|
|
52
51
|
await queryClient.invalidateQueries({ queryKey: ["{{resource}}"] });
|
|
53
|
-
if (options.onSuccess) return options.onSuccess(
|
|
52
|
+
if (options.onSuccess) return options.onSuccess(d, v, c);
|
|
54
53
|
},
|
|
55
54
|
...options,
|
|
56
55
|
});
|