refactor: update the variable interfaces. (#8388)

This commit is contained in:
Aaron Dodson
2024-07-18 11:01:22 -07:00
committed by GitHub
parent 9fa4b2c966
commit 32f8e24337
5 changed files with 97 additions and 49 deletions

View File

@@ -4,8 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {IVariableModel} from './i_variable_model.js';
import {State} from '../serialization/variables.js';
import type {IVariableModel, IVariableState} from './i_variable_model.js';
/**
* Variable maps are container objects responsible for storing and managing the
@@ -14,7 +13,7 @@ import {State} from '../serialization/variables.js';
* Any of these methods may define invariants about which names and types are
* legal, and throw if they are not met.
*/
export interface IVariableMap<T extends IVariableModel, U extends State> {
export interface IVariableMap<T extends IVariableModel<IVariableState>> {
/* Returns the variable corresponding to the given ID, or null if none. */
getVariableById(id: string): T | null;
@@ -46,6 +45,9 @@ export interface IVariableMap<T extends IVariableModel, U extends State> {
*/
createVariable(name: string, id?: string, type?: string | null): T;
/* Adds a variable to this variable map. */
addVariable(variable: T): void;
/**
* Changes the name of the given variable to the name provided and returns the
* renamed variable.
@@ -60,13 +62,4 @@ export interface IVariableMap<T extends IVariableModel, U extends State> {
/* Removes all variables from this variable map. */
clear(): void;
/* Returns an object representing the serialized state of the variable. */
saveVariable(variable: T): U;
/**
* Creates a variable in this variable map corresponding to the given state
* (produced by a call to `saveVariable`).
*/
loadVariable(state: U): T;
}

View File

@@ -4,8 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
import type {Workspace} from '../workspace.js';
/* Representation of a variable. */
export interface IVariableModel {
export interface IVariableModel<T extends IVariableState> {
/* Returns the unique ID of this variable. */
getId(): string;
@@ -23,4 +25,33 @@ export interface IVariableModel {
/* Sets the type of this variable. */
setType(type: string): this;
getWorkspace(): Workspace;
/* Serializes this variable */
save(): T;
}
export interface IVariableModelStatic<T extends IVariableState> {
new (
workspace: Workspace,
name: string,
type?: string,
id?: string,
): IVariableModel<T>;
/**
* Creates a new IVariableModel corresponding to the given state on the
* specified workspace. This method must be static in your implementation.
*/
load(state: T, workspace: Workspace): IVariableModel<T>;
}
/**
* Represents the state of a given variable.
*/
export interface IVariableState {
name: string;
id: string;
type?: string;
}

View File

@@ -24,6 +24,12 @@ import type {IPaster} from './interfaces/i_paster.js';
import type {ICopyData, ICopyable} from './interfaces/i_copyable.js';
import type {IConnectionPreviewer} from './interfaces/i_connection_previewer.js';
import type {IDragger} from './interfaces/i_dragger.js';
import type {
IVariableModel,
IVariableModelStatic,
IVariableState,
} from './interfaces/i_variable_model.js';
import type {IVariableMap} from './interfaces/i_variable_map.js';
/**
* A map of maps. With the keys being the type and name of the class we are
@@ -109,6 +115,14 @@ export class Type<_T> {
/** @internal */
static PASTER = new Type<IPaster<ICopyData, ICopyable<ICopyData>>>('paster');
static VARIABLE_MODEL = new Type<IVariableModelStatic<IVariableState>>(
'variableModel',
);
static VARIABLE_MAP = new Type<IVariableMap<IVariableModel<IVariableState>>>(
'variableMap',
);
}
/**

View File

@@ -7,20 +7,13 @@
// Former goog.module ID: Blockly.serialization.variables
import type {ISerializer} from '../interfaces/i_serializer.js';
import type {IVariableState} from '../interfaces/i_variable_model.js';
import type {Workspace} from '../workspace.js';
import * as priorities from './priorities.js';
import * as registry from '../registry.js';
import * as serializationRegistry from './registry.js';
/**
* Represents the state of a given variable.
*/
export interface State {
name: string;
id: string;
type: string | undefined;
}
/**
* Serializer for saving and loading variable state.
*/
@@ -40,23 +33,9 @@ export class VariableSerializer implements ISerializer {
* @returns The state of the workspace's variables, or null if there are no
* variables.
*/
save(workspace: Workspace): State[] | null {
const variableStates = [];
for (const variable of workspace.getAllVariables()) {
const state = {
'name': variable.name,
'id': variable.getId(),
};
if (variable.type) {
(state as AnyDuringMigration)['type'] = variable.type;
}
variableStates.push(state);
}
// AnyDuringMigration because: Type '{ name: string; id: string; }[] |
// null' is not assignable to type 'State[] | null'.
return (
variableStates.length ? variableStates : null
) as AnyDuringMigration;
save(workspace: Workspace): IVariableState[] | null {
const variableStates = workspace.getAllVariables().map((v) => v.save());
return variableStates.length ? variableStates : null;
}
/**
@@ -66,14 +45,14 @@ export class VariableSerializer implements ISerializer {
* @param state The state of the variables to deserialize.
* @param workspace The workspace to deserialize into.
*/
load(state: State[], workspace: Workspace) {
for (const varState of state) {
workspace.createVariable(
varState['name'],
varState['type'],
varState['id'],
);
}
load(state: IVariableState[], workspace: Workspace) {
const VariableModel = registry.getObject(
registry.Type.VARIABLE_MODEL,
registry.DEFAULT,
);
state.forEach((s) => {
VariableModel?.load(s, workspace);
});
}
/**

View File

@@ -15,8 +15,9 @@
import './events/events_var_create.js';
import * as idGenerator from './utils/idgenerator.js';
import * as registry from './registry.js';
import type {Workspace} from './workspace.js';
import {IVariableModel} from './interfaces/i_variable_model.js';
import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js';
/**
* Class for a variable model.
@@ -24,7 +25,7 @@ import {IVariableModel} from './interfaces/i_variable_model.js';
*
* @see {Blockly.FieldVariable}
*/
export class VariableModel implements IVariableModel {
export class VariableModel implements IVariableModel<IVariableState> {
type: string;
private readonly id_: string;
@@ -95,6 +96,30 @@ export class VariableModel implements IVariableModel {
return this;
}
getWorkspace(): Workspace {
return this.workspace;
}
save(): IVariableState {
const state: IVariableState = {
'name': this.getName(),
'id': this.getId(),
};
const type = this.getType();
if (type) {
state['type'] = type;
}
return state;
}
static load(state: IVariableState, workspace: Workspace) {
// TODO(adodson): Once VariableMap implements IVariableMap, directly
// construct a variable, retrieve the variable map from the workspace,
// add the variable to that variable map, and fire a VAR_CREATE event.
workspace.createVariable(state['name'], state['type'], state['id']);
}
/**
* A custom compare function for the VariableModel objects.
*
@@ -108,3 +133,9 @@ export class VariableModel implements IVariableModel {
return var1.name.localeCompare(var2.name, undefined, {sensitivity: 'base'});
}
}
registry.register(
registry.Type.VARIABLE_MODEL,
registry.DEFAULT,
VariableModel,
);