Skip to content

Commit

Permalink
feat: allow inlining standalone clients with
Browse files Browse the repository at this point in the history
  • Loading branch information
mrlubos committed Jul 18, 2024
1 parent 96ad83b commit 68c3921
Show file tree
Hide file tree
Showing 51 changed files with 6,298 additions and 134 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-apples-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': minor
---

feat: allow inlining standalone clients with `client.inline = true`
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.9.0
20.10.0
1 change: 1 addition & 0 deletions packages/openapi-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"@angular/platform-browser": "17.3.9",
"@angular/platform-browser-dynamic": "17.3.9",
"@angular/router": "17.3.9",
"@hey-api/client-fetch": "workspace:*",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "15.2.3",
"@types/cross-spawn": "6.0.6",
Expand Down
53 changes: 32 additions & 21 deletions packages/openapi-ts/src/compiler/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,43 @@ import {

/**
* Create export all declaration. Example: `export * from './y'`.
* @param module - module to export from.
* @param module - module containing exports
* @returns ts.ExportDeclaration
*/
export const createExportAllDeclaration = (module: string) =>
ts.factory.createExportDeclaration(
export const createExportAllDeclaration = ({
module,
}: {
module: string;
}): ts.ExportDeclaration => {
const statement = ts.factory.createExportDeclaration(

Check warning on line 20 in packages/openapi-ts/src/compiler/module.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/compiler/module.ts#L16-L20

Added lines #L16 - L20 were not covered by tests
undefined,
false,
undefined,
ots.string(module),
);
return statement;
};

Check warning on line 27 in packages/openapi-ts/src/compiler/module.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/compiler/module.ts#L26-L27

Added lines #L26 - L27 were not covered by tests

type ImportExportItem = ImportExportItemObject | string;

/**
* Create a named export declaration. Example: `export { X } from './y'`.
* @param items - the items to export.
* @param module - module to export it from.
* @returns ExportDeclaration
* @param exports - named imports to export
* @param module - module containing exports
* @returns ts.ExportDeclaration
*/
export const createNamedExportDeclarations = (
items: Array<ImportExportItem> | ImportExportItem,
module: string,
): ts.ExportDeclaration => {
items = Array.isArray(items) ? items : [items];
const exportedTypes = Array.isArray(items) ? items : [items];
export const createNamedExportDeclarations = ({
exports,
module,
}: {
exports: Array<ImportExportItem> | ImportExportItem;
module: string;
}): ts.ExportDeclaration => {
const exportedTypes = Array.isArray(exports) ? exports : [exports];
const hasNonTypeExport = exportedTypes.some(
(item) => typeof item !== 'object' || !item.asType,
);
const elements = items.map((name) => {
const elements = exportedTypes.map((name) => {
const item = typeof name === 'string' ? { name } : name;
return ots.export({
alias: item.alias,
Expand Down Expand Up @@ -101,15 +109,18 @@ export const createExportConstVariable = ({

/**
* Create a named import declaration. Example: `import { X } from './y'`.
* @param items - the items to export.
* @param module - module to export it from.
* @returns ImportDeclaration
* @param imports - named exports to import
* @param module - module containing imports
* @returns ts.ImportDeclaration
*/
export const createNamedImportDeclarations = (
items: Array<ImportExportItem> | ImportExportItem,
module: string,
): ts.ImportDeclaration => {
const importedTypes = Array.isArray(items) ? items : [items];
export const createNamedImportDeclarations = ({
imports,
module,
}: {
imports: Array<ImportExportItem> | ImportExportItem;
module: string;
}): ts.ImportDeclaration => {
const importedTypes = Array.isArray(imports) ? imports : [imports];
const hasNonTypeImport = importedTypes.some(
(item) => typeof item !== 'object' || !item.asType,
);
Expand Down
4 changes: 3 additions & 1 deletion packages/openapi-ts/src/generate/__tests__/class.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ vi.mock('node:fs');
describe('generateClientClass', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
12 changes: 9 additions & 3 deletions packages/openapi-ts/src/generate/__tests__/core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ describe('generateCore', () => {
};

setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down Expand Up @@ -82,7 +84,9 @@ describe('generateCore', () => {
};

const config = setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down Expand Up @@ -122,7 +126,9 @@ describe('generateCore', () => {

const config = setConfig({
base: 'foo',
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/openapi-ts/src/generate/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ vi.mock('node:fs');
describe('generateIndexFile', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/openapi-ts/src/generate/__tests__/output.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ vi.mock('node:fs');
describe('generateOutput', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/openapi-ts/src/generate/__tests__/schemas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ vi.mock('node:fs');
describe('generateSchemas', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
16 changes: 12 additions & 4 deletions packages/openapi-ts/src/generate/__tests__/services.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ vi.mock('node:fs');
describe('generateServices', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down Expand Up @@ -129,7 +131,9 @@ describe('methodNameBuilder', () => {

it('use default name', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down Expand Up @@ -169,7 +173,9 @@ describe('methodNameBuilder', () => {
const methodNameBuilder = vi.fn().mockReturnValue('customName');

setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down Expand Up @@ -212,7 +218,9 @@ describe('methodNameBuilder', () => {
const methodNameBuilder = vi.fn().mockReturnValue('customName');

setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/openapi-ts/src/generate/__tests__/types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ vi.mock('node:fs');
describe('generateTypes', () => {
it('writes to filesystem', async () => {
setConfig({
client: 'fetch',
client: {
name: 'fetch',
},
configFile: '',
debug: false,
dryRun: false,
Expand Down
56 changes: 56 additions & 0 deletions packages/openapi-ts/src/generate/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { copyFileSync, readFileSync, writeFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';

import { getConfig, isStandaloneClient } from '../utils/config';
import { ensureDirSync } from './utils';

const require = createRequire(import.meta.url);

/**
* (optional) Creates a `client.ts` file containing the same exports as a
* standalone client package. Creates a `core` directory containing the modules
* from standalone client. These files are generated only when `client.inline`
* is set to true.
*/
export const generateClient = async (
outputPath: string,
moduleName: string,
) => {
const config = getConfig();

if (!isStandaloneClient(config) || !config.client.inline) {
return;
}

// create directory for client modules
const dirPath = path.resolve(outputPath, 'core');
ensureDirSync(dirPath);

const clientModulePath = path.normalize(require.resolve(moduleName));
const clientModulePathComponents = clientModulePath.split(path.sep);
const clientSrcPath = [
...clientModulePathComponents.slice(
0,
clientModulePathComponents.indexOf('dist'),
),
'src',
].join(path.sep);

// copy client modules
const files = ['index.ts', 'types.ts', 'utils.ts'];
files.forEach((file) => {
copyFileSync(
path.resolve(clientSrcPath, file),
path.resolve(dirPath, file),
);
});

// copy index file with cherry-picked exports
const nodeIndexFile = readFileSync(
path.resolve(clientSrcPath, 'node', 'index.ts'),
'utf-8',
);
const indexFile = nodeIndexFile.replaceAll('../', './core/');
writeFileSync(path.resolve(outputPath, 'client.ts'), indexFile, 'utf-8');
};

Check warning on line 56 in packages/openapi-ts/src/generate/client.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/client.ts#L25-L56

Added lines #L25 - L56 were not covered by tests
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/generate/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const generateCore = async (
...context,
}),
);
if (config.client !== 'angular') {
if (config.client.name !== 'angular') {
await writeFileSync(
path.resolve(outputPath, 'CancelablePromise.ts'),
templates.core.cancelablePromise({
Expand Down
51 changes: 34 additions & 17 deletions packages/openapi-ts/src/generate/indexFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,50 @@ export const generateIndexFile = async ({
const config = getConfig();

if (config.name) {
files.index.add(compiler.export.named([config.name], `./${config.name}`));
files.index.add(
compiler.export.named({
exports: config.name,
module: `./${config.name}`,
}),
);

Check warning on line 17 in packages/openapi-ts/src/generate/indexFile.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/indexFile.ts#L12-L17

Added lines #L12 - L17 were not covered by tests
}

if (config.exportCore) {
files.index.add(compiler.export.named('ApiError', './core/ApiError'));
files.index.add(
compiler.export.named({
exports: 'ApiError',
module: './core/ApiError',
}),
);
if (config.services.response === 'response') {
files.index.add(
compiler.export.named(
{ asType: true, name: 'ApiResult' },
'./core/ApiResult',
),
compiler.export.named({
exports: { asType: true, name: 'ApiResult' },
module: './core/ApiResult',
}),

Check warning on line 32 in packages/openapi-ts/src/generate/indexFile.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/indexFile.ts#L29-L32

Added lines #L29 - L32 were not covered by tests
);
}
if (config.name) {
files.index.add(
compiler.export.named('BaseHttpRequest', './core/BaseHttpRequest'),
compiler.export.named({
exports: 'BaseHttpRequest',
module: './core/BaseHttpRequest',
}),

Check warning on line 40 in packages/openapi-ts/src/generate/indexFile.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/indexFile.ts#L37-L40

Added lines #L37 - L40 were not covered by tests
);
}
if (config.client !== 'angular') {
if (config.client.name !== 'angular') {
files.index.add(
compiler.export.named(
['CancelablePromise', 'CancelError'],
'./core/CancelablePromise',
),
compiler.export.named({
exports: ['CancelablePromise', 'CancelError'],
module: './core/CancelablePromise',
}),
);
}
files.index.add(
compiler.export.named(
['OpenAPI', { asType: true, name: 'OpenAPIConfig' }],
'./core/OpenAPI',
),
compiler.export.named({
exports: ['OpenAPI', { asType: true, name: 'OpenAPIConfig' }],
module: './core/OpenAPI',
}),
);
}

Expand All @@ -48,6 +61,10 @@ export const generateIndexFile = async ({
return;
}

files.index.add(compiler.export.all(`./${file.getName(false)}`));
files.index.add(
compiler.export.all({
module: `./${file.getName(false)}`,
}),
);

Check warning on line 68 in packages/openapi-ts/src/generate/indexFile.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/indexFile.ts#L64-L68

Added lines #L64 - L68 were not covered by tests
});
};
Loading

0 comments on commit 68c3921

Please sign in to comment.