Skip to content

Commit d023fde

Browse files
chore(internal): add pure annotations, make base APIResource abstract
1 parent 03bd2dd commit d023fde

File tree

13 files changed

+60
-51
lines changed

13 files changed

+60
-51
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"publint": "^0.2.12",
4646
"ts-jest": "^29.1.0",
4747
"ts-node": "^10.5.0",
48-
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz",
48+
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz",
4949
"tsconfig-paths": "^4.0.0",
5050
"typescript": "5.8.3",
5151
"ws": "^8.18.0",

scripts/build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fi
3131
node scripts/utils/make-dist-package-json.cjs > dist/package.json
3232

3333
# build to .js/.mjs/.d.ts files
34-
npm exec tsc-multi
34+
./node_modules/.bin/tsc-multi
3535
# we need to patch index.js so that `new module.exports()` works for cjs backwards
3636
# compat. No way to get that from index.ts because it would cause compile errors
3737
# when building .mjs

src/core/resource.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { OpenAI } from '../client';
44

5-
export class APIResource {
5+
export abstract class APIResource {
66
protected _client: OpenAI;
77

88
constructor(client: OpenAI) {

src/internal/headers.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

3+
import { isReadonlyArray } from './utils/values';
4+
35
type HeaderValue = string | undefined | null;
46
export type HeadersLike =
57
| Headers
@@ -9,7 +11,7 @@ export type HeadersLike =
911
| null
1012
| NullableHeaders;
1113

12-
const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders');
14+
const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');
1315

1416
/**
1517
* @internal
@@ -25,8 +27,6 @@ export type NullableHeaders = {
2527
nulls: Set<string>;
2628
};
2729

28-
const isArray = Array.isArray as (val: unknown) => val is readonly unknown[];
29-
3030
function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [string, string | null]> {
3131
if (!headers) return;
3232

@@ -43,7 +43,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
4343
let iter: Iterable<readonly (HeaderValue | readonly HeaderValue[])[]>;
4444
if (headers instanceof Headers) {
4545
iter = headers.entries();
46-
} else if (isArray(headers)) {
46+
} else if (isReadonlyArray(headers)) {
4747
iter = headers;
4848
} else {
4949
shouldClear = true;
@@ -52,7 +52,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [strin
5252
for (let row of iter) {
5353
const name = row[0];
5454
if (typeof name !== 'string') throw new TypeError('expected header name to be a string');
55-
const values = isArray(row[1]) ? row[1] : [row[1]];
55+
const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
5656
let didClear = false;
5757
for (const value of values) {
5858
if (value === undefined) continue;

src/internal/qs/formats.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { Format } from './types';
22

33
export const default_format: Format = 'RFC3986';
4+
export const default_formatter = (v: PropertyKey) => String(v);
45
export const formatters: Record<Format, (str: PropertyKey) => string> = {
56
RFC1738: (v: PropertyKey) => String(v).replace(/%20/g, '+'),
6-
RFC3986: (v: PropertyKey) => String(v),
7+
RFC3986: default_formatter,
78
};
89
export const RFC1738 = 'RFC1738';
910
export const RFC3986 = 'RFC3986';

src/internal/qs/stringify.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { encode, is_buffer, maybe_map } from './utils';
2-
import { default_format, formatters } from './formats';
1+
import { encode, is_buffer, maybe_map, has } from './utils';
2+
import { default_format, default_formatter, formatters } from './formats';
33
import type { NonNullableProperties, StringifyOptions } from './types';
4-
5-
const has = Object.prototype.hasOwnProperty;
4+
import { isArray } from '../utils/values';
65

76
const array_prefix_generators = {
87
brackets(prefix: PropertyKey) {
@@ -17,13 +16,11 @@ const array_prefix_generators = {
1716
},
1817
};
1918

20-
const is_array = Array.isArray;
21-
const push = Array.prototype.push;
2219
const push_to_array = function (arr: any[], value_or_array: any) {
23-
push.apply(arr, is_array(value_or_array) ? value_or_array : [value_or_array]);
20+
Array.prototype.push.apply(arr, isArray(value_or_array) ? value_or_array : [value_or_array]);
2421
};
2522

26-
const to_ISO = Date.prototype.toISOString;
23+
let toISOString;
2724

2825
const defaults = {
2926
addQueryPrefix: false,
@@ -38,11 +35,11 @@ const defaults = {
3835
encoder: encode,
3936
encodeValuesOnly: false,
4037
format: default_format,
41-
formatter: formatters[default_format],
38+
formatter: default_formatter,
4239
/** @deprecated */
4340
indices: false,
4441
serializeDate(date) {
45-
return to_ISO.call(date);
42+
return (toISOString ??= Function.prototype.call.bind(Date.prototype.toISOString))(date);
4643
},
4744
skipNulls: false,
4845
strictNullHandling: false,
@@ -105,7 +102,7 @@ function inner_stringify(
105102
obj = filter(prefix, obj);
106103
} else if (obj instanceof Date) {
107104
obj = serializeDate?.(obj);
108-
} else if (generateArrayPrefix === 'comma' && is_array(obj)) {
105+
} else if (generateArrayPrefix === 'comma' && isArray(obj)) {
109106
obj = maybe_map(obj, function (value) {
110107
if (value instanceof Date) {
111108
return serializeDate?.(value);
@@ -148,14 +145,14 @@ function inner_stringify(
148145
}
149146

150147
let obj_keys;
151-
if (generateArrayPrefix === 'comma' && is_array(obj)) {
148+
if (generateArrayPrefix === 'comma' && isArray(obj)) {
152149
// we need to join elements in
153150
if (encodeValuesOnly && encoder) {
154151
// @ts-expect-error values only
155152
obj = maybe_map(obj, encoder);
156153
}
157154
obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
158-
} else if (is_array(filter)) {
155+
} else if (isArray(filter)) {
159156
obj_keys = filter;
160157
} else {
161158
const keys = Object.keys(obj);
@@ -165,9 +162,9 @@ function inner_stringify(
165162
const encoded_prefix = encodeDotInKeys ? String(prefix).replace(/\./g, '%2E') : String(prefix);
166163

167164
const adjusted_prefix =
168-
commaRoundTrip && is_array(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix;
165+
commaRoundTrip && isArray(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix;
169166

170-
if (allowEmptyArrays && is_array(obj) && obj.length === 0) {
167+
if (allowEmptyArrays && isArray(obj) && obj.length === 0) {
171168
return adjusted_prefix + '[]';
172169
}
173170

@@ -184,7 +181,7 @@ function inner_stringify(
184181
// @ts-ignore
185182
const encoded_key = allowDots && encodeDotInKeys ? (key as any).replace(/\./g, '%2E') : key;
186183
const key_prefix =
187-
is_array(obj) ?
184+
isArray(obj) ?
188185
typeof generateArrayPrefix === 'function' ?
189186
generateArrayPrefix(adjusted_prefix, encoded_key)
190187
: adjusted_prefix
@@ -205,7 +202,7 @@ function inner_stringify(
205202
skipNulls,
206203
encodeDotInKeys,
207204
// @ts-ignore
208-
generateArrayPrefix === 'comma' && encodeValuesOnly && is_array(obj) ? null : encoder,
205+
generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
209206
filter,
210207
sort,
211208
allowDots,
@@ -244,15 +241,15 @@ function normalize_stringify_options(
244241

245242
let format = default_format;
246243
if (typeof opts.format !== 'undefined') {
247-
if (!has.call(formatters, opts.format)) {
244+
if (!has(formatters, opts.format)) {
248245
throw new TypeError('Unknown format option provided.');
249246
}
250247
format = opts.format;
251248
}
252249
const formatter = formatters[format];
253250

254251
let filter = defaults.filter;
255-
if (typeof opts.filter === 'function' || is_array(opts.filter)) {
252+
if (typeof opts.filter === 'function' || isArray(opts.filter)) {
256253
filter = opts.filter;
257254
}
258255

@@ -316,7 +313,7 @@ export function stringify(object: any, opts: StringifyOptions = {}) {
316313
if (typeof options.filter === 'function') {
317314
filter = options.filter;
318315
obj = filter('', obj);
319-
} else if (is_array(options.filter)) {
316+
} else if (isArray(options.filter)) {
320317
filter = options.filter;
321318
obj_keys = filter;
322319
}

src/internal/qs/utils.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { RFC1738 } from './formats';
22
import type { DefaultEncoder, Format } from './types';
3+
import { isArray } from '../utils/values';
34

4-
const has = Object.prototype.hasOwnProperty;
5-
const is_array = Array.isArray;
5+
export let has = (obj: object, key: PropertyKey): boolean => (
6+
(has = (Object as any).hasOwn ?? Function.prototype.call.bind(Object.prototype.hasOwnProperty)),
7+
has(obj, key)
8+
);
69

7-
const hex_table = (() => {
10+
const hex_table = /* @__PURE__ */ (() => {
811
const array = [];
912
for (let i = 0; i < 256; ++i) {
1013
array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
@@ -20,7 +23,7 @@ function compact_queue<T extends Record<string, any>>(queue: Array<{ obj: T; pro
2023

2124
const obj = item.obj[item.prop];
2225

23-
if (is_array(obj)) {
26+
if (isArray(obj)) {
2427
const compacted: unknown[] = [];
2528

2629
for (let j = 0; j < obj.length; ++j) {
@@ -56,13 +59,10 @@ export function merge(
5659
}
5760

5861
if (typeof source !== 'object') {
59-
if (is_array(target)) {
62+
if (isArray(target)) {
6063
target.push(source);
6164
} else if (target && typeof target === 'object') {
62-
if (
63-
(options && (options.plainObjects || options.allowPrototypes)) ||
64-
!has.call(Object.prototype, source)
65-
) {
65+
if ((options && (options.plainObjects || options.allowPrototypes)) || !has(Object.prototype, source)) {
6666
target[source] = true;
6767
}
6868
} else {
@@ -77,14 +77,14 @@ export function merge(
7777
}
7878

7979
let mergeTarget = target;
80-
if (is_array(target) && !is_array(source)) {
80+
if (isArray(target) && !isArray(source)) {
8181
// @ts-ignore
8282
mergeTarget = array_to_object(target, options);
8383
}
8484

85-
if (is_array(target) && is_array(source)) {
85+
if (isArray(target) && isArray(source)) {
8686
source.forEach(function (item, i) {
87-
if (has.call(target, i)) {
87+
if (has(target, i)) {
8888
const targetItem = target[i];
8989
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
9090
target[i] = merge(targetItem, item, options);
@@ -101,7 +101,7 @@ export function merge(
101101
return Object.keys(source).reduce(function (acc, key) {
102102
const value = source[key];
103103

104-
if (has.call(acc, key)) {
104+
if (has(acc, key)) {
105105
acc[key] = merge(acc[key], value, options);
106106
} else {
107107
acc[key] = value;
@@ -254,7 +254,7 @@ export function combine(a: any, b: any) {
254254
}
255255

256256
export function maybe_map<T>(val: T[], fn: (v: T) => T) {
257-
if (is_array(val)) {
257+
if (isArray(val)) {
258258
const mapped = [];
259259
for (let i = 0; i < val.length; i += 1) {
260260
mapped.push(fn(val[i]!));

src/internal/uploads.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export const multipartFormRequestOptions = async (
9090
return { ...opts, body: await createForm(opts.body, fetch) };
9191
};
9292

93-
const supportsFormDataMap = new WeakMap<Fetch, Promise<boolean>>();
93+
const supportsFormDataMap = /** @__PURE__ */ new WeakMap<Fetch, Promise<boolean>>();
9494

9595
/**
9696
* node-fetch doesn't support the global FormData object in recent node versions. Instead of sending

src/internal/utils/log.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const noopLogger = {
5858
debug: noop,
5959
};
6060

61-
let cachedLoggers = new WeakMap<Logger, [LogLevel, Logger]>();
61+
let cachedLoggers = /** @__PURE__ */ new WeakMap<Logger, [LogLevel, Logger]>();
6262

6363
export function loggerFor(client: OpenAI): Logger {
6464
const logger = client.logger;

src/internal/utils/path.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,4 @@ export const createPathTagFunction = (pathEncoder = encodeURIPath) =>
6060
/**
6161
* URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced.
6262
*/
63-
export const path = createPathTagFunction(encodeURIPath);
63+
export const path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);

0 commit comments

Comments
 (0)