Grabbed dndbeyond's source code

```
~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js
```
This commit is contained in:
2025-05-28 11:50:03 -07:00
commit 8df9031d27
3592 changed files with 319051 additions and 0 deletions
@@ -0,0 +1,134 @@
import { log, LOG_LEVEL } from './utils/log';
var FeaturePreprocessor = /** @class */ (function () {
function FeaturePreprocessor() {
this.featureMap = new Map();
this.statementList = [];
}
FeaturePreprocessor.prototype.process = function (_a) {
var rootFeatureIds = _a.rootFeatureIds, featureMap = _a.featureMap;
this.featureMap = featureMap;
// Add statements from root level features, and their subfeatures.
for (var _i = 0, rootFeatureIds_1 = rootFeatureIds; _i < rootFeatureIds_1.length; _i++) {
var featureId = rootFeatureIds_1[_i];
var feature = featureMap.get(featureId);
if (feature === undefined) {
log(LOG_LEVEL.ERROR, "Feature " + featureId + " not found");
}
else {
this.deriveStatements(feature, null, null);
}
}
return this.statementList;
};
FeaturePreprocessor.prototype.deriveStatements = function (feature, featureReferenceId, parameters) {
for (var _i = 0, _a = feature.statements; _i < _a.length; _i++) {
var statement = _a[_i];
// Make a deep copy of the statement. The copy gets the featureReferenceId set.
// Also, the engine will be modifying the expressions in the statements, so a deep copy is needed.
var statementCopy = JSON.parse(JSON.stringify(statement));
if (featureReferenceId !== null && parameters !== null) {
// targets might be parameterized
statementCopy.target = this.evaluateStatementTarget(statementCopy.target, parameters);
// then dive into the statement's expressions to evaluate parameterized static and dynamic values
this.processExpression(statementCopy.operand, parameters);
}
this.statementList.push(statementCopy);
}
for (var _b = 0, _c = feature.subfeatures; _b < _c.length; _b++) {
var featureReference = _c[_b];
// the featureReference might also be parameterized, in order to pass parameters down multiple levels
var referenceCopy = JSON.parse(JSON.stringify(featureReference)); // copy might not be needed
if (parameters !== null) {
this.processReferenceParameters(referenceCopy.parameters, parameters);
}
var subfeatureDef = this.featureMap.get(referenceCopy.featureId);
if (subfeatureDef === undefined) {
log(LOG_LEVEL.ERROR, "Feature " + referenceCopy.featureId + " not found");
}
else {
this.deriveStatements(subfeatureDef, referenceCopy.featureReferenceId, referenceCopy.parameters);
}
}
};
FeaturePreprocessor.prototype.evaluateStatementTarget = function (target, parameters) {
var newTargetList = [];
for (var i = 0; i < target.length; i++) {
var part = target[i];
if (typeof part === 'string' && part.startsWith('$inputs.')) {
var evaluated = this.lookupInput(part, parameters);
if (evaluated === null || evaluated.some(function (x) { return typeof x !== 'string'; })) {
throw new Error('Parameter values for dynamic targets must be strings');
}
newTargetList.push.apply(newTargetList, evaluated);
}
else {
newTargetList.push(part);
}
}
return newTargetList;
};
// Some duplicated code here. The difference is that targets must be strings,
// while expression parameters might be numbers.
FeaturePreprocessor.prototype.evaluateExpressionValues = function (values, parameters) {
// An array of strings might turn into an array of numbers, if the parameter values are numbers.
// I don't like this :O
var evaluatedValues = [];
for (var i = 0; i < values.length; i++) {
var part = values[i];
if (typeof part === 'string' && part.startsWith('$inputs.')) {
var evaluated = this.lookupInput(part, parameters);
if (evaluated === null) {
throw new Error('Parameter values for static or dynamic values cannot be null');
}
evaluatedValues.push.apply(evaluatedValues, evaluated);
}
else {
evaluatedValues.push(part);
}
}
if (evaluatedValues.every(function (x) { return typeof x === 'string'; })) {
return evaluatedValues;
}
if (evaluatedValues.every(function (x) { return typeof x === 'number'; })) {
return evaluatedValues;
}
throw new Error('Parameter value type needs to match the type of non-parameterized values');
};
FeaturePreprocessor.prototype.lookupInput = function (inputName, parameters) {
var splits = inputName.split('$inputs.');
if (splits.length !== 2) {
throw new Error('Invalid $inputs format');
}
var key = splits[1];
if (!parameters.hasOwnProperty(key)) {
throw new Error("Parameters is missing key " + key);
}
return parameters[key]; // TODO: Check to make sure the parameter is there
};
FeaturePreprocessor.prototype.processExpression = function (expression, parameters) {
// If the expression has values, evaluate any $inputs
if (expression.values !== null && expression.values.length) {
expression.values = this.evaluateExpressionValues(expression.values, parameters);
}
// If the expression has operands, recurse!
if (expression.operands !== null && expression.operands.length) {
for (var _i = 0, _a = expression.operands; _i < _a.length; _i++) {
var operand = _a[_i];
this.processExpression(operand, parameters);
}
}
};
FeaturePreprocessor.prototype.processReferenceParameters = function (childParameters, parentParameters) {
// FeatureParameters is Record<string, Array<string> | Array<number> | null>
var parameterKeys = Object.keys(childParameters);
for (var _i = 0, parameterKeys_1 = parameterKeys; _i < parameterKeys_1.length; _i++) {
var key = parameterKeys_1[_i];
var parameterValues = childParameters[key];
if (parameterValues !== null) {
childParameters[key] = this.evaluateExpressionValues(parameterValues, parentParameters);
}
}
};
return FeaturePreprocessor;
}());
export { FeaturePreprocessor };
@@ -0,0 +1,320 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import pkg from 'lodash';
import { ExpressionOperators } from './types';
import { log, LOG_LEVEL } from './utils/log';
var get = pkg.get, set = pkg.set;
var ADDITIVE_IDENTITY = 0;
var MULTIPLICATIVE_IDENTITY = 1;
var ValueUnavailble = /** @class */ (function (_super) {
__extends(ValueUnavailble, _super);
function ValueUnavailble(message) {
return _super.call(this, message) || this;
}
return ValueUnavailble;
}(Error));
function add(state, operands) {
var sum = ADDITIVE_IDENTITY;
for (var _i = 0, operands_1 = operands; _i < operands_1.length; _i++) {
var operand = operands_1[_i];
var value = Number(run(state, operand));
log(LOG_LEVEL.INFO, ExpressionOperators.ADD + ": value " + value);
if (isNaN(value)) {
log(LOG_LEVEL.WARN, ExpressionOperators.ADD + ": This was not a number");
}
else {
sum += value;
}
}
log(LOG_LEVEL.INFO, ExpressionOperators.ADD + ": result " + sum);
return sum;
}
function multiply(state, operands) {
var product = MULTIPLICATIVE_IDENTITY;
for (var _i = 0, operands_2 = operands; _i < operands_2.length; _i++) {
var operand = operands_2[_i];
var value = Number(run(state, operand));
log(LOG_LEVEL.INFO, ExpressionOperators.ADD + ": value " + value);
if (isNaN(value)) {
log(LOG_LEVEL.WARN, ExpressionOperators.ADD + ": This was not a number");
}
else {
product *= value;
}
}
log(LOG_LEVEL.INFO, ExpressionOperators.MULTIPLY + ": result " + product);
return product;
}
function keepHighest() {
var rest = [];
for (var _i = 0; _i < arguments.length; _i++) {
rest[_i] = arguments[_i];
}
log(LOG_LEVEL.INFO, "KEEP HIGHEST: options " + String(rest));
var result = Math.max.apply(Math, rest.filter(function (x) { return !isNaN(x); }));
log(LOG_LEVEL.INFO, "KEEP HIGHEST: result " + result);
return result;
}
function min(state, operands) {
var options = operands.map(function (x) { return run(state, x); });
log(LOG_LEVEL.INFO, ExpressionOperators.MIN + ": options " + String(options));
var restult = Math.min.apply(Math, options);
log(LOG_LEVEL.INFO, ExpressionOperators.MIN + ": result " + restult);
return restult;
}
function max(state, operands) {
var options = operands.map(function (x) { return run(state, x); });
log(LOG_LEVEL.INFO, ExpressionOperators.MAX + ": options " + String(options));
var restult = Math.max.apply(Math, options);
log(LOG_LEVEL.INFO, ExpressionOperators.MAX + ": result " + restult);
return restult;
}
function getNestedValue(state, path) {
return get(state, path);
}
function setNestedValue(state, path, value) {
if (isNaN(value)) {
throw new Error("Value " + value + " is not a number");
}
set(state, path, value);
}
function dynamicValue(state, key) {
key = key.flatMap(function (x) { return x.split('.'); });
log(LOG_LEVEL.INFO, ExpressionOperators.DYNAMIC_VALUE + ": key " + key);
if (!getNestedValue(state, key)) {
throw new ValueUnavailble('key not available');
}
var result = getNestedValue(state, key);
log(LOG_LEVEL.INFO, ExpressionOperators.DYNAMIC_VALUE + ": result " + result);
return result;
}
function floor(state, operand) {
return Math.floor(run(state, operand[0]));
}
function run(state, operand) {
var result;
switch (operand.operator) {
case ExpressionOperators.STATIC_VALUE: {
var values = operand.values;
if (!Array.isArray(values)) {
throw new Error('STATIC_VALUE has to be an array');
}
if (!values[0]) {
throw new Error('STATIC_VALUE must have a value for index 0');
}
result = values[0];
break;
}
case ExpressionOperators.DYNAMIC_VALUE: {
var values = operand.values;
if (!Array.isArray(values) || values.some(function (v) { return typeof v !== 'string'; })) {
throw new Error('DYNAMIC_VALUE has to be array of string');
}
if (!values[0]) {
throw new Error('DYNAMIC_VALUE must have a value for index 0');
}
result = dynamicValue(state, values);
break;
}
case ExpressionOperators.ADD:
if (!Array.isArray(operand.operands)) {
throw new Error('ADD only supports an array');
}
result = add(state, operand.operands);
break;
case ExpressionOperators.MIN:
if (!Array.isArray(operand.operands)) {
throw new Error('MIN only supports an array');
}
result = min(state, operand.operands);
break;
case ExpressionOperators.MAX:
if (!Array.isArray(operand.operands)) {
throw new Error('MAX only supports an array');
}
result = max(state, operand.operands);
break;
case ExpressionOperators.FLOOR:
if (!Array.isArray(operand.operands)) {
throw new Error('FLOOR not correct format');
}
result = floor(state, operand.operands);
break;
case ExpressionOperators.MULTIPLY:
if (!Array.isArray(operand.operands)) {
throw new Error('MULTIPLY only supports an array');
}
result = multiply(state, operand.operands);
break;
default:
throw new Error("run: Unknown operator " + operand.operator);
}
log(LOG_LEVEL.INFO, "Performing " + operand.operator + " :> Result " + result);
return result;
}
function determineRequirements(operand) {
switch (operand.operator) {
case 'DYNAMIC_VALUE':
if (!operand.values) {
throw new Error('DYNAMIC_VALUE reqires values');
}
return [operand.values.join('.')];
case 'STATIC_VALUE':
return [];
case 'MAX':
case 'MIN':
case 'ADD':
case 'MULTIPLY':
case 'FLOOR':
if (!Array.isArray(operand.operands)) {
throw new Error('no operands array');
}
var dynamicValueKeys = [];
for (var _i = 0, _a = operand.operands; _i < _a.length; _i++) {
var childOperand = _a[_i];
dynamicValueKeys = dynamicValueKeys.concat(determineRequirements(childOperand));
}
return dynamicValueKeys;
default:
throw new Error("determineRequirements: Unknown operator " + operand.operator);
}
}
function getRequiremets(expression) {
if (!expression.operand) {
throw new Error('getRequiremets: no operands');
}
var requirements = determineRequirements(expression.operand);
return requirements.filter(function (x) { return x !== expression.target.join('.'); });
}
export function runProgram(_a) {
var _b;
var initState = _a.state, initExpressions = _a.expressions, initTargetResolutionPolicies = _a.targetResolutionPolicies, _c = _a.forceRun, forceRun = _c === void 0 ? false : _c;
var state = initState !== null && initState !== void 0 ? initState : {};
var expressions = initExpressions !== null && initExpressions !== void 0 ? initExpressions : [];
var targetResolutionPolicies = initTargetResolutionPolicies !== null && initTargetResolutionPolicies !== void 0 ? initTargetResolutionPolicies : {};
var reprocess = [];
var _loop_1 = function (expression) {
try {
var requirements_1 = getRequiremets(expression);
log(LOG_LEVEL.INFO, expression.target + " requires " + requirements_1);
var shouldWait = expressions.filter(function (x) { return x !== expression; }).some(function (x) { return requirements_1.includes(x.target.join('.')); }) ||
requirements_1.some(function (x) { return !getNestedValue(state, x.split('.')); });
log(LOG_LEVEL.ERROR, "Can process " + ((_b = expression.statementId) !== null && _b !== void 0 ? _b : 'id') + " -> " + expression.target + " :> " + (shouldWait ? 'Not yet' : 'Yes'));
if (!forceRun && shouldWait) {
log(LOG_LEVEL.WARN, "Forcing " + expression.target + " to process");
reprocess.push(expression);
}
else {
var result = run(state, expression.operand);
if (targetResolutionPolicies.hasOwnProperty(expression.target.join('.'))) {
switch (targetResolutionPolicies[expression.target.join('.')]) {
case 'KEEP_HIGHEST':
setNestedValue(state, expression.target, keepHighest(getNestedValue(state, expression.target), result));
break;
default:
throw new Error('resolution policy not implemented');
}
}
else {
log(LOG_LEVEL.INFO, "Applying " + expression.target + " = " + result);
setNestedValue(state, expression.target, result);
}
}
}
catch (err) {
if (err instanceof ValueUnavailble) {
reprocess.push(expression);
}
else {
}
}
};
for (var _i = 0, expressions_1 = expressions; _i < expressions_1.length; _i++) {
var expression = expressions_1[_i];
_loop_1(expression);
}
if (!forceRun && reprocess.length && reprocess.length === expressions.length) {
// throw new Error('cannot resolve'); // Tthis is a circular dependency so just run now
return runProgram({ state: state, expressions: reprocess, targetResolutionPolicies: targetResolutionPolicies, forceRun: true });
}
if (!forceRun && reprocess.length) {
return runProgram({ state: state, expressions: reprocess, targetResolutionPolicies: targetResolutionPolicies });
}
return state;
}
export function initProgram(_a) {
var _b;
var initState = _a.state, initExpressions = _a.expressions, initTargetResolutionPolicies = _a.targetResolutionPolicies;
var state = initState !== null && initState !== void 0 ? initState : {};
var statements = initExpressions !== null && initExpressions !== void 0 ? initExpressions : [];
var targetResolutionPolicies = initTargetResolutionPolicies !== null && initTargetResolutionPolicies !== void 0 ? initTargetResolutionPolicies : {};
//TODO: consider a init program to run once
// const sorted = expressions.sort((a: Statement, b: Statement) => (a?.precedence ?? 0) - (b?.precedence ?? 0));
var getSections = function () { return ({
noDynamicValues: [],
onlySelfDynamics: [],
complexDynamics: [],
}); };
var statementMap = {};
for (var i = 0; i < statements.length; i++) {
var statement = statements[i];
var reqs = determineRequirements(statement.operand);
statementMap[statement.precedence] = (_b = statementMap[statement.precedence]) !== null && _b !== void 0 ? _b : getSections();
var sections = statementMap[statement.precedence];
if (reqs.length === 0) {
sections.noDynamicValues.push(statement);
}
else if (reqs.length === 1 && reqs.includes(statement.target.join('.'))) {
sections.onlySelfDynamics.push(statement);
}
else if (reqs.length > 1 && reqs.includes(statement.target.join('.'))) {
sections.onlySelfDynamics.push(statement);
}
else {
sections.complexDynamics.push(statement);
}
}
// const sections = sorted.reduce(
// (sections, expression) => {
// const reqs = determineRequirements(expression.operand);
// if (reqs.length === 0) {
// sections.noDynamicValues.push(expression);
// } else if (reqs.length === 1 && reqs.includes(expression.target)) {
// sections.onlySelfDynamics.push(expression);
// } else {
// sections.complexDynamics.push(expression);
// }
// return sections;
// },
// {
// noDynamicValues: [] as Statement[],
// onlySelfDynamics: [] as Statement[],
// complexDynamics: [] as Statement[],
// },
// );
var precedences = Object.keys(statementMap).sort(function (a, b) { return Number(a) - Number(b); });
for (var i = 0; i < precedences.length; i++) {
var precedence = Number(precedences[i]);
var precedenceMap = statementMap[precedence];
state = runProgram({ state: state, expressions: precedenceMap.noDynamicValues, targetResolutionPolicies: targetResolutionPolicies });
state = runProgram({ state: state, expressions: precedenceMap.onlySelfDynamics, targetResolutionPolicies: targetResolutionPolicies });
state = runProgram({ state: state, expressions: precedenceMap.complexDynamics, targetResolutionPolicies: targetResolutionPolicies });
}
log(LOG_LEVEL.INFO, 'STATE:');
log(LOG_LEVEL.INFO, JSON.stringify(state, null, 2));
return state;
}
// runProgram(dynamicAddTest);
+11
View File
@@ -0,0 +1,11 @@
import { FeaturePreprocessor } from './FeaturePreprocessor';
import { initProgram } from './LoopResolutionCalculator';
export * from './types';
export function generateCharacterState(_a) {
var rootFeatureIds = _a.rootFeatureIds, featureMap = _a.featureMap;
var derivedStatements = new FeaturePreprocessor().process({ rootFeatureIds: rootFeatureIds, featureMap: featureMap });
var state = initProgram({
expressions: derivedStatements,
});
return state;
}
+15
View File
@@ -0,0 +1,15 @@
export var ExpressionOperators;
(function (ExpressionOperators) {
ExpressionOperators["ADD"] = "ADD";
ExpressionOperators["MIN"] = "MIN";
ExpressionOperators["MAX"] = "MAX";
ExpressionOperators["FLOOR"] = "FLOOR";
ExpressionOperators["MULTIPLY"] = "MULTIPLY";
ExpressionOperators["DYNAMIC_VALUE"] = "DYNAMIC_VALUE";
ExpressionOperators["STATIC_VALUE"] = "STATIC_VALUE";
})(ExpressionOperators || (ExpressionOperators = {}));
export var StatementOperators;
(function (StatementOperators) {
StatementOperators["SET"] = "SET";
StatementOperators["PUSH"] = "PUSH";
})(StatementOperators || (StatementOperators = {}));
+46
View File
@@ -0,0 +1,46 @@
export var LOG_LEVEL;
(function (LOG_LEVEL) {
LOG_LEVEL[LOG_LEVEL["INFO"] = 0] = "INFO";
LOG_LEVEL[LOG_LEVEL["WARN"] = 1] = "WARN";
LOG_LEVEL[LOG_LEVEL["ERROR"] = 2] = "ERROR";
LOG_LEVEL[LOG_LEVEL["NONE"] = 3] = "NONE";
})(LOG_LEVEL || (LOG_LEVEL = {}));
var logLevel = LOG_LEVEL.NONE;
export function log(level, msg) {
if (process.env.NODE_ENV === 'development') {
if (level >= logLevel) {
switch (level) {
case LOG_LEVEL.INFO: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #aaaaff11; color: #00aaff');
break;
}
case LOG_LEVEL.WARN: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #aaffff11; color: #ffffaa');
break;
}
case LOG_LEVEL.ERROR: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #ffaaaa11; color: #ff5555');
break;
}
}
}
}
if (process.env.NODE_ENV === 'test') {
if (level >= logLevel) {
switch (level) {
case LOG_LEVEL.INFO: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #aaaaff11; color: #00aaff');
break;
}
case LOG_LEVEL.WARN: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #aaffff11; color: #ffffaa');
break;
}
case LOG_LEVEL.ERROR: {
console.log("%c FEATURE ENGINE :> " + msg + " ", 'background: #ffaaaa11; color: #ff5555');
break;
}
}
}
}
}