cyclosproject / ng-openapi-gen

An OpenAPI 3.0 codegen for Angular
MIT License
403 stars 134 forks source link

Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. [plugin angular-compiler] #330

Open marcschroeder opened 2 months ago

marcschroeder commented 2 months ago

Angular seems to default to "isolatedModules": true.

This causes an issue for the generated files:

X [ERROR] TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. [plugin angular-compiler]

Is there a workaround available or should the export be changed to "export type"? Happy to provide a PR if the requirements are clear.

xDivisionByZerox commented 1 month ago

One of the highlights in the README:

Generated files should compile using strict TypeScript compiler flags [...]

That's why I expected this scenario to already be handled. Would be great if this could be handled by the library.

I'm willing to provide help with this issue as well if required.

cjackson234 commented 1 month ago

Here is my temporary fix. Create a new file "fix-openapi-exports.js"

const path = require('path');

// Define the directory where ng-openapi-gen generates files
const dir = './src/app/api'; // Adjust this path to match your actual generated directory

function updateExports(directory) {
  fs.readdir(directory, (err, files) => {
    if (err) throw err;

    files.forEach(file => {
      const filePath = path.join(directory, file);
      if (fs.lstatSync(filePath).isDirectory()) {
        // Recursively update exports in subdirectories
        updateExports(filePath);
      } else if (file.endsWith('.ts')) {
        // Read the TypeScript file
        fs.readFile(filePath, 'utf8', (err, data) => {
          if (err) throw err;

          const updatedData = data.replace(/export \{ ([\w, ]+) \} from/g, 'export type { $1 } from');

          // Write the updated content back to the file
          fs.writeFile(filePath, updatedData, 'utf8', err => {
            if (err) throw err;
            console.log(`Updated exports in: ${filePath}`);
          });
        });
      }
    });
  });
}
updateExports(dir);

then you add "post-process-openapi": "node fix-openapi-exports.js", to your package.json

for reference, my scripts are as follows

"post-process-openapi": "node fix-openapi-exports.js",
"api": "ng-openapi-gen -c swagger-gen.json && npm run post-process-openapi"
luisfpg commented 1 month ago

The easiest fix is to use a custom template for it. Just create a folder in your project, copy the modelIndex.handlebars file from the original templates and reference that folder in you ng-openapi-gen.json file ("templates": "your-folder"). Then modify that file and add the type to exports.

I'll have to think in a solution for this, because by default ng-openapi-gen generates model enums as actual typescript enums with pascal case. Those are not strict type aliases, but actual enum classes, and exporting them as type would result in build errors.

Another option is to skip the model index altogether (you can disable its generation in the configuration options) and deep-import all entities directly.

metal3d commented 3 weeks ago

For your interest, I do this in TypeScript. That could be interesting as an alternative to @cjackson234 answer if you want to keep only TypeScript in your project:

import fs from 'fs';
import path from 'path';

const modelsPath = path.join(__dirname, '..', 'src', 'app', 'api', 'models.ts');
const models = fs.readFileSync(modelsPath, 'utf-8');
const fixedModels = models.replace(/^export\s+/gm, 'export type ');
fs.writeFileSync(modelsPath, fixedModels);

I only added this in a "scripts" directory at the project root, and added this in my package.json file:

  "scripts": {
    "openapi": "npm run openapi:gen && npm run openapi:fix",
    "openapi:gen": "ng-openapi-gen --input http://localhost:8000/api/schema",
    "openapi:fix": "tsx scripts/fixup-models.ts",
metal3d commented 3 weeks ago

(of course, I added tsx in devDependencies: npm install --save-dev tsx)