Fold only items located in root in a JSON editor

Hey there,

I have a use case which I need to fold only the first level of json.

e,g, this json:

{
  "0": {
    "a": 1
  },
  "1": {
    "b": 2
  },
}

I want to folded like this:

{
  {...},
  {...},
}

And not:

{...}

I tried to look at foldEffect/foldInside but i am not sure how it can help and how.

Thanks you very much in advance :pray:

You could walk the syntax tree to find all the lines that start a 1st-level nesting, collect foldEffects for those lines, and dispatch those. For big documents it may be somewhat tricky to get the editor to parse the entire document, but you can use ensureSyntaxTree if you want to force it to do that immediately.

Thanks @marijn for the response.
How can I detect that a node is start a 1st level nesting?

I am doing something like that:

                    syntaxTree(this.editor.state).iterate({
                        from,
                        to,
                        enter: (node) => {
                           //do something here
                        },
                    });

I guess i need to collect them, but how?

How can I detect out of node if it start a 1st-level nesting?

@marijn Sorry for nudging, I really need your help here :pray:

I’m sorry, I don’t have the time or energy to help people write specific code here. I provide the library, I wrote docs, if you can’t take it from there you’ll have to do more studying or hire someone to implement this.

import { syntaxTree, foldEffect } from "@codemirror/language";

function onCollapse() {
  const tree = syntaxTree(cm.state);

  tree.iterate({
    enter(node) {
      const firstChild = node.node.firstChild;
      const lastChild = node.node.lastChild;
      const isObjectOrArray =
        (firstChild?.type.name === "{" && lastChild?.type.name === "}") ||
        (firstChild?.type.name === "[" && lastChild?.type.name === "]");
      const isNestedOneLevel = node.node.parent?.parent?.from === 0;

      if (isObjectOrArray && isNestedOneLevel) {
        cm.dispatch({
          effects: foldEffect.of({
            from: node.from + 1,
            to: node.to - 1,
          }),
        });
      }
    },
  });
};

Thanks @joshw , I managed to solve it with this code:

const foldAllTree = (cm: EditorView) => {
    const effects: any[] = [];
    const from = 0;
    const to = cm.state.doc.length;

    ensureSyntaxTree(cm.state, to, 5000)?.iterate({
        from,
        to,
        enter: (node: SyntaxNodeRef) => {
            const foldRange = foldable(cm.state, node.from, node.to);
            if (foldRange) {
                effects.push(foldEffect.of({ from: foldRange.from, to: foldRange.to }));
            }
        },
    });

    if (effects.length) cm.dispatch({ effects: effects });
};