Files
zulip/frontend_tests/node_tests/vdom.js
Anders Kaseorg ac7b09d57e js: Convert _.map(a, …) to a.map(…).
And convert the corresponding function expressions to arrow style
while we’re here.

import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";

const checkExpression = (node: n.Node): node is K.ExpressionKind =>
  n.Expression.check(node);

for (const file of process.argv.slice(2)) {
  console.log("Parsing", file);
  const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
    parser: path.extname(file) === ".ts" ? tsParser : babelParser,
  });
  let changed = false;

  recast.visit(ast, {
    visitCallExpression(path) {
      const { callee, arguments: args } = path.node;
      if (
        n.MemberExpression.check(callee) &&
        !callee.computed &&
        n.Identifier.check(callee.object) &&
        callee.object.name === "_" &&
        n.Identifier.check(callee.property) &&
        callee.property.name === "map" &&
        args.length === 2 &&
        checkExpression(args[0]) &&
        checkExpression(args[1])
      ) {
        const [arr, fn] = args;
        path.replace(
          b.callExpression(b.memberExpression(arr, b.identifier("map")), [
            n.FunctionExpression.check(fn) ||
            n.ArrowFunctionExpression.check(fn)
              ? b.arrowFunctionExpression(
                  fn.params,
                  n.BlockStatement.check(fn.body) &&
                    fn.body.body.length === 1 &&
                    n.ReturnStatement.check(fn.body.body[0])
                    ? fn.body.body[0].argument || b.identifier("undefined")
                    : fn.body
                )
              : fn,
          ])
        );
        changed = true;
      }
      this.traverse(path);
    },
  });

  if (changed) {
    console.log("Writing", file);
    fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
  }
}

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00

274 lines
5.6 KiB
JavaScript

set_global('blueslip', global.make_zblueslip());
zrequire('util');
zrequire('vdom');
run_test('basics', () => {
const opts = {
keyed_nodes: [],
attrs: [
['class', 'foo'],
['title', 'cats & <"dogs">'],
],
};
const ul = vdom.ul(opts);
const html = vdom.render_tag(ul);
assert.equal(
html,
'<ul class="foo" title="cats &amp; &lt;&quot;dogs&quot;&gt;">\n\n' +
'</ul>'
);
});
run_test('attributes', () => {
const opts = {
keyed_nodes: [],
attrs: [
['class', 'same'],
['color', 'blue'],
['id', '101'],
],
};
const ul = vdom.ul(opts);
const html = vdom.render_tag(ul);
assert.equal(
html,
'<ul class="same" color="blue" id="101">\n\n' +
'</ul>'
);
let updated;
let removed;
function find() {
return {
children: () => [],
attr: (k, v) => {
assert.equal(k, 'color');
assert.equal(v, 'red');
updated = true;
},
removeAttr: (k) => {
assert.equal(k, 'id');
removed = true;
},
};
}
const new_opts = {
keyed_nodes: [],
attrs: [
['class', 'same'], // unchanged
['color', 'red'],
],
};
const new_ul = vdom.ul(new_opts);
const replace_content = undefined;
vdom.update(replace_content, find, new_ul, ul);
assert(updated);
assert(removed);
});
function make_child(i, name) {
const render = () => {
return '<li>' + name + '</li>';
};
const eq = (other) => {
return name === other.name;
};
return {
key: i,
render: render,
name: name,
eq: eq,
};
}
function make_children(lst) {
return lst.map(i => make_child(i, 'foo' + i));
}
run_test('children', () => {
let rendered_html;
function replace_content(html) {
rendered_html = html;
}
const find = undefined;
const nodes = make_children([1, 2, 3]);
const opts = {
keyed_nodes: nodes,
attrs: [],
};
const ul = vdom.ul(opts);
vdom.update(replace_content, find, ul);
assert.equal(
rendered_html,
'<ul>\n' +
'<li>foo1</li>\n' +
'<li>foo2</li>\n' +
'<li>foo3</li>\n' +
'</ul>'
);
// Force a complete redraw.
const new_nodes = make_children([4, 5]);
const new_opts = {
keyed_nodes: new_nodes,
attrs: [
['class', 'main'],
],
};
const new_ul = vdom.ul(new_opts);
vdom.update(replace_content, find, new_ul, ul);
assert.equal(
rendered_html,
'<ul class="main">\n' +
'<li>foo4</li>\n' +
'<li>foo5</li>\n' +
'</ul>'
);
});
run_test('partial updates', () => {
let rendered_html;
let replace_content = (html) => {
rendered_html = html;
};
let find;
const nodes = make_children([1, 2, 3]);
const opts = {
keyed_nodes: nodes,
attrs: [],
};
const ul = vdom.ul(opts);
vdom.update(replace_content, find, ul);
assert.equal(
rendered_html,
'<ul>\n' +
'<li>foo1</li>\n' +
'<li>foo2</li>\n' +
'<li>foo3</li>\n' +
'</ul>'
);
replace_content = () => {
throw Error('should not replace entire html');
};
let patched_html;
find = () => {
return {
children: () => {
return {
eq: (i) => {
assert.equal(i, 0);
return {
replaceWith: (html) => {
patched_html = html;
},
};
},
};
},
};
};
const new_nodes = make_children([1, 2, 3]);
new_nodes[0] = make_child(1, 'modified1');
const new_opts = {
keyed_nodes: new_nodes,
attrs: [],
};
const new_ul = vdom.ul(new_opts);
vdom.update(replace_content, find, new_ul, ul);
assert.equal(patched_html, '<li>modified1</li>');
});
run_test('eq_array easy cases', () => {
const bogus_eq = () => {
throw Error('we should not be comparing elements');
};
assert.equal(
vdom.eq_array(undefined, undefined, bogus_eq),
true);
const x = [1, 2, 3];
assert.equal(
vdom.eq_array(x, undefined, bogus_eq),
false);
assert.equal(
vdom.eq_array(undefined, x, bogus_eq),
false);
assert.equal(vdom.eq_array(x, x, bogus_eq), true);
// length check should also short-circuit
const y = [1, 2, 3, 4, 5];
assert.equal(vdom.eq_array(x, y, bogus_eq), false);
// same length, same values, but different order
const eq = (a, b) => a === b;
const z = [3, 2, 1];
assert.equal(vdom.eq_array(x, z, eq), false);
});
run_test('eq_array elementwise', () => {
const a = [51, 32, 93];
const b = [31, 52, 43];
const eq = (a, b) => a % 10 === b % 10;
assert.equal(vdom.eq_array(a, b, eq), true);
});
run_test('error checking', () => {
blueslip.set_test_data(
'error',
'We need keyed_nodes for updates.');
const replace_content = 'whatever';
const find = 'whatever';
const ul = {opts: { attrs: [] }};
vdom.update(replace_content, find, ul, ul);
assert.equal(blueslip.get_test_logs('error').length, 1);
blueslip.set_test_data(
'error',
'We need keyed_nodes to render innards.');
vdom.render_tag(ul);
});