Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ Create an `intrig.config.json` file in your project root:
```

You can set the generator to either "react" or "next" depending on your target framework.
Install the matching binding plugin (e.g. `@intrig/react-binding`) so Intrig can discover it in `node_modules`.
Each plugin's `package.json` must declare the plugin type:

```json
{
"intrig": {
"plugin": {
"type": "generator",
"for": "react"
}
}
}
```

### CLI Commands

Expand Down
16 changes: 9 additions & 7 deletions app/intrig/src/app/cli/cli.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import {SourcesCommand} from "./commands/sources.command";
import {CommonModule} from "common";
import {DiscoveryModule} from "../discovery/discovery.module";
import {HttpModule} from "@nestjs/axios";
import {NextCliModule, NextCliService} from "next-binding";
import {GENERATORS} from "./tokens";
import {SearchCommand} from "./commands/search.command";
import {ReactCliModule, ReactCliService} from "react-binding";
import {loadInstalledPlugins} from "../plugins/plugin-loader";
import {PrebuildCommand} from "./commands/prebuild.command";
import {PostbuildCommand} from "./commands/postbuild.command";

const PLUGINS = loadInstalledPlugins();
const cliModules = PLUGINS.map(p => p.plugin.cliModule);
const cliServices = PLUGINS.map(p => p.plugin.cliService);

@Module({
imports: [CommonModule, DiscoveryModule, HttpModule, NextCliModule, ReactCliModule],
imports: [CommonModule, DiscoveryModule, HttpModule, ...cliModules],
providers: [
ProcessManagerService,
...DeamonCommand.registerWithSubCommands(),
Expand All @@ -28,12 +31,11 @@ import {PostbuildCommand} from "./commands/postbuild.command";
HttpModule,
PrebuildCommand,
PostbuildCommand,
...cliServices,
{
provide: GENERATORS,
inject: [NextCliService, ReactCliService],
useFactory(nextCliService: NextCliService, reactCliService: ReactCliService) {
return [nextCliService, reactCliService]
}
inject: cliServices,
useFactory: (...services: any[]) => services
}
],
})
Expand Down
2 changes: 1 addition & 1 deletion app/intrig/src/app/deamon/deamon.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { SourcesController } from './controllers/sources.controller';
import { CommonModule } from 'common';
import { CommonModule } from '@intrig/common';
import { IntrigConfigService } from './services/intrig-config.service';
import { OpenapiService } from './services/openapi.service';
import { OperationsController } from './controllers/operations.controller';
Expand Down
37 changes: 19 additions & 18 deletions app/intrig/src/app/deamon/generator/generator.module.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import {DynamicModule, Module} from '@nestjs/common';
import {IntrigConfigService} from "../services/intrig-config.service";
import {ReactBindingService} from "react-binding";
import {IntrigNextBindingService} from "next-binding";
import {GeneratorBinding} from "common";
import {GeneratorBinding} from "@intrig/common";
import {loadInstalledPlugins, LoadedPlugin} from "../../plugins/plugin-loader";

@Module({})
export class GeneratorModule {
static register(): DynamicModule {
static register(plugins: LoadedPlugin[] = loadInstalledPlugins()): DynamicModule {
const bindingModules = plugins.map(p => p.plugin.bindingModule);
const bindingServices = plugins.map(p => p.plugin.bindingService);
return {
module: GeneratorModule,
imports: [],
imports: [...bindingModules],
providers: [
IntrigConfigService,
ReactBindingService,
IntrigNextBindingService,
...bindingServices,
{
provide: GeneratorBinding,
inject: [IntrigConfigService, ReactBindingService, IntrigNextBindingService],
useFactory: (configService: IntrigConfigService, reactBinding: ReactBindingService, nextBinding: IntrigNextBindingService): GeneratorBinding => {
try {
switch (configService.get().generator) {
case "react":
return reactBinding;
case "next":
return nextBinding;
}
} catch (e) { /* empty */ }
return reactBinding;
inject: [IntrigConfigService, ...bindingServices],
useFactory: (configService: IntrigConfigService, ...bindings: GeneratorBinding[]): GeneratorBinding => {
const generator = configService.get().generator;
const matches = plugins.filter(p => p.config?.type === 'generator' && (p.plugin.name === generator || p.config?.for === generator));
if (matches.length > 1) {
throw new Error(`Generator plugin conflict for "${generator}"`);
}
if (matches.length === 0) {
throw new Error(`Generator binding not found for "${generator}"`);
}
const idx = plugins.indexOf(matches[0]);
return bindings[idx];
}
}
],
Expand Down
3 changes: 2 additions & 1 deletion app/intrig/src/app/deamon/services/data-search.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import {GeneratorBinding, Page, ResourceDescriptor, RestData} from "common";
import {GeneratorBinding} from "@intrig/common";
import {Page, ResourceDescriptor, RestData} from "common";
import {SearchService} from "./search.service";

@Injectable()
Expand Down
3 changes: 2 additions & 1 deletion app/intrig/src/app/deamon/services/operations.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Injectable, Logger} from '@nestjs/common';
import {GeneratorBinding} from "@intrig/common";
import {
GeneratorBinding, IntrigSourceConfig,
IntrigSourceConfig,
PackageManagerService,
ResourceDescriptor, RestData, Schema,
SyncEventContext,
Expand Down
2 changes: 1 addition & 1 deletion app/intrig/src/app/deamon/services/search.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Injectable, OnModuleInit} from '@nestjs/common';
import MiniSearch from 'minisearch';
import {isRestDescriptor, isSchemaDescriptor, ResourceDescriptor, RestData, Schema} from 'common';
import {isRestDescriptor, isSchemaDescriptor, ResourceDescriptor, RestData, Schema} from '@intrig/common';
import {IntrigConfigService} from "./intrig-config.service";
import {IntrigOpenapiService} from "openapi-source";
import {SourceStats} from "../models/source-stats";
Expand Down
61 changes: 61 additions & 0 deletions app/intrig/src/app/plugins/plugin-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as fs from 'fs';
import * as path from 'path';
import { createRequire } from 'module';
import { Logger } from '@nestjs/common';
import { IntrigPlugin } from '@intrig/common';

export interface LoadedPlugin {
plugin: IntrigPlugin;
config: any;
}

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

export function loadInstalledPlugins(rootDir = process.cwd()): LoadedPlugin[] {
const logger = new Logger('PluginLoader');
const nodeModules = path.join(rootDir, 'node_modules');
if (!fs.existsSync(nodeModules)) {
logger.warn(`node_modules directory not found`);
return [];
}

const packages: string[] = [];
for (const entry of fs.readdirSync(nodeModules, { withFileTypes: true })) {
const entryPath = path.join(nodeModules, entry.name);
if (!entry.isDirectory()) continue;
if (entry.name.startsWith('@')) {
for (const sub of fs.readdirSync(entryPath, { withFileTypes: true })) {
if (sub.isDirectory()) {
packages.push(`${entry.name}/${sub.name}`);
}
}
} else {
packages.push(entry.name);
}
}

const plugins: LoadedPlugin[] = [];

for (const pkgName of packages) {
try {
const pkgJsonPath = path.join(nodeModules, pkgName, 'package.json');
if (!fs.existsSync(pkgJsonPath)) continue;
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
const pluginCfg = pkgJson.intrig?.plugin;
if (!pluginCfg) continue;

// eslint-disable-next-line @typescript-eslint/no-var-requires
const mod = require(path.join(nodeModules, pkgName));
const plugin = (mod.default ?? mod.plugin) as IntrigPlugin | undefined;
if (plugin) {
plugins.push({ plugin, config: pluginCfg });
} else {
logger.warn(`No plugin export found in ${pkgName}`);
}
} catch (e) {
logger.error(`Failed to load plugin ${pkgName}`, e as any);
}
}

return plugins;
}
2 changes: 1 addition & 1 deletion app/intrig/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"path": "../../lib/next-binding/tsconfig.lib.json"
},
{
"path": "../../lib/common/tsconfig.lib.json"
"path": "../../lib/common-bindings/tsconfig.lib.json"
}
]
}
2 changes: 1 addition & 1 deletion app/intrig/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"path": "../../lib/next-binding"
},
{
"path": "../../lib/common"
"path": "../../lib/common-bindings"
},
{
"path": "./tsconfig.app.json"
Expand Down
4 changes: 2 additions & 2 deletions lib/common/package.json → lib/common-bindings/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "common",
"name": "@intrig/common",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
Expand Down
14 changes: 14 additions & 0 deletions lib/common-bindings/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "common-bindings",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "lib/common-bindings/src",
"projectType": "library",
"tags": [],
"targets": {
"nx-release-publish": {
"executor": "@nx/js:release-publish",
"options": {"packageRoot": "dist/lib/common-bindings"},
"dependsOn": ["^build"]
}
}
}
10 changes: 6 additions & 4 deletions lib/common/src/index.ts → lib/common-bindings/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export * from './lib/generator-binding';
export * from './lib/plugin.interface';

// Common
export * from './lib/common.module';
export * from './lib/spec-management.service';
export * from './lib/source-management.service';
export * from './lib/package-manager.service';

// Interfaces
export * from './lib/interfaces/generator.interface';
export * from './lib/interfaces/generator-cli.interface'
export * from './lib/interfaces/page.interface'
export * from './lib/interfaces/generator-cli.interface';
export * from './lib/interfaces/page.interface';

// Models
export * from './lib/model/content-types';
Expand All @@ -29,4 +31,4 @@ export * from './lib/template/md-literal';

// Utils
export * from './lib/util/change-case';
export type { Differences } from './lib/util/openapi3-diff'
export type { Differences } from './lib/util/openapi3-diff';
9 changes: 9 additions & 0 deletions lib/common-bindings/src/lib/generator-binding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export abstract class GeneratorBinding {
abstract generateGlobal(...args: any[]): Promise<any>;
abstract generateSource(...args: any[]): Promise<void>;
abstract getLibName(): string;
abstract postBuild(): Promise<void>;
abstract getSchemaDocumentation(...args: any[]): Promise<any>;
abstract getEndpointDocumentation(...args: any[]): Promise<any>;
getRestOptions(): any { return {}; }
}
7 changes: 7 additions & 0 deletions lib/common-bindings/src/lib/plugin.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface IntrigPlugin {
name: string;
bindingModule: any;
bindingService: any;
cliModule: any;
cliService: any;
}
File renamed without changes.
File renamed without changes.
3 changes: 0 additions & 3 deletions lib/common/README.md

This file was deleted.

9 changes: 0 additions & 9 deletions lib/common/project.json

This file was deleted.

17 changes: 0 additions & 17 deletions lib/common/src/lib/interfaces/generator.interface.ts

This file was deleted.

14 changes: 11 additions & 3 deletions lib/next-binding/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "next-binding",
"name": "@intrig/next-binding",
"version": "0.0.1",
"private": true,

"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
Expand All @@ -12,5 +12,13 @@
},
"./package.json": "./package.json"
},
"dependencies": {}
"dependencies": {
"@intrig/common": "*"
},
"intrig": {
"plugin": {
"type": "generator",
"for": "next"
}
}
}
9 changes: 7 additions & 2 deletions lib/next-binding/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"sourceRoot": "lib/next-binding/src",
"projectType": "library",
"tags": [],
"// targets": "to see all targets run: nx show project next-binding --web",
"targets": {}
"targets": {
"nx-release-publish": {
"executor": "@nx/js:release-publish",
"options": {"packageRoot": "dist/lib/next-binding"},
"dependsOn": ["^build"]
}
}
}
15 changes: 15 additions & 0 deletions lib/next-binding/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,18 @@ export * from './lib/next-binding.module';
export * from './lib/next-binding.service';
export * from './lib/cli/next-cli.module'
export * from './lib/cli/next-cli.service'

import {IntrigPlugin} from '@intrig/common';
import {NextBindingModule} from './lib/next-binding.module';
import {IntrigNextBindingService} from './lib/next-binding.service';
import {NextCliModule} from './lib/cli/next-cli.module';
import {NextCliService} from './lib/cli/next-cli.service';

export const plugin: IntrigPlugin = {
name: 'next',
bindingModule: NextBindingModule,
bindingService: IntrigNextBindingService,
cliModule: NextCliModule,
cliService: NextCliService,
};
export default plugin;
2 changes: 1 addition & 1 deletion lib/next-binding/src/lib/next-binding.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Injectable} from '@nestjs/common';
import {GeneratorBinding} from "@intrig/common";
import {
GeneratorBinding,
IIntrigSourceConfig, isRestDescriptor, isSchemaDescriptor, RelatedType,
ResourceDescriptor,
RestData, RestDocumentation, RestOptions, Schema, SchemaDocumentation,
Expand Down
2 changes: 1 addition & 1 deletion lib/next-binding/src/lib/templates/docs/react-hook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {camelCase, mdLiteral, pascalCase, ResourceDescriptor, RestData} from 'common'
import {camelCase, mdLiteral, pascalCase, ResourceDescriptor, RestData} from '@intrig/common'

export function reactHookDocs(descriptor: ResourceDescriptor<RestData>) {
const md = mdLiteral('react-hook.md')
Expand Down
Loading
Loading