Skip to content

Commit

Permalink
fix(ava/advisor): add advisor export types
Browse files Browse the repository at this point in the history
  • Loading branch information
chenluli committed Jun 17, 2024
1 parent a86960e commit 3d32447
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { getChartTypeRecommendations } from './get-chart-Type';

import type {
AdvisorPipelineContext,
ChartTypeRecommendInputParams,
ChartTypeRecommendInput,
ChartTypeRecommendOutput,
PluginType,
AdvisorPluginType,
} from '../../../../types';

export const chartTypeRecommendPlugin: PluginType<ChartTypeRecommendInputParams, ChartTypeRecommendOutput> = {
export const chartTypeRecommendPlugin: AdvisorPluginType<ChartTypeRecommendInput, ChartTypeRecommendOutput> = {
name: 'defaultChartTypeRecommend',
stage: ['chartTypeRecommend'],
execute(input: ChartTypeRecommendInputParams, context?: AdvisorPipelineContext): ChartTypeRecommendOutput {
execute(input: ChartTypeRecommendInput, context?: AdvisorPipelineContext): ChartTypeRecommendOutput {
const { dataProps } = input;
const { advisor, options } = context || {};
const chartTypeRecommendations = getChartTypeRecommendations({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ import { cloneDeep } from 'lodash';
import { getDataProps } from './get-data-properties';
import { getSelectedData } from './get-selected-data';

import type { AdvisorPipelineContext, DataProcessorInput, DataProcessorOutput, PluginType } from '../../../../types';
import type {
AdvisorPipelineContext,
DataProcessorInput,
DataProcessorOutput,
AdvisorPluginType,
} from '../../../../types';

export const dataProcessorPlugin: PluginType<DataProcessorInput, DataProcessorOutput> = {
export const dataProcessorPlugin: AdvisorPluginType<DataProcessorInput, DataProcessorOutput> = {
name: 'defaultDataProcessor',
stage: ['dataAnalyze'],
execute: (input: DataProcessorInput, context: AdvisorPipelineContext): DataProcessorOutput => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import { DEFAULT_COLOR } from '../../../constants';
import { applyDesignRules, applySmartColor, applyTheme } from './spec-processors';
import { getChartTypeSpec } from './get-chart-spec';

import type { AdvisorPipelineContext, SpecGeneratorInput, SpecGeneratorOutput, PluginType } from '../../../../types';
import type {
AdvisorPipelineContext,
SpecGeneratorInput,
SpecGeneratorOutput,
AdvisorPluginType,
} from '../../../../types';

export const specGeneratorPlugin: PluginType<SpecGeneratorInput, SpecGeneratorOutput> = {
// todo 内置的 visualEncode 和 spec generate 插件需要明确支持哪些图表类型
export const specGeneratorPlugin: AdvisorPluginType<SpecGeneratorInput, SpecGeneratorOutput> = {
name: 'defaultSpecGenerator',
stage: ['specGenerate'],
// todo 目前上一步输出是一个图表列表数组,这里原子能力实际上应该是只生成 spec
execute: (input: SpecGeneratorInput, context: AdvisorPipelineContext): SpecGeneratorOutput => {
const { chartTypeRecommendations, dataProps, data } = input;
const { options, advisor } = context || {};
Expand All @@ -18,12 +23,15 @@ export const specGeneratorPlugin: PluginType<SpecGeneratorInput, SpecGeneratorOu
const advices = chartTypeRecommendations
?.map((chartTypeAdvice) => {
const { chartType } = chartTypeAdvice;
const chartTypeSpec = getChartTypeSpec({
chartType,
data,
dataProps,
chartKnowledge: advisor.ckb[chartType],
});
const chartKnowledge = advisor.ckb[chartType];
const chartTypeSpec =
chartKnowledge?.toSpec(data, dataProps) ??
getChartTypeSpec({
chartType,
data,
dataProps,
chartKnowledge,
});

// step 3: apply spec processors such as design rules, theme, color, to improve spec
if (chartTypeSpec && refine) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PluginType, VisualEncoderInput } from '../../../../types';
import type { AdvisorPluginType, VisualEncoderInput } from '../../../../types';

export const visualEncoderPlugin: PluginType<VisualEncoderInput, VisualEncoderInput> = {
export const visualEncoderPlugin: AdvisorPluginType<VisualEncoderInput, VisualEncoderInput> = {
name: 'defaultVisualEncoder',
stage: ['encode'],
execute: (input) => {
Expand Down
25 changes: 12 additions & 13 deletions packages/ava/src/advisor/advisor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import type {
Lint,
AdvisorPipelineContext,
PipelineStageType,
PluginType,
AdvisorPluginType,
DataProcessorInput,
DataProcessorOutput,
ChartTypeRecommendInputParams,
ChartTypeRecommendInput,
ChartTypeRecommendOutput,
VisualEncoderInput,
VisualEncoderOutput,
Expand All @@ -43,32 +43,36 @@ export class Advisor {

dataAnalyzer: BaseComponent<DataProcessorInput, DataProcessorOutput>;

chartTypeRecommender: BaseComponent<ChartTypeRecommendInputParams, ChartTypeRecommendOutput>;
chartTypeRecommender: BaseComponent<ChartTypeRecommendInput, ChartTypeRecommendOutput>;

chartEncoder: BaseComponent<VisualEncoderInput, VisualEncoderOutput>;

specGenerator: BaseComponent<SpecGeneratorInput, SpecGeneratorOutput>;

context: AdvisorPipelineContext;

plugins: PluginType[];
plugins: AdvisorPluginType[];

pipeline: Pipeline;

constructor(
config: AdvisorConfig = {},
custom: {
plugins?: PluginType[];
plugins?: AdvisorPluginType[];
components?: BaseComponent[];
/** extra info to pass through the pipeline
* 额外透传到推荐 pipeline 中的业务信息
*/
extra?: Record<string, any>;
} = {}
) {
// init
const { plugins, components, extra = {} } = custom;
this.ckb = ckb(config.ckbCfg);
this.ruleBase = processRuleCfg(config.ruleCfg);
this.context = { advisor: this };
this.context = { advisor: this, extra };
this.initDefaultComponents();
const defaultComponents = [this.dataAnalyzer, this.chartTypeRecommender, this.chartEncoder, this.specGenerator];
const { plugins, components } = custom;
this.plugins = plugins;
this.pipeline = new Pipeline({ components: components ?? defaultComponents });
}
Expand All @@ -83,11 +87,6 @@ export class Advisor {
this.specGenerator = new BaseComponent('specGenerate', { plugins: [specGeneratorPlugin], context: this.context });
}

// todo 定义多个链路串并联的方法
// private definePipeline(components: BaseComponent[]) {
// this.pipeline.components = components;
// }

// todo 暂时还在用旧链路,需要改造到新链路
advise(params: AdviseParams): Advice[] {
const adviseResult = dataToAdvices({ adviseParams: params, ckb: this.ckb, ruleBase: this.ruleBase });
Expand Down Expand Up @@ -119,7 +118,7 @@ export class Advisor {
return lintResult;
}

registerPlugins(plugins: PluginType[]) {
registerPlugins(plugins: AdvisorPluginType[]) {
const stage2Components: Record<PipelineStageType, BaseComponent> = {
dataAnalyze: this.dataAnalyzer,
chartTypeRecommend: this.chartTypeRecommender,
Expand Down
29 changes: 9 additions & 20 deletions packages/ava/src/advisor/pipeline/component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { AsyncParallelHook, SyncHook } from 'tapable';
import { last } from 'lodash';

import type { PluginType, AdvisorPipelineContext } from '../types';
import type { AdvisorPluginType, AdvisorPipelineContext } from '../types';

/** 收集多个 plugin 的输出结果 */
type PluginResultMap<Output = any> = Record<string, Output>;

export class BaseComponent<Input = any, Output = any> {
name: string;

plugins: PluginType<Input, Output>[] = [];
plugins: AdvisorPluginType<Input, Output>[] = [];

/** 是否存在异步插件 */
private hasAsyncPlugin: boolean;
Expand All @@ -18,15 +18,15 @@ export class BaseComponent<Input = any, Output = any> {

syncPluginManager: SyncHook<[Input, PluginResultMap<Output>], Output>;

afterPluginsExecute?: (params: PluginResultMap<Output>) => Output;
afterPluginsExecute?: (params: PluginResultMap<Output>, context?: AdvisorPipelineContext) => Output;

context?: AdvisorPipelineContext;

constructor(
name,
options?: {
plugins?: PluginType<Input, Output>[];
afterPluginsExecute?: (params: PluginResultMap<Output>) => Output;
plugins?: AdvisorPluginType<Input, Output>[];
afterPluginsExecute?: (params: PluginResultMap<Output>, context?: AdvisorPipelineContext) => Output;
context?: AdvisorPipelineContext;
}
) {
Expand All @@ -45,7 +45,7 @@ export class BaseComponent<Input = any, Output = any> {
return last(Object.values(params));
}

private isPluginAsync(plugin: PluginType) {
private isPluginAsync(plugin: AdvisorPluginType) {
// 检测插件是否为异步的,并设置hasAsyncPlugin标志位
if (plugin.execute.constructor.name === 'AsyncFunction') {
return true;
Expand All @@ -54,7 +54,7 @@ export class BaseComponent<Input = any, Output = any> {
}

// 处理 之前都是同步的插件,新追加注册一个异步的插件 的情况 -- 需要执行的地方就不能用
registerPlugin(plugin: PluginType) {
registerPlugin(plugin: AdvisorPluginType) {
plugin.onLoad?.(this.context);
this.plugins.push(plugin);
if (this.isPluginAsync(plugin)) {
Expand Down Expand Up @@ -94,22 +94,11 @@ export class BaseComponent<Input = any, Output = any> {
// console.warn('存在异步执行的插件,建议使用 executeAsync')
const pluginsOutput = {};
return this.pluginManager.promise(params, pluginsOutput).then(async () => {
return this.afterPluginsExecute?.(pluginsOutput);
return this.afterPluginsExecute?.(pluginsOutput, this.context);
});
}
const pluginsOutput = {};
this.syncPluginManager.call(params, pluginsOutput);
return this.afterPluginsExecute?.(pluginsOutput);
return this.afterPluginsExecute?.(pluginsOutput, this.context);
}

// todo 是否应该区分同步和异步接口
// executeAsync(params: Input): Promise<Output> {
// if(!this.hasAsyncPlugin) {
// console.warn('插件均同步执行,建议使用 execute')
// }
// const pluginsOutput = {};
// return this.pluginManager.promise(params, pluginsOutput).then(async () => {
// return this.afterPluginsExecute?.(pluginsOutput);
// });
// }
}
10 changes: 7 additions & 3 deletions packages/ava/src/advisor/types/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { MarkEncode } from './mark';
export type PipelineStageType = 'dataAnalyze' | 'chartTypeRecommend' | 'encode' | 'specGenerate';

/** 基础插件接口定义 */
export interface PluginType<Input = any, Output = any> {
export interface AdvisorPluginType<Input = any, Output = any> {
/** 插件的唯一标识 */
name: string;
/** 插件运行的阶段,用于指定插件在 pipeline 的哪个环节运行 * */
Expand All @@ -30,7 +30,7 @@ export type DataProcessorOutput = {
dataProps: BasicDataPropertyForAdvice[];
};

export type ChartTypeRecommendInputParams = {
export type ChartTypeRecommendInput = {
dataProps: BasicDataPropertyForAdvice[];
};

Expand All @@ -43,7 +43,11 @@ export type SpecGeneratorInput = {
// 单独调用 SpecGenerator 时,还要额外计算 dataProps 么
dataProps: BasicDataPropertyForAdvice[];
};
export type SpecGeneratorOutput = { advices: Advice[] };
export type SpecGeneratorOutput = {
advices: (Omit<Advice, 'spec'> & {
spec: Record<string, any> | null;
})[];
};

export type VisualEncoderInput = {
chartType: ChartId;
Expand Down
6 changes: 3 additions & 3 deletions packages/ava/src/advisor/types/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ export type ChartAdviseParams = {
data: Data;
/** customized data props to advise */
dataProps?: Partial<BasicDataPropertyForAdvice>[];
/** @todo 确认下为啥这里和 options 里面都有 data fields to focus, apply in `data` and `dataProps` */
/** data fields to focus, apply in `data` and `dataProps`
* @todo 确认下为啥这里和 options 里面都有 是否应该废弃一处的
*/
fields?: string[];
/** advising options such as purpose, layout preferences */
options?: AdvisorOptions;
Expand Down Expand Up @@ -223,6 +225,4 @@ export type AdvisorPipelineContext = {
extra?: {
[key: string]: any;
};
/** 过程中的日志信息,开发调试用, todo 明确类型 */
logs?: { [key: string]: any }[];
};
8 changes: 8 additions & 0 deletions packages/ava/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export type {
LintParams,
RuleModule,
AdvisorConfig,
AdvisorPluginType,
AdvisorPipelineContext,
DataProcessorInput,
DataProcessorOutput,
ChartTypeRecommendInput,
ChartTypeRecommendOutput,
SpecGeneratorInput,
SpecGeneratorOutput,
} from './advisor';

/* CKB */
Expand Down

0 comments on commit 3d32447

Please sign in to comment.