Skip to content

Conversation

@michaelbe812
Copy link
Contributor

@michaelbe812 michaelbe812 commented Aug 3, 2025

Summary

This PR implements Crystal Plugin (Project Inference) support for the Nx OpenAPI plugin, resolving #16. Updated to address PR feedback with configurable file patterns.

Changes Made

  • Added plugin.ts with CreateNodesV2 implementation
  • Automatic OpenAPI spec detection using configurable glob patterns
  • Inferred task creation for generate-api tasks
  • Configurable plugin options for target names and file patterns
  • Package.json updates to declare the plugin to Nx

Features

  • ✅ Detects OpenAPI specification files automatically
  • ✅ Creates generate-api tasks without manual configuration
  • Configurable file patterns for custom OpenAPI spec naming
  • ✅ Configurable target names and output paths
  • ✅ Maintains backward compatibility with existing configurations

Configurable File Patterns

The plugin now supports custom file patterns through the specFilePatterns option:

Default patterns:

  • **/*.openapi.{json,yaml,yml}
  • **/openapi.{json,yaml,yml}
  • Plus common API spec patterns like -spec, api-spec, swagger

Custom configuration example:

{
  "plugins": [
    {
      "plugin": "@lambda-solutions/nx-plugin-openapi", 
      "options": {
        "targetName": "generate-api",
        "specFilePatterns": [
          "**/*-api.json",
          "**/api-docs/*.yaml",  
          "services/**/swagger.json"
        ]
      }
    }
  ]
}

Technical Details

The plugin scans for OpenAPI files using an expanded pattern and filters based on user-specified patterns. Users can configure the plugin in nx.json with custom file patterns, target names, and output paths.

Testing

  • ✅ Plugin compiles successfully
  • ✅ Linting passes
  • ✅ Configurable patterns implemented and tested
  • ✅ Backward compatibility maintained

Migration

This change is fully backward compatible. Existing explicit task configurations will continue to work alongside the new inferred tasks. Users can optionally adopt configurable patterns for custom OpenAPI file naming conventions.

🤖 Generated with Claude Code

Mac Mini and others added 7 commits August 2, 2025 22:42
- Updated schema.json to accept inputSpec as either string or Record<string, string>
- Updated TypeScript interface to match new schema
- Modified executor to handle multiple input specs by generating each in subdirectories
- Added comprehensive unit tests for the new functionality

Resolves #36
- Updated reference documentation to show both string and object types
- Added examples for single and multiple API specifications
- Added comprehensive example for microservice architecture use case
- Updated hasher Zod schema to accept union of string and record
- Added logic to handle both single and multiple inputSpec hashing
- Added comprehensive tests for multiple inputSpec scenarios
- Ensures proper caching support for the new feature
- Cast path parameters to string in mock implementations
- Ensures proper type handling for readFileSync and fetch mocks
Allow users to provide a custom target name when running the add-generate-api-target generator.
If a build target exists, automatically add the custom target to its dependsOn array.

Closes #38

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add plugin.ts with CreateNodesV2 implementation
- Automatically detect OpenAPI spec files in workspace
- Create generate-api tasks for detected specs
- Support configurable target names and output paths
- Export plugin from index.ts
- Update package.json with nx-plugin configuration

Resolves #16

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused imports (relative, existsSync)
- Replace any types with unknown type
- Fix unused variable warnings
- Remove unused defaultSpecFilePatterns variable
- Add proper error handling without unused catch variable

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@michaelbe812
Copy link
Contributor Author

michaelbe812 commented Aug 3, 2025

Claude encountered an error —— View job

Failed with exit code 128

I'll analyze this and get back to you.

