svelte-reflector 2.1.0 → 2.1.3

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.
@@ -54,6 +54,7 @@ export class Reflector {
54
54
  const runtimeFiles = RuntimeFilesEmitter.build({
55
55
  propertiesNames: this.propertiesNames,
56
56
  context: this.context,
57
+ config: this.config,
57
58
  });
58
59
  await Promise.all([
59
60
  ...moduleSchemaFiles.map((f) => f.save()),
@@ -12,6 +12,8 @@ export interface ReflectorConfig {
12
12
  environmentImport: string;
13
13
  /** Name of the exported environment flag — values other than `DEV` are treated as prod. */
14
14
  environmentFlag: string;
15
+ /** Full import path to the toast module (default export must expose `.error({ title, description })`). */
16
+ toastImport: string;
15
17
  }
16
18
  export declare const DEFAULT_REFLECTOR_CONFIG: ReflectorConfig;
17
19
  export declare function resolveReflectorConfig(partial?: Partial<ReflectorConfig>): ReflectorConfig;
@@ -3,6 +3,7 @@ export const DEFAULT_REFLECTOR_CONFIG = {
3
3
  validatorsImport: "$lib/sanitizers/validateFormats",
4
4
  environmentImport: "$env/static/public",
5
5
  environmentFlag: "PUBLIC_ENVIRONMENT",
6
+ toastImport: "$lib/utils/toast.svelte",
6
7
  };
7
8
  export function resolveReflectorConfig(partial) {
8
9
  return { ...DEFAULT_REFLECTOR_CONFIG, ...(partial ?? {}) };
@@ -1,5 +1,6 @@
1
1
  import { Source } from "../../file.js";
2
2
  import type { CodegenContext } from "../CodegenContext.js";
3
+ import type { ReflectorConfig } from "../config/ReflectorConfig.js";
3
4
  /**
4
5
  * Emits the shared runtime-support files that sit alongside the generated
5
6
  * module files: the reflector runtime template, the FIELD_NAMES list, the
@@ -9,5 +10,6 @@ export declare class RuntimeFilesEmitter {
9
10
  static build(params: {
10
11
  propertiesNames: Set<string>;
11
12
  context: CodegenContext;
13
+ config: ReflectorConfig;
12
14
  }): Source[];
13
15
  }
@@ -4,6 +4,7 @@ import { Source } from "../../file.js";
4
4
  import { loadReflectorTemplate } from "../../loadTemplate.js";
5
5
  import { generatedDir } from "../../vars.global.js";
6
6
  import { dedent } from "../../helpers/codegen.js";
7
+ import { DEFAULT_REFLECTOR_CONFIG } from "../config/ReflectorConfig.js";
7
8
  function generated(relPath) {
8
9
  return path.resolve(process.cwd(), `${generatedDir}/${relPath}`);
9
10
  }
@@ -14,19 +15,23 @@ function generated(relPath) {
14
15
  */
15
16
  export class RuntimeFilesEmitter {
16
17
  static build(params) {
17
- const { propertiesNames, context } = params;
18
+ const { propertiesNames, context, config } = params;
19
+ let templateData = loadReflectorTemplate();
20
+ if (config.toastImport !== DEFAULT_REFLECTOR_CONFIG.toastImport) {
21
+ templateData = templateData.replace(`from "${DEFAULT_REFLECTOR_CONFIG.toastImport}"`, `from "${config.toastImport}"`);
22
+ }
18
23
  const typesSrc = new Source({
19
24
  path: generated("reflector.svelte.ts"),
20
- data: loadReflectorTemplate(),
25
+ data: templateData,
21
26
  });
22
27
  const fieldLiterals = Array.from(propertiesNames).map((p) => `'${p}'`);
23
28
  const fieldsFile = new Source({
24
29
  path: generated("fields.ts"),
25
- data: dedent `
26
- export const FIELD_NAMES = [
27
- ${fieldLiterals}
28
- ] as const;
29
- export type FieldName = (typeof FIELD_NAMES)[number]
30
+ data: dedent `
31
+ export const FIELD_NAMES = [
32
+ ${fieldLiterals}
33
+ ] as const;
34
+ export type FieldName = (typeof FIELD_NAMES)[number]
30
35
  `,
31
36
  });
32
37
  const enumss = Array.from(context.enumTypes)
@@ -41,13 +46,13 @@ export class RuntimeFilesEmitter {
41
46
  .join(";");
42
47
  const mockedFile = new Source({
43
48
  path: generated("mocked-params.svelte.ts"),
44
- data: dedent `
45
- class MockedParams {
46
- ${mockedFields}
47
- }
48
-
49
- const mockedParams = new MockedParams()
50
- export default mockedParams
49
+ data: dedent `
50
+ class MockedParams {
51
+ ${mockedFields}
52
+ }
53
+
54
+ const mockedParams = new MockedParams()
55
+ export default mockedParams
51
56
  `,
52
57
  });
53
58
  return [typesSrc, fieldsFile, enumFile, mockedFile];
@@ -1,3 +1,4 @@
1
+ import { queryOverrideTypeLiteral } from "./queryOverride.js";
1
2
  export class ApiCallStrategy {
2
3
  listStateAccess(_method) {
3
4
  return "this.data";
@@ -15,6 +16,11 @@ export class ApiCallStrategy {
15
16
  buildParamsType(method) {
16
17
  const responseType = method.responseTypeInterface;
17
18
  const pathsBlock = this.buildPathsInfo(method);
19
+ const queryBlock = queryOverrideTypeLiteral(method.analyzers.props.querys);
20
+ if (queryBlock) {
21
+ const pathsArg = pathsBlock ?? "void";
22
+ return `ApiCallParams<${responseType}, ${pathsArg}, ${queryBlock}>`;
23
+ }
18
24
  if (pathsBlock) {
19
25
  return `ApiCallParams<${responseType}, ${pathsBlock}>`;
20
26
  }
@@ -8,36 +8,36 @@ export class CallMethodGenerator {
8
8
  const { inside, outside } = this.buildApiCall(method, strategy);
9
9
  const methodReturn = this.buildMethodReturn(method, strategy);
10
10
  const signature = strategy.buildSignature(method);
11
- return `
12
- ${description}
13
- ${signature} {
14
-
15
- const behavior = params?.behavior ?? new Behavior();
16
- const { onError, onSuccess } = behavior;
17
-
18
- this.loading = true;
19
- ${props}
20
- const endpoint = ${endpoint}
21
-
22
- ${outside}
23
-
24
- try {
25
- ${inside}
26
- await onSuccess?.(response);
27
-
28
- return ${methodReturn};
29
- } catch (e) {
30
- let parsedError: ApiErrorResponse;
31
- try {
32
- parsedError = JSON.parse((e as Error).message) as ApiErrorResponse;
33
- } catch {
34
- parsedError = { error: 'unknown', message: (e as Error).message ?? String(e) };
35
- }
36
- return await onError?.(parsedError);
37
- } finally {
38
- this.loading = false;
39
- }
40
- }
11
+ return `
12
+ ${description}
13
+ ${signature} {
14
+
15
+ const behavior = params?.behavior ?? new Behavior();
16
+ const { onError, onSuccess } = behavior;
17
+
18
+ this.loading = true;
19
+ ${props}
20
+ const endpoint = ${endpoint}
21
+
22
+ ${outside}
23
+
24
+ try {
25
+ ${inside}
26
+ await onSuccess?.(response);
27
+
28
+ return ${methodReturn};
29
+ } catch (e) {
30
+ let parsedError: ApiErrorResponse;
31
+ try {
32
+ parsedError = JSON.parse((e as Error).message) as ApiErrorResponse;
33
+ } catch {
34
+ parsedError = { error: 'unknown', message: (e as Error).message ?? String(e) };
35
+ }
36
+ return await onError?.(parsedError);
37
+ } finally {
38
+ this.loading = false;
39
+ }
40
+ }
41
41
  `;
42
42
  }
43
43
  buildProps(method) {
@@ -73,13 +73,13 @@ export class CallMethodGenerator {
73
73
  }
74
74
  buildListCall(method, responseType, strategy) {
75
75
  const querys = this.joinNames(method.analyzers.props.querys);
76
- const inside = `
77
- const response = await api.get<${responseType}, unknown>({
78
- endpoint,
79
- queryData: { ${querys} }
80
- })
81
- ${strategy.listStateAccess(method)} = ${method.analyzers.request.responseType}.from(response.data);
82
- this.totalPages = response.totalPages;
76
+ const inside = `
77
+ const response = await api.get<${responseType}, unknown>({
78
+ endpoint,
79
+ queryData: { ${querys} }
80
+ })
81
+ ${strategy.listStateAccess(method)} = ${method.analyzers.request.responseType}.from(response.data);
82
+ this.totalPages = response.totalPages;
83
83
  `;
84
84
  return { inside, outside: "" };
85
85
  }
@@ -90,13 +90,13 @@ export class CallMethodGenerator {
90
90
  const assignment = rType && !isPrimitive
91
91
  ? `${strategy.entityStateAccess(method)} = new ${rType}({ data: response })`
92
92
  : "";
93
- const inside = `
94
- const response = await api.get<${responseType}, unknown>({
95
- endpoint,
96
- ${querys}
97
- })
98
-
99
- ${assignment}
93
+ const inside = `
94
+ const response = await api.get<${responseType}, unknown>({
95
+ endpoint,
96
+ ${querys}
97
+ })
98
+
99
+ ${assignment}
100
100
  `;
101
101
  return { inside, outside: "" };
102
102
  }
@@ -111,23 +111,23 @@ export class CallMethodGenerator {
111
111
  if (hasHeaders) {
112
112
  outside.push(`const headers = this.headers.bundle()`);
113
113
  }
114
- const inside = `
115
- const response = await api.${apiType}<${responseType}>({
116
- endpoint,
117
- ${hasData ? "data," : ""}
118
- ${hasHeaders ? "headers," : ""}
119
- })
114
+ const inside = `
115
+ const response = await api.${apiType}<${responseType}>({
116
+ endpoint,
117
+ ${hasData ? "data," : ""}
118
+ ${hasHeaders ? "headers," : ""}
119
+ })
120
120
  `;
121
121
  return { inside, outside: outside.join("\n") };
122
122
  }
123
123
  buildDeleteCall(method, responseType, bodyType, strategy) {
124
124
  const hasData = !!bodyType;
125
125
  const outside = hasData ? `const data = ${strategy.formStateAccess(method)}.bundle()` : "";
126
- const inside = `
127
- const response = await api.delete<${responseType}, unknown>({
128
- endpoint,
129
- ${hasData ? "data," : ""}
130
- })
126
+ const inside = `
127
+ const response = await api.delete<${responseType}, unknown>({
128
+ endpoint,
129
+ ${hasData ? "data," : ""}
130
+ })
131
131
  `;
132
132
  return { inside, outside };
133
133
  }
@@ -7,5 +7,4 @@ export declare class ModuleCallStrategy implements CallStrategy {
7
7
  private buildParamsType;
8
8
  private buildPathsBlock;
9
9
  private buildQueryOverrideBlock;
10
- private queryOverrideType;
11
10
  }
@@ -1,4 +1,5 @@
1
1
  import { treatByUppercase } from "../../helpers/helpers.js";
2
+ import { queryOverrideEntryType } from "./queryOverride.js";
2
3
  export class ModuleCallStrategy {
3
4
  listStateAccess(method) {
4
5
  return `this.list${method.stateSuffix}`;
@@ -21,21 +22,21 @@ export class ModuleCallStrategy {
21
22
  const blocks = [`behavior?: ${behaviorType};`, pathsBlock, queryBlock]
22
23
  .filter((b) => !!b)
23
24
  .join("\n");
24
- return `{
25
- ${blocks}
25
+ return `{
26
+ ${blocks}
26
27
  }`;
27
28
  }
28
29
  buildPathsBlock(method) {
29
30
  const paths = method.analyzers.props.paths;
30
31
  if (paths.length === 0)
31
32
  return undefined;
32
- return `paths?: {
33
+ return `paths?: {
33
34
  ${paths
34
35
  .map((p) => {
35
36
  const type = p.rawType ?? p.type;
36
37
  return `${p.name}: ${type}`;
37
38
  })
38
- .join("\n")}
39
+ .join("\n")}
39
40
  };`;
40
41
  }
41
42
  buildQueryOverrideBlock(method) {
@@ -43,17 +44,10 @@ export class ModuleCallStrategy {
43
44
  if (querys.length === 0)
44
45
  return undefined;
45
46
  const fields = querys
46
- .map((q) => `${q.name}?: ${this.queryOverrideType(q)}`)
47
+ .map((q) => `${q.name}?: ${queryOverrideEntryType(q)}`)
47
48
  .join("\n");
48
- return `queryOverride?: {
49
- ${fields}
49
+ return `queryOverride?: {
50
+ ${fields}
50
51
  };`;
51
52
  }
52
- queryOverrideType(q) {
53
- if ("isEnum" in q && q.isEnum)
54
- return `${q.type}[]`;
55
- if (!("rawType" in q) && !("enumName" in q))
56
- return "string[]";
57
- return "string | null";
58
- }
59
53
  }
@@ -0,0 +1,12 @@
1
+ import type { AttributeProp } from "../../types/types.js";
2
+ /** TS type literal for a single query override entry. Mirrors the
3
+ * shape produced by each Prop's bundle entry:
4
+ * PrimitiveProp / EnumProp → `string | null`
5
+ * ArrayProp (enum) → `${type}[]`
6
+ * ArrayProp (non-enum, raro) → `string[]`
7
+ */
8
+ export declare function queryOverrideEntryType(q: AttributeProp): string;
9
+ /** Inline TS object type literal for the full queryOverride bag,
10
+ * derived from the method's query props. Returns undefined when there
11
+ * are no query params (caller should skip emitting the slot). */
12
+ export declare function queryOverrideTypeLiteral(querys: AttributeProp[]): string | undefined;
@@ -0,0 +1,22 @@
1
+ /** TS type literal for a single query override entry. Mirrors the
2
+ * shape produced by each Prop's bundle entry:
3
+ * PrimitiveProp / EnumProp → `string | null`
4
+ * ArrayProp (enum) → `${type}[]`
5
+ * ArrayProp (non-enum, raro) → `string[]`
6
+ */
7
+ export function queryOverrideEntryType(q) {
8
+ if ("isEnum" in q && q.isEnum)
9
+ return `${q.type}[]`;
10
+ if (!("rawType" in q) && !("enumName" in q))
11
+ return "string[]";
12
+ return "string | null";
13
+ }
14
+ /** Inline TS object type literal for the full queryOverride bag,
15
+ * derived from the method's query props. Returns undefined when there
16
+ * are no query params (caller should skip emitting the slot). */
17
+ export function queryOverrideTypeLiteral(querys) {
18
+ if (querys.length === 0)
19
+ return undefined;
20
+ const fields = querys.map((q) => `${q.name}?: ${queryOverrideEntryType(q)}`).join("; ");
21
+ return `{ ${fields} }`;
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-reflector",
3
- "version": "2.1.0",
3
+ "version": "2.1.3",
4
4
  "description": "Reflects zod types from openAPI schemas",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",