[
  {
    "path": ".gitignore",
    "content": "*.bundle.*\nlib/\nnode_modules/\n*.egg-info/\n.ipynb_checkpoints\npackage-lock.json\n"
  },
  {
    "path": ".prettierignore",
    "content": "node_modules\n**/lib\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true\n}"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2017, Project Jupyter Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# jupyterlab-toc\n\nA Table of Contents extension for JupyterLab.\nThis auto-generates a table of contents in the left area when you have a notebook\nor markdown document open. The entries are clickable, and scroll the document\nto the heading in question.\n\nHere is an animation showing the extension's use, with a notebook from the\n[Python Data Science Handbook](https://github.com/jakevdp/PythonDataScienceHandbook):\n![Table of Contents](toc.gif 'Table of Contents')\n\n## Prerequisites\n\n- JupyterLab 1.0\n\n## Installation\n\n```bash\njupyter labextension install @jupyterlab/toc\n```\n\n## Development\n\nFor a development install, do the following in the repository directory:\n\n```bash\njlpm install\njlpm run build\njupyter labextension install .\n```\n\nYou can then run JupyterLab in watch mode to automatically pick up changes to `@jupyterlab/toc`.\nOpen a terminal in the `@jupyterlab/toc` repository directory and enter\n\n```bash\njlpm run watch\n```\n\nThen launch JupyterLab using\n\n```bash\njupyter lab --watch\n```\n\nThis will automatically recompile `@jupyterlab/toc` upon changes,\nand JupyterLab will rebuild itself. You should then be able to refresh the\npage and see your changes.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@jupyterlab/toc\",\n  \"version\": \"1.0.0-pre.1\",\n  \"private\": false,\n  \"description\": \"Table of Contents extension for JupyterLab\",\n  \"keywords\": [\n    \"jupyter\",\n    \"jupyterlab\",\n    \"jupyterlab-extension\"\n  ],\n  \"homepage\": \"https://github.com/jupyterlab/jupyterlab-toc\",\n  \"bugs\": {\n    \"url\": \"https://github.com/jupyterlab/jupyterlab-toc/issues\"\n  },\n  \"license\": \"BSD-3-Clause\",\n  \"author\": \"Project Jupyter\",\n  \"files\": [\n    \"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}\",\n    \"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"types\": \"lib/index.d.ts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/jupyterlab/jupyterlab-toc.git\"\n  },\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"clean\": \"rimraf lib\",\n    \"precommit\": \"lint-staged\",\n    \"prettier\": \"prettier --write '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}'\",\n    \"watch\": \"tsc -w\"\n  },\n  \"dependencies\": {\n    \"@jupyterlab/application\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/apputils\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/cells\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/coreutils\": \"3.0.0-alpha.6\",\n    \"@jupyterlab/docmanager\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/docregistry\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/fileeditor\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/markdownviewer\": \"^1.0.0-alpha.6\",\n    \"@jupyterlab/notebook\": \"^1.0.0-alpha.7\",\n    \"@jupyterlab/rendermime\": \"^1.0.0-alpha.6\",\n    \"@phosphor/algorithm\": \"^1.1.2\",\n    \"@phosphor/coreutils\": \"^1.3.0\",\n    \"@phosphor/messaging\": \"^1.2.2\",\n    \"@phosphor/widgets\": \"^1.6.0\",\n    \"react\": \"~16.4.2\",\n    \"react-dom\": \"~16.4.2\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"~16.4.13\",\n    \"@types/react-dom\": \"~16.0.5\",\n    \"husky\": \"^0.14.3\",\n    \"lint-staged\": \"^7.2.0\",\n    \"prettier\": \"^1.13.7\",\n    \"rimraf\": \"^2.6.1\",\n    \"tslint\": \"^5.10.0\",\n    \"tslint-config-prettier\": \"^1.13.0\",\n    \"tslint-plugin-prettier\": \"^1.3.0\",\n    \"typescript\": \"~3.1.1\"\n  },\n  \"jupyterlab\": {\n    \"extension\": \"lib/extension.js\"\n  },\n  \"lint-staged\": {\n    \"**/*{.ts,.tsx,.css,.json,.md}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"resolutions\": {\n    \"@types/react\": \"~16.4.13\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "src/extension.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport {\n  ILabShell,\n  ILayoutRestorer,\n  JupyterFrontEnd,\n  JupyterFrontEndPlugin\n} from '@jupyterlab/application';\n\nimport { IDocumentManager } from '@jupyterlab/docmanager';\n\nimport { IEditorTracker } from '@jupyterlab/fileeditor';\n\nimport { IMarkdownViewerTracker } from '@jupyterlab/markdownviewer';\n\nimport { INotebookTracker } from '@jupyterlab/notebook';\n\nimport { IRenderMimeRegistry } from '@jupyterlab/rendermime';\n\nimport { TableOfContents } from './toc';\n\nimport {\n  createLatexGenerator,\n  createNotebookGenerator,\n  createMarkdownGenerator,\n  createRenderedMarkdownGenerator\n} from './generators';\n\nimport { ITableOfContentsRegistry, TableOfContentsRegistry } from './registry';\n\nimport '../style/index.css';\n\n/**\n * Initialization data for the jupyterlab-toc extension.\n */\nconst extension: JupyterFrontEndPlugin<ITableOfContentsRegistry> = {\n  id: 'jupyterlab-toc',\n  autoStart: true,\n  provides: ITableOfContentsRegistry,\n  requires: [\n    IDocumentManager,\n    IEditorTracker,\n    ILabShell,\n    ILayoutRestorer,\n    IMarkdownViewerTracker,\n    INotebookTracker,\n    IRenderMimeRegistry\n  ],\n  activate: activateTOC\n};\n\n/**\n * Activate the ToC extension.\n */\nfunction activateTOC(\n  app: JupyterFrontEnd,\n  docmanager: IDocumentManager,\n  editorTracker: IEditorTracker,\n  labShell: ILabShell,\n  restorer: ILayoutRestorer,\n  markdownViewerTracker: IMarkdownViewerTracker,\n  notebookTracker: INotebookTracker,\n  rendermime: IRenderMimeRegistry\n): ITableOfContentsRegistry {\n  // Create the ToC widget.\n  const toc = new TableOfContents({ docmanager, rendermime });\n\n  // Create the ToC registry.\n  const registry = new TableOfContentsRegistry();\n\n  // Add the ToC to the left area.\n  toc.title.iconClass = 'jp-TableOfContents-icon jp-SideBar-tabIcon';\n  toc.title.caption = 'Table of Contents';\n  toc.id = 'table-of-contents';\n  labShell.add(toc, 'left', { rank: 700 });\n\n  // Add the ToC widget to the application restorer.\n  restorer.add(toc, 'juputerlab-toc');\n\n  // Create a notebook TableOfContentsRegistry.IGenerator\n  const notebookGenerator = createNotebookGenerator(\n    notebookTracker,\n    rendermime.sanitizer,\n    toc\n  );\n  registry.addGenerator(notebookGenerator);\n\n  // Create an markdown editor TableOfContentsRegistry.IGenerator\n  const markdownGenerator = createMarkdownGenerator(\n    editorTracker,\n    toc,\n    rendermime.sanitizer\n  );\n  registry.addGenerator(markdownGenerator);\n\n  // Create an rendered markdown editor TableOfContentsRegistry.IGenerator\n  const renderedMarkdownGenerator = createRenderedMarkdownGenerator(\n    markdownViewerTracker,\n    rendermime.sanitizer,\n    toc\n  );\n  registry.addGenerator(renderedMarkdownGenerator);\n\n  // Create a latex editor TableOfContentsRegistry.IGenerator\n  const latexGenerator = createLatexGenerator(editorTracker);\n  registry.addGenerator(latexGenerator);\n\n  // Change the ToC when the active widget changes.\n  labShell.currentChanged.connect(() => {\n    let widget = app.shell.currentWidget;\n    if (!widget) {\n      return;\n    }\n    let generator = registry.findGeneratorForWidget(widget);\n    if (!generator) {\n      // If the previously used widget is still available, stick with it.\n      // Otherwise, set the current TOC widget to null.\n      if (toc.current && toc.current.widget.isDisposed) {\n        toc.current = null;\n      }\n      return;\n    }\n    toc.current = { widget, generator };\n  });\n\n  return registry;\n}\nexport default extension;\n"
  },
  {
    "path": "src/generators/index.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nexport * from './markdowndocgenerator';\nexport * from './latexgenerator';\nexport * from './notebookgenerator';\n"
  },
  {
    "path": "src/generators/latexgenerator.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { IDocumentWidget } from '@jupyterlab/docregistry';\n\nimport { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';\n\nimport { TableOfContentsRegistry } from '../registry';\n\nimport { IHeading } from '../toc';\n\n/**\n * Create a TOC generator for LaTeX files.\n *\n * @param tracker: A file editor tracker.\n *\n * @returns A TOC generator that can parse LaTeX files.\n */\nexport function createLatexGenerator(\n  tracker: IEditorTracker\n): TableOfContentsRegistry.IGenerator<IDocumentWidget<FileEditor>> {\n  return {\n    tracker,\n    usesLatex: true,\n    isEnabled: editor => {\n      // Only enable this if the editor mimetype matches\n      // one of a few LaTeX variants.\n      let mime = editor.content.model.mimeType;\n      return mime === 'text/x-latex' || mime === 'text/x-stex';\n    },\n    generate: editor => {\n      let headings: IHeading[] = [];\n      let model = editor.content.model;\n\n      // Split the text into lines, with the line number for each.\n      // We will use the line number to scroll the editor upon\n      // TOC item click.\n      const lines = model.value.text.split('\\n').map((value, idx) => {\n        return { value, idx };\n      });\n\n      // Iterate over the lines to get the header level and\n      // the text for the line.\n      lines.forEach(line => {\n        const match = line.value.match(\n          /^\\s*\\\\(section|subsection|subsubsection){(.+)}/\n        );\n        if (match) {\n          const level = Private.latexLevels[match[1]];\n          const text = match[2];\n          const onClick = () => {\n            editor.content.editor.setCursorPosition({\n              line: line.idx,\n              column: 0\n            });\n          };\n          headings.push({ text, level, onClick });\n        }\n      });\n      return headings;\n    }\n  };\n}\n\n/**\n * A private namespace for miscellaneous things.\n */\nnamespace Private {\n  /**\n   * A mapping from LaTeX section headers to HTML header\n   * levels. `part` and `chapter` are less common in my experience,\n   * so assign them to header level 1.\n   */\n  export const latexLevels: { [label: string]: number } = {\n    part: 1, // Only available for report and book classes\n    chapter: 1, // Only available for report and book classes\n    section: 1,\n    subsection: 2,\n    subsubsection: 3,\n    paragraph: 4,\n    subparagraph: 5\n  };\n}\n"
  },
  {
    "path": "src/generators/markdowndocgenerator/index.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { ISanitizer } from '@jupyterlab/apputils';\n\nimport { IDocumentWidget } from '@jupyterlab/docregistry';\n\nimport { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';\n\nimport {\n  IMarkdownViewerTracker,\n  MarkdownDocument\n} from '@jupyterlab/markdownviewer';\n\nimport { TableOfContentsRegistry } from '../../registry';\n\nimport {\n  generateNumbering,\n  sanitizerOptions,\n  isMarkdown,\n  INumberedHeading\n} from '../shared';\n\nimport { MarkdownDocGeneratorOptionsManager } from './optionsmanager';\n\nimport { TableOfContents } from '../../toc';\n\nimport { markdownDocItemRenderer } from './itemrenderer';\n\nimport { markdownDocGeneratorToolbar } from './toolbargenerator';\n\n/**\n * Create a TOC generator for markdown files.\n *\n * @param tracker: A file editor tracker.\n *\n * @returns A TOC generator that can parse markdown files.\n */\nexport function createMarkdownGenerator(\n  tracker: IEditorTracker,\n  widget: TableOfContents,\n  sanitizer: ISanitizer\n): TableOfContentsRegistry.IGenerator<IDocumentWidget<FileEditor>> {\n  // Create a option manager to manage user settings\n  const options = new MarkdownDocGeneratorOptionsManager(widget, {\n    needsNumbering: true,\n    sanitizer\n  });\n  return {\n    tracker,\n    usesLatex: true,\n    options: options,\n    toolbarGenerator: () => {\n      return markdownDocGeneratorToolbar(options);\n    },\n    itemRenderer: (item: INumberedHeading) => {\n      return markdownDocItemRenderer(options, item);\n    },\n    isEnabled: editor => {\n      // Only enable this if the editor mimetype matches\n      // one of a few markdown variants.\n      return isMarkdown(editor.content.model.mimeType);\n    },\n    generate: editor => {\n      let numberingDict: { [level: number]: number } = {};\n      let model = editor.content.model;\n      let onClickFactory = (line: number) => {\n        return () => {\n          editor.content.editor.setCursorPosition({ line, column: 0 });\n        };\n      };\n      return Private.getMarkdownDocHeadings(\n        model.value.text,\n        onClickFactory,\n        numberingDict\n      );\n    }\n  };\n}\n\n/**\n * Create a TOC generator for rendered markdown files.\n *\n * @param tracker: A file editor tracker.\n *\n * @returns A TOC generator that can parse markdown files.\n */\nexport function createRenderedMarkdownGenerator(\n  tracker: IMarkdownViewerTracker,\n  sanitizer: ISanitizer,\n  widget: TableOfContents\n): TableOfContentsRegistry.IGenerator<MarkdownDocument> {\n  const options = new MarkdownDocGeneratorOptionsManager(widget, {\n    needsNumbering: true,\n    sanitizer\n  });\n  return {\n    tracker,\n    usesLatex: true,\n    options: options,\n    toolbarGenerator: () => {\n      return markdownDocGeneratorToolbar(options);\n    },\n    itemRenderer: (item: INumberedHeading) => {\n      return markdownDocItemRenderer(options, item);\n    },\n    generate: widget => {\n      let numberingDict: { [level: number]: number } = {};\n      return Private.getRenderedHTMLHeadingsForMarkdownDoc(\n        widget.content.node,\n        sanitizer,\n        numberingDict,\n        options.numbering\n      );\n    }\n  };\n}\n\n/**\n * A private namespace for miscellaneous things.\n */\nnamespace Private {\n  export function getMarkdownDocHeadings(\n    text: string,\n    onClickFactory: (line: number) => (() => void),\n    numberingDict: { [level: number]: number }\n  ): INumberedHeading[] {\n    // Split the text into lines.\n    const lines = text.split('\\n');\n    let headings: INumberedHeading[] = [];\n\n    let inCodeBlock = false;\n    // Iterate over the lines to get the header level and\n    // the text for the line.\n    lines.forEach((line, idx) => {\n      // Don't check for markdown headings if we\n      // are in a code block (demarcated by backticks).\n      if (line.indexOf('```') === 0) {\n        inCodeBlock = !inCodeBlock;\n      }\n      if (inCodeBlock) {\n        return;\n      }\n      // Make an onClick handler for this line.\n      const onClick = onClickFactory(idx);\n\n      // First test for '#'-style headers.\n      let match = line.match(/^([#]{1,6}) (.*)/);\n      if (match) {\n        const level = match[1].length;\n        // Take special care to parse markdown links into raw text.\n        const text = match[2].replace(/\\[(.+)\\]\\(.+\\)/g, '$1');\n        let numbering = generateNumbering(numberingDict, level);\n        headings.push({\n          text,\n          numbering,\n          level,\n          onClick\n        });\n        return;\n      }\n\n      // Next test for '==='-style headers.\n      match = line.match(/^([=]{2,}|[-]{2,})/);\n      if (match && idx > 0) {\n        const level = match[1][0] === '=' ? 1 : 2;\n        const prev = lines[idx - 1];\n        // If the previous line is already a '#'-style heading,\n        // then this is not a '===' style heading.\n        const prevMatch = prev.match(/^([#]{1,6}) (.*)/);\n        if (prevMatch) {\n          return;\n        }\n        // Take special care to parse markdown links into raw text.\n        const text = prev.replace(/\\[(.+)\\]\\(.+\\)/g, '$1');\n        let numbering = generateNumbering(numberingDict, level);\n        headings.push({\n          text,\n          numbering,\n          level,\n          onClick\n        });\n        return;\n      }\n\n      // Finally test for HTML headers. This will not catch multiline\n      // headers, nor will it catch multiple headers on the same line.\n      // It should do a decent job of catching many, though.\n      match = line.match(/<h([1-6])>(.*)<\\/h\\1>/i);\n      if (match) {\n        const level = parseInt(match[1], 10);\n        const text = match[2];\n        let numbering = generateNumbering(numberingDict, level);\n        headings.push({\n          text,\n          numbering,\n          level,\n          onClick\n        });\n        return;\n      }\n    });\n    return headings;\n  }\n\n  /**\n   * Given a HTML DOM element, get the markdown headings\n   * in that string.\n   */\n  export function getRenderedHTMLHeadingsForMarkdownDoc(\n    node: HTMLElement,\n    sanitizer: ISanitizer,\n    numberingDict: { [level: number]: number },\n    needsNumbering = true\n  ): INumberedHeading[] {\n    let headings: INumberedHeading[] = [];\n    let headingNodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6');\n    for (let i = 0; i < headingNodes.length; i++) {\n      const heading = headingNodes[i];\n      const level = parseInt(heading.tagName[1], 10);\n      let text = heading.textContent ? heading.textContent : '';\n      let shallHide = !needsNumbering;\n\n      // Show/hide numbering DOM element based on user settings\n      if (heading.getElementsByClassName('numbering-entry').length > 0) {\n        heading.removeChild(\n          heading.getElementsByClassName('numbering-entry')[0]\n        );\n      }\n      let html = sanitizer.sanitize(heading.innerHTML, sanitizerOptions);\n      html = html.replace('¶', ''); // Remove the anchor symbol.\n      const onClick = () => {\n        heading.scrollIntoView();\n      };\n\n      // Get the numbering string\n      let numbering = generateNumbering(numberingDict, level);\n\n      // Generate the DOM element for numbering\n      let numDOM = '';\n      if (!shallHide) {\n        numDOM = '<span class=\"numbering-entry\">' + numbering + '</span>';\n      }\n\n      // Add DOM numbering element to document\n      heading.innerHTML = numDOM + html;\n\n      text = text.replace('¶', '');\n      headings.push({\n        level,\n        text,\n        numbering,\n        html,\n        onClick\n      });\n    }\n    return headings;\n  }\n}\n"
  },
  {
    "path": "src/generators/markdowndocgenerator/itemrenderer.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { MarkdownDocGeneratorOptionsManager } from './optionsmanager';\n\nimport { INumberedHeading, sanitizerOptions } from '../shared';\n\nimport * as React from 'react';\n\nexport function markdownDocItemRenderer(\n  options: MarkdownDocGeneratorOptionsManager,\n  item: INumberedHeading\n) {\n  let fontSizeClass = 'toc-level-size-default';\n\n  // Render numbering if needed\n  let numbering = item.numbering && options.numbering ? item.numbering : '';\n  fontSizeClass = 'toc-level-size-' + item.level;\n  let jsx;\n  if (item.html) {\n    jsx = (\n      <span\n        dangerouslySetInnerHTML={{\n          __html:\n            numbering + options.sanitizer.sanitize(item.html, sanitizerOptions)\n        }}\n        className={'toc-markdown-cell ' + fontSizeClass}\n      />\n    );\n  } else {\n    jsx = <span className={fontSizeClass}> {numbering + item.text}</span>;\n  }\n  return jsx;\n}\n"
  },
  {
    "path": "src/generators/markdowndocgenerator/optionsmanager.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { ISanitizer } from '@jupyterlab/apputils';\n\nimport { TableOfContentsRegistry } from '../../registry';\n\nimport { TableOfContents } from '../../toc';\n\nexport class MarkdownDocGeneratorOptionsManager extends TableOfContentsRegistry.IGeneratorOptionsManager {\n  constructor(\n    widget: TableOfContents,\n    options: { needsNumbering: boolean; sanitizer: ISanitizer }\n  ) {\n    super();\n    this._numbering = options.needsNumbering;\n    this._widget = widget;\n    this.sanitizer = options.sanitizer;\n  }\n\n  readonly sanitizer: ISanitizer;\n\n  set numbering(value: boolean) {\n    this._numbering = value;\n    this._widget.update();\n  }\n\n  get numbering() {\n    return this._numbering;\n  }\n\n  // initialize options, will NOT change notebook metadata\n  initializeOptions(numbering: boolean) {\n    this._numbering = numbering;\n    this._widget.update();\n  }\n\n  private _numbering: boolean;\n  private _widget: TableOfContents;\n}\n"
  },
  {
    "path": "src/generators/markdowndocgenerator/toolbargenerator.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { MarkdownDocGeneratorOptionsManager } from './optionsmanager';\n\nimport * as React from 'react';\n\ninterface INotebookGeneratorToolbarProps {}\n\ninterface INotebookGeneratorToolbarState {\n  numbering: boolean;\n}\n\nexport function markdownDocGeneratorToolbar(\n  options: MarkdownDocGeneratorOptionsManager\n) {\n  // Render the toolbar\n  return class extends React.Component<\n    INotebookGeneratorToolbarProps,\n    INotebookGeneratorToolbarState\n  > {\n    constructor(props: INotebookGeneratorToolbarProps) {\n      super(props);\n      this.state = { numbering: false };\n      options.initializeOptions(false);\n    }\n\n    render() {\n      const toggleAutoNumbering = () => {\n        options.numbering = !options.numbering;\n        this.setState({ numbering: options.numbering });\n      };\n      let numberingIcon = this.state.numbering ? (\n        <div\n          className=\"toc-toolbar-auto-numbering-button toc-toolbar-button\"\n          onClick={event => toggleAutoNumbering()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Auto-Numbering\"\n            title=\"Toggle Auto-Numbering\"\n            className=\"toc-toolbar-auto-numbering-icon toc-toolbar-icon-selected\"\n          />\n        </div>\n      ) : (\n        <div\n          className=\"toc-toolbar-auto-numbering-button toc-toolbar-button\"\n          onClick={event => toggleAutoNumbering()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Auto-Numbering\"\n            title=\"Toggle Auto-Numbering\"\n            className=\"toc-toolbar-auto-numbering-icon toc-toolbar-icon\"\n          />\n        </div>\n      );\n\n      return (\n        <div>\n          <div className={'toc-toolbar'}>{numberingIcon}</div>\n        </div>\n      );\n    }\n  };\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/codemirror.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport * as React from 'react';\n\nimport { ISanitizer } from '@jupyterlab/apputils';\n\nimport { INotebookHeading } from './heading';\n\nimport { sanitizerOptions } from '../shared';\n\nexport interface ICodeComponentProps {\n  sanitizer: ISanitizer;\n  heading: INotebookHeading;\n}\n\nexport interface ICodeComponentState {\n  heading: INotebookHeading;\n}\n\nexport class CodeComponent extends React.Component<\n  ICodeComponentProps,\n  ICodeComponentState\n> {\n  constructor(props: ICodeComponentProps) {\n    super(props);\n    this.state = { heading: props.heading };\n  }\n\n  componentWillReceiveProps(nextProps: ICodeComponentProps) {\n    this.setState({ heading: nextProps.heading });\n  }\n\n  render() {\n    // Grab the rendered CodeMirror DOM in the document, show it in TOC.\n    let html = this.state.heading.cellRef!.editor.host.innerHTML;\n    // Sanitize it to be safe.\n    html = this.props.sanitizer.sanitize(html, sanitizerOptions);\n    return (\n      <div className=\"cm-toc\" dangerouslySetInnerHTML={{ __html: html }} />\n    );\n  }\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/heading.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { Cell } from '@jupyterlab/cells';\n\nimport { INumberedHeading } from '../shared';\n\n/**\n * A heading for a notebook cell.\n */\nexport interface INotebookHeading extends INumberedHeading {\n  type: 'header' | 'markdown' | 'code';\n  prompt?: string;\n  cellRef: Cell;\n  hasChild?: boolean;\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/index.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { ISanitizer } from '@jupyterlab/apputils';\n\nimport { CodeCell, CodeCellModel, MarkdownCell, Cell } from '@jupyterlab/cells';\n\nimport { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';\n\nimport { notebookItemRenderer } from './itemrenderer';\n\nimport { notebookGeneratorToolbar } from './toolbargenerator';\n\nimport { TableOfContentsRegistry } from '../../registry';\n\nimport { TableOfContents } from '../../toc';\n\nimport { NotebookGeneratorOptionsManager } from './optionsmanager';\n\nimport { INotebookHeading } from './heading';\n\nimport {\n  generateNumbering,\n  isDOM,\n  isMarkdown,\n  sanitizerOptions\n} from '../shared';\n\n/**\n * Create a TOC generator for notebooks.\n *\n * @param tracker: A notebook tracker.\n *\n * @returns A TOC generator that can parse notebooks.\n */\nexport function createNotebookGenerator(\n  tracker: INotebookTracker,\n  sanitizer: ISanitizer,\n  widget: TableOfContents\n): TableOfContentsRegistry.IGenerator<NotebookPanel> {\n  // Create a option manager to manage user settings\n  const options = new NotebookGeneratorOptionsManager(widget, tracker, {\n    needsNumbering: false,\n    sanitizer: sanitizer\n  });\n  return {\n    tracker,\n    usesLatex: true,\n    options: options,\n    toolbarGenerator: () => {\n      return notebookGeneratorToolbar(options, tracker);\n    },\n    itemRenderer: (item: INotebookHeading) => {\n      return notebookItemRenderer(options, item);\n    },\n    generate: panel => {\n      let headings: INotebookHeading[] = [];\n      let numberingDict: { [level: number]: number } = {};\n      let collapseLevel = -1;\n      // Keep track of the previous heading, so it can be\n      // marked as having a child if one is discovered\n      let prevHeading: INotebookHeading | null = null;\n      // Iterate through the cells in the notebook, generating their headings\n      for (let i = 0; i < panel.content.widgets.length; i++) {\n        let cell: Cell = panel.content.widgets[i];\n        let collapsed = cell.model.metadata.get('toc-hr-collapsed') as boolean;\n        collapsed = collapsed !== undefined ? collapsed : false;\n        let model = cell.model;\n        if (model.type === 'code') {\n          // Code is shown by default, overridden by previously saved settings\n          if (!widget || (widget && options.showCode)) {\n            // Generate the heading and add to headings if appropriate\n            let executionCountNumber = (cell as CodeCell).model\n              .executionCount as number | null;\n            let executionCount =\n              executionCountNumber !== null\n                ? '[' + executionCountNumber + ']: '\n                : '[ ]: ';\n            let text = (model as CodeCellModel).value.text;\n            const onClickFactory = (line: number) => {\n              return () => {\n                panel.content.activeCellIndex = i;\n                cell.node.scrollIntoView();\n              };\n            };\n            let lastLevel = Private.getLastLevel(headings);\n            let renderedHeading = Private.getCodeCells(\n              text,\n              onClickFactory,\n              executionCount,\n              lastLevel,\n              cell\n            );\n            [headings, prevHeading] = Private.addMDOrCode(\n              headings,\n              renderedHeading,\n              prevHeading,\n              collapseLevel,\n              options.filtered\n            );\n          }\n          // Iterate over the code cell outputs to check for MD/HTML\n          for (let j = 0; j < (model as CodeCellModel).outputs.length; j++) {\n            const outputModel = (model as CodeCellModel).outputs.get(j);\n            const dataTypes = Object.keys(outputModel.data);\n            const htmlData = dataTypes.filter(t => isMarkdown(t) || isDOM(t));\n            if (!htmlData.length) {\n              continue;\n            }\n            // If MD/HTML generate the heading and add to headings if applicable\n            const outputWidget = (cell as CodeCell).outputArea.widgets[j];\n            const onClickFactory = (el: Element) => {\n              return () => {\n                panel.content.activeCellIndex = i;\n                panel.content.mode = 'command';\n                el.scrollIntoView();\n              };\n            };\n            let lastLevel = Private.getLastLevel(headings);\n            let numbering = options.numbering;\n            let renderedHeading = Private.getRenderedHTMLHeading(\n              outputWidget.node,\n              onClickFactory,\n              sanitizer,\n              numberingDict,\n              lastLevel,\n              numbering,\n              cell\n            );\n            [headings, prevHeading, collapseLevel] = Private.processMD(\n              renderedHeading,\n              options.showMarkdown,\n              headings,\n              prevHeading,\n              collapseLevel,\n              options.filtered,\n              collapsed\n            );\n          }\n        } else if (model.type === 'markdown') {\n          let mdCell = cell as MarkdownCell;\n          let renderedHeading: INotebookHeading | undefined = undefined;\n          let lastLevel = Private.getLastLevel(headings);\n          // If the cell is rendered, generate the ToC items from the HTML\n          if (mdCell.rendered && !mdCell.inputHidden) {\n            const onClickFactory = (el: Element) => {\n              return () => {\n                if (!mdCell.rendered) {\n                  panel.content.activeCellIndex = i;\n                  el.scrollIntoView();\n                } else {\n                  panel.content.mode = 'command';\n                  cell.node.scrollIntoView();\n                  panel.content.activeCellIndex = i;\n                }\n              };\n            };\n            renderedHeading = Private.getRenderedHTMLHeading(\n              cell.node,\n              onClickFactory,\n              sanitizer,\n              numberingDict,\n              lastLevel,\n              options.numbering,\n              cell\n            );\n            // If not rendered, generate ToC items from the text of the cell\n          } else {\n            const onClickFactory = (line: number) => {\n              return () => {\n                panel.content.activeCellIndex = i;\n                cell.node.scrollIntoView();\n              };\n            };\n            renderedHeading = Private.getMarkdownHeading(\n              model!.value.text,\n              onClickFactory,\n              numberingDict,\n              lastLevel,\n              cell\n            );\n          }\n          // Add to headings if applicable\n          [headings, prevHeading, collapseLevel] = Private.processMD(\n            renderedHeading,\n            options.showMarkdown,\n            headings,\n            prevHeading,\n            collapseLevel,\n            options.filtered,\n            collapsed\n          );\n        }\n      }\n      return headings;\n    }\n  };\n}\n\nnamespace Private {\n  /**\n   * Determine whether a heading is filtered out by selected tags.\n   */\n  export function headingIsFilteredOut(\n    heading: INotebookHeading,\n    tags: string[]\n  ) {\n    if (tags.length === 0) {\n      return false;\n    }\n    if (heading && heading.cellRef) {\n      let cellMetadata = heading.cellRef.model.metadata;\n      let cellTagsData = cellMetadata.get('tags') as string[];\n      if (cellTagsData) {\n        for (let j = 0; j < cellTagsData.length; j++) {\n          let name = cellTagsData[j];\n          for (let k = 0; k < tags.length; k++) {\n            if (tags[k] === name) {\n              return false;\n            }\n          }\n        }\n      }\n    }\n    return true;\n  }\n\n  export function getLastLevel(headings: INotebookHeading[]) {\n    if (headings.length > 0) {\n      let location = headings.length - 1;\n      while (location >= 0) {\n        if (headings[location].type === 'header') {\n          return headings[location].level;\n        }\n        location = location - 1;\n      }\n    }\n    return 0;\n  }\n\n  export function processMD(\n    renderedHeading: INotebookHeading | undefined,\n    showMarkdown: boolean,\n    headings: INotebookHeading[],\n    prevHeading: INotebookHeading | null,\n    collapseLevel: number,\n    filtered: string[],\n    collapsed: boolean\n  ): [INotebookHeading[], INotebookHeading | null, number] {\n    // If the heading is MD and MD is shown, add to headings\n    if (\n      renderedHeading &&\n      renderedHeading.type === 'markdown' &&\n      showMarkdown\n    ) {\n      [headings, prevHeading] = Private.addMDOrCode(\n        headings,\n        renderedHeading,\n        prevHeading,\n        collapseLevel,\n        filtered\n      );\n      // Otherwise, if the heading is a header, add to headings\n    } else if (renderedHeading && renderedHeading.type === 'header') {\n      [headings, prevHeading, collapseLevel] = Private.addHeader(\n        headings,\n        renderedHeading,\n        prevHeading,\n        collapseLevel,\n        filtered,\n        collapsed\n      );\n    }\n    return [headings, prevHeading, collapseLevel];\n  }\n\n  export function addMDOrCode(\n    headings: INotebookHeading[],\n    renderedHeading: INotebookHeading,\n    prevHeading: INotebookHeading | null,\n    collapseLevel: number,\n    filtered: string[]\n  ): [INotebookHeading[], INotebookHeading | null] {\n    if (\n      !Private.headingIsFilteredOut(renderedHeading, filtered) &&\n      renderedHeading &&\n      renderedHeading.text\n    ) {\n      // If there is a previous header, find it and mark hasChild true\n      if (prevHeading && prevHeading.type === 'header') {\n        for (let j = headings.length - 1; j >= 0; j--) {\n          if (headings[j] === prevHeading) {\n            headings[j].hasChild = true;\n          }\n        }\n      }\n      if (collapseLevel < 0) {\n        headings.push(renderedHeading);\n      }\n      prevHeading = renderedHeading;\n    }\n    return [headings, prevHeading];\n  }\n\n  export function addHeader(\n    headings: INotebookHeading[],\n    renderedHeading: INotebookHeading,\n    prevHeading: INotebookHeading | null,\n    collapseLevel: number,\n    filtered: string[],\n    collapsed: boolean\n  ): [INotebookHeading[], INotebookHeading | null, number] {\n    if (!Private.headingIsFilteredOut(renderedHeading, filtered)) {\n      // if the previous heading is a header of a higher level,\n      // find it and mark it as having a child\n      if (\n        prevHeading &&\n        prevHeading.type === 'header' &&\n        prevHeading.level < renderedHeading.level\n      ) {\n        for (let j = headings.length - 1; j >= 0; j--) {\n          if (headings[j] === prevHeading) {\n            headings[j].hasChild = true;\n          }\n        }\n      }\n      // if the collapse level doesn't include the header, or if there is no\n      // collapsing, add to headings and adjust the collapse level appropriately\n      if (collapseLevel >= renderedHeading.level || collapseLevel < 0) {\n        headings.push(renderedHeading);\n        collapseLevel = collapsed ? renderedHeading.level : -1;\n      }\n      prevHeading = renderedHeading;\n    } else if (prevHeading && renderedHeading.level <= prevHeading.level) {\n      // If header is filtered out and has a previous heading of smaller level, go\n      // back through headings to determine if it has a parent\n      let k = headings.length - 1;\n      let parentHeading = false;\n      while (k >= 0 && parentHeading === false) {\n        if (headings[k].level < renderedHeading.level) {\n          prevHeading = headings[k];\n          parentHeading = true;\n        }\n        k--;\n      }\n      // If there is no parent, set prevHeading to null and reset collapsing\n      if (!parentHeading) {\n        prevHeading = null;\n        collapseLevel = -1;\n        // Otherwise, reset collapsing appropriately\n      } else {\n        let parentState = headings[k + 1].cellRef.model.metadata.get(\n          'toc-hr-collapsed'\n        ) as boolean;\n        parentState = parentState !== undefined ? parentState : false;\n        collapseLevel = parentState ? headings[k + 1].level : -1;\n      }\n    }\n    return [headings, prevHeading, collapseLevel];\n  }\n\n  /**\n   * Given a string of code, get the code entry.\n   */\n  export function getCodeCells(\n    text: string,\n    onClickFactory: (line: number) => (() => void),\n    executionCount: string,\n    lastLevel: number,\n    cellRef: Cell\n  ): INotebookHeading {\n    let headings: INotebookHeading[] = [];\n    if (text) {\n      const lines = text.split('\\n');\n      let headingText = '';\n      let numLines = Math.min(lines.length, 3);\n      for (let i = 0; i < numLines - 1; i++) {\n        headingText = headingText + lines[i] + '\\n';\n      }\n      headingText = headingText + lines[numLines - 1];\n      const onClick = onClickFactory(0);\n      const level = lastLevel + 1;\n      headings.push({\n        text: headingText,\n        level,\n        onClick,\n        type: 'code',\n        prompt: executionCount,\n        cellRef: cellRef,\n        hasChild: false\n      });\n    }\n    return headings[0];\n  }\n\n  /**\n   * Given a string of markdown, get the markdown headings in that string.\n   */\n  export function getMarkdownHeading(\n    text: string,\n    onClickFactory: (line: number) => (() => void),\n    numberingDict: any,\n    lastLevel: number,\n    cellRef: Cell\n  ): INotebookHeading {\n    const lines = text.split('\\n');\n    const line = lines[0];\n    const line2 = lines.length > 1 ? lines[1] : undefined;\n    const onClick = onClickFactory(0);\n    // First test for '#'-style headers.\n    let match = line.match(/^([#]{1,6}) (.*)/);\n    let match2 = line2 && line2.match(/^([=]{2,}|[-]{2,})/);\n    let match3 = line.match(/<h([1-6])>(.*)<\\/h\\1>/i);\n    if (match) {\n      const level = match[1].length;\n      // Take special care to parse markdown links into raw text.\n      const text = match[2].replace(/\\[(.+)\\]\\(.+\\)/g, '$1');\n      let numbering = generateNumbering(numberingDict, level);\n      return {\n        text,\n        level,\n        numbering,\n        onClick,\n        type: 'header',\n        cellRef: cellRef,\n        hasChild: false\n      };\n    } else if (match2) {\n      // Next test for '==='-style headers.\n      const level = match2[1][0] === '=' ? 1 : 2;\n      // Take special care to parse markdown links into raw text.\n      const text = line.replace(/\\[(.+)\\]\\(.+\\)/g, '$1');\n      let numbering = generateNumbering(numberingDict, level);\n      return {\n        text,\n        level,\n        numbering,\n        onClick,\n        type: 'header',\n        cellRef: cellRef,\n        hasChild: false\n      };\n    } else if (match3) {\n      // Finally test for HTML headers. This will not catch multiline\n      // headers, nor will it catch multiple headers on the same line.\n      // It should do a decent job of catching many, though.\n      const level = parseInt(match3[1], 10);\n      const text = match3[2];\n      let numbering = generateNumbering(numberingDict, level);\n      return {\n        text,\n        level,\n        numbering,\n        onClick,\n        type: 'header',\n        cellRef: cellRef,\n        hasChild: false\n      };\n    } else {\n      return {\n        text: line,\n        level: lastLevel + 1,\n        onClick,\n        type: 'markdown',\n        cellRef: cellRef,\n        hasChild: false\n      };\n    }\n  }\n\n  /**\n   * Given an HTML element, generate ToC headings\n   * by finding all the headers and making IHeading objects for them.\n   */\n  export function getRenderedHTMLHeading(\n    node: HTMLElement,\n    onClickFactory: (el: Element) => (() => void),\n    sanitizer: ISanitizer,\n    numberingDict: { [level: number]: number },\n    lastLevel: number,\n    needsNumbering = false,\n    cellRef: Cell\n  ): INotebookHeading | undefined {\n    let headingNodes = node.querySelectorAll('h1, h2, h3, h4, h5, h6, p');\n    if (headingNodes.length > 0) {\n      let markdownCell = headingNodes[0];\n      if (markdownCell.nodeName.toLowerCase() === 'p') {\n        if (markdownCell.innerHTML) {\n          let html = sanitizer.sanitize(\n            markdownCell.innerHTML,\n            sanitizerOptions\n          );\n          html = html.replace('¶', '');\n          return {\n            level: lastLevel + 1,\n            html: html,\n            text: markdownCell.textContent ? markdownCell.textContent : '',\n            onClick: onClickFactory(markdownCell),\n            type: 'markdown',\n            cellRef: cellRef,\n            hasChild: false\n          };\n        }\n      } else {\n        const heading = headingNodes[0];\n        const level = parseInt(heading.tagName[1], 10);\n        const text = heading.textContent ? heading.textContent : '';\n        let shallHide = !needsNumbering;\n        if (heading.getElementsByClassName('numbering-entry').length > 0) {\n          heading.removeChild(\n            heading.getElementsByClassName('numbering-entry')[0]\n          );\n        }\n        let html = sanitizer.sanitize(heading.innerHTML, sanitizerOptions);\n        html = html.replace('¶', '');\n        const onClick = onClickFactory(heading);\n        let numbering = generateNumbering(numberingDict, level);\n        let numDOM = '';\n        if (!shallHide) {\n          numDOM = '<span class=\"numbering-entry\">' + numbering + '</span>';\n        }\n        heading.innerHTML = numDOM + html;\n        return {\n          level,\n          text,\n          numbering,\n          html,\n          onClick,\n          type: 'header',\n          cellRef: cellRef,\n          hasChild: false\n        };\n      }\n    }\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/itemrenderer.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { CodeComponent } from './codemirror';\n\nimport { Cell } from '@jupyterlab/cells';\n\nimport { NotebookGeneratorOptionsManager } from './optionsmanager';\n\nimport { INotebookHeading } from './heading';\n\nimport { sanitizerOptions } from '../shared';\n\nimport * as React from 'react';\n\nexport function notebookItemRenderer(\n  options: NotebookGeneratorOptionsManager,\n  item: INotebookHeading\n) {\n  let jsx;\n  if (item.type === 'markdown' || item.type === 'header') {\n    const collapseOnClick = (cellRef?: Cell) => {\n      let collapsed = cellRef!.model.metadata.get(\n        'toc-hr-collapsed'\n      ) as boolean;\n      collapsed = collapsed != undefined ? collapsed : false;\n      cellRef!.model.metadata.set('toc-hr-collapsed', !collapsed);\n      options.updateWidget();\n    };\n    let fontSizeClass = 'toc-level-size-default';\n    let numbering = item.numbering && options.numbering ? item.numbering : '';\n    if (item.type === 'header') {\n      fontSizeClass = 'toc-level-size-' + item.level;\n    }\n    if (item.html && (item.type === 'header' || options.showMarkdown)) {\n      jsx = (\n        <span\n          dangerouslySetInnerHTML={{\n            __html:\n              numbering +\n              options.sanitizer.sanitize(item.html, sanitizerOptions)\n          }}\n          className={item.type + '-cell toc-cell-item ' + fontSizeClass}\n        />\n      );\n      // Render the headers\n      if (item.type === 'header') {\n        let collapsed = item.cellRef!.model.metadata.get(\n          'toc-hr-collapsed'\n        ) as boolean;\n        collapsed = collapsed != undefined ? collapsed : false;\n\n        // Render the twist button\n        let twistButton = (\n          <div\n            className=\"toc-collapse-button\"\n            onClick={event => {\n              event.stopPropagation();\n              collapseOnClick(item.cellRef);\n            }}\n          >\n            <div className=\"toc-twist-placeholder\">placeholder</div>\n            <div className=\"toc-downarrow-img toc-arrow-img\" />\n          </div>\n        );\n        if (collapsed) {\n          twistButton = (\n            <div\n              className=\"toc-collapse-button\"\n              onClick={event => {\n                event.stopPropagation();\n                collapseOnClick(item.cellRef);\n              }}\n            >\n              <div className=\"toc-twist-placeholder\">placeholder</div>\n              <div className=\"toc-rightarrow-img toc-arrow-img\" />\n            </div>\n          );\n        }\n        // Render the header item\n        jsx = (\n          <div className=\"toc-entry-holder\">\n            {item.hasChild && twistButton}\n            {jsx}\n          </div>\n        );\n      }\n    } else if (item.type === 'header' || options.showMarkdown) {\n      // Render headers/markdown for plain text\n      jsx = (\n        <span className={item.type + '-cell toc-cell-item ' + fontSizeClass}>\n          {numbering + item.text}\n        </span>\n      );\n      if (item.type === 'header') {\n        let collapsed = item.cellRef!.model.metadata.get(\n          'toc-hr-collapsed'\n        ) as boolean;\n        collapsed = collapsed != undefined ? collapsed : false;\n        let twistButton = (\n          <div\n            className=\"toc-collapse-button\"\n            onClick={event => {\n              event.stopPropagation();\n              collapseOnClick(item.cellRef);\n            }}\n          >\n            <div className=\"toc-twist-placeholder\">placeholder</div>\n            <div className=\"toc-downarrow-img toc-arrow-img\" />\n          </div>\n        );\n        if (collapsed) {\n          twistButton = (\n            <div\n              className=\"toc-collapse-button\"\n              onClick={event => {\n                event.stopPropagation();\n                collapseOnClick(item.cellRef);\n              }}\n            >\n              <div className=\"toc-twist-placeholder\">placeholder</div>\n              <div className=\"toc-rightarrow-img toc-arrow-img\" />\n            </div>\n          );\n        }\n        jsx = (\n          <div className=\"toc-entry-holder\">\n            {item.hasChild && twistButton}\n            {jsx}\n          </div>\n        );\n      }\n    } else {\n      jsx = null;\n    }\n  } else if (item.type === 'code' && options.showCode) {\n    // Render code cells\n    jsx = (\n      <div className=\"toc-code-cell-div\">\n        <div className=\"toc-code-cell-prompt\">{item.prompt}</div>\n        <span className={'toc-code-span'}>\n          <CodeComponent sanitizer={options.sanitizer} heading={item} />\n        </span>\n      </div>\n    );\n  } else {\n    jsx = null;\n  }\n  return jsx;\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/optionsmanager.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { ISanitizer } from '@jupyterlab/apputils';\n\nimport { INotebookTracker } from '@jupyterlab/notebook';\n\nimport { TableOfContentsRegistry } from '../../registry';\n\nimport { TableOfContents } from '../../toc';\n\nimport { TagsToolComponent } from './tagstool';\n\nexport class NotebookGeneratorOptionsManager extends TableOfContentsRegistry.IGeneratorOptionsManager {\n  constructor(\n    widget: TableOfContents,\n    notebook: INotebookTracker,\n    options: {\n      needsNumbering: boolean;\n      sanitizer: ISanitizer;\n      tagTool?: TagsToolComponent;\n    }\n  ) {\n    super();\n    this._numbering = options.needsNumbering;\n    this._widget = widget;\n    this._notebook = notebook;\n    this.sanitizer = options.sanitizer;\n    this.tagTool = null;\n    this.storeTags = [];\n  }\n\n  readonly sanitizer: ISanitizer;\n  public tagTool?: TagsToolComponent | null;\n\n  set notebookMetadata(value: [string, any]) {\n    if (this._notebook.currentWidget != null) {\n      this._notebook.currentWidget.model.metadata.set(value[0], value[1]);\n    }\n  }\n\n  set numbering(value: boolean) {\n    this._numbering = value;\n    this._widget.update();\n    this.notebookMetadata = ['toc-autonumbering', this._numbering];\n  }\n\n  get numbering() {\n    return this._numbering;\n  }\n\n  set showCode(value: boolean) {\n    this._showCode = value;\n    this.notebookMetadata = ['toc-showcode', this._showCode];\n    this._widget.update();\n  }\n\n  get showCode() {\n    return this._showCode;\n  }\n\n  set showMarkdown(value: boolean) {\n    this._showMarkdown = value;\n    this.notebookMetadata = ['toc-showmarkdowntxt', this._showMarkdown];\n    this._widget.update();\n  }\n\n  get showMarkdown() {\n    return this._showMarkdown;\n  }\n\n  set showTags(value: boolean) {\n    this._showTags = value;\n    this.notebookMetadata = ['toc-showtags', this._showTags];\n    this._widget.update();\n  }\n\n  get showTags() {\n    return this._showTags;\n  }\n\n  get filtered() {\n    if (this.tagTool) {\n      this._filtered = this.tagTool.getFiltered();\n    } else if (this.storeTags.length > 0) {\n      this._filtered = this.storeTags;\n    } else {\n      this._filtered = [];\n    }\n    return this._filtered;\n  }\n\n  set preRenderedToolbar(value: any) {\n    this._preRenderedToolbar = value;\n  }\n\n  get preRenderedToolbar() {\n    return this._preRenderedToolbar;\n  }\n\n  updateWidget() {\n    this._widget.update();\n  }\n\n  setTagTool(tagTool: TagsToolComponent | null) {\n    this.tagTool = tagTool;\n  }\n\n  // initialize options, will NOT change notebook metadata\n  initializeOptions(\n    numbering: boolean,\n    showCode: boolean,\n    showMarkdown: boolean,\n    showTags: boolean\n  ) {\n    this._numbering = numbering;\n    this._showCode = showCode;\n    this._showMarkdown = showMarkdown;\n    this._showTags = showTags;\n    this._widget.update();\n  }\n\n  private _preRenderedToolbar: any = null;\n  private _filtered: string[] = [];\n  private _numbering: boolean;\n  private _showCode = false;\n  private _showMarkdown = false;\n  private _showTags = false;\n  private _notebook: INotebookTracker;\n  private _widget: TableOfContents;\n  public storeTags: string[];\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/tagstool/index.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { INotebookTracker } from '@jupyterlab/notebook';\nimport { Cell } from '@jupyterlab/cells';\nimport { TagListComponent } from './tagslist';\nimport * as React from 'react';\nimport { NotebookGeneratorOptionsManager } from '../optionsmanager';\n\nexport interface ITagsToolComponentProps {\n  allTagsList: string[];\n  tracker: INotebookTracker;\n  generatorOptionsRef: NotebookGeneratorOptionsManager;\n  inputFilter: string[];\n}\n\nexport interface ITagsToolComponentState {\n  selected: string[];\n}\n\n/*\n* Create a React component that handles state for the tag dropdown\n*/\nexport class TagsToolComponent extends React.Component<\n  ITagsToolComponentProps,\n  ITagsToolComponentState\n> {\n  constructor(props: ITagsToolComponentProps) {\n    super(props);\n    this.state = {\n      selected: this.props.inputFilter\n    };\n  }\n\n  /*\n  * Manage the selection state of the dropdown, taking in the name of a tag and\n  * whether to add or remove it.\n  */\n  changeSelectionState = (newState: string, add: boolean) => {\n    if (add) {\n      let selectedTags = this.state.selected;\n      selectedTags.push(newState);\n      this.setState({ selected: selectedTags });\n      this.filterTags(selectedTags);\n    } else {\n      let selectedTags = this.state.selected;\n      let newSelectedTags: string[] = [];\n      for (let i = 0; i < selectedTags.length; i++) {\n        if (selectedTags[i] !== newState) {\n          newSelectedTags.push(selectedTags[i]);\n        }\n      }\n      if (newSelectedTags.length === 0) {\n        newSelectedTags = [];\n      }\n      this.setState({ selected: newSelectedTags });\n      this.filterTags(newSelectedTags);\n    }\n  };\n\n  public getFiltered() {\n    return this.state.selected;\n  }\n\n  /*\n  * Deselect all tags in the dropdown and clear filters in the TOC.\n  */\n  deselectAllTags = () => {\n    this.setState({ selected: [] });\n    this.props.generatorOptionsRef.updateWidget();\n  };\n\n  /**\n   * Check whether a cell is tagged with a certain string\n   */\n  containsTag(tag: string, cell: Cell) {\n    if (cell === null) {\n      return false;\n    }\n    let tagList = cell.model.metadata.get('tags') as string[];\n    if (tagList) {\n      for (let i = 0; i < tagList.length; i++) {\n        if (tagList[i] === tag) {\n          return true;\n        }\n      }\n      return false;\n    }\n  }\n\n  /*\n  * Tells the generator to filter the TOC by the selected tags.\n  */\n  filterTags = (selected: string[]) => {\n    this.setState({ selected });\n    this.props.generatorOptionsRef.updateWidget();\n  };\n\n  updateFilters = () => {\n    let temp: string[] = [];\n    let idx = 0;\n    let needsUpdate = false;\n    for (let i = 0; i < this.state.selected.length; i++) {\n      if (\n        this.props.allTagsList.indexOf(this.state.selected[i] as string) > -1\n      ) {\n        temp[idx] = this.state.selected[i];\n        idx++;\n      } else if (this.props.generatorOptionsRef.showTags === true) {\n        needsUpdate = true;\n      }\n    }\n    if (needsUpdate) {\n      this.filterTags(temp);\n      this.setState({ selected: temp });\n    }\n  };\n\n  componentWillUpdate() {\n    this.updateFilters();\n  }\n\n  /*\n  * Render the interior of the tag dropdown.\n  */\n  render() {\n    let renderedJSX = <div className=\"toc-no-tags-div\">No Tags Available</div>;\n    let filterText;\n    if (this.state.selected.length === 0) {\n      filterText = (\n        <span className={'toc-filter-button-na'}> Clear Filters </span>\n      );\n    } else if (this.state.selected.length === 1) {\n      filterText = (\n        <span\n          className={'toc-filter-button'}\n          onClick={() => this.deselectAllTags()}\n        >\n          {' '}\n          Clear 1 Filter{' '}\n        </span>\n      );\n    } else {\n      filterText = (\n        <span\n          className={'toc-filter-button'}\n          onClick={() => this.deselectAllTags()}\n        >\n          {' '}\n          Clear {this.state.selected.length} Filters{' '}\n        </span>\n      );\n    }\n    if (this.props.allTagsList && this.props.allTagsList.length > 0) {\n      renderedJSX = (\n        <div className={'toc-tags-container'}>\n          <TagListComponent\n            allTagsList={this.props.allTagsList}\n            selectionStateHandler={this.changeSelectionState}\n            selectedTags={this.state.selected}\n          />\n          {filterText}\n        </div>\n      );\n    }\n    return renderedJSX;\n  }\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/tagstool/tag.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport * as React from 'react';\n\nexport interface ITagComponentProps {\n  selectionStateHandler: (newState: string, add: boolean) => void;\n  selectedTags: string[];\n  tag: string;\n}\n\n/*\n* Create a React component containing one tag label\n*/\nexport abstract class TagComponent extends React.Component<ITagComponentProps> {\n  constructor(props: ITagComponentProps) {\n    super(props);\n  }\n\n  render() {\n    const tag = this.props.tag as string;\n    return (\n      <div>\n        <label className=\"toc-tag-label\" key={new Date().toLocaleTimeString()}>\n          {tag}\n        </label>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/tagstool/tagslist.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { TagComponent } from './tag';\n\nimport * as React from 'react';\n\n/*\n* The TagList takes a list of selected tags, a handler to change selection state,\n* and a list of all tags (strings).\n*/\nexport interface ITagListComponentProps {\n  selectedTags: string[];\n  selectionStateHandler: (newState: string, add: boolean) => void;\n  allTagsList: string[] | null;\n}\n\n/*\n* The TagList state contains a list of selected tags\n*/\nexport interface ITagListComponentState {\n  selected: string[];\n}\n\n/*\n* Create a React component that renders all tags in a list.\n*/\nexport class TagListComponent extends React.Component<\n  ITagListComponentProps,\n  ITagListComponentState\n> {\n  constructor(props: ITagListComponentProps) {\n    super(props);\n    this.state = { selected: this.props.selectedTags };\n  }\n\n  /*\n  * Toggle whether a tag is selected when it is clicked\n  */\n  selectedTagWithName = (name: string) => {\n    if (this.props.selectedTags.indexOf(name) >= 0) {\n      this.props.selectionStateHandler(name, false);\n    } else {\n      this.props.selectionStateHandler(name, true);\n    }\n  };\n\n  /*\n  * Render a tag, putting it in a TagComponent\n  */\n  renderElementForTags = (tags: string[]) => {\n    const selectedTags = this.props.selectedTags;\n    const _self = this;\n    return tags.map((tag, index) => {\n      const tagClass =\n        selectedTags.indexOf(tag) >= 0\n          ? 'toc-selected-tag toc-tag'\n          : 'toc-unselected-tag toc-tag';\n      return (\n        <div\n          key={tag}\n          className={tagClass}\n          onClick={event => {\n            _self.selectedTagWithName(tag);\n          }}\n          tabIndex={-1}\n        >\n          <TagComponent\n            selectionStateHandler={this.props.selectionStateHandler}\n            selectedTags={this.props.selectedTags}\n            tag={tag}\n          />\n        </div>\n      );\n    });\n  };\n\n  /*\n  * Render the list of tags in the TOC tags dropdown.\n  */\n  render() {\n    let allTagsList = this.props.allTagsList;\n    let renderedTagsForAllCells = null;\n    if (allTagsList) {\n      renderedTagsForAllCells = this.renderElementForTags(allTagsList);\n    }\n    return <div className=\"toc-tag-holder\">{renderedTagsForAllCells}</div>;\n  }\n}\n"
  },
  {
    "path": "src/generators/notebookgenerator/toolbargenerator.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { INotebookTracker } from '@jupyterlab/notebook';\n\nimport { JSONValue } from '@phosphor/coreutils';\n\nimport { NotebookGeneratorOptionsManager } from './optionsmanager';\n\nimport * as React from 'react';\n\nimport { TagsToolComponent } from './tagstool';\n\ninterface INotebookGeneratorToolbarProps {}\n\ninterface INotebookGeneratorToolbarState {\n  showCode: boolean;\n  showMarkdown: boolean;\n  showTags: boolean;\n  numbering: boolean;\n}\n\nexport function notebookGeneratorToolbar(\n  options: NotebookGeneratorOptionsManager,\n  tracker: INotebookTracker\n) {\n  // Render the toolbar\n  return class extends React.Component<\n    INotebookGeneratorToolbarProps,\n    INotebookGeneratorToolbarState\n  > {\n    constructor(props: INotebookGeneratorToolbarProps) {\n      super(props);\n      this.tagTool = null;\n      this.state = {\n        showCode: true,\n        showMarkdown: false,\n        showTags: false,\n        numbering: false\n      };\n      if (tracker.currentWidget) {\n        // Read saved user settings in notebook metadata\n        tracker.currentWidget.context.ready.then(() => {\n          if (tracker.currentWidget) {\n            tracker.currentWidget.content.activeCellChanged.connect(() => {\n              options.updateWidget();\n            });\n            let _numbering = tracker.currentWidget.model.metadata.get(\n              'toc-autonumbering'\n            ) as boolean;\n            let numbering =\n              _numbering != undefined ? _numbering : options.numbering;\n            let _showCode = tracker.currentWidget.model.metadata.get(\n              'toc-showcode'\n            ) as boolean;\n            let showCode =\n              _showCode != undefined ? _showCode : options.showCode;\n            let _showMarkdown = tracker.currentWidget.model.metadata.get(\n              'toc-showmarkdowntxt'\n            ) as boolean;\n            let showMarkdown =\n              _showMarkdown != undefined ? _showMarkdown : options.showMarkdown;\n            let _showTags = tracker.currentWidget.model.metadata.get(\n              'toc-showtags'\n            ) as boolean;\n            let showTags =\n              _showTags != undefined ? _showTags : options.showTags;\n            this.allTags = [];\n            options.initializeOptions(\n              numbering,\n              showCode,\n              showMarkdown,\n              showTags\n            );\n            this.setState({\n              showCode: options.showCode,\n              showMarkdown: options.showMarkdown,\n              showTags: options.showTags,\n              numbering: options.numbering\n            });\n          }\n        });\n      }\n    }\n\n    toggleCode = (component: React.Component) => {\n      options.showCode = !options.showCode;\n      this.setState({ showCode: options.showCode });\n    };\n\n    toggleMarkdown = (component: React.Component) => {\n      options.showMarkdown = !options.showMarkdown;\n      this.setState({ showMarkdown: options.showMarkdown });\n    };\n\n    toggleAutoNumbering = () => {\n      options.numbering = !options.numbering;\n      this.setState({ numbering: options.numbering });\n    };\n\n    toggleTagDropdown = () => {\n      if (options.showTags && this.tagTool) {\n        options.storeTags = this.tagTool.state.selected;\n      }\n      options.showTags = !options.showTags;\n      this.setState({ showTags: options.showTags });\n    };\n\n    // Load all tags in the document\n    getTags = () => {\n      let notebook = tracker.currentWidget;\n      if (notebook) {\n        const cells = notebook.model.cells;\n        const tagSet = new Set<string>();\n        this.allTags = [];\n        for (let i = 0; i < cells.length; i++) {\n          const cell = cells.get(i)!;\n          const tagData = cell.metadata.get('tags') as JSONValue;\n          if (Array.isArray(tagData)) {\n            tagData.forEach((tag: string) => tag && tagSet.add(tag));\n          }\n        }\n        this.allTags = Array.from(tagSet);\n      }\n    };\n\n    render() {\n      let codeIcon = this.state.showCode ? (\n        <div\n          className=\"toc-toolbar-code-button toc-toolbar-button\"\n          onClick={event => this.toggleCode.bind(this)()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Code Cells\"\n            title=\"Toggle Code Cells\"\n            className=\"toc-toolbar-code-icon toc-toolbar-icon-selected\"\n          />\n        </div>\n      ) : (\n        <div\n          className=\"toc-toolbar-code-button toc-toolbar-button\"\n          onClick={event => this.toggleCode.bind(this)()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Code Cells\"\n            title=\"Toggle Code Cells\"\n            className=\"toc-toolbar-code-icon toc-toolbar-icon\"\n          />\n        </div>\n      );\n\n      let markdownIcon = this.state.showMarkdown ? (\n        <div\n          className=\"toc-toolbar-markdown-button toc-toolbar-button\"\n          onClick={event => this.toggleMarkdown.bind(this)()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Markdown Text Cells\"\n            title=\"Toggle Markdown Text Cells\"\n            className=\"toc-toolbar-markdown-icon toc-toolbar-icon-selected\"\n          />\n        </div>\n      ) : (\n        <div\n          className=\"toc-toolbar-markdown-button toc-toolbar-button\"\n          onClick={event => this.toggleMarkdown.bind(this)()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Markdown Text Cells\"\n            title=\"Toggle Markdown Text Cells\"\n            className=\"toc-toolbar-markdown-icon toc-toolbar-icon\"\n          />\n        </div>\n      );\n\n      let numberingIcon = this.state.numbering ? (\n        <div\n          className=\"toc-toolbar-auto-numbering-button toc-toolbar-button\"\n          onClick={event => this.toggleAutoNumbering()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Auto-Numbering\"\n            title=\"Toggle Auto-Numbering\"\n            className=\"toc-toolbar-auto-numbering-icon toc-toolbar-icon-selected\"\n          />\n        </div>\n      ) : (\n        <div\n          className=\"toc-toolbar-auto-numbering-button toc-toolbar-button\"\n          onClick={event => this.toggleAutoNumbering()}\n        >\n          <div\n            role=\"text\"\n            aria-label=\"Toggle Auto-Numbering\"\n            title=\"Toggle Auto-Numbering\"\n            className=\"toc-toolbar-auto-numbering-icon toc-toolbar-icon\"\n          />\n        </div>\n      );\n\n      let tagDropdown = <div />;\n      let tagIcon = (\n        <div className=\"toc-toolbar-button\">\n          <div\n            role=\"text\"\n            aria-label=\"Show Tags Menu\"\n            title=\"Show Tags Menu\"\n            className=\"toc-toolbar-tag-icon toc-toolbar-icon\"\n          />\n        </div>\n      );\n      if (this.state.showTags) {\n        this.getTags();\n        let tagTool = (\n          <TagsToolComponent\n            allTagsList={this.allTags}\n            tracker={tracker}\n            generatorOptionsRef={options}\n            inputFilter={options.storeTags}\n            ref={tagTool => (this.tagTool = tagTool)}\n          />\n        );\n        options.setTagTool(this.tagTool);\n        tagDropdown = <div className={'toc-tag-dropdown'}> {tagTool} </div>;\n        tagIcon = (\n          <div\n            role=\"text\"\n            aria-label=\"Hide Tags Menu\"\n            title=\"Hide Tags Menu\"\n            className=\"toc-toolbar-tag-icon toc-toolbar-icon-selected\"\n          />\n        );\n      }\n\n      return (\n        <div>\n          <div className={'toc-toolbar'}>\n            {codeIcon}\n            {markdownIcon}\n            {numberingIcon}\n            <div\n              className={'toc-tag-dropdown-button'}\n              onClick={event => this.toggleTagDropdown()}\n            >\n              {tagIcon}\n            </div>\n          </div>\n          {tagDropdown}\n        </div>\n      );\n    }\n\n    allTags: string[];\n    tagTool: TagsToolComponent | null;\n  };\n}\n"
  },
  {
    "path": "src/generators/shared.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { IHeading } from '../toc';\n\nconst VDOM_MIME_TYPE = 'application/vdom.v1+json';\n\nconst HTML_MIME_TYPE = 'text/html';\n\nexport interface INumberedHeading extends IHeading {\n  numbering?: string | null;\n}\n\n/**\n * Given a dictionary that keep tracks of the numbering and the level,\n * update the dictionary.\n */\nfunction incrementNumberingDict(dict: any, level: number) {\n  let x = level + 1;\n  while (x <= 6) {\n    if (dict[x] != undefined) {\n      dict[x] = undefined;\n    }\n    x++;\n  }\n  if (dict[level] === undefined) {\n    dict[level] = 1;\n  } else {\n    dict[level]++;\n  }\n}\n\n/**\n * Given a dictionary that keep tracks of the numbering and the current level,\n * generate the current numbering based on the dictionary and current level.\n */\nexport function generateNumbering(\n  numberingDict: { [level: number]: number },\n  level: number\n) {\n  let numbering = undefined;\n  if (numberingDict != null) {\n    incrementNumberingDict(numberingDict, level);\n    numbering = '';\n    for (let j = 1; j <= level; j++) {\n      numbering +=\n        (numberingDict[j] == undefined ? '0' : numberingDict[j]) + '.';\n      if (j === level) {\n        numbering += ' ';\n      }\n    }\n  }\n  return numbering;\n}\n\n/**\n * Return whether the mime type is some flavor of markdown.\n */\nexport function isMarkdown(mime: string): boolean {\n  return (\n    mime === 'text/x-ipythongfm' ||\n    mime === 'text/x-markdown' ||\n    mime === 'text/x-gfm' ||\n    mime === 'text/markdown'\n  );\n}\n\n/**\n * Return whether the mime type is DOM-ish (html or vdom).\n */\nexport function isDOM(mime: string): boolean {\n  return mime === VDOM_MIME_TYPE || mime === HTML_MIME_TYPE;\n}\n\n/**\n * Allowed HTML tags for the ToC entries. We use this to\n * sanitize HTML headings, if they are given. We specifically\n * disallow anchor tags, since we are adding our own.\n */\nexport const sanitizerOptions = {\n  allowedTags: [\n    'p',\n    'blockquote',\n    'b',\n    'i',\n    'strong',\n    'em',\n    'strike',\n    'code',\n    'br',\n    'div',\n    'span',\n    'pre',\n    'del'\n  ],\n  allowedAttributes: {\n    // Allow \"class\" attribute for <code> tags.\n    code: ['class'],\n    // Allow \"class\" attribute for <span> tags.\n    span: ['class'],\n    // Allow \"class\" attribute for <div> tags.\n    div: ['class'],\n    // Allow \"class\" attribute for <p> tags.\n    p: ['class'],\n    // Allow \"class\" attribute for <pre> tags.\n    pre: ['class']\n  }\n};\n"
  },
  {
    "path": "src/index.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nexport * from './toc';\nexport * from './registry';\nexport * from './generators';\n"
  },
  {
    "path": "src/registry.ts",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { IInstanceTracker } from '@jupyterlab/apputils';\n\nimport { Token } from '@phosphor/coreutils';\n\nimport { Widget } from '@phosphor/widgets';\n\nimport { IHeading } from './toc';\n\n/**\n * An interface for a TableOfContentsRegistry.\n */\nexport interface ITableOfContentsRegistry extends TableOfContentsRegistry {}\n\n/* tslint:disable */\n/**\n * The TableOfContentsRegistry token.\n */\nexport const ITableOfContentsRegistry = new Token<TableOfContentsRegistry>(\n  'jupyterlab-toc:ITableOfContentsRegistry'\n);\n/* tslint:enable */\n\n/**\n * A class that keeps track of the different kinds\n * of widgets for which there can be tables-of-contents.\n */\nexport class TableOfContentsRegistry {\n  /**\n   * Given a widget, find an IGenerator for it,\n   * or undefined if none can be found.\n   */\n  findGeneratorForWidget(\n    widget: Widget\n  ): TableOfContentsRegistry.IGenerator | undefined {\n    let generator: TableOfContentsRegistry.IGenerator | undefined;\n    this._generators.forEach(gen => {\n      if (gen.tracker.has(widget)) {\n        // If isEnabled is present, check for it.\n        if (gen.isEnabled && !gen.isEnabled(widget)) {\n          return;\n        }\n        generator = gen;\n      }\n    });\n    return generator;\n  }\n\n  /**\n   * Add a new IGenerator to the registry.\n   */\n  addGenerator(generator: TableOfContentsRegistry.IGenerator): void {\n    this._generators.push(generator);\n  }\n\n  private _generators: TableOfContentsRegistry.IGenerator[] = [];\n}\n\n/**\n * A namespace for TableOfContentsRegistry statics.\n */\nexport namespace TableOfContentsRegistry {\n  /**\n   * An interface for an object that knows how to generate a table-of-contents\n   * for a type of widget.\n   */\n\n  export abstract class IGeneratorOptionsManager {}\n\n  export interface IGenerator<W extends Widget = Widget> {\n    /**\n     * An instance tracker for the widget.\n     */\n    tracker: IInstanceTracker<W>;\n\n    /**\n     * A function to test whether to generate a ToC for a widget.\n     *\n     * #### Notes\n     * By default is assumed to be enabled if the widget\n     * is hosted in `tracker`. However, the user may want to add\n     * additional checks. For instance, this can be used to generate\n     * a ToC for text files only if they have a given mimeType.\n     */\n    isEnabled?: (widget: W) => boolean;\n\n    /**\n     * Whether the document uses LaTeX typesetting.\n     *\n     * Defaults to `false`.\n     */\n    usesLatex?: boolean;\n\n    /**\n     * An object that manage user settings for the generator.\n     *\n     * Defaults to `undefined`.\n     */\n    options?: IGeneratorOptionsManager;\n\n    /**\n     * A function that generates JSX element for each heading\n     *\n     * If not given, the default renderer will be used, which renders the text\n     */\n    itemRenderer?: (item: IHeading) => JSX.Element | null;\n\n    /**\n     * A function that generates a toolbar for the generator\n     *\n     * If not given, no toolbar will show up\n     */\n    toolbarGenerator?: () => any;\n\n    /**\n     * A function that takes the widget, and produces\n     * a list of headings.\n     */\n    generate(widget: W): IHeading[];\n  }\n}\n"
  },
  {
    "path": "src/toc.tsx",
    "content": "// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n\nimport { ActivityMonitor, PathExt } from '@jupyterlab/coreutils';\n\nimport { IDocumentManager } from '@jupyterlab/docmanager';\n\nimport { IRenderMimeRegistry } from '@jupyterlab/rendermime';\n\nimport { Message } from '@phosphor/messaging';\n\nimport { Widget } from '@phosphor/widgets';\n\nimport { TableOfContentsRegistry } from './registry';\n\nimport * as React from 'react';\nimport * as ReactDOM from 'react-dom';\n\n/**\n * Timeout for throttling TOC rendering.\n */\nconst RENDER_TIMEOUT = 1000;\n\n/**\n * A widget for hosting a notebook table-of-contents.\n */\nexport class TableOfContents extends Widget {\n  /**\n   * Create a new table of contents.\n   */\n  constructor(options: TableOfContents.IOptions) {\n    super();\n    this._docmanager = options.docmanager;\n    this._rendermime = options.rendermime;\n  }\n\n  /**\n   * The current widget-generator tuple for the ToC.\n   */\n  get current(): TableOfContents.ICurrentWidget | null {\n    return this._current;\n  }\n  set current(value: TableOfContents.ICurrentWidget | null) {\n    // If they are the same as previously, do nothing.\n    if (\n      value &&\n      this._current &&\n      this._current.widget === value.widget &&\n      this._current.generator === value.generator\n    ) {\n      return;\n    }\n    this._current = value;\n\n    if (this.generator && this.generator.toolbarGenerator) {\n      this._toolbar = this.generator.toolbarGenerator();\n    }\n\n    // Dispose an old activity monitor if it existsd\n    if (this._monitor) {\n      this._monitor.dispose();\n      this._monitor = null;\n    }\n    // If we are wiping the ToC, update and return.\n    if (!this._current) {\n      this.updateTOC();\n      return;\n    }\n\n    // Find the document model associated with the widget.\n    const context = this._docmanager.contextForWidget(this._current.widget);\n    if (!context || !context.model) {\n      throw Error('Could not find a context for the Table of Contents');\n    }\n\n    // Throttle the rendering rate of the table of contents.\n    this._monitor = new ActivityMonitor({\n      signal: context.model.contentChanged,\n      timeout: RENDER_TIMEOUT\n    });\n    this._monitor.activityStopped.connect(this.update, this);\n    this.updateTOC();\n  }\n\n  /**\n   * Handle an update request.\n   */\n  protected onUpdateRequest(msg: Message): void {\n    // Don't bother if the TOC is not visible\n    /* if (!this.isVisible) {\n      return;\n    } */\n    this.updateTOC();\n  }\n\n  updateTOC() {\n    let toc: IHeading[] = [];\n    let title = 'Table of Contents';\n    if (this._current) {\n      toc = this._current.generator.generate(this._current.widget);\n      const context = this._docmanager.contextForWidget(this._current.widget);\n      if (context) {\n        title = PathExt.basename(context.localPath);\n      }\n    }\n    let itemRenderer: (item: IHeading) => JSX.Element | null = (\n      item: IHeading\n    ) => {\n      return <span>{item.text}</span>;\n    };\n    if (this._current && this._current.generator.itemRenderer) {\n      itemRenderer = this._current.generator.itemRenderer!;\n    }\n    let renderedJSX = (\n      <div className=\"jp-TableOfContents\">\n        <header>{title}</header>\n      </div>\n    );\n    if (this._current && this._current.generator) {\n      renderedJSX = (\n        <TOCTree\n          title={title}\n          toc={toc}\n          generator={this.generator}\n          itemRenderer={itemRenderer}\n          toolbar={this._toolbar}\n        />\n      );\n    }\n    ReactDOM.render(renderedJSX, this.node, () => {\n      if (\n        this._current &&\n        this._current.generator.usesLatex === true &&\n        this._rendermime.latexTypesetter\n      ) {\n        this._rendermime.latexTypesetter.typeset(this.node);\n      }\n    });\n  }\n\n  get generator() {\n    if (this._current) {\n      return this._current.generator;\n    }\n    return null;\n  }\n\n  /**\n   * Rerender after showing.\n   */\n  protected onAfterShow(msg: Message): void {\n    this.update();\n  }\n\n  private _toolbar: any;\n  private _rendermime: IRenderMimeRegistry;\n  private _docmanager: IDocumentManager;\n  private _current: TableOfContents.ICurrentWidget | null;\n  private _monitor: ActivityMonitor<any, any> | null;\n}\n\n/**\n * A namespace for TableOfContents statics.\n */\nexport namespace TableOfContents {\n  /**\n   * Options for the constructor.\n   */\n  export interface IOptions {\n    /**\n     * The document manager for the application.\n     */\n    docmanager: IDocumentManager;\n\n    /**\n     * The rendermime for the application.\n     */\n    rendermime: IRenderMimeRegistry;\n  }\n\n  /**\n   * A type representing a tuple of a widget,\n   * and a generator that knows how to generate\n   * heading information from that widget.\n   */\n  export interface ICurrentWidget<W extends Widget = Widget> {\n    widget: W;\n    generator: TableOfContentsRegistry.IGenerator<W>;\n  }\n}\n\n/**\n * An object that represents a heading.\n */\nexport interface IHeading {\n  /**\n   * The text of the heading.\n   */\n  text: string;\n\n  /**\n   * The HTML header level for the heading.\n   */\n  level: number;\n\n  /**\n   * A function to execute when clicking the ToC\n   * item. Typically this will be used to scroll\n   * the parent widget to this item.\n   */\n  onClick: () => void;\n\n  /**\n   * If there is special markup, we can instead\n   * render the heading using a raw HTML string. This\n   * HTML *should be properly sanitized!*\n   *\n   * For instance, this can be used to render\n   * already-renderd-to-html markdown headings.\n   */\n  html?: string;\n}\n\n/**\n * Props for the TOCItem component.\n */\nexport interface ITOCItemProps extends React.Props<TOCItem> {\n  /**\n   * An IHeading to render.\n   */\n  heading: IHeading;\n  itemRenderer: (item: IHeading) => JSX.Element | null;\n}\n\nexport interface ITOCItemStates {}\n\n/**\n * A React component for a table of contents entry.\n */\nexport class TOCItem extends React.Component<ITOCItemProps, ITOCItemStates> {\n  /**\n   * Render the item.\n   */\n  render() {\n    const { heading } = this.props;\n\n    // Create an onClick handler for the TOC item\n    // that scrolls the anchor into view.\n    const handleClick = (event: React.SyntheticEvent<HTMLSpanElement>) => {\n      event.preventDefault();\n      event.stopPropagation();\n      heading.onClick();\n    };\n\n    let content = this.props.itemRenderer(heading);\n    return content && <li onClick={handleClick}>{content}</li>;\n  }\n}\n\nexport interface ITOCTreeStates {}\n\n/**\n * Props for the TOCTree component.\n */\nexport interface ITOCTreeProps extends React.Props<TOCTree> {\n  /**\n   * A title to display.\n   */\n  title: string;\n\n  /**\n   * A list of IHeadings to render.\n   */\n  toc: IHeading[];\n  toolbar: any;\n  generator: TableOfContentsRegistry.IGenerator<Widget> | null;\n  itemRenderer: (item: IHeading) => JSX.Element | null;\n}\n\n/**\n * A React component for a table of contents.\n */\nexport class TOCTree extends React.Component<ITOCTreeProps, ITOCTreeStates> {\n  /**\n   * Render the TOCTree.\n   */\n\n  render() {\n    // Map the heading objects onto a list of JSX elements.\n    let i = 0;\n    const Toolbar = this.props.toolbar;\n    let listing: JSX.Element[] = this.props.toc.map(el => {\n      return (\n        <TOCItem\n          heading={el}\n          itemRenderer={this.props.itemRenderer}\n          key={`${el.text}-${el.level}-${i++}`}\n        />\n      );\n    });\n    return (\n      <div className=\"jp-TableOfContents\">\n        <header>{this.props.title}</header>\n        {Toolbar && <Toolbar />}\n        <ul className=\"jp-TableOfContents-content\">{listing}</ul>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "style/index.css",
    "content": "/*-----------------------------------------------------------------------------\n| Copyright (c) Jupyter Development Team.\n| Distributed under the terms of the Modified BSD License.\n|----------------------------------------------------------------------------*/\n\n/*-----------------------------------------------------------------------------\n| Table of Contents\n|----------------------------------------------------------------------------*/\n\n.jp-TableOfContents-content {\n  flex: 1 1 auto;\n  margin: 0;\n  padding: 0;\n  list-style-type: none;\n  overflow: auto;\n  background-color: var(--jp-layout-color1);\n}\n\n.jp-TableOfContents-content li {\n  display: flex;\n  flex-direction: row;\n  padding: 4px 12px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  cursor: pointer;\n  padding-top: 8px;\n  padding-bottom: 8px;\n}\n\n.jp-TableOfContents-content li:hover {\n  background: var(--jp-layout-color2);\n}\n\n.jp-TableOfContents {\n  display: flex;\n  flex-direction: column;\n  background: var(--jp-layout-color1);\n  color: var(--jp-ui-font-color1);\n  font-size: var(--jp-ui-font-size0);\n  height: 100%;\n}\n\n.jp-TableOfContents header {\n  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);\n  flex: 0 0 auto;\n  font-size: var(--jp-ui-font-size0);\n  font-weight: 600;\n  letter-spacing: 1px;\n  margin: 0px;\n  padding: 12px 0 4px 12px;\n  text-transform: uppercase;\n}\n\n[data-theme-light='true'] .jp-TableOfContents-icon {\n  background-image: url(list-light.svg);\n}\n\n[data-theme-light='false'] .jp-TableOfContents-icon {\n  background-image: url(list-dark.svg);\n}\n\n.jp-TableOfContents-codeContainer {\n  overflow: hidden;\n}\n\n.jp-TableOfContents-code {\n  font-size: 9px;\n  max-height: 70px;\n}\n\n.cm-toc .CodeMirror {\n  font-size: 9px;\n  z-index: 0;\n  border: var(--jp-border-width) solid var(--jp-cell-editor-border-color);\n  border-radius: 0px;\n  background: var(--jp-cell-editor-background);\n  max-width: 100%;\n  max-height: 36px;\n}\n\n.toc-code-span {\n  width: 100%;\n  max-width: 100%;\n  overflow: hidden;\n}\n\n.cm-toc .CodeMirror-scroll {\n  overflow: hidden !important;\n}\n\n.CodeMirror-scroll::-webkit-scrollbar-track {\n  background-color: transparent;\n}\n\n.toc-toolbar-icon,\n.toc-toolbar-icon-selected {\n  float: left;\n  padding: 0px;\n  margin: 4px;\n  background-repeat: no-repeat;\n  background-color: none;\n  background-size: 100%;\n  background-position: center;\n  height: 24px;\n  width: 24px;\n  margin: 4px;\n  border-radius: 2px;\n}\n\n[data-theme-light='true'] .toc-toolbar-code-icon {\n  background-image: url('img/code.svg');\n}\n\n[data-theme-light='false'] .toc-toolbar-code-icon {\n  background-image: url('img/code_darktheme.svg');\n}\n\n[data-theme-light='true'] .toc-toolbar-markdown-icon {\n  background-image: url('img/markdown.svg');\n}\n\n[data-theme-light='false'] .toc-toolbar-markdown-icon {\n  background-image: url('img/markdown_darktheme.svg');\n}\n\n[data-theme-light='true'] .toc-toolbar-auto-numbering-icon {\n  background-image: url('img/autonumbering.svg');\n}\n\n[data-theme-light='false'] .toc-toolbar-auto-numbering-icon {\n  background-image: url('img/autonumbering_darktheme.svg');\n}\n\n.toc-toolbar-tag-icon {\n  width: 30px;\n  height: 22px;\n  margin: 4px 9px 4px 4px;\n}\n\n[data-theme-light='true'] .toc-toolbar-tag-icon {\n  background-image: url('img/tag.svg');\n}\n\n[data-theme-light='false'] .toc-toolbar-tag-icon {\n  background-image: url('img/tag_darktheme.svg');\n}\n\n[data-theme-light='true'] .toc-toolbar-icon:hover {\n  background-color: var(--jp-input-background);\n}\n\n[data-theme-light='false'] .toc-toolbar-icon:hover {\n  background-color: #3a3a3a;\n}\n\n[data-theme-light='true'] .toc-toolbar-icon-selected {\n  background-color: var(--jp-layout-color2);\n}\n\n[data-theme-light='false'] .toc-toolbar-icon-selected {\n  background-color: #565656;\n}\n\n.toc-code-cell-prompt {\n  flex: 0 0 27px;\n  color: var(--jp-cell-prompt-not-active-font-color);\n  opacity: var(--jp-cell-prompt-not-active-opacity);\n  font-family: var(--jp-cell-prompt-font-family);\n  padding: var(--jp-code-padding);\n  padding-right: 0px;\n  padding-left: 0px;\n  letter-spacing: var(--jp-cell-prompt-letter-spacing);\n  line-height: var(--jp-code-line-height);\n  font-size: 8px;\n  border: var(--jp-border-width) solid transparent;\n  text-align: left;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.toc-toolbar {\n  position: relative;\n  width: 100%;\n  margin: 0px;\n  user-select: none;\n  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);\n  height: 36px;\n  display: flex;\n  align-items: center;\n}\n\n.toc-code-cell-div {\n  display: inline-flex;\n  width: 100%;\n}\n\n.toc-entry-holder {\n  display: inline-flex;\n  position: relative;\n  align-items: center;\n  width: 100%;\n}\n\n.toc-collapse-button {\n  padding-left: 3px;\n  cursor: default;\n  min-width: 11px;\n  position: absolute;\n}\n\n.toc-arrow-img {\n  top: 0;\n  bottom: 0;\n  margin: auto;\n  position: absolute;\n  background-repeat: no-repeat;\n}\n\n.toc-downarrow-img {\n  width: 12px;\n  height: 6px;\n}\n\n[data-theme-light='true'] .toc-downarrow-img {\n  background-image: url('img/toggle_down.svg');\n}\n\n[data-theme-light='false'] .toc-downarrow-img {\n  background-image: url('img/toggle_down_darktheme.svg');\n}\n\n.toc-rightarrow-img {\n  width: 7px;\n  height: 12px;\n}\n\n[data-theme-light='true'] .toc-rightarrow-img {\n  background-image: url('img/toggle_right.svg');\n}\n\n[data-theme-light='false'] .toc-rightarrow-img {\n  background-image: url('img/toggle_right_darktheme.svg');\n}\n\n.toc-twist-placeholder {\n  max-width: 10px;\n  opacity: 0;\n  overflow: hidden;\n}\n\n.cm-toc-plain-span {\n  width: 100%;\n  white-space: pre-wrap;\n  display: block;\n}\n\n.cm-toc-plain-textarea {\n  font-size: 9px;\n  z-index: 0;\n  border: var(--jp-border-width) solid var(--jp-cell-editor-border-color2);\n  border-radius: 0px;\n  background: var(--jp-cell-editor-background);\n  width: calc(100% - 9px);\n  overflow: hidden;\n  max-height: 74px;\n  resize: none;\n  font-family: var(--jp-code-font-family);\n  outline: none;\n  user-select: none;\n  white-space: pre;\n  padding: var(--jp-code-padding);\n}\n\n.cm-toc .CodeMirror-sizer {\n  min-width: 0px !important;\n  min-height: 0px !important;\n  margin-bottom: 0px !important;\n}\n\n.cm-toc .CodeMirror-line {\n  white-space: pre-wrap;\n  cursor: pointer;\n}\n\n.cm-toc .CodeMirror-lines {\n  cursor: pointer;\n}\n\n.toc-tag-dropdown {\n  display: flex;\n  width: 100%;\n}\n\n.toc-tag-dropdown-button {\n  margin-left: auto;\n}\n\n.toc-tags-container {\n  padding: 4px;\n  border-bottom: var(--jp-border-width) solid var(--jp-border-color2);\n}\n\n.toc-clear-button {\n  font-size: 12px;\n  color: var(--jp-ui-font-color1);\n  padding-left: 15px;\n  /* padding-top: 7px; */\n  user-select: none;\n  float: right;\n}\n\n.toc-clear-button:hover {\n  font-size: 12px;\n  color: var(--jp-ui-font-color2);\n  padding-left: 15px;\n  /* padding-top: 7px; */\n  user-select: none;\n}\n\n.toc-filter-button {\n  background-color: var(--jp-layout-color1);\n  border: solid 1px var(--jp-layout-color4);\n  border-radius: 3px;\n  width: fit-content;\n  padding: 5px;\n  padding-left: 6px;\n  padding-right: 6px;\n  margin-right: 17px;\n  color: var(--jp-layout-color5);\n  float: right;\n  font-size: 12px;\n  user-select: none;\n  margin-bottom: 13px;\n}\n\n.toc-filter-button:hover {\n  background-color: var(--jp-layout-color4);\n  border: solid 1px var(--jp-layout-color4);\n  color: var(--jp-layout-color1);\n}\n\n.toc-filter-button-na {\n  background-color: var(--jp-layout-color1);\n  border: solid 1px var(--jp-ui-font-color3);\n  border-radius: 3px;\n  width: fit-content;\n  padding: 5px;\n  padding-left: 6px;\n  padding-right: 6px;\n  margin-right: 17px;\n  color: var(--jp-ui-font-color3);\n  float: right;\n  font-size: 12px;\n  user-select: none;\n  margin-bottom: 13px;\n}\n\n.toc-no-tags-div {\n  font-size: 12px;\n  padding: 3px;\n  padding-bottom: 6px;\n  margin: auto;\n  color: var(--jp-layout-color4);\n}\n\n.toc-tags-container {\n  width: 100%;\n}\n\n.jp-TableOfContents-content code {\n  font-size: inherit;\n}\n\n.toc-cell-item {\n  padding-left: 24px;\n}\n\n/* styles for tags */\n\n.toc-tag-label {\n  font-size: 11px;\n  max-width: 100%;\n  text-overflow: ellipsis;\n  display: inline-block;\n  overflow: hidden;\n  box-sizing: border-box;\n  padding-top: 0px;\n  margin-top: -1px;\n  margin-bottom: 0px;\n  user-select: none;\n}\n\n.toc-tag {\n  box-sizing: border-box;\n  height: 24px;\n  border-radius: 20px;\n  padding: 10px;\n  padding-bottom: 4px;\n  padding-top: 5px;\n  margin: 3px;\n  width: fit-content;\n  max-width: calc(100% - 25px);\n}\n\n.toc-selected-tag {\n  color: white;\n  background-color: #2196f3;\n  outline: none;\n}\n\n.toc-unselected-tag {\n  background-color: var(--jp-layout-color2);\n  outline: none;\n}\n\n.toc-tag-holder {\n  display: flex;\n  flex-wrap: wrap;\n  height: fit-content;\n  padding-bottom: 6px;\n  padding-right: 20px;\n  padding-left: 9px;\n  padding-top: 6px;\n}\n\n/* Font level sizes */\n\n.toc-level-size-1 {\n  font-size: 16.89px;\n}\n\n.toc-level-size-2 {\n  font-size: 14.82px;\n}\n\n.toc-level-size-3 {\n  font-size: 13px;\n}\n\n.toc-level-size-4 {\n  font-size: 11.4px;\n}\n\n.toc-level-size-5 {\n  font-size: 10px;\n}\n\n.toc-level-size-6 {\n  font-size: 9px;\n}\n\n.toc-level-size-default {\n  font-size: 9px;\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"noImplicitAny\": true,\n    \"strictNullChecks\": true,\n    \"skipLibCheck\": true,\n    \"noEmitOnError\": true,\n    \"noUnusedLocals\": true,\n    \"lib\": [\"DOM\", \"ES6\"],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"target\": \"ES6\",\n    \"outDir\": \"lib\",\n    \"rootDir\": \"src\",\n    \"jsx\": \"react\"\n  },\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"rulesDirectory\": [\"tslint-plugin-prettier\"],\n  \"rules\": {\n    \"prettier\": [true, { \"singleQuote\": true }],\n    \"align\": [true, \"parameters\", \"statements\"],\n    \"ban\": [\n      true,\n      [\"_\", \"forEach\"],\n      [\"_\", \"each\"],\n      [\"$\", \"each\"],\n      [\"angular\", \"forEach\"]\n    ],\n    \"class-name\": true,\n    \"comment-format\": [true, \"check-space\"],\n    \"curly\": true,\n    \"eofline\": true,\n    \"forin\": false,\n    \"indent\": [true, \"spaces\", 2],\n    \"interface-name\": [true, \"always-prefix\"],\n    \"jsdoc-format\": true,\n    \"label-position\": true,\n    \"max-line-length\": [false],\n    \"member-access\": false,\n    \"member-ordering\": [false],\n    \"new-parens\": true,\n    \"no-angle-bracket-type-assertion\": true,\n    \"no-any\": false,\n    \"no-arg\": true,\n    \"no-bitwise\": true,\n    \"no-conditional-assignment\": true,\n    \"no-consecutive-blank-lines\": false,\n    \"no-console\": [true, \"debug\", \"info\", \"time\", \"timeEnd\", \"trace\"],\n    \"no-construct\": true,\n    \"no-debugger\": true,\n    \"no-default-export\": false,\n    \"no-duplicate-variable\": true,\n    \"no-empty\": true,\n    \"no-eval\": true,\n    \"no-inferrable-types\": false,\n    \"no-internal-module\": true,\n    \"no-invalid-this\": [true, \"check-function-in-method\"],\n    \"no-null-keyword\": false,\n    \"no-reference\": true,\n    \"no-require-imports\": false,\n    \"no-shadowed-variable\": false,\n    \"no-string-literal\": false,\n    \"no-switch-case-fall-through\": true,\n    \"no-trailing-whitespace\": true,\n    \"no-unused-expression\": true,\n    \"no-use-before-declare\": false,\n    \"no-var-keyword\": true,\n    \"no-var-requires\": true,\n    \"object-literal-sort-keys\": false,\n    \"one-line\": [\n      true,\n      \"check-open-brace\",\n      \"check-catch\",\n      \"check-else\",\n      \"check-finally\",\n      \"check-whitespace\"\n    ],\n    \"one-variable-per-declaration\": [true, \"ignore-for-loop\"],\n    \"quotemark\": [true, \"single\", \"avoid-escape\", \"jsx-double\"],\n    \"radix\": true,\n    \"semicolon\": [true, \"always\", \"ignore-bound-class-methods\"],\n    \"switch-default\": true,\n    \"trailing-comma\": [\n      false,\n      {\n        \"multiline\": \"never\",\n        \"singleline\": \"never\"\n      }\n    ],\n    \"triple-equals\": [true, \"allow-null-check\", \"allow-undefined-check\"],\n    \"typedef\": [false],\n    \"typedef-whitespace\": [\n      false,\n      {\n        \"call-signature\": \"nospace\",\n        \"index-signature\": \"nospace\",\n        \"parameter\": \"nospace\",\n        \"property-declaration\": \"nospace\",\n        \"variable-declaration\": \"nospace\"\n      },\n      {\n        \"call-signature\": \"space\",\n        \"index-signature\": \"space\",\n        \"parameter\": \"space\",\n        \"property-declaration\": \"space\",\n        \"variable-declaration\": \"space\"\n      }\n    ],\n    \"use-isnan\": true,\n    \"use-strict\": [false],\n    \"variable-name\": [\n      true,\n      \"check-format\",\n      \"allow-leading-underscore\",\n      \"ban-keywords\"\n    ],\n    \"whitespace\": [\n      true,\n      \"check-branch\",\n      \"check-operator\",\n      \"check-separator\",\n      \"check-type\"\n    ]\n  }\n}\n"
  }
]