- Unify test data for nonexistence of an object/string and collection. - Introduce more test through adding missing test data to existing tests. - Improve logic for checking absence of values to match tests. - Add missing tests for absent value validation. - Update documentation to include shared test functionality.
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
|
import { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition';
|
|
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
|
|
import { CodePosition } from '../Position/CodePosition';
|
|
import { IUserScriptGenerator } from './IUserScriptGenerator';
|
|
import { IUserScript } from './IUserScript';
|
|
import { ICodeBuilder } from './ICodeBuilder';
|
|
import { ICodeBuilderFactory } from './ICodeBuilderFactory';
|
|
import { CodeBuilderFactory } from './CodeBuilderFactory';
|
|
|
|
export class UserScriptGenerator implements IUserScriptGenerator {
|
|
constructor(private readonly codeBuilderFactory: ICodeBuilderFactory = new CodeBuilderFactory()) {
|
|
|
|
}
|
|
|
|
public buildCode(
|
|
selectedScripts: ReadonlyArray<SelectedScript>,
|
|
scriptingDefinition: IScriptingDefinition,
|
|
): IUserScript {
|
|
if (!selectedScripts) { throw new Error('missing scripts'); }
|
|
if (!scriptingDefinition) { throw new Error('missing definition'); }
|
|
if (!selectedScripts.length) {
|
|
return { code: '', scriptPositions: new Map<SelectedScript, ICodePosition>() };
|
|
}
|
|
let builder = this.codeBuilderFactory.create(scriptingDefinition.language);
|
|
builder = initializeCode(scriptingDefinition.startCode, builder);
|
|
const scriptPositions = selectedScripts.reduce((result, selection) => {
|
|
return appendSelection(selection, result, builder);
|
|
}, new Map<SelectedScript, ICodePosition>());
|
|
const code = finalizeCode(builder, scriptingDefinition.endCode);
|
|
return { code, scriptPositions };
|
|
}
|
|
}
|
|
|
|
function initializeCode(startCode: string, builder: ICodeBuilder): ICodeBuilder {
|
|
if (!startCode) {
|
|
return builder;
|
|
}
|
|
return builder
|
|
.appendLine(startCode)
|
|
.appendLine();
|
|
}
|
|
|
|
function finalizeCode(builder: ICodeBuilder, endCode: string): string {
|
|
if (!endCode) {
|
|
return builder.toString();
|
|
}
|
|
return builder.appendLine()
|
|
.appendLine(endCode)
|
|
.toString();
|
|
}
|
|
|
|
function appendSelection(
|
|
selection: SelectedScript,
|
|
scriptPositions: Map<SelectedScript, ICodePosition>,
|
|
builder: ICodeBuilder,
|
|
): Map<SelectedScript, ICodePosition> {
|
|
// Start from next line because first line will be empty to separate scripts
|
|
const startPosition = builder.currentLine + 1;
|
|
appendCode(selection, builder);
|
|
const endPosition = builder.currentLine - 1;
|
|
builder.appendLine();
|
|
const position = new CodePosition(startPosition, endPosition);
|
|
scriptPositions.set(selection, position);
|
|
return scriptPositions;
|
|
}
|
|
|
|
function appendCode(selection: SelectedScript, builder: ICodeBuilder): ICodeBuilder {
|
|
const { script } = selection;
|
|
const name = selection.revert ? `${script.name} (revert)` : script.name;
|
|
const scriptCode = selection.revert ? script.code.revert : script.code.execute;
|
|
return builder
|
|
.appendLine()
|
|
.appendFunction(name, scriptCode);
|
|
}
|