[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"sourceType\": \"module\",\n    \"ecmaVersion\": 8\n  },\n  \"env\": {\n    \"es6\": true\n  },\n  \"rules\": {\n    \"no-cond-assign\": 0\n  }\n}\n"
  },
  {
    "path": ".github/eslint.json",
    "content": "{\n  \"problemMatcher\": [\n    {\n      \"owner\": \"eslint-compact\",\n      \"pattern\": [\n        {\n          \"regexp\": \"^(.+):\\\\sline\\\\s(\\\\d+),\\\\scol\\\\s(\\\\d+),\\\\s(Error|Warning|Info)\\\\s-\\\\s(.+)\\\\s\\\\((.+)\\\\)$\",\n          \"file\": 1,\n          \"line\": 2,\n          \"column\": 3,\n          \"severity\": 4,\n          \"message\": 5,\n          \"code\": 6\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/workflows/node.js.yml",
    "content": "# https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [14.x]\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - run: yarn --frozen-lockfile\n    - run: |\n        echo ::add-matcher::.github/eslint.json\n        yarn run eslint src test --format=compact\n    - run: yarn test\n"
  },
  {
    "path": ".gitignore",
    "content": "*.sublime-workspace\n.DS_Store\ndist/\nnode_modules\nnpm-debug.log\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2010-2021 Mike Bostock\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\nOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\nTORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\nTHIS SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# d3-transition\n\n<a href=\"https://d3js.org\"><img src=\"https://github.com/d3/d3/raw/main/docs/public/logo.svg\" width=\"256\" height=\"256\"></a>\n\nA transition is a [selection](https://github.com/d3/d3-selection)-like interface for animating changes to the DOM. Instead of applying changes instantaneously, transitions smoothly interpolate the DOM from its current state to the desired target state over a given duration.\n\n## Resources\n\n- [Documentation](https://d3js.org/d3-transition)\n- [Examples](https://observablehq.com/collection/@d3/d3-transition)\n- [Releases](https://github.com/d3/d3-transition/releases)\n- [Getting help](https://d3js.org/community)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"d3-transition\",\n  \"version\": \"3.0.1\",\n  \"description\": \"Animated transitions for D3 selections.\",\n  \"homepage\": \"https://d3js.org/d3-transition/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/d3/d3-transition.git\"\n  },\n  \"keywords\": [\n    \"d3\",\n    \"d3-module\",\n    \"dom\",\n    \"transition\",\n    \"animation\"\n  ],\n  \"license\": \"ISC\",\n  \"author\": {\n    \"name\": \"Mike Bostock\",\n    \"url\": \"https://bost.ocks.org/mike\"\n  },\n  \"type\": \"module\",\n  \"files\": [\n    \"dist/**/*.js\",\n    \"src/**/*.js\"\n  ],\n  \"module\": \"src/index.js\",\n  \"main\": \"src/index.js\",\n  \"jsdelivr\": \"dist/d3-transition.min.js\",\n  \"unpkg\": \"dist/d3-transition.min.js\",\n  \"exports\": {\n    \"umd\": \"./dist/d3-transition.min.js\",\n    \"default\": \"./src/index.js\"\n  },\n  \"sideEffects\": [\n    \"./src/index.js\",\n    \"./src/selection/index.js\"\n  ],\n  \"dependencies\": {\n    \"d3-color\": \"1 - 3\",\n    \"d3-dispatch\": \"1 - 3\",\n    \"d3-ease\": \"1 - 3\",\n    \"d3-interpolate\": \"1 - 3\",\n    \"d3-timer\": \"1 - 3\"\n  },\n  \"devDependencies\": {\n    \"d3-selection\": \"2 - 3\",\n    \"eslint\": \"7\",\n    \"jsdom\": \"16\",\n    \"mocha\": \"9\",\n    \"rollup\": \"2\",\n    \"rollup-plugin-terser\": \"7\"\n  },\n  \"scripts\": {\n    \"test\": \"mocha 'test/**/*-test.js' && eslint src test\",\n    \"prepublishOnly\": \"rm -rf dist && yarn test && rollup -c && git push\",\n    \"postpublish\": \"git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \\\"${npm_package_name} ${npm_package_version}\\\" && git push && cd -\"\n  },\n  \"engines\": {\n    \"node\": \">=12\"\n  },\n  \"peerDependencies\": {\n    \"d3-selection\": \"2 - 3\"\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import {readFileSync} from \"fs\";\nimport {terser} from \"rollup-plugin-terser\";\nimport * as meta from \"./package.json\";\n\n// Extract copyrights from the LICENSE.\nconst copyright = readFileSync(\"./LICENSE\", \"utf-8\")\n  .split(/\\n/g)\n  .filter(line => /^Copyright\\s+/.test(line))\n  .map(line => line.replace(/^Copyright\\s+/, \"\"))\n  .join(\", \");\n\nconst config = {\n  input: \"src/index.js\",\n  external: Object.keys({...meta.dependencies, ...meta.peerDependencies}).filter(key => /^d3-/.test(key)),\n  output: {\n    file: `dist/${meta.name}.js`,\n    name: \"d3\",\n    format: \"umd\",\n    indent: false,\n    extend: true,\n    banner: `// ${meta.homepage} v${meta.version} Copyright ${copyright}`,\n    globals: Object.assign({}, ...Object.keys({...meta.dependencies, ...meta.peerDependencies}).filter(key => /^d3-/.test(key)).map(key => ({[key]: \"d3\"})))\n  },\n  plugins: [],\n  onwarn(message, warn) {\n    if (message.code === \"CIRCULAR_DEPENDENCY\") return;\n    warn(message);\n  }\n};\n\nexport default [\n  config,\n  {\n    ...config,\n    output: {\n      ...config.output,\n      file: `dist/${meta.name}.min.js`\n    },\n    plugins: [\n      ...config.plugins,\n      terser({\n        output: {\n          preamble: config.output.banner\n        }\n      })\n    ]\n  }\n];\n"
  },
  {
    "path": "src/active.js",
    "content": "import {Transition} from \"./transition/index.js\";\nimport {SCHEDULED} from \"./transition/schedule.js\";\n\nvar root = [null];\n\nexport default function(node, name) {\n  var schedules = node.__transition,\n      schedule,\n      i;\n\n  if (schedules) {\n    name = name == null ? null : name + \"\";\n    for (i in schedules) {\n      if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {\n        return new Transition([[node]], root, name, +i);\n      }\n    }\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import \"./selection/index.js\";\nexport {default as transition} from \"./transition/index.js\";\nexport {default as active} from \"./active.js\";\nexport {default as interrupt} from \"./interrupt.js\";\n"
  },
  {
    "path": "src/interrupt.js",
    "content": "import {STARTING, ENDING, ENDED} from \"./transition/schedule.js\";\n\nexport default function(node, name) {\n  var schedules = node.__transition,\n      schedule,\n      active,\n      empty = true,\n      i;\n\n  if (!schedules) return;\n\n  name = name == null ? null : name + \"\";\n\n  for (i in schedules) {\n    if ((schedule = schedules[i]).name !== name) { empty = false; continue; }\n    active = schedule.state > STARTING && schedule.state < ENDING;\n    schedule.state = ENDED;\n    schedule.timer.stop();\n    schedule.on.call(active ? \"interrupt\" : \"cancel\", node, node.__data__, schedule.index, schedule.group);\n    delete schedules[i];\n  }\n\n  if (empty) delete node.__transition;\n}\n"
  },
  {
    "path": "src/selection/index.js",
    "content": "import {selection} from \"d3-selection\";\nimport selection_interrupt from \"./interrupt.js\";\nimport selection_transition from \"./transition.js\";\n\nselection.prototype.interrupt = selection_interrupt;\nselection.prototype.transition = selection_transition;\n"
  },
  {
    "path": "src/selection/interrupt.js",
    "content": "import interrupt from \"../interrupt.js\";\n\nexport default function(name) {\n  return this.each(function() {\n    interrupt(this, name);\n  });\n}\n"
  },
  {
    "path": "src/selection/transition.js",
    "content": "import {Transition, newId} from \"../transition/index.js\";\nimport schedule from \"../transition/schedule.js\";\nimport {easeCubicInOut} from \"d3-ease\";\nimport {now} from \"d3-timer\";\n\nvar defaultTiming = {\n  time: null, // Set on use.\n  delay: 0,\n  duration: 250,\n  ease: easeCubicInOut\n};\n\nfunction inherit(node, id) {\n  var timing;\n  while (!(timing = node.__transition) || !(timing = timing[id])) {\n    if (!(node = node.parentNode)) {\n      throw new Error(`transition ${id} not found`);\n    }\n  }\n  return timing;\n}\n\nexport default function(name) {\n  var id,\n      timing;\n\n  if (name instanceof Transition) {\n    id = name._id, name = name._name;\n  } else {\n    id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + \"\";\n  }\n\n  for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n      if (node = group[i]) {\n        schedule(node, name, id, i, group, timing || inherit(node, id));\n      }\n    }\n  }\n\n  return new Transition(groups, this._parents, name, id);\n}\n"
  },
  {
    "path": "src/transition/attr.js",
    "content": "import {interpolateTransformSvg as interpolateTransform} from \"d3-interpolate\";\nimport {namespace} from \"d3-selection\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction attrRemove(name) {\n  return function() {\n    this.removeAttribute(name);\n  };\n}\n\nfunction attrRemoveNS(fullname) {\n  return function() {\n    this.removeAttributeNS(fullname.space, fullname.local);\n  };\n}\n\nfunction attrConstant(name, interpolate, value1) {\n  var string00,\n      string1 = value1 + \"\",\n      interpolate0;\n  return function() {\n    var string0 = this.getAttribute(name);\n    return string0 === string1 ? null\n        : string0 === string00 ? interpolate0\n        : interpolate0 = interpolate(string00 = string0, value1);\n  };\n}\n\nfunction attrConstantNS(fullname, interpolate, value1) {\n  var string00,\n      string1 = value1 + \"\",\n      interpolate0;\n  return function() {\n    var string0 = this.getAttributeNS(fullname.space, fullname.local);\n    return string0 === string1 ? null\n        : string0 === string00 ? interpolate0\n        : interpolate0 = interpolate(string00 = string0, value1);\n  };\n}\n\nfunction attrFunction(name, interpolate, value) {\n  var string00,\n      string10,\n      interpolate0;\n  return function() {\n    var string0, value1 = value(this), string1;\n    if (value1 == null) return void this.removeAttribute(name);\n    string0 = this.getAttribute(name);\n    string1 = value1 + \"\";\n    return string0 === string1 ? null\n        : string0 === string00 && string1 === string10 ? interpolate0\n        : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n  };\n}\n\nfunction attrFunctionNS(fullname, interpolate, value) {\n  var string00,\n      string10,\n      interpolate0;\n  return function() {\n    var string0, value1 = value(this), string1;\n    if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);\n    string0 = this.getAttributeNS(fullname.space, fullname.local);\n    string1 = value1 + \"\";\n    return string0 === string1 ? null\n        : string0 === string00 && string1 === string10 ? interpolate0\n        : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n  };\n}\n\nexport default function(name, value) {\n  var fullname = namespace(name), i = fullname === \"transform\" ? interpolateTransform : interpolate;\n  return this.attrTween(name, typeof value === \"function\"\n      ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, \"attr.\" + name, value))\n      : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname)\n      : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));\n}\n"
  },
  {
    "path": "src/transition/attrTween.js",
    "content": "import {namespace} from \"d3-selection\";\n\nfunction attrInterpolate(name, i) {\n  return function(t) {\n    this.setAttribute(name, i.call(this, t));\n  };\n}\n\nfunction attrInterpolateNS(fullname, i) {\n  return function(t) {\n    this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));\n  };\n}\n\nfunction attrTweenNS(fullname, value) {\n  var t0, i0;\n  function tween() {\n    var i = value.apply(this, arguments);\n    if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);\n    return t0;\n  }\n  tween._value = value;\n  return tween;\n}\n\nfunction attrTween(name, value) {\n  var t0, i0;\n  function tween() {\n    var i = value.apply(this, arguments);\n    if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);\n    return t0;\n  }\n  tween._value = value;\n  return tween;\n}\n\nexport default function(name, value) {\n  var key = \"attr.\" + name;\n  if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n  if (value == null) return this.tween(key, null);\n  if (typeof value !== \"function\") throw new Error;\n  var fullname = namespace(name);\n  return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));\n}\n"
  },
  {
    "path": "src/transition/delay.js",
    "content": "import {get, init} from \"./schedule.js\";\n\nfunction delayFunction(id, value) {\n  return function() {\n    init(this, id).delay = +value.apply(this, arguments);\n  };\n}\n\nfunction delayConstant(id, value) {\n  return value = +value, function() {\n    init(this, id).delay = value;\n  };\n}\n\nexport default function(value) {\n  var id = this._id;\n\n  return arguments.length\n      ? this.each((typeof value === \"function\"\n          ? delayFunction\n          : delayConstant)(id, value))\n      : get(this.node(), id).delay;\n}\n"
  },
  {
    "path": "src/transition/duration.js",
    "content": "import {get, set} from \"./schedule.js\";\n\nfunction durationFunction(id, value) {\n  return function() {\n    set(this, id).duration = +value.apply(this, arguments);\n  };\n}\n\nfunction durationConstant(id, value) {\n  return value = +value, function() {\n    set(this, id).duration = value;\n  };\n}\n\nexport default function(value) {\n  var id = this._id;\n\n  return arguments.length\n      ? this.each((typeof value === \"function\"\n          ? durationFunction\n          : durationConstant)(id, value))\n      : get(this.node(), id).duration;\n}\n"
  },
  {
    "path": "src/transition/ease.js",
    "content": "import {get, set} from \"./schedule.js\";\n\nfunction easeConstant(id, value) {\n  if (typeof value !== \"function\") throw new Error;\n  return function() {\n    set(this, id).ease = value;\n  };\n}\n\nexport default function(value) {\n  var id = this._id;\n\n  return arguments.length\n      ? this.each(easeConstant(id, value))\n      : get(this.node(), id).ease;\n}\n"
  },
  {
    "path": "src/transition/easeVarying.js",
    "content": "import {set} from \"./schedule.js\";\n\nfunction easeVarying(id, value) {\n  return function() {\n    var v = value.apply(this, arguments);\n    if (typeof v !== \"function\") throw new Error;\n    set(this, id).ease = v;\n  };\n}\n\nexport default function(value) {\n  if (typeof value !== \"function\") throw new Error;\n  return this.each(easeVarying(this._id, value));\n}\n"
  },
  {
    "path": "src/transition/end.js",
    "content": "import {set} from \"./schedule.js\";\n\nexport default function() {\n  var on0, on1, that = this, id = that._id, size = that.size();\n  return new Promise(function(resolve, reject) {\n    var cancel = {value: reject},\n        end = {value: function() { if (--size === 0) resolve(); }};\n\n    that.each(function() {\n      var schedule = set(this, id),\n          on = schedule.on;\n\n      // If this node shared a dispatch with the previous node,\n      // just assign the updated shared dispatch and we’re done!\n      // Otherwise, copy-on-write.\n      if (on !== on0) {\n        on1 = (on0 = on).copy();\n        on1._.cancel.push(cancel);\n        on1._.interrupt.push(cancel);\n        on1._.end.push(end);\n      }\n\n      schedule.on = on1;\n    });\n\n    // The selection was empty, resolve end immediately\n    if (size === 0) resolve();\n  });\n}\n"
  },
  {
    "path": "src/transition/filter.js",
    "content": "import {matcher} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\n\nexport default function(match) {\n  if (typeof match !== \"function\") match = matcher(match);\n\n  for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {\n      if ((node = group[i]) && match.call(node, node.__data__, i, group)) {\n        subgroup.push(node);\n      }\n    }\n  }\n\n  return new Transition(subgroups, this._parents, this._name, this._id);\n}\n"
  },
  {
    "path": "src/transition/index.js",
    "content": "import {selection} from \"d3-selection\";\nimport transition_attr from \"./attr.js\";\nimport transition_attrTween from \"./attrTween.js\";\nimport transition_delay from \"./delay.js\";\nimport transition_duration from \"./duration.js\";\nimport transition_ease from \"./ease.js\";\nimport transition_easeVarying from \"./easeVarying.js\";\nimport transition_filter from \"./filter.js\";\nimport transition_merge from \"./merge.js\";\nimport transition_on from \"./on.js\";\nimport transition_remove from \"./remove.js\";\nimport transition_select from \"./select.js\";\nimport transition_selectAll from \"./selectAll.js\";\nimport transition_selection from \"./selection.js\";\nimport transition_style from \"./style.js\";\nimport transition_styleTween from \"./styleTween.js\";\nimport transition_text from \"./text.js\";\nimport transition_textTween from \"./textTween.js\";\nimport transition_transition from \"./transition.js\";\nimport transition_tween from \"./tween.js\";\nimport transition_end from \"./end.js\";\n\nvar id = 0;\n\nexport function Transition(groups, parents, name, id) {\n  this._groups = groups;\n  this._parents = parents;\n  this._name = name;\n  this._id = id;\n}\n\nexport default function transition(name) {\n  return selection().transition(name);\n}\n\nexport function newId() {\n  return ++id;\n}\n\nvar selection_prototype = selection.prototype;\n\nTransition.prototype = transition.prototype = {\n  constructor: Transition,\n  select: transition_select,\n  selectAll: transition_selectAll,\n  selectChild: selection_prototype.selectChild,\n  selectChildren: selection_prototype.selectChildren,\n  filter: transition_filter,\n  merge: transition_merge,\n  selection: transition_selection,\n  transition: transition_transition,\n  call: selection_prototype.call,\n  nodes: selection_prototype.nodes,\n  node: selection_prototype.node,\n  size: selection_prototype.size,\n  empty: selection_prototype.empty,\n  each: selection_prototype.each,\n  on: transition_on,\n  attr: transition_attr,\n  attrTween: transition_attrTween,\n  style: transition_style,\n  styleTween: transition_styleTween,\n  text: transition_text,\n  textTween: transition_textTween,\n  remove: transition_remove,\n  tween: transition_tween,\n  delay: transition_delay,\n  duration: transition_duration,\n  ease: transition_ease,\n  easeVarying: transition_easeVarying,\n  end: transition_end,\n  [Symbol.iterator]: selection_prototype[Symbol.iterator]\n};\n"
  },
  {
    "path": "src/transition/interpolate.js",
    "content": "import {color} from \"d3-color\";\nimport {interpolateNumber, interpolateRgb, interpolateString} from \"d3-interpolate\";\n\nexport default function(a, b) {\n  var c;\n  return (typeof b === \"number\" ? interpolateNumber\n      : b instanceof color ? interpolateRgb\n      : (c = color(b)) ? (b = c, interpolateRgb)\n      : interpolateString)(a, b);\n}\n"
  },
  {
    "path": "src/transition/merge.js",
    "content": "import {Transition} from \"./index.js\";\n\nexport default function(transition) {\n  if (transition._id !== this._id) throw new Error;\n\n  for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {\n    for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {\n      if (node = group0[i] || group1[i]) {\n        merge[i] = node;\n      }\n    }\n  }\n\n  for (; j < m0; ++j) {\n    merges[j] = groups0[j];\n  }\n\n  return new Transition(merges, this._parents, this._name, this._id);\n}\n"
  },
  {
    "path": "src/transition/on.js",
    "content": "import {get, set, init} from \"./schedule.js\";\n\nfunction start(name) {\n  return (name + \"\").trim().split(/^|\\s+/).every(function(t) {\n    var i = t.indexOf(\".\");\n    if (i >= 0) t = t.slice(0, i);\n    return !t || t === \"start\";\n  });\n}\n\nfunction onFunction(id, name, listener) {\n  var on0, on1, sit = start(name) ? init : set;\n  return function() {\n    var schedule = sit(this, id),\n        on = schedule.on;\n\n    // If this node shared a dispatch with the previous node,\n    // just assign the updated shared dispatch and we’re done!\n    // Otherwise, copy-on-write.\n    if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);\n\n    schedule.on = on1;\n  };\n}\n\nexport default function(name, listener) {\n  var id = this._id;\n\n  return arguments.length < 2\n      ? get(this.node(), id).on.on(name)\n      : this.each(onFunction(id, name, listener));\n}\n"
  },
  {
    "path": "src/transition/remove.js",
    "content": "function removeFunction(id) {\n  return function() {\n    var parent = this.parentNode;\n    for (var i in this.__transition) if (+i !== id) return;\n    if (parent) parent.removeChild(this);\n  };\n}\n\nexport default function() {\n  return this.on(\"end.remove\", removeFunction(this._id));\n}\n"
  },
  {
    "path": "src/transition/schedule.js",
    "content": "import {dispatch} from \"d3-dispatch\";\nimport {timer, timeout} from \"d3-timer\";\n\nvar emptyOn = dispatch(\"start\", \"end\", \"cancel\", \"interrupt\");\nvar emptyTween = [];\n\nexport var CREATED = 0;\nexport var SCHEDULED = 1;\nexport var STARTING = 2;\nexport var STARTED = 3;\nexport var RUNNING = 4;\nexport var ENDING = 5;\nexport var ENDED = 6;\n\nexport default function(node, name, id, index, group, timing) {\n  var schedules = node.__transition;\n  if (!schedules) node.__transition = {};\n  else if (id in schedules) return;\n  create(node, id, {\n    name: name,\n    index: index, // For context during callback.\n    group: group, // For context during callback.\n    on: emptyOn,\n    tween: emptyTween,\n    time: timing.time,\n    delay: timing.delay,\n    duration: timing.duration,\n    ease: timing.ease,\n    timer: null,\n    state: CREATED\n  });\n}\n\nexport function init(node, id) {\n  var schedule = get(node, id);\n  if (schedule.state > CREATED) throw new Error(\"too late; already scheduled\");\n  return schedule;\n}\n\nexport function set(node, id) {\n  var schedule = get(node, id);\n  if (schedule.state > STARTED) throw new Error(\"too late; already running\");\n  return schedule;\n}\n\nexport function get(node, id) {\n  var schedule = node.__transition;\n  if (!schedule || !(schedule = schedule[id])) throw new Error(\"transition not found\");\n  return schedule;\n}\n\nfunction create(node, id, self) {\n  var schedules = node.__transition,\n      tween;\n\n  // Initialize the self timer when the transition is created.\n  // Note the actual delay is not known until the first callback!\n  schedules[id] = self;\n  self.timer = timer(schedule, 0, self.time);\n\n  function schedule(elapsed) {\n    self.state = SCHEDULED;\n    self.timer.restart(start, self.delay, self.time);\n\n    // If the elapsed delay is less than our first sleep, start immediately.\n    if (self.delay <= elapsed) start(elapsed - self.delay);\n  }\n\n  function start(elapsed) {\n    var i, j, n, o;\n\n    // If the state is not SCHEDULED, then we previously errored on start.\n    if (self.state !== SCHEDULED) return stop();\n\n    for (i in schedules) {\n      o = schedules[i];\n      if (o.name !== self.name) continue;\n\n      // While this element already has a starting transition during this frame,\n      // defer starting an interrupting transition until that transition has a\n      // chance to tick (and possibly end); see d3/d3-transition#54!\n      if (o.state === STARTED) return timeout(start);\n\n      // Interrupt the active transition, if any.\n      if (o.state === RUNNING) {\n        o.state = ENDED;\n        o.timer.stop();\n        o.on.call(\"interrupt\", node, node.__data__, o.index, o.group);\n        delete schedules[i];\n      }\n\n      // Cancel any pre-empted transitions.\n      else if (+i < id) {\n        o.state = ENDED;\n        o.timer.stop();\n        o.on.call(\"cancel\", node, node.__data__, o.index, o.group);\n        delete schedules[i];\n      }\n    }\n\n    // Defer the first tick to end of the current frame; see d3/d3#1576.\n    // Note the transition may be canceled after start and before the first tick!\n    // Note this must be scheduled before the start event; see d3/d3-transition#16!\n    // Assuming this is successful, subsequent callbacks go straight to tick.\n    timeout(function() {\n      if (self.state === STARTED) {\n        self.state = RUNNING;\n        self.timer.restart(tick, self.delay, self.time);\n        tick(elapsed);\n      }\n    });\n\n    // Dispatch the start event.\n    // Note this must be done before the tween are initialized.\n    self.state = STARTING;\n    self.on.call(\"start\", node, node.__data__, self.index, self.group);\n    if (self.state !== STARTING) return; // interrupted\n    self.state = STARTED;\n\n    // Initialize the tween, deleting null tween.\n    tween = new Array(n = self.tween.length);\n    for (i = 0, j = -1; i < n; ++i) {\n      if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {\n        tween[++j] = o;\n      }\n    }\n    tween.length = j + 1;\n  }\n\n  function tick(elapsed) {\n    var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),\n        i = -1,\n        n = tween.length;\n\n    while (++i < n) {\n      tween[i].call(node, t);\n    }\n\n    // Dispatch the end event.\n    if (self.state === ENDING) {\n      self.on.call(\"end\", node, node.__data__, self.index, self.group);\n      stop();\n    }\n  }\n\n  function stop() {\n    self.state = ENDED;\n    self.timer.stop();\n    delete schedules[id];\n    for (var i in schedules) return; // eslint-disable-line no-unused-vars\n    delete node.__transition;\n  }\n}\n"
  },
  {
    "path": "src/transition/select.js",
    "content": "import {selector} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n  var name = this._name,\n      id = this._id;\n\n  if (typeof select !== \"function\") select = selector(select);\n\n  for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {\n      if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {\n        if (\"__data__\" in node) subnode.__data__ = node.__data__;\n        subgroup[i] = subnode;\n        schedule(subgroup[i], name, id, i, subgroup, get(node, id));\n      }\n    }\n  }\n\n  return new Transition(subgroups, this._parents, name, id);\n}\n"
  },
  {
    "path": "src/transition/selectAll.js",
    "content": "import {selectorAll} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n  var name = this._name,\n      id = this._id;\n\n  if (typeof select !== \"function\") select = selectorAll(select);\n\n  for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {\n    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n      if (node = group[i]) {\n        for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) {\n          if (child = children[k]) {\n            schedule(child, name, id, k, children, inherit);\n          }\n        }\n        subgroups.push(children);\n        parents.push(node);\n      }\n    }\n  }\n\n  return new Transition(subgroups, parents, name, id);\n}\n"
  },
  {
    "path": "src/transition/selection.js",
    "content": "import {selection} from \"d3-selection\";\n\nvar Selection = selection.prototype.constructor;\n\nexport default function() {\n  return new Selection(this._groups, this._parents);\n}\n"
  },
  {
    "path": "src/transition/style.js",
    "content": "import {interpolateTransformCss as interpolateTransform} from \"d3-interpolate\";\nimport {style} from \"d3-selection\";\nimport {set} from \"./schedule.js\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction styleNull(name, interpolate) {\n  var string00,\n      string10,\n      interpolate0;\n  return function() {\n    var string0 = style(this, name),\n        string1 = (this.style.removeProperty(name), style(this, name));\n    return string0 === string1 ? null\n        : string0 === string00 && string1 === string10 ? interpolate0\n        : interpolate0 = interpolate(string00 = string0, string10 = string1);\n  };\n}\n\nfunction styleRemove(name) {\n  return function() {\n    this.style.removeProperty(name);\n  };\n}\n\nfunction styleConstant(name, interpolate, value1) {\n  var string00,\n      string1 = value1 + \"\",\n      interpolate0;\n  return function() {\n    var string0 = style(this, name);\n    return string0 === string1 ? null\n        : string0 === string00 ? interpolate0\n        : interpolate0 = interpolate(string00 = string0, value1);\n  };\n}\n\nfunction styleFunction(name, interpolate, value) {\n  var string00,\n      string10,\n      interpolate0;\n  return function() {\n    var string0 = style(this, name),\n        value1 = value(this),\n        string1 = value1 + \"\";\n    if (value1 == null) string1 = value1 = (this.style.removeProperty(name), style(this, name));\n    return string0 === string1 ? null\n        : string0 === string00 && string1 === string10 ? interpolate0\n        : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n  };\n}\n\nfunction styleMaybeRemove(id, name) {\n  var on0, on1, listener0, key = \"style.\" + name, event = \"end.\" + key, remove;\n  return function() {\n    var schedule = set(this, id),\n        on = schedule.on,\n        listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined;\n\n    // If this node shared a dispatch with the previous node,\n    // just assign the updated shared dispatch and we’re done!\n    // Otherwise, copy-on-write.\n    if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);\n\n    schedule.on = on1;\n  };\n}\n\nexport default function(name, value, priority) {\n  var i = (name += \"\") === \"transform\" ? interpolateTransform : interpolate;\n  return value == null ? this\n      .styleTween(name, styleNull(name, i))\n      .on(\"end.style.\" + name, styleRemove(name))\n    : typeof value === \"function\" ? this\n      .styleTween(name, styleFunction(name, i, tweenValue(this, \"style.\" + name, value)))\n      .each(styleMaybeRemove(this._id, name))\n    : this\n      .styleTween(name, styleConstant(name, i, value), priority)\n      .on(\"end.style.\" + name, null);\n}\n"
  },
  {
    "path": "src/transition/styleTween.js",
    "content": "function styleInterpolate(name, i, priority) {\n  return function(t) {\n    this.style.setProperty(name, i.call(this, t), priority);\n  };\n}\n\nfunction styleTween(name, value, priority) {\n  var t, i0;\n  function tween() {\n    var i = value.apply(this, arguments);\n    if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);\n    return t;\n  }\n  tween._value = value;\n  return tween;\n}\n\nexport default function(name, value, priority) {\n  var key = \"style.\" + (name += \"\");\n  if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n  if (value == null) return this.tween(key, null);\n  if (typeof value !== \"function\") throw new Error;\n  return this.tween(key, styleTween(name, value, priority == null ? \"\" : priority));\n}\n"
  },
  {
    "path": "src/transition/text.js",
    "content": "import {tweenValue} from \"./tween.js\";\n\nfunction textConstant(value) {\n  return function() {\n    this.textContent = value;\n  };\n}\n\nfunction textFunction(value) {\n  return function() {\n    var value1 = value(this);\n    this.textContent = value1 == null ? \"\" : value1;\n  };\n}\n\nexport default function(value) {\n  return this.tween(\"text\", typeof value === \"function\"\n      ? textFunction(tweenValue(this, \"text\", value))\n      : textConstant(value == null ? \"\" : value + \"\"));\n}\n"
  },
  {
    "path": "src/transition/textTween.js",
    "content": "function textInterpolate(i) {\n  return function(t) {\n    this.textContent = i.call(this, t);\n  };\n}\n\nfunction textTween(value) {\n  var t0, i0;\n  function tween() {\n    var i = value.apply(this, arguments);\n    if (i !== i0) t0 = (i0 = i) && textInterpolate(i);\n    return t0;\n  }\n  tween._value = value;\n  return tween;\n}\n\nexport default function(value) {\n  var key = \"text\";\n  if (arguments.length < 1) return (key = this.tween(key)) && key._value;\n  if (value == null) return this.tween(key, null);\n  if (typeof value !== \"function\") throw new Error;\n  return this.tween(key, textTween(value));\n}\n"
  },
  {
    "path": "src/transition/transition.js",
    "content": "import {Transition, newId} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function() {\n  var name = this._name,\n      id0 = this._id,\n      id1 = newId();\n\n  for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n      if (node = group[i]) {\n        var inherit = get(node, id0);\n        schedule(node, name, id1, i, group, {\n          time: inherit.time + inherit.delay + inherit.duration,\n          delay: 0,\n          duration: inherit.duration,\n          ease: inherit.ease\n        });\n      }\n    }\n  }\n\n  return new Transition(groups, this._parents, name, id1);\n}\n"
  },
  {
    "path": "src/transition/tween.js",
    "content": "import {get, set} from \"./schedule.js\";\n\nfunction tweenRemove(id, name) {\n  var tween0, tween1;\n  return function() {\n    var schedule = set(this, id),\n        tween = schedule.tween;\n\n    // If this node shared tween with the previous node,\n    // just assign the updated shared tween and we’re done!\n    // Otherwise, copy-on-write.\n    if (tween !== tween0) {\n      tween1 = tween0 = tween;\n      for (var i = 0, n = tween1.length; i < n; ++i) {\n        if (tween1[i].name === name) {\n          tween1 = tween1.slice();\n          tween1.splice(i, 1);\n          break;\n        }\n      }\n    }\n\n    schedule.tween = tween1;\n  };\n}\n\nfunction tweenFunction(id, name, value) {\n  var tween0, tween1;\n  if (typeof value !== \"function\") throw new Error;\n  return function() {\n    var schedule = set(this, id),\n        tween = schedule.tween;\n\n    // If this node shared tween with the previous node,\n    // just assign the updated shared tween and we’re done!\n    // Otherwise, copy-on-write.\n    if (tween !== tween0) {\n      tween1 = (tween0 = tween).slice();\n      for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {\n        if (tween1[i].name === name) {\n          tween1[i] = t;\n          break;\n        }\n      }\n      if (i === n) tween1.push(t);\n    }\n\n    schedule.tween = tween1;\n  };\n}\n\nexport default function(name, value) {\n  var id = this._id;\n\n  name += \"\";\n\n  if (arguments.length < 2) {\n    var tween = get(this.node(), id).tween;\n    for (var i = 0, n = tween.length, t; i < n; ++i) {\n      if ((t = tween[i]).name === name) {\n        return t.value;\n      }\n    }\n    return null;\n  }\n\n  return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));\n}\n\nexport function tweenValue(transition, name, value) {\n  var id = transition._id;\n\n  transition.each(function() {\n    var schedule = set(this, id);\n    (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);\n  });\n\n  return function(node) {\n    return get(node, id).value[name];\n  };\n}\n"
  },
  {
    "path": "test/.eslintrc.json",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"sourceType\": \"module\",\n    \"ecmaVersion\": 8\n  },\n  \"env\": {\n    \"mocha\": true,\n    \"node\": true,\n    \"es6\": true,\n    \"browser\": true\n  }\n}\n"
  },
  {
    "path": "test/active-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport {active} from \"../src/index.js\";\nimport it from \"./jsdom.js\";\n\nit(\"active(node) returns null if the specified node has no active transition with the null name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n\n  // No transitions pending.\n  assert.strictEqual(active(root), null);\n\n  // Two transitions created.\n  s.transition().delay(50).duration(50);\n  s.transition(\"foo\").duration(50);\n  assert.strictEqual(active(root), null);\n\n  // One transition scheduled; one active with a different name.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root), null);\n    resolve();\n  }));\n\n  // No transitions remaining after the transition ends.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root), null);\n    resolve();\n  }, 100));\n});\n\nit(\"active(node, null) returns null if the specified node has no active transition with the null name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n\n  // No transitions pending.\n  assert.strictEqual(active(root, null), null);\n\n  // Two transitions created.\n  s.transition().delay(50).duration(50);\n  s.transition(\"foo\").duration(50);\n  assert.strictEqual(active(root, null), null);\n\n  // One transition scheduled; one active with a different name.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, null), null);\n    resolve();\n  }));\n\n  // No transitions remaining after the transition ends.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, null), null);\n    resolve();\n  }, 100));\n});\n\nit(\"active(node, undefined) returns null if the specified node has no active transition with the null name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n\n  // No transitions pending.\n  assert.strictEqual(active(root, undefined), null);\n\n  // Two transitions created.\n  s.transition().delay(50).duration(50);\n  s.transition(\"foo\").duration(50);\n  assert.strictEqual(active(root, undefined), null);\n\n  // One transition scheduled; one active with a different name.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, undefined), null);\n    resolve();\n  }));\n\n  // No transitions remaining after the transition ends.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, undefined), null);\n    resolve();\n  }, 100));\n});\n\nit(\"active(node, name) returns null if the specified node has no active transition with the specified name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n\n  // No transitions pending.\n  assert.strictEqual(active(root, \"foo\"), null);\n\n  // Two transitions created.\n  s.transition(\"foo\").delay(50).duration(50);\n  s.transition().duration(50);\n  assert.strictEqual(active(root, null), null);\n\n  // One transition scheduled; one active with a different name.\n  assert.strictEqual(active(root, \"foo\"), null);\n\n  // One transition scheduled.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, \"foo\"), null);\n    resolve();\n  }));\n\n  // No transitions remaining after the transition ends.\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(active(root, \"foo\"), null);\n    resolve();\n  }, 100));\n});\n\nit(\"active(node) returns the active transition on the specified node with the null name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().on(\"start\", check).tween(\"tween\", tweened).on(\"end\", check);\n\n  function check() {\n    const a = active(root);\n    assert.deepStrictEqual(a._groups, [[root]]);\n    assert.deepStrictEqual(a._parents, [null]);\n    assert.strictEqual(a._name, null);\n    assert.strictEqual(a._id, t._id);\n  }\n\n  function tweened() {\n    check();\n    return t => {\n      if (t >= 1) check();\n    };\n  }\n\n  await t.end();\n});\n\nit(\"active(node, name) returns the active transition on the specified node with the specified name\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition(\"foo\").on(\"start\", check).tween(\"tween\", tweened).on(\"end\", check);\n\n  function check() {\n    const a = active(root, \"foo\");\n    assert.deepStrictEqual(a._groups, [[root]]);\n    assert.deepStrictEqual(a._parents, [null]);\n    assert.strictEqual(a._name, \"foo\");\n    assert.strictEqual(a._id, t._id);\n  }\n\n  function tweened() {\n    check();\n    return t => {\n      if (t >= 1) check();\n    };\n  }\n\n  await t.end();\n});\n"
  },
  {
    "path": "test/error-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../src/index.js\";\nimport it from \"./jsdom.js\";\n\ndescribe(\"with an uncaught error\", () => {\n  let listeners;\n\n  beforeEach(() => {\n    listeners = process.listeners(\"uncaughtException\");\n    process.removeAllListeners(\"uncaughtException\");\n    process.once(\"uncaughtException\", () => {});\n  });\n\n  afterEach(() => {\n    for (const listener of listeners) {\n      process.on(\"uncaughtException\", listener);\n    }\n  });\n\n  it(\"transition.on(\\\"start\\\", error) terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().on(\"start\", () => { throw new Error; });\n    await new Promise(resolve => timeout(resolve));\n    assert.strictEqual(root.__transition, undefined);\n  });\n\n  it(\"transition.on(\\\"start\\\", error) with delay terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().delay(50).on(\"start\", () => { throw new Error; });\n    await new Promise(resolve => timeout(resolve, 50));\n    assert.strictEqual(root.__transition, undefined);\n  });\n\n  it(\"transition.tween(\\\"foo\\\", error) terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().tween(\"foo\", () => { throw new Error; });\n    await new Promise(resolve => timeout(resolve));\n    assert.strictEqual(root.__transition, undefined);\n  });\n\n  it(\"transition.tween(\\\"foo\\\", error) with delay terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().delay(50).tween(\"foo\", () => { throw new Error; });\n    await new Promise(resolve => timeout(resolve, 50));\n    assert.strictEqual(root.__transition, undefined);\n  });\n\n  it(\"transition.tween(\\\"foo\\\", deferredError) terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().duration(50).tween(\"foo\", () => { return function(t) { if (t === 1) throw new Error; }; });\n    await new Promise(resolve => timeout(resolve, 50));\n    assert.strictEqual(root.__transition, undefined);\n  });\n\n  it(\"transition.on(\\\"end\\\", error) terminates the transition\", async () => {\n    const root = document.documentElement;\n    const s = select(root);\n    s.transition().delay(50).duration(50).on(\"end\", () => { throw new Error; });\n    await new Promise(resolve => timeout(resolve, 100));\n    assert.strictEqual(root.__transition, undefined);\n  });\n});\n"
  },
  {
    "path": "test/interrupt-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {interrupt} from \"../src/index.js\";\nimport it from \"./jsdom.js\";\n\nit(\"interrupt(node) cancels any pending transitions on the specified node\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition();\n  const t2 = t1.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  interrupt(root);\n  assert.strictEqual(root.__transition, undefined);\n});\n\nit(\"selection.interrupt(name) only cancels pending transitions with the specified name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  interrupt(root, \"foo\");\n  assert.strictEqual(t1._id in root.__transition, false);\n  assert.strictEqual(t2._id in root.__transition, true);\n});\n"
  },
  {
    "path": "test/jsdom.js",
    "content": "import {JSDOM} from \"jsdom\";\n\nexport default function jsdomit(message, html, run) {\n  if (arguments.length < 3) run = html, html = \"\";\n  return it(message, async () => {\n    try {\n      const dom = new JSDOM(html);\n      global.window = dom.window;\n      global.document = dom.window.document;\n      await run();\n    } finally {\n      delete global.window;\n      delete global.document;\n    }\n  });\n}\n"
  },
  {
    "path": "test/selection/interrupt-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {CREATED, ENDED, ENDING, SCHEDULED, STARTED, STARTING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"selection.interrupt() returns the selection\", () => {\n  const s = select(document);\n  assert.strictEqual(s.interrupt(), s);\n});\n\nit(\"selection.interrupt() cancels any pending transitions on the selected elements\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition();\n  const t2 = t1.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt(), s);\n  assert.strictEqual(root.__transition, undefined);\n});\n\nit(\"selection.interrupt() only cancels pending transitions with the null name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt(), s);\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, false);\n});\n\nit(\"selection.interrupt(null) only cancels pending transitions with the null name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt(null), s);\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, false);\n});\n\nit(\"selection.interrupt(undefined) only cancels pending transitions with the null name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt(undefined), s);\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, false);\n});\n\nit(\"selection.interrupt(name) only cancels pending transitions with the specified name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt(\"foo\"), s);\n  assert.strictEqual(t1._id in root.__transition, false);\n  assert.strictEqual(t2._id in root.__transition, true);\n});\n\nit(\"selection.interrupt(name) coerces the name to a string\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition(\"foo\");\n  const t2 = s.transition();\n  assert.strictEqual(t1._id in root.__transition, true);\n  assert.strictEqual(t2._id in root.__transition, true);\n  assert.strictEqual(s.interrupt({toString() { return \"foo\"; }}), s);\n  assert.strictEqual(t1._id in root.__transition, false);\n  assert.strictEqual(t2._id in root.__transition, true);\n});\n\nit(\"selection.interrupt() does nothing if there is no transition on the selected elements\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  assert.strictEqual(root.__transition, undefined);\n  assert.strictEqual(s.interrupt(), s);\n  assert.strictEqual(root.__transition, undefined);\n});\n\nit(\"selection.interrupt() dispatches an interrupt event to the started transition on the selected elements\", async () => {\n  const root = document.documentElement;\n  let interrupts = 0;\n  const s = select(root);\n  const t = s.transition().on(\"interrupt\", () => { ++interrupts; });\n  await new Promise(resolve => timeout(() => {\n    const schedule = root.__transition[t._id];\n    assert.strictEqual(schedule.state, STARTED);\n    s.interrupt();\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(root.__transition, undefined);\n    assert.strictEqual(interrupts, 1);\n    resolve();\n  }));\n});\n\nit(\"selection.interrupt() destroys the schedule after dispatching the interrupt event\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().on(\"interrupt\", interrupted);\n  await new Promise(resolve => timeout(() => {\n    s.interrupt();\n    resolve();\n  }));\n  function interrupted() {\n    assert.strictEqual(t.delay(), 0);\n    assert.strictEqual(t.duration(), 250);\n    assert.strictEqual(t.on(\"interrupt\"), interrupted);\n  }\n});\n\nit(\"selection.interrupt() does not dispatch an interrupt event to a starting transition\", async () => {\n  const root = document.documentElement;\n  let interrupts = 0;\n  const s = select(root);\n  const t = s.transition().on(\"interrupt\", () => { ++interrupts; });\n  await new Promise(resolve => t.on(\"start\", () => {\n    const schedule = root.__transition[t._id];\n    assert.strictEqual(schedule.state, STARTING);\n    s.interrupt();\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(root.__transition, undefined);\n    assert.strictEqual(interrupts, 0);\n    resolve();\n  }));\n});\n\nit(\"selection.interrupt() prevents a created transition from starting\", async () => {\n  const root = document.documentElement;\n  let starts = 0;\n  const s = select(root);\n  const t = s.transition().on(\"start\", () => { ++starts; });\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.state, CREATED);\n  s.interrupt();\n  assert.strictEqual(schedule.timer._call, null);\n  assert.strictEqual(schedule.state, ENDED);\n  assert.strictEqual(root.__transition, undefined);\n  await new Promise(resolve => timeout(resolve, 10));\n  assert.strictEqual(starts, 0);\n});\n\nit(\"selection.interrupt() prevents a scheduled transition from starting\", async () => {\n  const root = document.documentElement;\n  let starts = 0;\n  const s = select(root);\n  const t = s.transition().delay(50).on(\"start\", () => { ++starts; });\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => timeout(resolve));\n  assert.strictEqual(schedule.state, SCHEDULED);\n  s.interrupt();\n  assert.strictEqual(schedule.timer._call, null);\n  assert.strictEqual(schedule.state, ENDED);\n  assert.strictEqual(root.__transition, undefined);\n  await new Promise(resolve => timeout(resolve, 60));\n  assert.strictEqual(starts, 0);\n});\n\nit(\"selection.interrupt() prevents a starting transition from initializing tweens\", async () => {\n  const root = document.documentElement;\n  let tweens = 0;\n  const s = select(root);\n  const t = s.transition().tween(\"tween\", () => { ++tweens; });\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => t.on(\"start\", () => {\n    assert.strictEqual(schedule.state, STARTING);\n    s.interrupt();\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(root.__transition, undefined);\n    resolve();\n  }));\n  await new Promise(resolve => timeout(resolve, 10));\n  assert.strictEqual(tweens, 0);\n});\n\nit(\"selection.interrupt() during tween initialization prevents an active transition from continuing\", async () => {\n  const root = document.documentElement;\n  let tweens = 0;\n  const s = select(root);\n  const t = s.transition().tween(\"tween\", () => { s.interrupt(); return () => { ++tweens; }; });\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => timeout(resolve, 10));\n  assert.strictEqual(schedule.timer._call, null);\n  assert.strictEqual(schedule.state, ENDED);\n  assert.strictEqual(root.__transition, undefined);\n  assert.strictEqual(tweens, 0);\n});\n\nit(\"selection.interrupt() prevents an active transition from continuing\", async () => {\n  const root = document.documentElement;\n  let interrupted = false;\n  let tweens = 0;\n  const s = select(root);\n  const t = s.transition().tween(\"tween\", () => () => { if (interrupted) ++tweens; });\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => timeout(() => {\n    interrupted = true;\n    assert.strictEqual(schedule.state, STARTED);\n    s.interrupt();\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(root.__transition, undefined);\n    resolve();\n  }, 10));\n  await new Promise(resolve => timeout(resolve, 50));\n  assert.strictEqual(tweens, 0);\n});\n\nit(\"selection.interrupt() during the final tween invocation prevents the end event from being dispatched\", async () => {\n  const root = document.documentElement;\n  let ends = 0;\n  const s = select(root);\n  const t = s.transition().duration(50).tween(\"tween\", tween).on(\"end\", () => { ++ends; });\n  const schedule = root.__transition[t._id];\n  function tween() {\n    return (t) => {\n      if (t >= 1) {\n        assert.strictEqual(schedule.state, ENDING);\n        s.interrupt();\n      }\n    };\n  }\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(root.__transition, undefined);\n    assert.strictEqual(ends, 0);\n    resolve();\n  }, 60));\n});\n\nit(\"selection.interrupt() has no effect on an ended transition\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().duration(50);\n  const schedule = root.__transition[t._id];\n  await t.end();\n  assert.strictEqual(schedule.state, ENDED);\n  assert.strictEqual(schedule.timer._call, null);\n  s.interrupt();\n  assert.strictEqual(schedule.state, ENDED);\n  assert.strictEqual(schedule.timer._call, null);\n  assert.strictEqual(root.__transition, undefined);\n});\n\nit(\"selection.interrupt() has no effect on an interrupting transition\", async () => {\n  const root = document.documentElement;\n  let interrupts = 0;\n  const s = select(root);\n  const t = s.transition().duration(50).on(\"interrupt\", interrupted);\n  const schedule = root.__transition[t._id];\n\n  function interrupted() {\n    ++interrupts;\n    s.interrupt();\n  }\n\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(schedule.state, STARTED);\n    s.interrupt();\n    assert.strictEqual(schedule.state, ENDED);\n    assert.strictEqual(schedule.timer._call, null);\n    assert.strictEqual(interrupts, 1);\n    resolve();\n  }));\n});\n"
  },
  {
    "path": "test/selection/transition-test.js",
    "content": "import assert from \"assert\";\nimport {easeBounce, easeCubic} from \"d3-ease\";\nimport {select, selectAll} from \"d3-selection\";\nimport {now, timeout} from \"d3-timer\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"selection.transition() returns an instanceof transition\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition();\n  assert.strictEqual(t instanceof transition, true);\n});\n\nit(\"selection.transition() uses the default timing parameters\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition();\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.time, now());\n  assert.strictEqual(schedule.delay, 0);\n  assert.strictEqual(schedule.duration, 250);\n  assert.strictEqual(schedule.ease, easeCubic);\n});\n\nit(\"selection.transition() assigns a monotonically-increasing id\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t1 = s.transition();\n  const t2 = s.transition();\n  const t3 = s.transition();\n  assert(t2._id > t1._id);\n  assert(t3._id > t2._id);\n});\n\nit(\"selection.transition() uses a default name of null\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition();\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"selection.transition(null) uses a name of null\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition(null);\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"selection.transition(undefined) uses a name of null\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition(undefined);\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"selection.transition(name) uses the specified name\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition(\"foo\");\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.name, \"foo\");\n});\n\nit(\"selection.transition(name) coerces the name to a string\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition({toString() { return \"foo\"; }});\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(schedule.name, \"foo\");\n});\n\nit(\"selection.transition(transition) inherits the id, name and timing from the corresponding parent in the specified transition\", \"<h1 id='one'><child></h1><h1 id='two'><child></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const s = selectAll([one, two]);\n  const t = s.transition().delay(function(d, i) { return i * 50; }).duration(100).ease(easeBounce);\n  const schedule1 = one.__transition[t._id];\n  const schedule2 = two.__transition[t._id];\n  const t1b = select(one.firstChild).transition(t);\n  const schedule1b = one.firstChild.__transition[t._id];\n  assert.strictEqual(t1b._id, t._id);\n  assert.strictEqual(schedule1b.name, schedule1.name);\n  assert.strictEqual(schedule1b.delay, schedule1.delay);\n  assert.strictEqual(schedule1b.duration, schedule1.duration);\n  assert.strictEqual(schedule1b.ease, schedule1.ease);\n  assert.strictEqual(schedule1b.time, schedule1.time);\n  await new Promise(resolve => timeout(resolve, 10));\n  const t2b = select(two.firstChild).transition(t);\n  const schedule2b = two.firstChild.__transition[t._id];\n  assert.strictEqual(t2b._id, t._id);\n  assert.strictEqual(schedule2b.name, schedule2.name);\n  assert.strictEqual(schedule2b.delay, schedule2.delay);\n  assert.strictEqual(schedule2b.duration, schedule2.duration);\n  assert.strictEqual(schedule2b.ease, schedule2.ease);\n  assert.strictEqual(schedule2b.time, schedule2.time);\n});\n\nit(\"selection.transition(transition) reselects the existing transition with the specified transition’s id, if any\", () => {\n  const root = document.documentElement;\n  const foo = () => {};\n  const bar = () => {};\n  const s = select(root);\n  const t1 = s.transition().tween(\"tween\", foo);\n  const schedule1 = root.__transition[t1._id];\n  const t2 = s.transition(t1).tween(\"tween\", bar);\n  const schedule2 = root.__transition[t2._id];\n  assert.strictEqual(t1._id, t2._id);\n  assert.strictEqual(schedule1, schedule2);\n  assert.strictEqual(t1.tween(\"tween\"), bar);\n  assert.strictEqual(t2.tween(\"tween\"), bar);\n});\n\nit(\"selection.transition(transition) throws an error if the specified transition is not found\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = select(one).transition();\n  const t2 = select(two).transition().delay(50);\n  assert.throws(() => select(two).transition(t1), /transition .* not found/);\n  assert.throws(() => select(one).transition(t2), /transition .* not found/);\n});\n"
  },
  {
    "path": "test/transition/attr-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {interpolateNumber, interpolateRgb, interpolateString} from \"d3-interpolate\";\nimport {select, selectAll} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.attr(name, value) creates an tween to the specified value\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).attr(\"fill\", \"red\");\n  s.transition().attr(\"fill\", \"blue\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"fill\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) creates a namespaced tween to the specified value\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).attr(\"svg:fill\", \"red\");\n  s.transition().attr(\"svg:fill\", \"blue\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) creates an tween to the value returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).attr(\"fill\", \"red\");\n  s.transition().attr(\"fill\", function() { return \"blue\"; });\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"fill\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) creates a namespaced tween to the value returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).attr(\"svg:fill\", \"red\");\n  s.transition().attr(\"svg:fill\", function() { return \"blue\"; });\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, constant) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"foo\", 1);\n  s.transition().attr(\"foo\", 1);\n  timeout(() => root.setAttribute(\"foo\", 2), 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttribute(\"foo\"), \"2\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.attr(ns:name, constant) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"svg:foo\", 1);\n  s.transition().attr(\"svg:foo\", 1);\n  timeout(() => root.setAttributeNS(\"http://www.w3.org/2000/svg\", \"foo\", 2), 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"foo\"), \"2\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.attr(name, function) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"foo\", 1);\n  s.transition().attr(\"foo\", function() { return 1; });\n  timeout(() => root.setAttribute(\"foo\", 2), 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttribute(\"foo\"), \"2\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.attr(ns:name, function) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"svg:foo\", 1);\n  s.transition().attr(\"svg:foo\", function() { return 1; });\n  timeout(() => root.setAttributeNS(\"http://www.w3.org/2000/svg\", \"foo\", 2), 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"foo\"), \"2\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.attr(name, constant) uses interpolateNumber if value is a number\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"foo\", \"15px\");\n  s.transition().attr(\"foo\", 10);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttribute(\"foo\"), \"NaN\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, function) uses interpolateNumber if value is a number\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"foo\", \"15px\");\n  s.transition().attr(\"foo\", () => 10);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.getAttribute(\"foo\"), \"NaN\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) immediately evaluates the specified function with the expected context and arguments\", \"<h1 id='one' fill='cyan'></h1><h1 id='two' fill='magenta'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate1 = interpolateRgb(\"cyan\", \"red\");\n  const interpolate2 = interpolateRgb(\"magenta\", \"green\");\n  const s = selectAll([one, two]).data([\"red\", \"green\"]);\n  const result = [];\n  s.transition().attr(\"fill\", function(d, i, nodes) { result.push([d, i, nodes, this]); return d; });\n  assert.deepStrictEqual(result, [\n    [\"red\", 0, [one, two], one],\n    [\"green\", 1, [one, two], two]\n  ]);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(one.getAttribute(\"fill\"), interpolate1(ease(elapsed / duration)));\n    assert.strictEqual(two.getAttribute(\"fill\"), interpolate2(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) constructs an interpolator using the current value on start\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root);\n  s.transition().on(\"start\", function() { s.attr(\"fill\", \"red\"); }).attr(\"fill\", function() { return \"blue\"; });\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"fill\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, null) creates an tween which removes the specified attribute post-start\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"fill\", \"red\");\n  const started = () => assert.strictEqual(root.getAttribute(\"fill\"), \"red\");\n  s.transition().attr(\"fill\", null).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.hasAttribute(\"fill\"), false);\n    resolve();\n  }));\n});\n\nit(\"transition.attr(name, null) creates an tween which removes the specified namespaced attribute post-start\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"svg:fill\", \"red\");\n  const started = () => assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), \"red\");\n  s.transition().attr(\"svg:fill\", null).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.hasAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), false);\n    resolve();\n  }));\n});\n\nit(\"transition.attr(name, value) creates an tween which removes the specified attribute post-start if the specified function returns null\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"fill\", \"red\");\n  const started = () => assert.strictEqual(root.getAttribute(\"fill\"), \"red\");\n  s.transition().attr(\"fill\", function() {}).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.hasAttribute(\"fill\"), false);\n    resolve();\n  }));\n});\n\nit(\"transition.attr(name, value) creates an tween which removes the specified namespaced attribute post-start if the specified function returns null\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"svg:fill\", \"red\");\n  const started = () => assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), \"red\");\n  s.transition().attr(\"svg:fill\", function() {}).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.hasAttributeNS(\"http://www.w3.org/2000/svg\", \"fill\"), false);\n    resolve();\n  }));\n});\n\nit(\"transition.attr(name, value) interpolates numbers\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateNumber(1, 2);\n  const s = select(root).attr(\"foo\", 1);\n  s.transition().attr(\"foo\", 2);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"foo\"), interpolate(ease(elapsed / duration)) + \"\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) interpolates strings\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateString(\"1px\", \"2px\");\n  const s = select(root).attr(\"foo\", \"1px\");\n  s.transition().attr(\"foo\", \"2px\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"foo\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) interpolates colors\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"#f00\", \"#00f\");\n  const s = select(root).attr(\"foo\", \"#f00\");\n  s.transition().attr(\"foo\", \"#00f\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"foo\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attr(name, value) creates an attrTween with the specified name\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"fill\", \"red\");\n  const t = s.transition().attr(\"fill\", \"blue\");\n  assert.strictEqual(t.attrTween(\"fill\").call(root).call(root, 0.5), \"rgb(128, 0, 128)\");\n});\n\nit(\"transition.attr(name, value) creates a tween with the name \\\"attr.name\\\"\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"fill\", \"red\");\n  const t = s.transition().attr(\"fill\", \"blue\");\n  t.tween(\"attr.fill\").call(root).call(root, 0.5);\n  assert.strictEqual(root.getAttribute(\"fill\"), \"rgb(128, 0, 128)\");\n});\n"
  },
  {
    "path": "test/transition/attrTween-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {interpolateHcl} from \"d3-interpolate\";\nimport {select, selectAll} from \"d3-selection\";\nimport {timeout, now} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {ENDING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.attrTween(name, value) defines an attribute tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  select(root).transition().attrTween(\"foo\", () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"foo\"), interpolate(easeCubic(elapsed / 250)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attrTween(name, value) invokes the value function with the expected context and arguments\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const result = [];\n  selectAll([one, two]).data([\"one\", \"two\"]).transition().attrTween(\"foo\", function(d, i, nodes) { result.push([d, i, nodes, this]); });\n  await new Promise(resolve => timeout(resolve));\n  assert.deepStrictEqual(result, [\n    [\"one\", 0, [one, two], one],\n    [\"two\", 1, [one, two], two]\n  ]);\n});\n\nit(\"transition.attrTween(name, value) passes the eased time to the interpolator\", async () => {\n  const root = document.documentElement;\n  const then = now();\n  const duration = 250;\n  const ease = easeCubic;\n  const t = select(root).transition().attrTween(\"foo\", () => interpolate);\n  const schedule = root.__transition[t._id];\n  function interpolate(t) {\n    assert.strictEqual(this, root);\n    assert.strictEqual(t, schedule.state === ENDING ? 1 : ease((now() - then) / duration));\n  }\n  await t.end();\n});\n\nit(\"transition.attrTween(name, value) allows the specified function to return null for a noop\", async () => {\n  const root = document.documentElement;\n  const s = select(root).attr(\"foo\", \"42\").attr(\"svg:bar\", \"43\");\n  s.transition().attrTween(\"foo\", () => {}).attrTween(\"svg:bar\", () => {});\n  await new Promise(resolve => timeout(resolve, 125));\n  assert.strictEqual(root.getAttribute(\"foo\"), \"42\");\n  assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"bar\"), \"43\");\n});\n\nit(\"transition.attrTween(name, value) defines a namespaced attribute tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  select(root).transition().attrTween(\"svg:foo\", () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttributeNS(\"http://www.w3.org/2000/svg\", \"foo\"), interpolate(easeCubic(elapsed / 250)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attrTween(name, value) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  select(root).transition().attrTween({toString() { return \"foo\"; }}, () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.getAttribute(\"foo\"), interpolate(easeCubic(elapsed / 250)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.attrTween(name, value) throws an error if value is not null and not a function\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.attrTween(\"foo\", 42); });\n});\n\nit(\"transition.attrTween(name, null) removes the specified attribute tween\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const t = select(root).transition().attrTween(\"foo\", () => interpolate).attrTween(\"foo\", null);\n  assert.strictEqual(t.attrTween(\"foo\"), null);\n  assert.strictEqual(t.tween(\"attr.foo\"), null);\n  await new Promise(resolve => timeout(resolve, 125));\n  assert.strictEqual(root.hasAttribute(\"foo\"), false);\n});\n\nit(\"transition.attrTween(name) returns the attribute tween with the specified name\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const tween = () => interpolate;\n  const started = () => assert.strictEqual(t.attrTween(\"foo\"), tween);\n  const ended = () => assert.strictEqual(t.attrTween(\"foo\"), tween);\n  const t = select(root).transition().attrTween(\"foo\", tween).on(\"start\", started).on(\"end\", ended);\n  assert.strictEqual(t.attrTween(\"foo\"), tween);\n  assert.strictEqual(t.attrTween(\"bar\"), null);\n  await t.end();\n});\n\nit(\"transition.attrTween(name) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const tween = () => {};\n  const t = select(root).transition().attrTween(\"color\", tween);\n  assert.strictEqual(t.attrTween({toString() { return \"color\"; }}), tween);\n});\n"
  },
  {
    "path": "test/transition/call-test.js",
    "content": "import assert from \"assert\";\nimport {selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.call is the same as selection.call\", () => {\n  assert.strictEqual(transition.prototype.call, selection.prototype.call);\n});\n"
  },
  {
    "path": "test/transition/delay-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll} from \"d3-selection\";\nimport it from \"../jsdom.js\";\nimport \"../../src/index.js\";\n\nit(\"transition.delay() returns the delay for the first non-null node\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = select(one).transition();\n  const t2 = select(two).transition().delay(50);\n  assert.strictEqual(one.__transition[t1._id].delay, 0);\n  assert.strictEqual(two.__transition[t2._id].delay, 50);\n  assert.strictEqual(t1.delay(), 0);\n  assert.strictEqual(t2.delay(), 50);\n  assert.strictEqual(select(one).transition(t1).delay(), 0);\n  assert.strictEqual(select(two).transition(t2).delay(), 50);\n  assert.strictEqual(selectAll([null, one]).transition(t1).delay(), 0);\n  assert.strictEqual(selectAll([null, two]).transition(t2).delay(), 50);\n});\n\nit(\"transition.delay(number) sets the delay for each selected element to the specified number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().delay(50);\n  assert.strictEqual(one.__transition[t._id].delay, 50);\n  assert.strictEqual(two.__transition[t._id].delay, 50);\n});\n\nit(\"transition.delay(value) coerces the specified value to a number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().delay(\"50\");\n  assert.strictEqual(one.__transition[t._id].delay, 50);\n  assert.strictEqual(two.__transition[t._id].delay, 50);\n});\n\nit(\"transition.delay(function) passes the expected arguments and context to the function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const result = [];\n  const s = selectAll([one, two]).data([\"one\", \"two\"]);\n  const t = s.transition().delay(function(d, i, nodes) { result.push([d, i, nodes, this]); });\n  assert.deepStrictEqual(result, [\n    [\"one\", 0, t._groups[0], one],\n    [\"two\", 1, t._groups[0], two]\n  ]);\n});\n\nit(\"transition.delay(function) sets the delay for each selected element to the number returned by the specified function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().delay(function(d, i) { return i * 20; });\n  assert.strictEqual(one.__transition[t._id].delay, 0);\n  assert.strictEqual(two.__transition[t._id].delay, 20);\n});\n\nit(\"transition.delay(function) coerces the value returned by the specified function to a number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().delay(function(d, i) { return i * 20 + \"\"; });\n  assert.strictEqual(one.__transition[t._id].delay, 0);\n  assert.strictEqual(two.__transition[t._id].delay, 20);\n});\n"
  },
  {
    "path": "test/transition/duration-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll} from \"d3-selection\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.duration() returns the duration for the first non-null node\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = select(one).transition();\n  const t2 = select(two).transition().duration(50);\n  assert.strictEqual(one.__transition[t1._id].duration, 250);\n  assert.strictEqual(two.__transition[t2._id].duration, 50);\n  assert.strictEqual(t1.duration(), 250);\n  assert.strictEqual(t2.duration(), 50);\n  assert.strictEqual(select(one).transition(t1).duration(), 250);\n  assert.strictEqual(select(two).transition(t2).duration(), 50);\n  assert.strictEqual(selectAll([null, one]).transition(t1).duration(), 250);\n  assert.strictEqual(selectAll([null, two]).transition(t2).duration(), 50);\n});\n\nit(\"transition.duration(number) sets the duration for each selected element to the specified number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().duration(50);\n  assert.strictEqual(one.__transition[t._id].duration, 50);\n  assert.strictEqual(two.__transition[t._id].duration, 50);\n});\n\nit(\"transition.duration(value) coerces the specified value to a number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().duration(\"50\");\n  assert.strictEqual(one.__transition[t._id].duration, 50);\n  assert.strictEqual(two.__transition[t._id].duration, 50);\n});\n\nit(\"transition.duration(function) passes the expected arguments and context to the function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const result = [];\n  const s = selectAll([one, two]).data([\"one\", \"two\"]);\n  const t = s.transition().duration(function(d, i, nodes) { result.push([d, i, nodes, this]); });\n  assert.deepStrictEqual(result, [\n    [\"one\", 0, t._groups[0], one],\n    [\"two\", 1, t._groups[0], two]\n  ]);\n});\n\nit(\"transition.duration(function) sets the duration for each selected element to the number returned by the specified function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().duration(function(d, i) { return i * 20; });\n  assert.strictEqual(one.__transition[t._id].duration, 0);\n  assert.strictEqual(two.__transition[t._id].duration, 20);\n});\n\nit(\"transition.duration(function) coerces the value returned by the specified function to a number\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().duration(function(d, i) { return i * 20 + \"\"; });\n  assert.strictEqual(one.__transition[t._id].duration, 0);\n  assert.strictEqual(two.__transition[t._id].duration, 20);\n});\n"
  },
  {
    "path": "test/transition/each-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll, selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.each is the same as selection.each\", () => {\n  assert.strictEqual(transition.prototype.each, selection.prototype.each);\n});\n\nit(\"transition.each() runs as expected\", () => {\n  const root = document.documentElement;\n  let a = 0;\n  select(root).transition().each(() => { ++a; });\n  assert.strictEqual(a, 1);\n  a = 0;\n  selectAll([null, root]).transition().each(() => { ++a; });\n  assert.strictEqual(a, 1);\n});\n"
  },
  {
    "path": "test/transition/ease-test.js",
    "content": "import assert from \"assert\";\nimport {easeBounce, easeCubic} from \"d3-ease\";\nimport {select, selectAll} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {ENDING, RUNNING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.ease() returns the easing function for the first non-null node\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = select(one).transition();\n  const t2 = select(two).transition().ease(easeBounce);\n  assert.strictEqual(one.__transition[t1._id].ease, easeCubic);\n  assert.strictEqual(two.__transition[t2._id].ease, easeBounce);\n  assert.strictEqual(t1.ease(), easeCubic);\n  assert.strictEqual(t2.ease(), easeBounce);\n  assert.strictEqual(select(one).transition(t1).ease(), easeCubic);\n  assert.strictEqual(select(two).transition(t2).ease(), easeBounce);\n  assert.strictEqual(selectAll([null, one]).transition(t1).ease(), easeCubic);\n  assert.strictEqual(selectAll([null, two]).transition(t2).ease(), easeBounce);\n});\n\nit(\"transition.ease(ease) throws an error if ease is not a function\", () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.ease(42); });\n  assert.throws(() => { t.ease(null); });\n});\n\nit(\"transition.ease(ease) sets the easing function for each selected element to the specified function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().ease(easeBounce);\n  assert.strictEqual(one.__transition[t._id].ease, easeBounce);\n  assert.strictEqual(two.__transition[t._id].ease, easeBounce);\n});\n\nit(\"transition.ease(ease) passes the easing function the normalized time in [0, 1]\", async () => {\n  let actual;\n  const root = document.documentElement;\n  const ease = t => { actual = t; return t; };\n\n  select(root).transition().ease(ease);\n\n  await new Promise(resolve => timeout((elapsed) => {\n    assert.strictEqual(actual, elapsed / 250);\n    resolve()\n  }, 100));\n});\n\nit(\"transition.ease(ease) does not invoke the easing function on the last frame\", async () => {\n  const root = document.documentElement;\n  const ease = t => { assert.strictEqual(schedule.state, RUNNING); return t; };\n  const t = select(root).transition().ease(ease);\n  const schedule = root.__transition[t._id];\n  await t.end();\n});\n\nit(\"transition.ease(ease) observes the eased time returned by the easing function\", async () => {\n  const root = document.documentElement;\n  let expected;\n  const ease = () => { return expected = Math.random() * 2 - 0.5; };\n  const tween = () => { return t => { assert.strictEqual(t, schedule.state === ENDING ? 1 : expected); }; };\n  const t = select(root).transition().ease(ease).tween(\"tween\", tween);\n  const schedule = root.__transition[t._id];\n  await t.end();\n});\n"
  },
  {
    "path": "test/transition/easeVarying-test.js",
    "content": "import assert from \"assert\";\nimport {easePolyIn} from \"d3-ease\";\nimport {select} from \"d3-selection\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.easeVarying(factory) accepts an easing function factory\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const t = select(document).selectAll(\"h1\").data([{exponent: 3}, {exponent: 4}]).transition();\n  t.easeVarying(d => easePolyIn.exponent(d.exponent));\n  assert.strictEqual(t.ease()(0.5), easePolyIn.exponent(3)(0.5));\n});\n\nit(\"transition.easeVarying(factory) passes factory datum, index, group with the node as this\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const t = select(document).selectAll(\"h1\").data([{exponent: 3}, {exponent: 4}]).transition();\n  const results = [];\n  t.easeVarying(function(d, i, e) { results.push([d, i, e, this]); return t => t; });\n  assert.deepStrictEqual(results, [\n    [{exponent: 3}, 0, [...t], document.querySelector(\"#one\")],\n    [{exponent: 4}, 1, [...t], document.querySelector(\"#two\")],\n  ]);\n});\n\nit(\"transition.easeVarying() throws an error if the argument is not a function\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const t = select(document).selectAll(\"h1\").data([{exponent: 3}, {exponent: 4}]).transition();\n  assert.throws(() => { t.easeVarying(); });\n  assert.throws(() => { t.easeVarying(\"a\"); });\n});\n"
  },
  {
    "path": "test/transition/empty-test.js",
    "content": "import assert from \"assert\";\nimport {selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\n\nit(\"transition.empty is the same as selection.empty\", () => {\n  assert.strictEqual(transition.prototype.empty, selection.prototype.empty);\n});\n"
  },
  {
    "path": "test/transition/filter-test.js",
    "content": "import assert from \"assert\";\nimport {selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.filter(selector) retains the elements matching the specified selector\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.filter(\"#two\");\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[two]]);\n  assert.strictEqual(t2._parents, t1._parents);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n});\n\nit(\"transition.filter(function) retains the elements for which the specified function returns true\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.filter(function() { return this === two; });\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[two]]);\n  assert.strictEqual(t2._parents, t1._parents);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n});\n"
  },
  {
    "path": "test/transition/index-test.js",
    "content": "import assert from \"assert\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition() returns a transition on the document element with the null name\", () => {\n  const root = document.documentElement;\n  const t = transition();\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(t.node(), root);\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"transition(null) returns a transition on the document element with the null name\", () => {\n  const root = document.documentElement;\n  const t = transition(null);\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(t.node(), root);\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"transition(undefined) returns a transition on the document element with the null name\", () => {\n  const root = document.documentElement;\n  const t = transition(undefined);\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(t.node(), root);\n  assert.strictEqual(schedule.name, null);\n});\n\nit(\"transition(name) returns a transition on the document element with the specified name\", () => {\n  const root = document.documentElement;\n  const t = transition(\"foo\");\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(t.node(), root);\n  assert.strictEqual(schedule.name, \"foo\");\n});\n\nit(\"transition.prototype can be extended\", () => {\n  try {\n    let pass = 0;\n    transition.prototype.test = () => { return ++pass; };\n    assert.strictEqual(transition().test(), 1);\n    assert.strictEqual(pass, 1);\n  } finally {\n    delete transition.prototype.test;\n  }\n});\n\nit(\"transitions are instanceof transition\", () => {\n  assert.strictEqual(transition() instanceof transition, true);\n});\n"
  },
  {
    "path": "test/transition/merge-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.merge(other) merges elements from the specified other transition for null elements in this transition\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t0 = select(document.documentElement).transition();\n  const t1 = selectAll([null, two]).transition(t0);\n  const t2 = selectAll([one, null]).transition(t0);\n  const t3 = t1.merge(t2);\n  assert.strictEqual(t3 instanceof transition, true);\n  assert.deepStrictEqual(t3._groups, [[one, two]]);\n  assert.strictEqual(t3._parents, t1._parents);\n  assert.strictEqual(t3._name, t1._name);\n  assert.strictEqual(t3._id, t1._id);\n});\n\nit(\"transition.merge(other) throws an error if the other transition has a different id\", \"<h1 id='one'></h1><h1 id='two'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([null, two]).transition();\n  const t2 = selectAll([one, null]).transition();\n  assert.throws(() => { t1.merge(t2); });\n});\n"
  },
  {
    "path": "test/transition/node-test.js",
    "content": "import assert from \"assert\";\nimport {selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.node is the same as selection.node\", () => {\n  assert.strictEqual(transition.prototype.node, selection.prototype.node);\n});\n"
  },
  {
    "path": "test/transition/nodes-test.js",
    "content": "import assert from \"assert\";\nimport {selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.nodes is the same as selection.nodes\", () => {\n  assert.strictEqual(transition.prototype.nodes, selection.prototype.nodes);\n});\n"
  },
  {
    "path": "test/transition/on-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {ENDED, ENDING, STARTING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.on(type, listener) throws an error if listener is not a function\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.on(\"start\", 42); });\n});\n\nit(\"transition.on(typename) returns the listener with the specified typename, if any\", async () => {\n  const root = document.documentElement;\n  const foo = () => {};\n  const bar = () => {};\n  const t = select(root).transition().on(\"start\", foo).on(\"start.bar\", bar);\n  assert.strictEqual(t.on(\"start\"), foo);\n  assert.strictEqual(t.on(\"start.foo\"), undefined);\n  assert.strictEqual(t.on(\"start.bar\"), bar);\n  assert.strictEqual(t.on(\"end\"), undefined);\n});\n\nit(\"transition.on(typename) throws an error if the specified type is not supported\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.on(\"foo\"); });\n});\n\nit(\"transition.on(typename, listener) throws an error if the specified type is not supported\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.on(\"foo\", () => {}); });\n});\n\nit(\"transition.on(typename, listener) throws an error if the specified listener is not a function\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.on(\"foo\", 42); });\n});\n\nit(\"transition.on(typename, null) removes the listener with the specified typename, if any\", async () => {\n  const root = document.documentElement;\n  let starts = 0;\n  const t = select(root).transition().on(\"start.foo\", () => { ++starts; });\n  const schedule = root.__transition[t._id];\n  assert.strictEqual(t.on(\"start.foo\", null), t);\n  assert.strictEqual(t.on(\"start.foo\"), undefined);\n  assert.strictEqual(schedule.on.on(\"start.foo\"), undefined);\n  await new Promise(resolve => timeout(resolve));\n  assert.strictEqual(starts, 0);\n});\n\nit(\"transition.on(\\\"start\\\", listener) registers a listener for the start event\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => t.on(\"start\", () => {\n    assert.strictEqual(schedule.state, STARTING)\n    resolve();\n  }));\n});\n\nit(\"transition.on(\\\"interrupt\\\", listener) registers a listener for the interrupt event (during start)\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition();\n  const schedule = root.__transition[t._id];\n  timeout(() => s.interrupt());\n  await new Promise(resolve => t.on(\"interrupt\", () => {\n    assert.strictEqual(schedule.state, ENDED);\n    resolve();\n  }));\n});\n\nit(\"transition.on(\\\"interrupt\\\", listener) registers a listener for the interrupt event (during run)\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition();\n  const schedule = root.__transition[t._id];\n  timeout(() => s.interrupt(), 50);\n  await new Promise(resolve => t.on(\"interrupt\", () => {\n    assert.strictEqual(schedule.state, ENDED);\n    resolve();\n  }));\n});\n\nit(\"transition.on(\\\"end\\\", listener) registers a listener for the end event\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition().duration(50);\n  const schedule = root.__transition[t._id];\n  await new Promise(resolve => t.on(\"end\", () => {\n    assert.strictEqual(schedule.state, ENDING);\n    resolve();\n  }));\n});\n\nit(\"transition.on(typename, listener) uses copy-on-write to apply changes\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const foo = () => {};\n  const bar = () => {};\n  const t = selectAll([one, two]).transition();\n  const schedule1 = one.__transition[t._id];\n  const schedule2 = two.__transition[t._id];\n  t.on(\"start\", foo);\n  assert.strictEqual(schedule1.on.on(\"start\"), foo);\n  assert.strictEqual(schedule2.on, schedule1.on);\n  t.on(\"start\", bar);\n  assert.strictEqual(schedule1.on.on(\"start\"), bar);\n  assert.strictEqual(schedule2.on, schedule1.on);\n  select(two).transition(t).on(\"start\", foo);\n  assert.strictEqual(schedule1.on.on(\"start\"), bar);\n  assert.strictEqual(schedule2.on.on(\"start\"), foo);\n});\n"
  },
  {
    "path": "test/transition/remove-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.remove() creates an end listener to remove the element\", async () => {\n  const root = document.documentElement;\n  const body = document.body;\n  const s = select(body);\n  const t = s.transition().remove().on(\"start\", started).on(\"end\", ended);\n  const end = t.end();\n\n  function started() {\n    assert.strictEqual(body.parentNode, root);\n  }\n\n  function ended() {\n    assert.strictEqual(body.parentNode, null);\n  }\n\n  await new Promise(resolve => timeout(resolve));\n  assert.strictEqual(body.parentNode, root);\n  await end;\n});\n\nit(\"transition.remove() creates an end listener named end.remove\", async () => {\n  const root = document.documentElement;\n  const body = document.body;\n  const s = select(body);\n  const t = s.transition().remove().on(\"start\", started).on(\"end\", ended);\n  const end = t.end();\n\n  function started() {\n    assert.strictEqual(body.parentNode, root);\n  }\n\n  function ended() {\n    assert.strictEqual(body.parentNode, root);\n  }\n\n  t.on(\"end.remove\").call(body);\n  assert.strictEqual(body.parentNode, null);\n  t.on(\"end.remove\", null);\n  root.appendChild(body);\n  await end;\n});\n"
  },
  {
    "path": "test/transition/select-test.js",
    "content": "import assert from \"assert\";\nimport {selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.select(selector) selects the descendants matching the specified selector, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.select(\"child\");\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[one.firstChild, two.firstChild]]);\n  assert.strictEqual(t2._parents, t1._parents);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(one.firstChild.__data__, 1);\n  assert.strictEqual(two.firstChild.__data__, 2);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n\nit(\"transition.select(function) selects the descendants returned by the specified function, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.select(function() { return this.firstChild; });\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[one.firstChild, two.firstChild]]);\n  assert.strictEqual(t2._parents, t1._parents);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(one.firstChild.__data__, 1);\n  assert.strictEqual(two.firstChild.__data__, 2);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n"
  },
  {
    "path": "test/transition/selectAll-test.js",
    "content": "import assert from \"assert\";\nimport {selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.selectAll(selector) selects the descendants matching the specified selector, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.selectAll(\"child\");\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups.map(group => Array.from(group)), [[one.firstChild], [two.firstChild]]);\n  assert.deepStrictEqual(t2._parents, [one, two]);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(\"__data__\" in one.firstChild, false);\n  assert.strictEqual(\"__data__\" in two.firstChild, false);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n\nit(\"transition.selectAll(function) selects the descendants returned by the specified function, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.selectAll(function() { return [this.firstChild]; });\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[one.firstChild], [two.firstChild]]);\n  assert.deepStrictEqual(t2._parents, [one, two]);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(\"__data__\" in one.firstChild, false);\n  assert.strictEqual(\"__data__\" in two.firstChild, false);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n"
  },
  {
    "path": "test/transition/selectChild-test.js",
    "content": "import assert from \"assert\";\nimport {selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.selectChild(selector) selects the child matching the specified selector, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.selectChild(\"child\");\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups, [[one.firstChild, two.firstChild]]);\n  assert.strictEqual(t2._parents, t1._parents);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(one.firstChild.__data__, 1);\n  assert.strictEqual(two.firstChild.__data__, 2);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n"
  },
  {
    "path": "test/transition/selectChildren-test.js",
    "content": "import assert from \"assert\";\nimport {selectAll} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.selectChildren(selector) selects the children matching the specified selector, then derives a transition\", \"<h1 id='one'><child/></h1><h1 id='two'><child/></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t1 = selectAll([one, two]).data([1, 2]).transition().delay(function(d) { return d * 10; });\n  const t2 = t1.selectChildren(\"child\");\n  assert.strictEqual(t2 instanceof transition, true);\n  assert.deepStrictEqual(t2._groups.map(group => Array.from(group)), [[one.firstChild], [two.firstChild]]);\n  assert.deepStrictEqual(t2._parents, [one, two]);\n  assert.strictEqual(t2._name, t1._name);\n  assert.strictEqual(t2._id, t1._id);\n  assert.strictEqual(\"__data__\" in one.firstChild, false);\n  assert.strictEqual(\"__data__\" in two.firstChild, false);\n  assert.strictEqual(one.firstChild.__transition[t1._id].delay, 10);\n  assert.strictEqual(two.firstChild.__transition[t1._id].delay, 20);\n});\n"
  },
  {
    "path": "test/transition/selection-test.js",
    "content": "import assert from \"assert\";\nimport {select, selection} from \"d3-selection\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.selection() returns the transition’s selection\", \"<h1 id='one'>one</h1><h1 id='two'>two</h1>\", () => {\n  const s0 = select(document.body).selectAll(\"h1\");\n  const t = s0.transition();\n  const s1 = t.selection();\n  assert(s1 instanceof selection);\n  assert.strictEqual(s1._groups, s0._groups);\n  assert.strictEqual(s1._parents, s0._parents);\n});\n"
  },
  {
    "path": "test/transition/size-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll, selection} from \"d3-selection\";\nimport {transition} from \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.size is the same as selection.size\", () => {\n  assert.strictEqual(transition.prototype.size, selection.prototype.size);\n});\n\nit(\"transition.size() returns the expected value\", () => {\n  const root = document.documentElement;\n  assert.strictEqual(select(root).transition().size(), 1);\n  assert.strictEqual(selectAll([null, root]).transition().size(), 1);\n});\n"
  },
  {
    "path": "test/transition/style-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {interpolateNumber, interpolateRgb, interpolateString} from \"d3-interpolate\";\nimport {select, selectAll} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.style(name, value) creates an tween to the specified value\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).style(\"color\", \"red\");\n  s.transition().style(\"color\", \"blue\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) creates an tween to the value returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root).style(\"color\", \"red\");\n  s.transition().style(\"color\", () => \"blue\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) immediately evaluates the specified function with the expected context and arguments\", \"<h1 id='one' style='color:#0ff;'></h1><h1 id='two' style='color:#f0f;'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate1 = interpolateRgb(\"cyan\", \"red\");\n  const interpolate2 = interpolateRgb(\"magenta\", \"green\");\n  const t = selectAll([one, two]).data([\"red\", \"green\"]);\n  const result = [];\n  t.transition().style(\"color\", function(d, i, nodes) { result.push([d, i, nodes, this]); return d; });\n  assert.deepStrictEqual(result, [\n    [\"red\", 0, [one, two], one],\n    [\"green\", 1, [one, two], two]\n  ]);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(one.style.getPropertyValue(\"color\"), interpolate1(ease(elapsed / duration)));\n    assert.strictEqual(two.style.getPropertyValue(\"color\"), interpolate2(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) recycles tweens \", \"<h1 id='one' style='color:#f0f;'></h1><h1 id='two' style='color:#f0f;'></h1>\", () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const t = selectAll([one, two]).transition().style(\"color\", \"red\");\n  assert.strictEqual(one.__transition[t._id].tween, two.__transition[t._id].tween);\n});\n\nit(\"transition.style(name, value) constructs an interpolator using the current value on start\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"red\", \"blue\");\n  const s = select(root);\n  s.transition().on(\"start\", () => { s.style(\"color\", \"red\"); }).style(\"color\", () => \"blue\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, null) creates an tween which removes the specified style post-start\", async () => {\n  const root = document.documentElement;\n  const started = () => assert.strictEqual(root.style.getPropertyValue(\"color\"), \"red\");\n  const s = select(root).style(\"color\", \"red\");\n  s.transition().style(\"color\", null).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), \"\");\n    resolve();\n  }));\n});\n\nit(\"transition.style(name, null) creates an tween which removes the specified style post-start\", async () => {\n  const root = document.documentElement;\n  const started = () => assert.strictEqual(root.style.getPropertyValue(\"color\"), \"red\");\n  const selection = select(root).style(\"color\", \"red\");\n  selection.transition().style(\"color\", () => null).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), \"\");\n    resolve();\n  }));\n});\n\nit(\"transition.style(name, value) creates an tween which removes the specified style post-start if the specified function returns null\", async () => {\n  const root = document.documentElement;\n  const started = () => assert.strictEqual(root.style.getPropertyValue(\"color\"), \"red\");\n  const selection = select(root).style(\"color\", \"red\");\n  selection.transition().style(\"color\", function() {}).on(\"start\", started);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), \"\");\n    resolve();\n  }));\n});\n\nit(\"transition.style(name, constant) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const selection = select(root).style(\"opacity\", 1);\n  selection.transition().style(\"opacity\", 1);\n  timeout(() => { root.style.opacity = 0.5; }, 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"opacity\"), \"0.5\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.style(name, function) is a noop if the string-coerced value matches the current value on tween initialization\", async () => {\n  const root = document.documentElement;\n  const selection = select(root).style(\"opacity\", 1);\n  selection.transition().style(\"opacity\", function() { return 1; });\n  timeout(() => { root.style.opacity = 0.5; }, 125);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"opacity\"), \"0.5\");\n    resolve();\n  }, 250));\n});\n\nit(\"transition.style(name, value) interpolates numbers\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateNumber(0, 1);\n  const s = select(root).style(\"opacity\", 0);\n  s.transition().style(\"opacity\", 1);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"opacity\"), interpolate(ease(elapsed / duration)) + \"\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, constant) uses interpolateNumber if value is a number\", async () => {\n  const root = document.documentElement;\n  const s = select(root).style(\"font-size\", \"15px\");\n  s.transition().style(\"font-size\", 10);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"font-size\"), \"15px\"); // ignores NaN\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, function) uses interpolateNumber if value is a number\", async () => {\n  const root = document.documentElement;\n  const s = select(root).style(\"font-size\", \"15px\");\n  s.transition().style(\"font-size\", () => 10);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"font-size\"), \"15px\"); // ignores NaN\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) interpolates strings\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateString(\"1px\", \"2px\");\n  const s = select(root).style(\"font-size\", \"1px\");\n  s.transition().style(\"font-size\", \"2px\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"font-size\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) interpolates colors\", async () => {\n  const root = document.documentElement;\n  const ease = easeCubic;\n  const duration = 250;\n  const interpolate = interpolateRgb(\"#f00\", \"#00f\");\n  const s = select(root).style(\"color\", \"#f00\");\n  s.transition().style(\"color\", \"#00f\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / duration)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.style(name, value) creates an styleTween with the specified name\", async () => {\n  const root = document.documentElement;\n  const s = select(root).style(\"color\", \"red\");\n  const t = s.transition().style(\"color\", \"blue\");\n  assert.strictEqual(t.styleTween(\"color\").call(root).call(root, 0.5), \"rgb(128, 0, 128)\");\n});\n\nit(\"transition.style(name, value) creates a tween with the name \\\"style.name\\\"\", async () => {\n  const root = document.documentElement;\n  const s = select(root).style(\"color\", \"red\");\n  const t = s.transition().style(\"color\", \"blue\");\n  t.tween(\"style.color\").call(root).call(root, 0.5);\n  assert.strictEqual(root.style.getPropertyValue(\"color\"), \"rgb(128, 0, 128)\");\n});\n"
  },
  {
    "path": "test/transition/styleTween-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {interpolateHcl} from \"d3-interpolate\";\nimport {select, selectAll} from \"d3-selection\";\nimport {now, timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {ENDING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.styleTween(name, value) defines a style tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const ease = easeCubic;\n  select(root).transition().styleTween(\"color\", () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.deepStrictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / 250)));\n    assert.deepStrictEqual(root.style.getPropertyPriority(\"color\"), \"\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.styleTween(name, value, priority) defines a style tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const ease = easeCubic;\n  select(root).transition().styleTween(\"color\", () => interpolate, \"important\");\n  await new Promise(resolve => timeout(elapsed => {\n    assert.deepStrictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / 250)));\n    assert.deepStrictEqual(root.style.getPropertyPriority(\"color\"), \"important\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.styleTween(name, value) invokes the value function with the expected context and arguments\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const result = [];\n  selectAll([one, two]).data([\"one\", \"two\"]).transition().styleTween(\"color\", function(d, i, nodes) { result.push([d, i, nodes, this]); });\n  await new Promise(resolve => timeout(resolve));\n  assert.deepStrictEqual(result, [\n    [\"one\", 0, [one, two], one],\n    [\"two\", 1, [one, two], two]\n  ]);\n});\n\nit(\"transition.styleTween(name, value) passes the eased time to the interpolator\", async () => {\n  const root = document.documentElement;\n  const then = now();\n  const duration = 250;\n  const ease = easeCubic;\n  const t = select(root).transition().styleTween(\"color\", () => interpolate);\n  const schedule = root.__transition[t._id];\n  function interpolate(t) {\n    assert.strictEqual(this, root);\n    assert.strictEqual(t, schedule.state === ENDING ? 1 : ease((now() - then) / duration));\n  }\n  await t.end();\n});\n\nit(\"transition.styleTween(name, value) allows the specified function to return null for a noop\", async () => {\n  const root = document.documentElement;\n  const s = select(root).style(\"color\", \"red\");\n  s.transition().styleTween(\"color\", () => {});\n  await new Promise(resolve => timeout(() => {\n    assert.deepStrictEqual(root.style.getPropertyValue(\"color\"), \"red\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.styleTween(name, value) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const ease = easeCubic;\n  select(root).transition().styleTween({toString() { return \"color\"; }}, () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.deepStrictEqual(root.style.getPropertyValue(\"color\"), interpolate(ease(elapsed / 250)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.styleTween(name, value) throws an error if value is not null and not a function\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.styleTween(\"color\", 42); });\n});\n\nit(\"transition.styleTween(name, null) removes the specified style tween\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const t = select(root).transition().styleTween(\"color\", () => interpolate).styleTween(\"color\", null);\n  assert.strictEqual(t.styleTween(\"color\"), null);\n  assert.strictEqual(t.tween(\"style.color\"), null);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(root.style.getPropertyValue(\"color\"), \"\");\n    resolve();\n  }, 125));\n});\n\nit(\"transition.styleTween(name) returns the style tween with the specified name\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const tween = () => interpolate;\n  const started = () => { assert.strictEqual(t.styleTween(\"color\"), tween); };\n  const ended = () => { assert.strictEqual(t.styleTween(\"color\"), tween); };\n  const t = select(root).transition().styleTween(\"color\", tween).on(\"start\", started).on(\"end\", ended);\n  assert.strictEqual(t.styleTween(\"color\"), tween);\n  assert.strictEqual(t.styleTween(\"bar\"), null);\n  await t.end();\n});\n\nit(\"transition.styleTween(name) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const tween = () => {};\n  const t = select(root).transition().styleTween(\"color\", tween);\n  assert.strictEqual(t.styleTween({toString() { return \"color\"; }}), tween);\n});\n"
  },
  {
    "path": "test/transition/text-test.js",
    "content": "import assert from \"assert\";\nimport {select, selectAll} from \"d3-selection\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.text(value) creates a tween to set the text content to the specified value post-start\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().text(\"hello\");\n\n  await new Promise(resolve => t.on(\"start\", () => {\n    assert.strictEqual(root.textContent, \"\");\n    resolve();\n  }));\n\n  assert.strictEqual(root.textContent, \"hello\");\n});\n\nit(\"transition.text(value) creates a tween to set the text content to the value returned by the specified function post-start\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().text(() => \"hello\");\n\n  await new Promise(resolve => t.on(\"start\", () => {\n    assert.strictEqual(root.textContent, \"\");\n    resolve();\n  }));\n\n  assert.strictEqual(root.textContent, \"hello\");\n});\n\nit(\"transition.text(value) immediately evaluates the specified function with the expected context and arguments\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const s = selectAll([one, two]).data([\"red\", \"green\"]);\n  const result = [];\n  const t = s.transition().text(function(d, i, nodes) { result.push([d, i, nodes, this]); return d; });\n\n  assert.deepStrictEqual(result, [\n    [\"red\", 0, [one, two], one],\n    [\"green\", 1, [one, two], two]\n  ]);\n\n  await new Promise(resolve => t.on(\"start\", resolve));\n  assert.strictEqual(one.textContent, \"red\");\n  assert.strictEqual(two.textContent, \"green\");\n});\n\nit(\"transition.text(value) creates a tween with the name \\\"text\\\"\", () => {\n  const root = document.documentElement;\n  const s = select(root);\n  const t = s.transition().text(\"hello\");\n  assert.strictEqual(t.tween(\"text\").call(root), undefined);\n  assert.strictEqual(root.textContent, \"hello\");\n});\n"
  },
  {
    "path": "test/transition/textTween-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {interpolateHcl} from \"d3-interpolate\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.textTween(value) defines a text tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  const interpolate = interpolateHcl(\"red\", \"blue\");\n  const ease = easeCubic;\n  select(root).transition().textTween(() => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.deepStrictEqual(root.textContent, interpolate(ease(elapsed / 250)));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.textTween() returns the existing text tween\", () => {\n  const root = document.documentElement;\n  const factory = () => {};\n  const t = select(root).transition().textTween(factory);\n  assert.strictEqual(t.textTween(), factory);\n});\n\nit(\"transition.textTween(null) removes an existing text tween\", () => {\n  const root = document.documentElement;\n  const factory = () => {};\n  const t = select(root).transition().textTween(factory);\n  t.textTween(undefined);\n  assert.strictEqual(t.textTween(), null);\n});\n"
  },
  {
    "path": "test/transition/transition-test.js",
    "content": "import assert from \"assert\";\nimport {select} from \"d3-selection\";\nimport {timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.transition() allows preceeding transitions with zero duration to end naturally\", async () => {\n  let end0 = false;\n  let end1 = false;\n  let end2 = false;\n  const s = select(document.documentElement);\n  const t = s.transition().duration(0).on(\"end\", () => { end0 = true; });\n  s.transition().duration(0).on(\"end\", () => { end1 = true; });\n  t.transition().duration(0).on(\"end\", () => { end2 = true; });\n  await new Promise(resolve => timeout(resolve, 50));\n  assert.strictEqual(end0, true);\n  assert.strictEqual(end1, true);\n  assert.strictEqual(end2, true);\n});\n"
  },
  {
    "path": "test/transition/tween-test.js",
    "content": "import assert from \"assert\";\nimport {easeCubic} from \"d3-ease\";\nimport {select, selectAll} from \"d3-selection\";\nimport {now, timeout} from \"d3-timer\";\nimport \"../../src/index.js\";\nimport {ENDING} from \"../../src/transition/schedule.js\";\nimport it from \"../jsdom.js\";\n\nit(\"transition.tween(name, value) defines an tween using the interpolator returned by the specified function\", async () => {\n  const root = document.documentElement;\n  let value;\n  const interpolate = t => { value = t; };\n  select(root).transition().tween(\"foo\", () => interpolate);\n  await new Promise(resolve => timeout(elapsed => {\n    assert.strictEqual(value, easeCubic(elapsed / 250));\n    resolve();\n  }, 125));\n});\n\nit(\"transition.tween(name, value) invokes the value function with the expected context and arguments\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const result = [];\n  selectAll([one, two]).data([\"one\", \"two\"]).transition().tween(\"foo\", function(d, i, nodes) { result.push([d, i, nodes, this]); });\n  await new Promise(resolve => timeout(resolve));\n  assert.deepStrictEqual(result, [\n    [\"one\", 0, [one, two], one],\n    [\"two\", 1, [one, two], two]\n  ]);\n});\n\nit(\"transition.tween(name, value) passes the eased time to the interpolator\", async () => {\n  const root = document.documentElement;\n  const then = now();\n  const duration = 250;\n  const ease = easeCubic;\n  const t = select(root).transition().tween(\"foo\", () => interpolate);\n  const schedule = root.__transition[t._id];\n  function interpolate(t) {\n    assert.strictEqual(this, root);\n    assert.strictEqual(t, schedule.state === ENDING ? 1 : ease((now() - then) / duration));\n  }\n  await t.end();\n});\n\nit(\"transition.tween(name, value) allows the specified function to return null for a noop\", async () => {\n  const root = document.documentElement;\n  const s = select(root);\n  s.transition().tween(\"foo\", () => {});\n});\n\nit(\"transition.tween(name, value) uses copy-on-write to apply changes\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const foo = () => {};\n  const bar = () => {};\n  const t = selectAll([one, two]).transition();\n  const schedule1 = one.__transition[t._id];\n  const schedule2 = two.__transition[t._id];\n  t.tween(\"foo\", foo);\n  assert.deepStrictEqual(schedule1.tween, [{name: \"foo\", value: foo}]);\n  assert.strictEqual(schedule2.tween, schedule1.tween);\n  t.tween(\"foo\", bar);\n  assert.deepStrictEqual(schedule1.tween, [{name: \"foo\", value: bar}]);\n  assert.strictEqual(schedule2.tween, schedule1.tween);\n  select(two).transition(t).tween(\"foo\", foo);\n  assert.deepStrictEqual(schedule1.tween, [{name: \"foo\", value: bar}]);\n  assert.deepStrictEqual(schedule2.tween, [{name: \"foo\", value: foo}]);\n});\n\nit(\"transition.tween(name, value) uses copy-on-write to apply removals\", \"<h1 id='one'></h1><h1 id='two'></h1>\", async () => {\n  const one = document.querySelector(\"#one\");\n  const two = document.querySelector(\"#two\");\n  const foo = () => {};\n  const t = selectAll([one, two]).transition();\n  const schedule1 = one.__transition[t._id];\n  const schedule2 = two.__transition[t._id];\n  t.tween(\"foo\", foo);\n  assert.deepStrictEqual(schedule1.tween, [{name: \"foo\", value: foo}]);\n  assert.strictEqual(schedule2.tween, schedule1.tween);\n  t.tween(\"bar\", null);\n  assert.deepStrictEqual(schedule1.tween, [{name: \"foo\", value: foo}]);\n  assert.strictEqual(schedule2.tween, schedule1.tween);\n  t.tween(\"foo\", null);\n  assert.deepStrictEqual(schedule1.tween, []);\n  assert.strictEqual(schedule2.tween, schedule1.tween);\n  select(two).transition(t).tween(\"foo\", foo);\n  assert.deepStrictEqual(schedule1.tween, []);\n  assert.deepStrictEqual(schedule2.tween, [{name: \"foo\", value: foo}]);\n});\n\nit(\"transition.tween(name, value) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const tween = () => {};\n  const t = select(root).transition().tween({toString() { return \"foo\"; }}, tween);\n  assert.strictEqual(t.tween(\"foo\"), tween);\n});\n\nit(\"transition.tween(name) coerces the specified name to a string\", async () => {\n  const root = document.documentElement;\n  const tween = () => {};\n  const t = select(root).transition().tween(\"foo\", tween);\n  assert.strictEqual(t.tween({toString() { return \"foo\"; }}), tween);\n});\n\nit(\"transition.tween(name, value) throws an error if value is not null and not a function\", async () => {\n  const root = document.documentElement;\n  const t = select(root).transition();\n  assert.throws(() => { t.tween(\"foo\", 42); });\n});\n\nit(\"transition.tween(name, null) removes the specified tween\", async () => {\n  const root = document.documentElement;\n  let frames = 0;\n  const interpolate = () => { ++frames; };\n  const t = select(root).transition().tween(\"foo\", () => interpolate).tween(\"foo\", null);\n  assert.strictEqual(t.tween(\"foo\"), null);\n  await new Promise(resolve => timeout(() => {\n    assert.strictEqual(frames, 0);\n    resolve();\n  }, 125));\n});\n\nit(\"transition.tween(name) returns the tween with the specified name\", async () => {\n  const root = document.documentElement;\n  const tween = () => {};\n  const started = () => { assert.strictEqual(t.tween(\"foo\"), tween); }\n  const ended = () => { assert.strictEqual(t.tween(\"foo\"), tween); }\n  const t = select(root).transition().tween(\"foo\", tween).on(\"start\", started).on(\"end\", ended);\n  assert.strictEqual(t.tween(\"foo\"), tween);\n  assert.strictEqual(t.tween(\"bar\"), null);\n  await t.end();\n});\n"
  }
]