feat(utils): add print util (#6020)

* feat(utils): add print util

* refactor: migrate console to print
This commit is contained in:
Aaron 2024-07-11 14:06:49 +08:00 committed by GitHub
parent 9ec96d0cc2
commit e3b1d48745
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 123 additions and 17 deletions

View File

@ -8,6 +8,6 @@ describe('bugs:continuous-invoke', () => {
await graph.render();
});
expect(fn).rejects.toThrow('Graph has been destroyed');
expect(fn).rejects.toThrow();
});
});

View File

@ -0,0 +1,52 @@
import { version } from '@/src';
import { print } from '@/src/utils/print';
describe('print', () => {
it('print', () => {
const spy = jest.spyOn(console, 'debug').mockImplementation();
print.debug('debug message');
expect(spy).toHaveBeenCalledWith(`[G6 v${version}] debug message`);
spy.mockRestore();
const spy2 = jest.spyOn(console, 'info').mockImplementation();
print.info('info message');
expect(spy2).toHaveBeenCalledWith(`[G6 v${version}] info message`);
spy2.mockRestore();
const spy3 = jest.spyOn(console, 'warn').mockImplementation();
print.warn('warn message');
expect(spy3).toHaveBeenCalledWith(`[G6 v${version}] warn message`);
spy3.mockRestore();
const spy4 = jest.spyOn(console, 'error').mockImplementation();
print.error('error message');
expect(spy4).toHaveBeenCalledWith(`[G6 v${version}] error message`);
spy4.mockRestore();
});
it('print mute', () => {
print.mute = true;
const spy = jest.spyOn(console, 'debug').mockImplementation();
print.debug('debug message');
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
const spy2 = jest.spyOn(console, 'info').mockImplementation();
print.info('info message');
expect(spy2).not.toHaveBeenCalled();
spy2.mockRestore();
const spy3 = jest.spyOn(console, 'warn').mockImplementation();
print.warn('warn message');
expect(spy3).not.toHaveBeenCalled();
spy3.mockRestore();
const spy4 = jest.spyOn(console, 'error').mockImplementation();
print.error('error message');
expect(spy4).not.toHaveBeenCalled();
spy4.mockRestore();
print.mute = false;
});
});

View File

