Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: update the variable interfaces. #8388

Merged
merged 1 commit into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions core/interfaces/i_variable_map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand All @@ -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;
gonfunko marked this conversation as resolved.
Show resolved Hide resolved

/**
* Creates a variable in this variable map corresponding to the given state
* (produced by a call to `saveVariable`).
*/
loadVariable(state: U): T;
}
33 changes: 32 additions & 1 deletion core/interfaces/i_variable_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
14 changes: 14 additions & 0 deletions core/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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',
);
}

/**
Expand Down
47 changes: 13 additions & 34 deletions core/serialization/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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;
}

/**
Expand All @@ -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);
});
}

/**
Expand Down
35 changes: 33 additions & 2 deletions core/variable_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
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.
* Holds information for the variable including name, ID, and type.
*
* @see {Blockly.FieldVariable}
*/
export class VariableModel implements IVariableModel {
export class VariableModel implements IVariableModel<IVariableState> {
type: string;
private readonly id_: string;

Expand Down Expand Up @@ -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
gonfunko marked this conversation as resolved.
Show resolved Hide resolved
// 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.
*
Expand All @@ -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,
);
Loading