"nx-plugin": {
"projectFilePatterns": [
"**/*.openapi.json",
"**/*.openapi.yaml",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a trailing space after "**/*.openapi.yaml" in the file pattern array that should be removed. While it might not cause immediate issues, it's best to keep these pattern strings clean to avoid potential pattern matching problems in different environments.

-  "**/*.openapi.yaml", 
+  "**/*.openapi.yaml",
Suggested change
"**/*.openapi.yaml",
"**/*.openapi.yaml",

Spotted by Diamond

Is this helpful? React 👍 or 👎 to let us know.

@michaelbe812
Copy link
Contributor Author

We should make the file pattern to find matching openapi-specs configurable to lot hardcode it to openapi.{json,yaml.yml}

@michaelbe812
Copy link
Contributor Author

Code Review Complete ✅

I've thoroughly reviewed this PR implementing Crystal Plugin support for the Nx OpenAPI plugin. Here's my detailed feedback:

Overview

This is an excellent implementation of Crystal Plugin (Project Inference) support that resolves #16. The code quality is high and the feature adds significant value to the plugin.

Code Quality Analysis 🔍

Strengths:

  1. Plugin Architecture: Clean implementation using CreateNodesV2 API with proper deprecation handling for createNodes
  2. OpenAPI Detection: Robust validation in isOpenApiSpec() that checks for both OpenAPI 3.x and Swagger 2.0 formats
  3. Service Naming Logic: Smart extractServiceName() function that handles various naming patterns intelligently
  4. Multiple Spec Support: Well-implemented support for both single string and multiple object inputSpec configurations
  5. Caching Strategy: Proper hasher implementation that handles both local files and remote URLs correctly

Code Patterns:

  • ✅ Follows existing project conventions
  • ✅ Proper error handling throughout
  • ✅ Clean separation of concerns
  • ✅ Type-safe implementation with zod validation

Testing Results 🧪

  • Unit Tests: All 127 tests pass ✅
  • Linting: No errors ✅
  • Build: Compiles successfully ✅
  • Backward Compatibility: Verified ✅

Minor Suggestions for Future Improvements 💡

  1. YAML Parsing: Consider using a proper YAML parser instead of string matching in isOpenApiSpec():

    // Current: content.includes('openapi:')
    // Consider: Using js-yaml or similar for robust parsing
  2. Type Safety: Consider adding more specific return types for validation functions

  3. Performance: For large workspaces, consider adding caching for OpenAPI spec validation results

Security Considerations 🔒

  • Remote URL fetching is properly implemented with error handling
  • No exposed secrets or keys
  • Follows security best practices

Documentation 📚

The documentation updates in generate-api.md clearly explain the new functionality and migration path.

Conclusion

This is a high-quality PR that significantly enhances the plugin's usability. The Crystal Plugin support will make it much easier for users to work with OpenAPI specifications in Nx workspaces without manual configuration.

Recommendation: Ready to merge after addressing any minor suggestions if desired. Great work! 🎉

- Make specFilePatterns configurable in plugin options
- Expand default glob pattern to include common API spec patterns
- Add pattern matching logic in createNodesInternal
- Update inputs to cover various OpenAPI file patterns
- Maintain backward compatibility with default patterns

Addresses PR feedback to make file patterns configurable instead of hardcoded.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Comment on lines +62 to +69
const regex = new RegExp(
'^' + pattern
.replace(/\./g, '\\.')
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\{([^}]+)\}/g, '($1)')
.replace(/,/g, '|') + '$'
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern conversion has an issue with the anchors (^ and $). These anchors force the pattern to match the entire string, but for file path matching, you need to match patterns that may appear anywhere in the path.

Consider either:

  1. Removing the anchors:
const regex = new RegExp(
  pattern
    .replace(/\./g, '\\.')
    .replace(/\*\*/g, '.*')
    .replace(/\*/g, '[^/]*')
    .replace(/\{([^}]+)\}/g, '($1)')
    .replace(/,/g, '|')
);
  1. Or using a dedicated glob-to-regex library like micromatch or minimatch which handles these edge cases correctly.

This will ensure patterns like **/openapi.json correctly match paths like apps/demo/openapi.json.

Suggested change
const regex = new RegExp(
'^' + pattern
.replace(/\./g, '\\.')
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\{([^}]+)\}/g, '($1)')
.replace(/,/g, '|') + '$'
);
const regex = new RegExp(
pattern
.replace(/\./g, '\\.')
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\{([^}]+)\}/g, '($1)')
.replace(/,/g, '|')
);

Spotted by Diamond

Is this helpful? React 👍 or 👎 to let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants