baldrick-broth
Version:
Build automation tool and task runner
213 lines (190 loc) • 5.15 kB
text/typescript
import json_mask from 'json-mask';
import type {AnyCommand, AnyDataValue, Ctx} from './build-model.js';
import {coloration} from './coloration.js';
import {
setDataValue,
getSupportedProperty,
isTruthy,
isFalsy,
} from './data-value-utils.js';
import {type LogMessage} from './log-model.js';
import {type Result, succeed, willFail} from './railway.js';
import {dasherizeTitle} from './string-utils.js';
import {getStringFromTemplate, mergeTemplateContext} from './templating.js';
type BasicExecution = Result<Ctx, LogMessage>;
const getPropertyList = (
memoryId: string,
ctx: Ctx,
valuePaths: string[]
): Array<AnyDataValue | undefined> =>
valuePaths.map((path) => getSupportedProperty(memoryId, ctx, path));
const asStringOrBlank = (value: unknown): string =>
typeof value === 'string' ? value : '';
const asAnyArray = (value: unknown): AnyDataValue[] =>
Array.isArray(value) ? value : [];
/**
* Create a range starting with stop as other parameters are optional
*/
const range = (stop: number, start = 1, step = 1) => {
const ranged = [];
for (let index = start; index <= stop; index += step) {
ranged.push(index);
}
return ranged;
};
export const basicCommandExecution = (
memoryId: string,
ctx: Ctx,
anyCommand: AnyCommand,
extra: Record<string, any>
): BasicExecution => {
const {a} = anyCommand;
const success: BasicExecution = succeed(ctx);
const name =
anyCommand.name === undefined
? dasherizeTitle(anyCommand.title)
: anyCommand.name;
switch (a) {
case 'get-property': {
const value = getSupportedProperty(memoryId, ctx, anyCommand.value);
setDataValue(memoryId, ctx, name, value);
return success;
}
case 'some-truthy': {
setDataValue(
memoryId,
ctx,
name,
getPropertyList(memoryId, ctx, anyCommand.values).some(isTruthy)
);
return success;
}
case 'some-falsy': {
setDataValue(
memoryId,
ctx,
name,
getPropertyList(memoryId, ctx, anyCommand.values).some(isFalsy)
);
return success;
}
case 'every-truthy': {
setDataValue(
memoryId,
ctx,
name,
getPropertyList(memoryId, ctx, anyCommand.values).every(isTruthy)
);
return success;
}
case 'every-falsy': {
setDataValue(
memoryId,
ctx,
name,
getPropertyList(memoryId, ctx, anyCommand.values).every(isFalsy)
);
return success;
}
case 'not': {
setDataValue(
memoryId,
ctx,
name,
isFalsy(getSupportedProperty(memoryId, ctx, anyCommand.value))
);
return success;
}
case 'split-string': {
setDataValue(
memoryId,
ctx,
name,
asStringOrBlank(
getSupportedProperty(memoryId, ctx, anyCommand.value)
).split(anyCommand.separator)
);
return success;
}
case 'split-lines': {
setDataValue(
memoryId,
ctx,
name,
asStringOrBlank(getSupportedProperty(memoryId, ctx, anyCommand.value))
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0)
);
return success;
}
case 'range': {
setDataValue(
memoryId,
ctx,
name,
range(anyCommand.end, anyCommand.start, anyCommand.step)
);
return success;
}
case 'concat-array': {
setDataValue(
memoryId,
ctx,
name,
getPropertyList(memoryId, ctx, anyCommand.values).flatMap(asAnyArray)
);
return success;
}
case 'mask-object': {
const objectValue =
getSupportedProperty(memoryId, ctx, anyCommand.value) || {};
if (typeof objectValue !== 'object') {
return willFail({
message: `mask-object for path ${
anyCommand.value
} expects an object but got ${typeof objectValue}`,
coloredMessage: `mask-object for path ${coloration.path(
anyCommand.value
)} expects an ${coloration.expected(
'object'
)} but got ${coloration.actual(typeof objectValue)}`,
});
}
const masked = json_mask(objectValue, anyCommand.mask);
setDataValue(memoryId, ctx, name, masked);
return success;
}
case 'template': {
const templateContext = mergeTemplateContext({
memoryId,
ctx,
extra,
command: anyCommand,
});
const stringValue = getStringFromTemplate(
anyCommand.template,
templateContext
);
setDataValue(memoryId, ctx, name, stringValue);
return success;
}
}
return success;
};
/**
* Mostly used for testing purpose
*/
export const basicCommandsExecution = (
memoryId: string,
ctx: Ctx,
anyCommands: AnyCommand[]
): BasicExecution => {
for (const anyCommand of anyCommands) {
const result = basicCommandExecution(memoryId, ctx, anyCommand, {});
if (result.status === 'failure') {
return result;
}
}
return succeed(ctx);
};