@ -1,6 +1,7 @@
import type { ID, IElementDragEvent, Point } from '../types';
import { idOf } from '../utils/id';
import { getLayoutProperty, invokeLayoutMethod } from '../utils/layout';
import { print } from '../utils/print';
import { add } from '../utils/vector';
import type { DragElementOptions } from './drag-element';
import { DragElement } from './drag-element';
@ -37,7 +38,7 @@ export class DragElementForce extends DragElement {
// 未使用力导布局 / The force layout is not used
if (!this.forceLayoutInstance) {
console.warn('DragElementForce only works with d3-force or d3-force-3d layout');
print.warn('DragElementForce only works with d3-force or d3-force-3d layout');
return false;
}

View File

@ -1,4 +1,5 @@
import type { RuntimeContext } from '../../runtime/types';
import { print } from '../../utils/print';
import type { ShortcutKey } from '../../utils/shortcut';
import { Shortcut } from '../../utils/shortcut';
import type { BasePluginOptions } from '../base-plugin';
@ -123,7 +124,7 @@ export class Fullscreen extends BasePlugin<FullscreenOptions> {
public request() {
if (document.fullscreenElement || !isFullscreenEnabled()) return;
this.$el.requestFullscreen().catch((err: Error) => {
console.debug(`Error attempting to enable full-screen: ${err.message} (${err.name})`);
print.warn(`Error attempting to enable full-screen: ${err.message} (${err.name})`);
});
}

View File

@ -5,6 +5,7 @@ import type { RuntimeContext } from '../../runtime/types';
import type { IEvent } from '../../types';
import { arrayDiff } from '../../utils/diff';
import { parseExtensions } from '../../utils/extension';
import { print } from '../../utils/print';
import type { STDExtensionOption } from './types';
export abstract class ExtensionController<E extends BaseExtension<any>> {
@ -42,7 +43,7 @@ export abstract class ExtensionController<E extends BaseExtension<any>> {
const { key, type } = extension;
const Ctor = getExtension(category, type);
if (!Ctor) return;
if (!Ctor) return print.warn(`The extension ${type} of ${category} is not registered.`);
const instance = new Ctor(this.context, extension);
this.extensionMap[key] = instance as E;

View File

@ -1,5 +1,6 @@
import { ExtensionCategory } from '../constants';
import type { Loosen } from '../types';
import { print } from '../utils/print';
import { BUILT_IN_EXTENSIONS } from './build-in';
import type { ExtensionRegistry } from './types';
@ -58,7 +59,7 @@ export function register<T extends ExtensionCategory>(
) {
const ext = EXTENSION_REGISTRY[category][type];
if (ext) {
if (ext !== Ctor) console.error(`The extension ${type} of ${category} has been registered before.`);
if (ext !== Ctor) print.warn(`The extension ${type} of ${category} has been registered before.`);
} else Object.assign(EXTENSION_REGISTRY[category]!, { [type]: Ctor });
}

View File

@ -25,6 +25,7 @@ import { arrayDiff } from '../utils/diff';
import { toG6Data, toGraphlibData } from '../utils/graphlib';
import { idOf, parentIdOf } from '../utils/id';
import { positionOf } from '../utils/position';
import { format, print } from '../utils/print';
import { dfs } from '../utils/traverse';
import { add } from '../utils/vector';
@ -188,7 +189,7 @@ export class DataController {
public getParentData(id: ID, hierarchyKey: HierarchyKey): NodeLikeData | undefined {
const { model } = this;
if (!hierarchyKey) {
console.error('The hierarchy structure key is not specified');
print.warn('The hierarchy structure key is not specified');
return undefined;
}
if (!model.hasNode(id) || !model.hasTreeStructure(hierarchyKey)) return undefined;
@ -761,7 +762,7 @@ export class DataController {
if (this.model.hasEdge(id)) return 'edge';
throw new Error(`Unknown element type of id: ${id}`);
throw new Error(format(`Unknown element type of id: ${id}`));
}
public destroy() {

View File

@ -31,6 +31,7 @@ import { AnimateEvent, ElementLifeCycleEvent, GraphLifeCycleEvent, emit } from '
import { idOf } from '../utils/id';
import { assignColorByPalette, parsePalette } from '../utils/palette';
import { positionOf } from '../utils/position';
import { print } from '../utils/print';
import { computeElementCallbackStyle } from '../utils/style';
import { themeOf } from '../utils/theme';
import type { RuntimeContext } from './types';
@ -366,7 +367,7 @@ export class ElementController {
// get shape constructor
const Ctor = getExtension(elementType, type);
if (!Ctor) return;
if (!Ctor) return print.warn(`The element ${type} of ${elementType} is not registered.`);
this.emit(new ElementLifeCycleEvent(GraphEvent.BEFORE_ELEMENT_CREATE, elementType, datum), context);
@ -791,7 +792,7 @@ export interface DrawContext {
animation: boolean;
/** <zh/> 当前绘制阶段 | <en/> Current draw stage */
stage?: AnimationStage;
/** <zh/> 是否不抛出事件 | <en/> Whether not to throw events */
/** <zh/> 是否不抛出事件 | <en/> Whether not to dispatch events */
silence?: boolean;
/** <zh/> 收起/展开的对象 ID | <en/> ID of the object to collapse/expand */
collapseExpandTarget?: ID;

View File

@ -45,6 +45,7 @@ import { sizeOf } from '../utils/dom';
import { GraphLifeCycleEvent, emit } from '../utils/event';
import { idOf } from '../utils/id';
import { parsePoint, toPointObject } from '../utils/point';
import { format } from '../utils/print';
import { subtract } from '../utils/vector';
import { Animation } from './animation';
import { BatchController } from './batch';
@ -1078,7 +1079,7 @@ export class Graph extends EventEmitter {
// Wait for synchronous tasks to complete, to avoid problems caused by calling destroy immediately after render
await Promise.resolve();
if (this.destroyed) throw new Error('Graph has been destroyed');
if (this.destroyed) throw new Error(format('The graph instance has been destroyed'));
await this.initCanvas();
this.initRuntime();

View File

@ -15,6 +15,7 @@ import { GraphLifeCycleEvent, emit } from '../utils/event';
import { createTreeStructure } from '../utils/graphlib';
import { idOf } from '../utils/id';
import { isTreeLayout, layoutAdapter, layoutMapping2GraphData } from '../utils/layout';
import { print } from '../utils/print';
import { parseSize } from '../utils/size';
import { dfs } from '../utils/traverse';
import type { RuntimeContext } from './types';
@ -103,6 +104,8 @@ export class LayoutController {
const { animation, enableWorker, iterations = 300 } = options;
const layout = this.initGraphLayout(options);
if (!layout) return {};
this.instances[index] = layout;
this.instance = layout;
@ -142,7 +145,7 @@ export class LayoutController {
// @ts-expect-error @antv/hierarchy 布局格式与 @antv/layout 不一致,其导出的是一个方法,而非 class
// The layout format of @antv/hierarchy is inconsistent with @antv/layout, it exports a method instead of a class
const layout = getExtension('layout', type) as (tree: TreeData, options: STDLayoutOptions) => TreeData;
if (!layout) throw new Error(`The layout type ${type} is not found`);
if (!layout) return {};
const { nodes = [], edges = [] } = data;
@ -256,7 +259,7 @@ export class LayoutController {
});
const Ctor = getExtension('layout', type);
if (!Ctor) throw new Error(`The layout type ${type} is not found`);
if (!Ctor) return print.warn(`The layout of ${type} is not registered.`);
const STDCtor =
Object.getPrototypeOf(Ctor.prototype) === BaseLayout.prototype

View File

@ -1,11 +1,12 @@
import type { IAnimation } from '@antv/g';
import { isEqual, isNil, isObject, isString } from '@antv/util';
import { isEqual, isNil, isObject } from '@antv/util';
import type { AnimationEffectTiming, AnimationOptions, STDAnimation } from '../animations/types';
import { DEFAULT_ANIMATION_OPTIONS, DEFAULT_ELEMENTS_ANIMATION_OPTIONS, ExtensionCategory } from '../constants';
import { getExtension } from '../registry';
import type { GraphOptions } from '../spec';
import type { AnimationStage } from '../spec/element/animation';
import type { ElementType, Keyframe } from '../types';
import { print } from './print';
import { themeOf } from './theme';
export function createAnimationsProxy(animations: IAnimation[]): IAnimation | null;
@ -161,7 +162,13 @@ export function getAnimationOptions(
* @returns <zh/> | <en/> animation configuration
*/
function animationOf(options: string | AnimationOptions[]): STDAnimation {
if (isString(options)) return getExtension(ExtensionCategory.ANIMATION, options) || [];
if (typeof options === 'string') {
const animation = getExtension(ExtensionCategory.ANIMATION, options);
if (animation) return animation;
print.warn(`The animation of ${options} is not registered.`);
return [];
}
return options;
}

View File

@ -1,5 +1,6 @@
import type { ComboData, EdgeData, GraphData, NodeData } from '../spec';
import type { DataID, ID } from '../types';
import { format } from './print';
/**
* <zh/> //Combo ID
@ -12,7 +13,7 @@ export function idOf(data: Partial<NodeData | EdgeData | ComboData>): ID {
if (data.id !== undefined) return data.id;
if (data.source !== undefined && data.target !== undefined) return `${data.source}-${data.target}`;
throw new Error('The data does not have available id.');
throw new Error(format('The datum does not have available id.'));
}
/**

View File

@ -5,6 +5,7 @@ import type { PaletteOptions, STDPaletteOptions } from '../spec/element/palette'
import type { ID } from '../types';
import type { ElementData, ElementDatum } from '../types/data';
import { idOf } from './id';
import { format } from './print';
/**
* <zh/>
@ -99,7 +100,7 @@ export function assignColorByPalette(data: ElementData, palette?: STDPaletteOpti
const [min, max] = data.reduce(
([min, max], datum) => {
const value = parseField(field, datum);
if (typeof value !== 'number') throw new Error(`Palette field ${field} is not a number`);
if (typeof value !== 'number') throw new Error(format(`Palette field ${field} is not a number`));
return [Math.min(min, value), Math.max(max, value)];
},
[Infinity, -Infinity],

View File

@ -0,0 +1,30 @@
import { version } from '../version';
const BRAND = 'G6';
/**
* <zh/>
*
* <en/> Format print
* @param message - <zh/> | <en/> Message
* @returns <zh/> | <en/> Formatted message
*/
export function format(message: string) {
return `[${BRAND} v${version}] ${message}`;
}
export const print = {
mute: false,
debug: (message: string): void => {
!print.mute && console.debug(format(message));
},
info: (message: string): void => {
!print.mute && console.info(format(message));
},
warn: (message: string): void => {
!print.mute && console.warn(format(message));
},
error: (message: string): void => {
!print.mute && console.error(format(message));
},
};

View File

@ -1,6 +1,7 @@
import { ExtensionCategory } from '../constants';
import { getExtension } from '../registry';
import type { GraphOptions } from '../spec';
import { print } from './print';
/**
* <zh/>
@ -14,5 +15,9 @@ export function themeOf(options: GraphOptions) {
if (!theme) return {};
const themeOptions = getExtension(ExtensionCategory.THEME, theme);
return themeOptions ?? {};
if (themeOptions) return themeOptions;
print.warn(`The theme of ${theme} is not registered.`);
return {};
}