Skip to content

Commit

Permalink
Add allowFunctionEvaluation prop.
Browse files Browse the repository at this point in the history
The logic here is a bit heavy. In summary, we need to keep track of whether we generated the `onSubmitValueParser` callback. If we did, then we can respond to changes to `allowFunctionEvaluation`, otherwise we ignore it.

This process moved onSubmitValueParser into `JsonTree`'s state, because we need to be able to modify and store it.
  • Loading branch information
Phanabani committed Jun 30, 2022
1 parent b4beafb commit 961ab09
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 7 deletions.
55 changes: 51 additions & 4 deletions src/JsonTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const propTypes = {
beforeUpdateAction: PropTypes.func,
logger: PropTypes.object,
onSubmitValueParser: PropTypes.func,
allowFunctionEvaluation: PropTypes.bool,
};
// Default props
const defaultProps = {
Expand All @@ -75,21 +76,41 @@ const defaultProps = {
beforeAddAction: (key, keyPath, deep, newValue) => new Promise(resolve => resolve()),
beforeUpdateAction: (key, keyPath, deep, oldValue, newValue) => new Promise(resolve => resolve()),
logger: { error: () => {} },
onSubmitValueParser: (isEditMode, keyPath, deep, name, rawValue) => parse(rawValue),
inputElement: (usage, keyPath, deep, keyName, data, dataType) => <input />,
textareaElement: (usage, keyPath, deep, keyName, data, dataType) => <textarea />,
/* eslint-enable */
/* eslint-enable no-unused-vars */
allowFunctionEvaluation: true,
};

const createParsingFunction = allowFunctionEvaluation =>
(isEditMode, keyPath, deep, name, rawValue) =>
parse(rawValue, allowFunctionEvaluation);

/* ************************************* */
/* ******** COMPONENT ******** */
/* ************************************* */
class JsonTree extends Component {
constructor(props) {
super(props);

let onSubmitValueParser;
// This WasGenerated value lets us know whether we generated the parsing
// function, so we can appropriately react to changes of
// `allowFunctionEvaluation`
let onSubmitValueParserWasGenerated;
if (props.onSubmitValueParser) {
onSubmitValueParser = props.onSubmitValueParser;
onSubmitValueParserWasGenerated = false;
} else {
onSubmitValueParser = createParsingFunction(props.allowFunctionEvaluation);
onSubmitValueParserWasGenerated = true;
}

this.state = {
data: props.data,
rootName: props.rootName,
onSubmitValueParser,
onSubmitValueParserWasGenerated,
};
// Bind
this.onUpdate = this.onUpdate.bind(this);
Expand All @@ -100,6 +121,33 @@ class JsonTree extends Component {
data: nextProps.data,
rootName: nextProps.rootName,
});

let onSubmitValueParserWasGenerated = this.state.onSubmitValueParserWasGenerated;
if (
nextProps.onSubmitValueParser &&
nextProps.onSubmitValueParser !== this.state.onSubmitValueParser
) {
// We just added a new submit value parser, so this is definitely
// not our default parser anymore
onSubmitValueParserWasGenerated = false;
this.setState({
onSubmitValueParser: nextProps.onSubmitValueParser,
onSubmitValueParserWasGenerated,
});
}

if (
onSubmitValueParserWasGenerated &&
nextProps.allowFunctionEvaluation !== this.props.allowFunctionEvaluation
) {
// Create a new submit value parser that adheres to the new
// `allowFunctionEvaluation` value as long as we know the parser
// was generated by us
this.setState({
onSubmitValueParser:
createParsingFunction(nextProps.allowFunctionEvaluation),
});
}
}

onUpdate(key, data) {
Expand All @@ -112,7 +160,7 @@ class JsonTree extends Component {
}

render() {
const { data, rootName } = this.state;
const { data, rootName, onSubmitValueParser } = this.state;
const {
isCollapsed,
onDeltaUpdate,
Expand All @@ -129,7 +177,6 @@ class JsonTree extends Component {
beforeAddAction,
beforeUpdateAction,
logger,
onSubmitValueParser,
} = this.props;

// Node type
Expand Down
10 changes: 7 additions & 3 deletions src/utils/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,16 @@ function createFunction(functionString) {
/**
* Parse a string into either a function or a JSON element.
* @param string {string} string to parse
* @param allowFunctionEvaluation {boolean} whether to parse strings that
* are function definitions as Javascript
* @returns {Function | Object | Array | null | boolean | number | string}
*/
function parse(string) {
function parse(string, allowFunctionEvaluation) {
// Try parsing (and sanitizing) a function
const func = createFunction(string);
if (func !== null) return func;
if (allowFunctionEvaluation) {
const func = createFunction(string);
if (func !== null) return func;
}

try {
return JSON.parse(string);
Expand Down

0 comments on commit 961ab09

Please sign in to comment.