Files
privacy.sexy/src/application/Context/State/Code/Generation/UserScriptGenerator.ts
undergroundwires 44d79e2c9a Add more and unify tests for absent object cases
- 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.
2022-01-21 22:34:11 +01:00

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);
}