mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			168 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
import path from 'path';
 | 
						|
import type { NodePlopAPI, PlopGeneratorConfig } from 'plop';
 | 
						|
 | 
						|
import {
 | 
						|
  formatEndpoints,
 | 
						|
  validateGroup,
 | 
						|
  validateVersion,
 | 
						|
  getFilesToFormat,
 | 
						|
  runGenerateApis,
 | 
						|
  formatFiles,
 | 
						|
  // The file extension is necessary to make the imports
 | 
						|
  // work with the '--experimental-strip-types' flag
 | 
						|
  // @ts-ignore
 | 
						|
} from './helpers.ts';
 | 
						|
// @ts-ignore
 | 
						|
import { type ActionConfig, type PlopData, isPlopData } from './types.ts';
 | 
						|
 | 
						|
export default function plopGenerator(plop: NodePlopAPI) {
 | 
						|
  // Grafana root path
 | 
						|
  const basePath = path.resolve(import.meta.dirname, '../..');
 | 
						|
 | 
						|
  // Register custom action types
 | 
						|
  plop.setActionType('runGenerateApis', runGenerateApis(basePath));
 | 
						|
  plop.setActionType('formatFiles', formatFiles(basePath));
 | 
						|
 | 
						|
  // Used in templates to format endpoints
 | 
						|
  plop.setHelper('formatEndpoints', formatEndpoints());
 | 
						|
 | 
						|
  const generateRtkApiActions = (data: PlopData) => {
 | 
						|
    const { reducerPath, groupName, version, isEnterprise } = data;
 | 
						|
 | 
						|
    const apiClientBasePath = isEnterprise ? 'public/app/extensions/api/clients' : 'public/app/api/clients';
 | 
						|
    const generateScriptPath = isEnterprise ? 'local/generate-enterprise-apis.ts' : 'scripts/generate-rtk-apis.ts';
 | 
						|
 | 
						|
    // Using app path, so the imports work on any file level
 | 
						|
    const clientImportPath = isEnterprise ? '../extensions/api/clients' : 'app/api/clients';
 | 
						|
 | 
						|
    const apiPathPrefix = isEnterprise ? '../public/app/extensions/api/clients' : '../public/app/api/clients';
 | 
						|
 | 
						|
    const templateData = {
 | 
						|
      ...data,
 | 
						|
      apiPathPrefix,
 | 
						|
    };
 | 
						|
 | 
						|
    // Base actions that are always added
 | 
						|
    const actions: ActionConfig[] = [
 | 
						|
      {
 | 
						|
        type: 'add',
 | 
						|
        path: path.join(basePath, `${apiClientBasePath}/${groupName}/${version}/baseAPI.ts`),
 | 
						|
        templateFile: './templates/baseAPI.ts.hbs',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'modify',
 | 
						|
        path: path.join(basePath, generateScriptPath),
 | 
						|
        pattern: '// PLOP_INJECT_API_CLIENT - Used by the API client generator',
 | 
						|
        templateFile: './templates/config-entry.hbs',
 | 
						|
        data: templateData,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'add',
 | 
						|
        path: path.join(basePath, `${apiClientBasePath}/${groupName}/${version}/index.ts`),
 | 
						|
        templateFile: './templates/index.ts.hbs',
 | 
						|
      },
 | 
						|
    ];
 | 
						|
 | 
						|
    // Only add redux reducer and middleware for OSS clients
 | 
						|
    if (!isEnterprise) {
 | 
						|
      actions.push(
 | 
						|
        {
 | 
						|
          type: 'modify',
 | 
						|
          path: path.join(basePath, 'public/app/core/reducers/root.ts'),
 | 
						|
          pattern: '// PLOP_INJECT_IMPORT',
 | 
						|
          template: `import { ${reducerPath} } from '${clientImportPath}/${groupName}/${version}';\n// PLOP_INJECT_IMPORT`,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'modify',
 | 
						|
          path: path.join(basePath, 'public/app/core/reducers/root.ts'),
 | 
						|
          pattern: '// PLOP_INJECT_REDUCER',
 | 
						|
          template: `[${reducerPath}.reducerPath]: ${reducerPath}.reducer,\n  // PLOP_INJECT_REDUCER`,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'modify',
 | 
						|
          path: path.join(basePath, 'public/app/store/configureStore.ts'),
 | 
						|
          pattern: '// PLOP_INJECT_IMPORT',
 | 
						|
          template: `import { ${reducerPath} } from '${clientImportPath}/${groupName}/${version}';\n// PLOP_INJECT_IMPORT`,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          type: 'modify',
 | 
						|
          path: path.join(basePath, 'public/app/store/configureStore.ts'),
 | 
						|
          pattern: '// PLOP_INJECT_MIDDLEWARE',
 | 
						|
          template: `${reducerPath}.middleware,\n        // PLOP_INJECT_MIDDLEWARE`,
 | 
						|
        }
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    // Add formatting and generation actions
 | 
						|
    actions.push(
 | 
						|
      {
 | 
						|
        type: 'formatFiles',
 | 
						|
        files: getFilesToFormat(groupName, version, isEnterprise),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'runGenerateApis',
 | 
						|
        isEnterprise,
 | 
						|
      }
 | 
						|
    );
 | 
						|
 | 
						|
    return actions;
 | 
						|
  };
 | 
						|
 | 
						|
  const generator: PlopGeneratorConfig = {
 | 
						|
    description: 'Generate RTK Query API client for a Grafana API group',
 | 
						|
    prompts: [
 | 
						|
      {
 | 
						|
        type: 'confirm',
 | 
						|
        name: 'isEnterprise',
 | 
						|
        message: 'Is this a Grafana Enterprise API?',
 | 
						|
        default: false,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'input',
 | 
						|
        name: 'groupName',
 | 
						|
        message: 'API group name (e.g. dashboard):',
 | 
						|
        validate: (input: string) => (input?.trim() ? true : 'Group name is required'),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'input',
 | 
						|
        name: 'group',
 | 
						|
        message: 'API group (e.g. dashboard.grafana.app):',
 | 
						|
        default: (answers: { groupName?: string }) => `${answers.groupName}.grafana.app`,
 | 
						|
        validate: validateGroup,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'input',
 | 
						|
        name: 'version',
 | 
						|
        message: 'API version (e.g. v0alpha1):',
 | 
						|
        default: 'v0alpha1',
 | 
						|
        validate: validateVersion,
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'input',
 | 
						|
        name: 'reducerPath',
 | 
						|
        message: 'Reducer path (e.g. dashboardAPIv0alpha1):',
 | 
						|
        default: (answers: { groupName?: string; version?: string }) => `${answers.groupName}API${answers.version}`,
 | 
						|
        validate: (input: string) =>
 | 
						|
          input?.endsWith('API') || input?.match(/API[a-z]\d+[a-z]*\d*$/)
 | 
						|
            ? true
 | 
						|
            : 'Reducer path should end with "API" or "API<version>" (e.g. dashboardAPI, dashboardAPIv0alpha1)',
 | 
						|
      },
 | 
						|
      {
 | 
						|
        type: 'input',
 | 
						|
        name: 'endpoints',
 | 
						|
        message: 'Endpoints to include (comma-separated, optional):',
 | 
						|
        validate: () => true,
 | 
						|
      },
 | 
						|
    ],
 | 
						|
    actions: function (data) {
 | 
						|
      if (!isPlopData(data)) {
 | 
						|
        throw new Error('Invalid data format received from prompts');
 | 
						|
      }
 | 
						|
 | 
						|
      return generateRtkApiActions(data);
 | 
						|
    },
 | 
						|
  };
 | 
						|
 | 
						|
  plop.setGenerator('rtk-api-client', generator);
 | 
						|
}
 |