重构tracer设计
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
import type { TracerCommand } from '../types/command';
|
||||
|
||||
export class Commander {
|
||||
private commands: TracerCommand<unknown>[];
|
||||
|
||||
private constructor() {
|
||||
this.commands = [];
|
||||
}
|
||||
|
||||
private static instance: Commander | null = null;
|
||||
|
||||
public static getInstance(): Commander {
|
||||
if (!this.instance) {
|
||||
this.instance = new Commander();
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
public command<T = never>(command: TracerCommand<T>) {
|
||||
this.commands.push(command);
|
||||
}
|
||||
|
||||
public output() {
|
||||
return JSON.stringify(this.commands);
|
||||
}
|
||||
}
|
||||
1
tracers.ts/src/context/index.ts
Normal file
1
tracers.ts/src/context/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './tracer-context';
|
||||
22
tracers.ts/src/context/tracer-context.ts
Normal file
22
tracers.ts/src/context/tracer-context.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { TracerCommand } from '../types';
|
||||
|
||||
const createTracerContext = () => {
|
||||
const commands: TracerCommand[] = [];
|
||||
|
||||
const getTracerContext = () => {
|
||||
const command = (command: TracerCommand) => {
|
||||
commands.push(command);
|
||||
};
|
||||
|
||||
return {
|
||||
commands,
|
||||
command,
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
getTracerContext,
|
||||
};
|
||||
};
|
||||
|
||||
export const { getTracerContext } = createTracerContext();
|
||||
@@ -1,10 +1,20 @@
|
||||
import { Commander } from './commander';
|
||||
import { ArrayTracer } from './tracer';
|
||||
import { getTracerContext } from './context';
|
||||
import {
|
||||
createArrayTracer,
|
||||
createControlTracer,
|
||||
createLogTracer,
|
||||
} from './tracers';
|
||||
|
||||
const arrayTracer = ArrayTracer.define<number>({ description: 'Array Tracer' });
|
||||
const logTracer = createLogTracer({ description: 'LogTracer' });
|
||||
const controlTracer = createControlTracer({ description: 'ControlTracer' });
|
||||
|
||||
arrayTracer.preset([1, 2, 3]);
|
||||
const arrayTracer = createArrayTracer<number>({
|
||||
description: 'ArrayTracer',
|
||||
array: [1, 2, 3],
|
||||
});
|
||||
|
||||
const commander = Commander.getInstance();
|
||||
const commands = commander.output();
|
||||
console.log(commands);
|
||||
arrayTracer.patch(0, 100);
|
||||
|
||||
controlTracer.step();
|
||||
|
||||
console.log(getTracerContext().commands);
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { TracerType } from "../types/tracer";
|
||||
|
||||
export class Registry {
|
||||
private tracers: Map<TracerType, string[]>;
|
||||
|
||||
private constructor() {
|
||||
this.tracers = new Map<TracerType, string[]>();
|
||||
}
|
||||
|
||||
private static instance: Registry | null = null;
|
||||
|
||||
public static getInstance() {
|
||||
if (!this.instance) {
|
||||
this.instance = new Registry();
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
public register(tracerType: TracerType, string: string) {
|
||||
if (!this.tracers.has(tracerType)) {
|
||||
this.tracers.set(tracerType, []);
|
||||
}
|
||||
this.tracers.get(tracerType)?.push(string);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import { Commander } from '../commander';
|
||||
import { Registry } from '../registry';
|
||||
|
||||
export interface ArrayTracerOption<T> {
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class ArrayTracer<T> {
|
||||
private tracerId: string;
|
||||
|
||||
private constructor() {
|
||||
this.tracerId = crypto.randomUUID();
|
||||
}
|
||||
|
||||
public static define<T>(option: ArrayTracerOption<T>): ArrayTracer<T> {
|
||||
const arrayTracer = new ArrayTracer();
|
||||
const registry = Registry.getInstance();
|
||||
registry.register('ArrayTracer', arrayTracer.tracerId);
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'define',
|
||||
tracer: null,
|
||||
payload: {
|
||||
type: 'ArrayTracer',
|
||||
id: arrayTracer.tracerId,
|
||||
desc: option.description,
|
||||
},
|
||||
});
|
||||
return arrayTracer;
|
||||
}
|
||||
|
||||
public preset(array: T[]) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'preset',
|
||||
tracer: this.tracerId,
|
||||
payload: array,
|
||||
});
|
||||
}
|
||||
|
||||
public extend(size: number) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'extend',
|
||||
tracer: this.tracerId,
|
||||
payload: { size },
|
||||
});
|
||||
}
|
||||
|
||||
public shrink(size: number) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'shrink',
|
||||
tracer: this.tracerId,
|
||||
payload: { size },
|
||||
});
|
||||
}
|
||||
|
||||
public pick(index: number) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'pick',
|
||||
tracer: this.tracerId,
|
||||
payload: { index },
|
||||
});
|
||||
}
|
||||
|
||||
public drop(index: number) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'drop',
|
||||
tracer: this.tracerId,
|
||||
payload: { index },
|
||||
});
|
||||
}
|
||||
|
||||
public patch(index: number, value: T) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'patch',
|
||||
tracer: this.tracerId,
|
||||
payload: { index, value },
|
||||
});
|
||||
}
|
||||
|
||||
public reset(index: number) {
|
||||
const commander = Commander.getInstance();
|
||||
commander.command({
|
||||
action: 'reset',
|
||||
tracer: this.tracerId,
|
||||
payload: { index },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./array-tracer";
|
||||
102
tracers.ts/src/tracers/array-tracer.ts
Normal file
102
tracers.ts/src/tracers/array-tracer.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { getTracerContext } from '../context';
|
||||
import type { JsonValue } from '../types';
|
||||
|
||||
interface ArrayTracerCreateOptions<T extends JsonValue> {
|
||||
description?: string;
|
||||
array?: T[];
|
||||
}
|
||||
|
||||
export const createArrayTracer = <T extends JsonValue>(
|
||||
options: ArrayTracerCreateOptions<T>,
|
||||
) => {
|
||||
const { description = 'ArrayTracer', array } = options;
|
||||
const tracer = crypto.randomUUID();
|
||||
|
||||
const { command } = getTracerContext();
|
||||
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'create',
|
||||
params: {
|
||||
description: description,
|
||||
array: array,
|
||||
},
|
||||
});
|
||||
|
||||
const preset = (array: T[]) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'preset',
|
||||
params: {
|
||||
array: array,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const scale = (size: number) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'scale',
|
||||
params: {
|
||||
size: size,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const pick = (index: number) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'pick',
|
||||
params: {
|
||||
index: index,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const drop = (index: number) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'drop',
|
||||
params: {
|
||||
index: index,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const patch = (index: number, value: T) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'patch',
|
||||
params: {
|
||||
index: index,
|
||||
value: value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const unset = (index: number) => {
|
||||
command({
|
||||
type: 'ArrayTracer',
|
||||
tracer: tracer,
|
||||
action: 'unset',
|
||||
params: {
|
||||
index: index,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
// preset,
|
||||
scale,
|
||||
pick,
|
||||
drop,
|
||||
patch,
|
||||
unset,
|
||||
};
|
||||
};
|
||||
81
tracers.ts/src/tracers/control-tracer.ts
Normal file
81
tracers.ts/src/tracers/control-tracer.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { getTracerContext } from '../context';
|
||||
|
||||
export const getLocation = (targetFn?: Function) => {
|
||||
const stackObject: { stack: string } = { stack: '' };
|
||||
Error.captureStackTrace(stackObject, targetFn ?? getLocation);
|
||||
const { stack } = stackObject;
|
||||
// D:\Projects\structrail-sdk\tracers.ts\src\index.ts:23:18
|
||||
const location = stack.split('\n').at(1)?.trim().split(' ').at(1)?.trim();
|
||||
// console.log(location);
|
||||
if (!location) return null;
|
||||
|
||||
const matches = location?.match(/:(\d+):?(\d+)?\)?$/);
|
||||
// console.log(matches);
|
||||
const file = location?.replace(matches?.at(0) ?? '', '');
|
||||
// console.log(file);
|
||||
const line = parseInt(matches?.at(1) ?? '0');
|
||||
// console.log(line);
|
||||
|
||||
return {
|
||||
file,
|
||||
line,
|
||||
};
|
||||
};
|
||||
|
||||
interface ControlTracerCreateOptions {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export const createControlTracer = (options: ControlTracerCreateOptions) => {
|
||||
const { description = 'ControlTracer' } = options;
|
||||
const tracer = crypto.randomUUID();
|
||||
|
||||
const { command } = getTracerContext();
|
||||
|
||||
command({
|
||||
type: 'ControlTracer',
|
||||
tracer: tracer,
|
||||
action: 'create',
|
||||
params: {
|
||||
description: description,
|
||||
},
|
||||
});
|
||||
|
||||
const step = (...range: (number | [number, number])[]) => {
|
||||
const { line: currentLine } = getLocation(step) ?? {};
|
||||
if (!currentLine) return;
|
||||
console.log(currentLine);
|
||||
|
||||
const linesSet = new Set<number>([currentLine]);
|
||||
range.forEach((item) => {
|
||||
if (Array.isArray(item) && item.length === 2) {
|
||||
const [offsetStart, offsetEnd] = item;
|
||||
const lineStart = currentLine - offsetStart;
|
||||
const lineEnd = currentLine - offsetEnd;
|
||||
const lineMin = Math.min(lineStart, lineEnd);
|
||||
const lineMax = Math.max(lineStart, lineEnd);
|
||||
for (let line = lineMin; line <= lineMax; line++) {
|
||||
linesSet.add(line);
|
||||
}
|
||||
}
|
||||
if (typeof item === 'number') {
|
||||
const line = item;
|
||||
linesSet.add(currentLine - line);
|
||||
}
|
||||
});
|
||||
const lines = Array.from(linesSet).sort((line1, line2) => line1 - line2);
|
||||
|
||||
command({
|
||||
type: 'ControlTracer',
|
||||
tracer: tracer,
|
||||
action: 'step',
|
||||
params: {
|
||||
lines: lines,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
step,
|
||||
};
|
||||
};
|
||||
3
tracers.ts/src/tracers/index.ts
Normal file
3
tracers.ts/src/tracers/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './array-tracer';
|
||||
export * from './control-tracer';
|
||||
export * from './log-tracer';
|
||||
44
tracers.ts/src/tracers/log-tracer.ts
Normal file
44
tracers.ts/src/tracers/log-tracer.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { getTracerContext } from '../context';
|
||||
|
||||
interface LogTracerCreateOptions {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export const createLogTracer = (options: LogTracerCreateOptions) => {
|
||||
const { description = 'LogTracer' } = options;
|
||||
const tracer = crypto.randomUUID();
|
||||
|
||||
const { command } = getTracerContext();
|
||||
|
||||
command({
|
||||
type: 'LogTracer',
|
||||
tracer: tracer,
|
||||
action: 'create',
|
||||
params: {
|
||||
description: description,
|
||||
},
|
||||
});
|
||||
|
||||
const log = (...args: unknown[]) => {
|
||||
const parsed = args.map((arg) => {
|
||||
if (typeof arg === 'string') {
|
||||
return arg;
|
||||
}
|
||||
return JSON.stringify(arg);
|
||||
});
|
||||
const message = parsed.join(' ');
|
||||
|
||||
command({
|
||||
type: 'LogTracer',
|
||||
tracer: tracer,
|
||||
action: 'log',
|
||||
params: {
|
||||
message: message,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
log,
|
||||
};
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { ArrayTracerCommand } from '../command';
|
||||
|
||||
export type ArrayTracerAction = ArrayTracerCommand['action'];
|
||||
|
||||
export type TracerAction = ArrayTracerAction;
|
||||
65
tracers.ts/src/types/array-tracer.ts
Normal file
65
tracers.ts/src/types/array-tracer.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { BaseTracerCommand, JsonValue } from './common';
|
||||
|
||||
type BaseArrayTracerCommand = BaseTracerCommand & {
|
||||
type: 'ArrayTracer';
|
||||
};
|
||||
|
||||
type ArrayTracerCreateCommand = BaseArrayTracerCommand & {
|
||||
action: 'create';
|
||||
params: {
|
||||
description: string;
|
||||
array?: JsonValue[];
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerPresetCommand = BaseArrayTracerCommand & {
|
||||
action: 'preset';
|
||||
params: {
|
||||
array: JsonValue[];
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerScaleCommand = BaseArrayTracerCommand & {
|
||||
action: 'scale';
|
||||
params: {
|
||||
size: number;
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerPickCommand = BaseArrayTracerCommand & {
|
||||
action: 'pick';
|
||||
params: {
|
||||
index: number;
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerDropCommand = BaseArrayTracerCommand & {
|
||||
action: 'drop';
|
||||
params: {
|
||||
index: number;
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerPatchCommand = BaseArrayTracerCommand & {
|
||||
action: 'patch';
|
||||
params: {
|
||||
index: number;
|
||||
value: JsonValue;
|
||||
};
|
||||
};
|
||||
|
||||
type ArrayTracerUnsetCommand = BaseArrayTracerCommand & {
|
||||
action: 'unset';
|
||||
params: {
|
||||
index: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type ArrayTracerCommand =
|
||||
| ArrayTracerCreateCommand
|
||||
| ArrayTracerPresetCommand
|
||||
| ArrayTracerScaleCommand
|
||||
| ArrayTracerPickCommand
|
||||
| ArrayTracerDropCommand
|
||||
| ArrayTracerPatchCommand
|
||||
| ArrayTracerUnsetCommand;
|
||||
8
tracers.ts/src/types/command.ts
Normal file
8
tracers.ts/src/types/command.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { ArrayTracerCommand } from './array-tracer';
|
||||
import type { ControlTracerCommand } from './control-tracer';
|
||||
import type { LogTracerCommand } from './log-tracer';
|
||||
|
||||
export type TracerCommand =
|
||||
| ArrayTracerCommand
|
||||
| LogTracerCommand
|
||||
| ControlTracerCommand;
|
||||
@@ -1,57 +0,0 @@
|
||||
export type ArrayTracerDefineCommand = {
|
||||
action: 'define';
|
||||
tracer: null;
|
||||
payload: { type: 'ArrayTracer'; id: string; desc?: string };
|
||||
};
|
||||
|
||||
export type ArrayTracerPresetCommand<T = unknown> = {
|
||||
action: 'preset';
|
||||
tracer: string;
|
||||
payload: T[];
|
||||
};
|
||||
|
||||
export type ArrayTracerExtendCommand = {
|
||||
action: 'extend';
|
||||
tracer: string;
|
||||
payload: { size: number };
|
||||
};
|
||||
|
||||
export type ArrayTracerShrinkCommand = {
|
||||
action: 'shrink';
|
||||
tracer: string;
|
||||
payload: { size: number };
|
||||
};
|
||||
|
||||
export type ArrayTracerPickCommand = {
|
||||
action: 'pick';
|
||||
tracer: string;
|
||||
payload: { index: number };
|
||||
};
|
||||
|
||||
export type ArrayTracerDropCommand = {
|
||||
action: 'drop';
|
||||
tracer: string;
|
||||
payload: { index: number };
|
||||
};
|
||||
|
||||
export type ArrayTracerPatchCommand<T = unknown> = {
|
||||
action: 'patch';
|
||||
tracer: string;
|
||||
payload: { index: number; value: T };
|
||||
};
|
||||
|
||||
export type ArrayTracerResetCommand = {
|
||||
action: 'reset';
|
||||
tracer: string;
|
||||
payload: { index: number };
|
||||
};
|
||||
|
||||
export type ArrayTracerCommand<T = never> =
|
||||
| ArrayTracerDefineCommand
|
||||
| ArrayTracerPresetCommand<T>
|
||||
| ArrayTracerExtendCommand
|
||||
| ArrayTracerShrinkCommand
|
||||
| ArrayTracerPickCommand
|
||||
| ArrayTracerDropCommand
|
||||
| ArrayTracerPatchCommand<T>
|
||||
| ArrayTracerResetCommand;
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { ArrayTracerCommand } from './array-tracer-command';
|
||||
|
||||
export * from './array-tracer-command';
|
||||
|
||||
export type TracerCommand<T = never> = ArrayTracerCommand<T>;
|
||||
16
tracers.ts/src/types/common.ts
Normal file
16
tracers.ts/src/types/common.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export type JsonValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| JsonValue[]
|
||||
| { [key: string]: JsonValue };
|
||||
|
||||
export type TracerType = 'ArrayTracer' | 'LogTracer' | 'ControlTracer';
|
||||
|
||||
export type TracerId = ReturnType<typeof crypto.randomUUID>;
|
||||
|
||||
export type BaseTracerCommand = {
|
||||
type: TracerType;
|
||||
tracer: TracerId;
|
||||
};
|
||||
23
tracers.ts/src/types/control-tracer.ts
Normal file
23
tracers.ts/src/types/control-tracer.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { BaseTracerCommand } from './common';
|
||||
|
||||
type BaseControlTracerCommand = BaseTracerCommand & {
|
||||
type: 'ControlTracer';
|
||||
};
|
||||
|
||||
type ControlTracerCreateCommand = BaseControlTracerCommand & {
|
||||
action: 'create';
|
||||
params: {
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
|
||||
type ControlTracerStepCommand = BaseControlTracerCommand & {
|
||||
action: 'step';
|
||||
params: {
|
||||
lines: number[];
|
||||
};
|
||||
};
|
||||
|
||||
export type ControlTracerCommand =
|
||||
| ControlTracerCreateCommand
|
||||
| ControlTracerStepCommand;
|
||||
5
tracers.ts/src/types/index.ts
Normal file
5
tracers.ts/src/types/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './array-tracer';
|
||||
export * from './command';
|
||||
export * from './common';
|
||||
export * from './control-tracer';
|
||||
export * from './log-tracer';
|
||||
21
tracers.ts/src/types/log-tracer.ts
Normal file
21
tracers.ts/src/types/log-tracer.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { BaseTracerCommand } from "./common";
|
||||
|
||||
type BaseLogTracerCommand = BaseTracerCommand & {
|
||||
type: 'LogTracer';
|
||||
};
|
||||
|
||||
type LogTracerCreateCommand = BaseLogTracerCommand & {
|
||||
action: 'create';
|
||||
params: {
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
|
||||
type LogTracerLogCommand = BaseLogTracerCommand & {
|
||||
action: 'log';
|
||||
params: {
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type LogTracerCommand = LogTracerCreateCommand | LogTracerLogCommand;
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { ArrayTracerDefineCommand } from '../command';
|
||||
|
||||
type ArrayTracer = ArrayTracerDefineCommand['payload']['type'];
|
||||
|
||||
export type TracerType = ArrayTracer;
|
||||
Reference in New Issue
Block a user