• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

homer0 / packages / 4422859008

pending completion
4422859008

push

github

homer0
fix(eslint-plugin): use project as an array in the preset

720 of 720 branches covered (100.0%)

Branch coverage included in aggregate %.

2027 of 2027 relevant lines covered (100.0%)

45.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/packages/public/api-utils/src/endpointsGenerator.ts
1
import urijs from 'urijs';
2✔
2
import { flat, copy } from '@homer0/object-utils';
2✔
3
import type { EndpointDefinition, EndpointDefinitionProps, EndpointsDict } from './types';
4
/**
5
 * The options for the service constructor.
6
 */
7
export type EndpointsGeneratorOptions = {
8
  /**
9
   * The base URL for the endpoints.
10
   */
11
  url: string;
12
  /**
13
   * The dictionary with the endpoints' definitions.
14
   */
15
  endpoints: EndpointsDict;
16
  /**
17
   * The format the placeholders must have in order to be replaced by the service. It can
18
   * be anything that includes `%name%`, for example `:%name%`, or `{{%name%}}`.
19
   *
20
   * @default ':%name%'
21
   */
22
  paramsPlaceholder?: string;
23
};
24
/**
25
 * A service that allows the generation of endpoints in a easy way.
26
 */
27
export class EndpointsGenerator {
2✔
28
  /**
29
   * The base URL for the endpoints.
30
   */
31
  protected url: string;
29✔
32
  /**
33
   * A flatten dictionary with the endpoints' definitions.
34
   */
35
  protected endpoints: Record<string, EndpointDefinition>;
29✔
36
  /**
37
   * The format the placeholders must have in order to be replaced by the service. It can
38
   * be anything that includes `%name%`, for example `:%name%`, or `{{%name%}}`.
39
   */
40
  protected paramsPlaceholder: string;
29✔
41
  constructor({
42
    url,
43
    endpoints,
44
    paramsPlaceholder = ':%name%',
28✔
45
  }: EndpointsGeneratorOptions) {
46
    this.url = url.replace(/\/+$/, '');
29✔
47
    this.endpoints = flat({
29✔
48
      target: endpoints,
49
      shouldFlatten: (_, value) => {
50
        const item = value as EndpointDefinition | EndpointsDict;
15✔
51
        return typeof item !== 'string' && !('path' in item);
15✔
52
      },
53
    });
54
    this.paramsPlaceholder = paramsPlaceholder;
29✔
55
  }
56
  /**
57
   * Generates an endpoint's URL.
58
   *
59
   * @param key         The key property of the endpoint in the flatten dictionary.
60
   * @param parameters  A dictionary of paramteres that will replace the placeholders
61
   *                    in the path. If a parameter doesn't have a placeholder, it will
62
   *                    be added to the query string.
63
   * @returns A generated endpoint URL.
64
   * @throws If the endpoint doesn't exist in the dictionary.
65
   */
66
  get(key: string, parameters: Record<string, unknown> = {}): string {
3✔
67
    // Get the endpoint information.
68
    const info = this.endpoints[key];
9✔
69
    // Validate that the endpoint exists.
70
    if (!info) {
9✔
71
      throw new Error(`Trying to access unknown endpoint: ${key}`);
1✔
72
    }
73
    // Get a new reference for the parameters.
74
    const params = { ...parameters };
8✔
75
    // If the endpoint is a string, format it into an object with `path`.
76
    const endpoint: EndpointDefinitionProps =
77
      typeof info === 'string' ? { path: info } : info;
8✔
78
    // Define the object that will have the query string.
79
    const newQuery: Record<string, unknown> = {};
8✔
80
    // We extract it so TypeScript can validate that it exists.
81
    const endpointQuery = endpoint.query;
8✔
82
    // If the endpoint has a `query` property...
83
    if (endpointQuery) {
8✔
84
      // ...Loog all the query parameters.
85
      Object.keys(endpointQuery).forEach((queryName) => {
2✔
86
        // Get the defined value of the parameter.
87
        const queryValue = endpointQuery[queryName];
3✔
88
        // If there's a value of this parameter on the received `parameters`...
89
        if (typeof params[queryName] !== 'undefined') {
3✔
90
          // ...add it to the query dictionary.
91
          newQuery[queryName] = params[queryName];
1✔
92
          // Remove the used parameter.
93
          delete params[queryName];
1✔
94
        } else if (queryValue !== null) {
2✔
95
          // If the default value of the parameter is not `null`, use it.
96
          newQuery[queryName] = queryValue;
1✔
97
        }
98
      });
99
    }
100
    // Get the endpoint path.
101
    let { path } = endpoint;
8✔
102
    // Loop all the received `parameters`...
103
    Object.keys(params).forEach((parameter) => {
8✔
104
      // Build how a placeholder for this parameter would look like.
105
      const placeholder = this.paramsPlaceholder.replace(/%name%/, parameter);
7✔
106
      // Get the parameter value.
107
      const value = params[parameter];
7✔
108
      // If the path has the placeholder...
109
      if (path.includes(placeholder)) {
7✔
110
        // ...replace the placeholder with the value.
111
        path = path.replace(placeholder, String(value));
6✔
112
      } else {
113
        // ...otherwise, add it on the query string.
114
        newQuery[parameter] = value;
1✔
115
      }
116
    });
117
    // Remove extra slashes, and a possible leading slash.
118
    path = path.replace(/\/+/g, '/').replace(/^\/+/, '');
8✔
119
    // Convert the URL into a `urijs` object.
120
    const uri = urijs(`${this.url}/${path}`);
8✔
121
    // Loop and add all the query string parameters.
122
    Object.keys(newQuery).forEach((queryName) => {
8✔
123
      uri.addQuery(queryName, newQuery[queryName]);
3✔
124
    });
125
    // Return the `urijs` object as a string.
126
    return uri.toString();
8✔
127
  }
128
  /**
129
   * Gets the dictionary of endpoints the service uses.
130
   */
131
  getEndpoints(): Record<string, EndpointDefinition> {
132
    return copy(this.endpoints);
2✔
133
  }
134
  /**
135
   * Gets the base URL for the endpoints.
136
   */
137
  getUrl(): string {
138
    return this.url;
2✔
139
  }
140
}
141
/**
142
 * Shorthand for `new EndpointsGenerator()`.
143
 *
144
 * @param args  The same parameters as the {@link EndpointsGenerator} constructor.
145
 * @returns A new instance of {@link EndpointsGenerator}.
146
 */
147
export const endpointsGenerator = (
2✔
148
  ...args: ConstructorParameters<typeof EndpointsGenerator>
149
): EndpointsGenerator => new EndpointsGenerator(...args);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc