@zimic/http 0.0.1-canary.2

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.
Files changed (61) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +230 -0
  3. package/dist/chunk-VHQRAQPQ.mjs +1371 -0
  4. package/dist/chunk-VHQRAQPQ.mjs.map +1 -0
  5. package/dist/chunk-VUDGONB5.js +1382 -0
  6. package/dist/chunk-VUDGONB5.js.map +1 -0
  7. package/dist/cli.js +116 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/cli.mjs +109 -0
  10. package/dist/cli.mjs.map +1 -0
  11. package/dist/index.d.ts +1306 -0
  12. package/dist/index.js +544 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/index.mjs +537 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/typegen.d.ts +86 -0
  17. package/dist/typegen.js +12 -0
  18. package/dist/typegen.js.map +1 -0
  19. package/dist/typegen.mjs +3 -0
  20. package/dist/typegen.mjs.map +1 -0
  21. package/index.d.ts +1 -0
  22. package/package.json +110 -0
  23. package/src/cli/cli.ts +92 -0
  24. package/src/cli/index.ts +4 -0
  25. package/src/cli/typegen/openapi.ts +24 -0
  26. package/src/formData/HttpFormData.ts +300 -0
  27. package/src/formData/types.ts +110 -0
  28. package/src/headers/HttpHeaders.ts +217 -0
  29. package/src/headers/types.ts +65 -0
  30. package/src/index.ts +55 -0
  31. package/src/pathParams/types.ts +67 -0
  32. package/src/searchParams/HttpSearchParams.ts +258 -0
  33. package/src/searchParams/types.ts +133 -0
  34. package/src/typegen/index.ts +12 -0
  35. package/src/typegen/namespace/TypegenNamespace.ts +18 -0
  36. package/src/typegen/openapi/generate.ts +168 -0
  37. package/src/typegen/openapi/transform/components.ts +481 -0
  38. package/src/typegen/openapi/transform/context.ts +67 -0
  39. package/src/typegen/openapi/transform/filters.ts +71 -0
  40. package/src/typegen/openapi/transform/imports.ts +15 -0
  41. package/src/typegen/openapi/transform/io.ts +86 -0
  42. package/src/typegen/openapi/transform/methods.ts +803 -0
  43. package/src/typegen/openapi/transform/operations.ts +120 -0
  44. package/src/typegen/openapi/transform/paths.ts +119 -0
  45. package/src/typegen/openapi/utils/types.ts +45 -0
  46. package/src/types/arrays.d.ts +4 -0
  47. package/src/types/json.ts +89 -0
  48. package/src/types/objects.d.ts +14 -0
  49. package/src/types/requests.ts +96 -0
  50. package/src/types/schema.ts +834 -0
  51. package/src/types/strings.d.ts +9 -0
  52. package/src/types/utils.ts +64 -0
  53. package/src/utils/console.ts +7 -0
  54. package/src/utils/data.ts +13 -0
  55. package/src/utils/files.ts +28 -0
  56. package/src/utils/imports.ts +12 -0
  57. package/src/utils/prettier.ts +13 -0
  58. package/src/utils/strings.ts +3 -0
  59. package/src/utils/time.ts +25 -0
  60. package/src/utils/urls.ts +52 -0
  61. package/typegen.d.ts +1 -0
@@ -0,0 +1,67 @@
1
+ import { convertToPascalCase } from '@/utils/strings';
2
+
3
+ import { parseRawFilter, groupParsedFiltersByMatch } from './filters';
4
+
5
+ export interface TypePathFilters {
6
+ positive: RegExp[];
7
+ negative: RegExp[];
8
+ }
9
+
10
+ type HttpTypeImportName =
11
+ | 'HttpSchema'
12
+ | 'HttpFormData'
13
+ | 'HttpFormDataSerialized'
14
+ | 'HttpSearchParams'
15
+ | 'HttpSearchParamsSerialized'
16
+ | 'HttpHeadersSerialized'
17
+ | 'HttpStatusCode'
18
+ | 'MergeHttpResponsesByStatusCode';
19
+
20
+ type OperationName = string;
21
+ export type OperationPath = OperationName;
22
+
23
+ export type ComponentGroupName = string;
24
+ export type ComponentName = string;
25
+ export type ComponentPath = `${ComponentGroupName}.${ComponentName}`;
26
+
27
+ export interface TypeTransformContext {
28
+ serviceName: string;
29
+ filters: {
30
+ paths: TypePathFilters;
31
+ };
32
+ typeImports: {
33
+ http: Set<HttpTypeImportName>;
34
+ };
35
+ referencedTypes: {
36
+ operations: Set<OperationPath>;
37
+ components: Set<ComponentPath>;
38
+ };
39
+ pendingActions: {
40
+ components: {
41
+ requests: { toMarkBodyAsOptional: Set<ComponentName> };
42
+ };
43
+ };
44
+ }
45
+
46
+ export function createTypeTransformationContext(serviceName: string, rawFilters: string[]): TypeTransformContext {
47
+ const parsedFilters = rawFilters.map(parseRawFilter);
48
+
49
+ return {
50
+ serviceName: convertToPascalCase(serviceName),
51
+ filters: {
52
+ paths: groupParsedFiltersByMatch(parsedFilters),
53
+ },
54
+ typeImports: {
55
+ http: new Set(),
56
+ },
57
+ referencedTypes: {
58
+ operations: new Set(),
59
+ components: new Set(),
60
+ },
61
+ pendingActions: {
62
+ components: {
63
+ requests: { toMarkBodyAsOptional: new Set() },
64
+ },
65
+ },
66
+ };
67
+ }
@@ -0,0 +1,71 @@
1
+ import chalk from 'chalk';
2
+ import filesystem from 'fs/promises';
3
+ import path from 'path';
4
+
5
+ import { HTTP_METHODS } from '@/types/schema';
6
+ import { logWithPrefix } from '@/utils/console';
7
+ import { isNonEmpty } from '@/utils/data';
8
+ import { createRegexFromWildcardPath } from '@/utils/urls';
9
+
10
+ import { TypePathFilters } from './context';
11
+
12
+ const HTTP_METHOD_OPTIONS = HTTP_METHODS.join('|');
13
+ const MODIFIER_GROUP = '(?<modifier>!?)';
14
+ const METHOD_FILTER_GROUP = `(?<method>(?:\\*|(?:${HTTP_METHOD_OPTIONS})(?:,\\s*(?:${HTTP_METHOD_OPTIONS}))*))`;
15
+ const PATH_FILTER_GROUP = '(?<path>.+)';
16
+ const FILTER_REGEX = new RegExp(`^${MODIFIER_GROUP}\\s*${METHOD_FILTER_GROUP}\\s+${PATH_FILTER_GROUP}$`, 'i');
17
+
18
+ interface ParsedTypePathFilter {
19
+ expression: RegExp;
20
+ isNegativeMatch: boolean;
21
+ }
22
+
23
+ export function parseRawFilter(rawFilter: string): ParsedTypePathFilter | undefined {
24
+ const filterMatch = rawFilter.match(FILTER_REGEX);
25
+ const { modifier: filterModifier, method: filteredMethodsOrWildcard, path: filteredPath } = filterMatch?.groups ?? {};
26
+
27
+ const isValidFilter = !filteredMethodsOrWildcard || !filteredPath;
28
+ if (isValidFilter) {
29
+ logWithPrefix(`Warning: Filter could not be parsed and was ignored: ${chalk.yellow(rawFilter)}`, {
30
+ method: 'warn',
31
+ });
32
+ return undefined;
33
+ }
34
+
35
+ const methodFilterGroup = `(?:${filteredMethodsOrWildcard.toUpperCase().replace(/,/g, '|').replace(/\*/g, '.*')}) `;
36
+ const isNegativeMatch = filterModifier === '!';
37
+
38
+ return {
39
+ expression: createRegexFromWildcardPath(filteredPath, { prefix: methodFilterGroup }),
40
+ isNegativeMatch,
41
+ };
42
+ }
43
+
44
+ export function groupParsedFiltersByMatch(parsedFilters: (ParsedTypePathFilter | undefined)[]) {
45
+ return parsedFilters.reduce<TypePathFilters>(
46
+ (groupedFilters, filter) => {
47
+ if (filter) {
48
+ if (filter.isNegativeMatch) {
49
+ groupedFilters.negative.push(filter.expression);
50
+ } else {
51
+ groupedFilters.positive.push(filter.expression);
52
+ }
53
+ }
54
+
55
+ return groupedFilters;
56
+ },
57
+ { positive: [], negative: [] },
58
+ );
59
+ }
60
+
61
+ export async function readPathFiltersFromFile(filePath: string) {
62
+ const fileContent = await filesystem.readFile(path.resolve(filePath), 'utf-8');
63
+ const fileContentWithoutComments = fileContent.replace(/#.*$/gm, '');
64
+
65
+ const filters = fileContentWithoutComments.split('\n');
66
+ return filters;
67
+ }
68
+
69
+ export function ignoreEmptyFilters(filters: string[]) {
70
+ return filters.map((line) => line.trim()).filter(isNonEmpty);
71
+ }
@@ -0,0 +1,15 @@
1
+ import { createImportDeclaration, createImportSpecifier } from '../utils/types';
2
+ import { TypeTransformContext } from './context';
3
+
4
+ /* istanbul ignore next -- @preserve
5
+ * The root import module is defined at build time. The fallback is not expected to be used. */
6
+ export const TYPEGEN_HTTP_IMPORT_MODULE = process.env.TYPEGEN_HTTP_IMPORT_MODULE ?? '@zimic/http';
7
+
8
+ export function createImportDeclarations(context: TypeTransformContext) {
9
+ const httpTypeImports = Array.from(context.typeImports.http).sort().map(createImportSpecifier);
10
+ const httpImportDeclaration = createImportDeclaration(httpTypeImports, TYPEGEN_HTTP_IMPORT_MODULE, {
11
+ typeOnly: true,
12
+ });
13
+
14
+ return [httpImportDeclaration];
15
+ }
@@ -0,0 +1,86 @@
1
+ import type { SchemaObject } from 'openapi-typescript';
2
+ import path from 'path';
3
+ import ts from 'typescript';
4
+
5
+ import { createCachedDynamicImport } from '@/utils/imports';
6
+ import { createFileURL, createURL } from '@/utils/urls';
7
+
8
+ import { createBlobType, createNullType } from '../utils/types';
9
+
10
+ const importOpenapiTypeScript = createCachedDynamicImport(() => import('openapi-typescript'));
11
+
12
+ function transformSchemaObject(schemaObject: SchemaObject) {
13
+ if (schemaObject.format === 'binary') {
14
+ const blobType = createBlobType();
15
+
16
+ if (schemaObject.nullable) {
17
+ const nullType = createNullType();
18
+ return ts.factory.createUnionTypeNode([blobType, nullType]);
19
+ }
20
+
21
+ return blobType;
22
+ }
23
+ }
24
+
25
+ function convertFilePathOrURLToURL(filePathOrURL: string) {
26
+ try {
27
+ return createURL(filePathOrURL);
28
+ } catch {
29
+ return createFileURL(path.resolve(filePathOrURL));
30
+ }
31
+ }
32
+
33
+ export async function importTypesFromOpenAPI(filePathOrURL: string) {
34
+ const schemaURL = convertFilePathOrURLToURL(filePathOrURL);
35
+
36
+ const { default: generateTypesFromOpenAPI } = await importOpenapiTypeScript();
37
+
38
+ const rawNodes = await generateTypesFromOpenAPI(schemaURL, {
39
+ alphabetize: false,
40
+ additionalProperties: false,
41
+ excludeDeprecated: false,
42
+ propertiesRequiredByDefault: false,
43
+ defaultNonNullable: true,
44
+ pathParamsAsTypes: false,
45
+ emptyObjectsUnknown: true,
46
+ exportType: false,
47
+ arrayLength: false,
48
+ immutable: false,
49
+ enumValues: false,
50
+ enum: false,
51
+ silent: true,
52
+ transform: transformSchemaObject,
53
+ });
54
+
55
+ return rawNodes;
56
+ }
57
+
58
+ export async function convertTypesToString(nodes: ts.Node[], options: { includeComments: boolean }) {
59
+ const { astToString: convertTypeASTToString } = await importOpenapiTypeScript();
60
+
61
+ const typeOutput = convertTypeASTToString(nodes, {
62
+ formatOptions: { removeComments: !options.includeComments },
63
+ });
64
+
65
+ return typeOutput;
66
+ }
67
+
68
+ export function prepareTypeOutputToSave(output: string) {
69
+ const formattedOutput = output
70
+ .replace(/^export (\w+)/gm, '\nexport $1')
71
+ .replace(/^( {4})+/gm, (match) => match.replace(/ {4}/g, ' '));
72
+
73
+ const formattedOutputWithPrefix = [
74
+ '// Auto-generated by zimic.',
75
+ '// NOTE: Do not manually edit this file. Changes will be overridden.\n',
76
+ formattedOutput,
77
+ ].join('\n');
78
+
79
+ return formattedOutputWithPrefix;
80
+ }
81
+
82
+ export async function writeTypeOutputToStandardOutput(formattedOutput: string) {
83
+ await new Promise((resolve) => {
84
+ process.stdout.write(formattedOutput, 'utf-8', resolve);
85
+ });
86
+ }