function loadYaml(fsPath) {
  return parseYaml(fs.readFileSync(path.join(__dirname, fsPath), "utf8"));
}

(props) => (
  <div className="buttonGroup buttonWrapper">{props.children}</div>
)

class Button extends React.Component {
  render() {
    return (
      <div className="pluginWrapper buttonWrapper">
        <a className="button" href={this.props.href} target={this.props.target}>
          {this.props.children}
        </a>
      </div>
    );
  }
}

render() {
    return (
        </a>
      </div>
    );
  }

render() {
    const language = this.props.language || "en";

    return (
      <div>
        <script src="landing.js" />
        <HomeSplash language={language} />
        <div className="mainContainer landingContainer">
          <TldrSection language={language} />
          <LanguagesSection />
          <EditorSupportSection />
          <UsersSection language={language} />
        </div>
      </div>
    );
  }

function Tidelift() {
  return (
    <a className="tidelift" href={siteConfig.tideliftUrl}>
      PRETTIER FOR ENTERPRISE
    </a>
  );
}

  <div className="homeContainer">
    <Tidelift />
    <div className="homeSplashFade">
      <div className="wrapper homeWrapper">
        <div className="animatedLogoWrapper">
          <AnimatedLogo version="wide" />
        </div>
        <div className="inner">
          <div className="section promoSection">
            <div className="promoRow">
              <div className="pluginRowBlock">
                <Button href="/playground/">Try It Online</Button>&nbsp;
                <Button href={"/docs/" + props.language + "/install.html"}>
                  Install Prettier
                </Button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
)

({ language }) => (
  <div className="tldrSection productShowcaseSection lightBackground">
    <Container>
      <div
        style={{
          display: "flex",
          flexFlow: "row wrap",
          justifyContent: "space-evenly",
        }}
      >
        <div style={{ display: "flex", flexDirection: "column" }}>
          <h2>What is Prettier?</h2>
          <ul style={{ flex: "1" }}>
            <li>An opinionated code formatter</li>
            <li>Supports many languages</li>
            <li>Integrates with most editors</li>
            <li>Has few options</li>
          </ul>
        </div>
          <h2>Why?</h2>
            <li>You press save and code is formatted</li>
            <li>No need to discuss style in code review</li>
            <li>Saves you time and energy</li>
            <li>
              <a href={"/docs/" + language + "/why-prettier.html"}>And more</a>
            </li>
          </ul>
        </div>
      </div>
    </Container>
  </div>
)

({ name, nameLink, showName, image, variants }) => (
  <div
    className="languageCategory"
    style={{
      display: "flex",
      alignItems: "flex-start",
      paddingBottom: "1em",
    }}
  >
    <img src={image} style={{ width: "50px", padding: "0 20px" }} />
    <ul>
      {showName && (
        <li className="accented">
          {nameLink ? <a href={nameLink}>{name}</a> : name}
        </li>
      )}
      {variants.map((variant) => (
        <li key={variant}>
          <MarkdownBlock>{variant}</MarkdownBlock>
        </li>
      ))}
    </ul>
  </div>
)

() => {
  const languageChunks = siteConfig.supportedLanguages.reduce(
    (acc, language) => {
      const last = acc[acc.length - 1];
      if (
        last &&
        last.length < 2 &&
        last.reduce((sum, lang) => sum + lang.variants.length, 0) +
          language.variants.length <
          9
      ) {
        last.push(language);
      } else {
        acc.push([language]);
      }
      return acc;
    },
    []
  );

  return (
    <div
      className="languagesSection productShowcaseSection"
      style={{ textAlign: "center" }}
    >
      <Container>
        <h2>Works with the Tools You Use</h2>
        <div
          style={{
            display: "flex",
            flexFlow: "row wrap",
            justifyContent: "space-around",
          }}
        >
          {languageChunks.map((languageChunk, index) => (
            <div key={index} style={{ flex: "1 1 auto" }}>
              {languageChunk.map((language) => (
                <Language key={language.name} {...language} />
              ))}
            </div>
          ))}
        </div>
      </Container>
    </div>
  );
}

({ content = "", image, name }) => (
  <div className="editor">
    <img className="editorImage" src={image} />
    <div className="editorInfo">
      <h3 className="editorName">{name}</h3>
      <MarkdownBlock>{content.replace(/\n/g, "  \n")}</MarkdownBlock>
    </div>
  </div>
)

() => (
  <div className="editorSupportSection productShowcaseSection lightBackground">
      <h2>Editor Support</h2>
      <div
        style={{
          justifyContent: "space-around",
        }}
      >
        {siteConfig.editors.map((editor) => (
          <Editor key={editor.name} {...editor} />
        ))}
      </div>

    <div style={{ float: "right" }}>
      <span>Got more? </span>
      <a
        href={`${siteConfig.githubUrl}/edit/main/website/data/editors.yml`}
        className="button"
      >
        Send a PR
      </a>
    </div>
  </div>
)

({ language }) => {
  const showcase = siteConfig.users
    .filter((user) => user.pinned)
    .map((user, i) => (
      <a key={i} className="growOnHover alignCenter" href={user.infoLink}>
        <img className="user" src={user.greyImage} title={user.caption} />
      </a>
    ));

  return (
    <div className="usersSection productShowcaseSection">
        <h2>Used By People You Rely On</h2>
        <div style={{ textAlign: "right" }} />
        <div
          style={{
          }}
        >
          {showcase}
        </div>
        <div className="more-users">
          <a
            className="button"
            href={siteConfig.baseUrl + language + "/users/"}
            target="_self"
            style={{ marginRight: "10px" }}
          >
            See Others
          </a>
        </div>

        <h2 className="ecosystemSubHeader">Established in the Ecosystem</h2>
        <div
          className="ecosystemSubSection"
          style={{
          }}
        >
          <div style={{ display: "flex", marginTop: "22px" }}>
            <a
              href="https://2020.stateofjs.com/en-US/other-tools/utilities"
              className="growOnHover"
            >
              <img
                src="/images/state_of_js_grey.svg"
                style={{ height: "100px" }}
              />
            </a>
            <div style={{ marginLeft: ".7em", width: "260px" }}>
              <p>
                Regularly used by more than <strong>70%</strong> of respondents
                to State of JS 2020
              </p>
              <Button href="https://2020.stateofjs.com/en-US/other-tools/utilities">
                Go to Survey Results
              </Button>
            </div>
          </div>

            <a
              href="https://github.com/prettier/prettier"
            >
              <img src="/images/github_grey.svg" style={{ height: "100px" }} />
            </a>
              <p>
                More than{" "}
                <strong data-placeholder="dependent-github">2.3 million</strong>{" "}
                dependent repositories on GitHub
              </p>
              <Button href="https://github.com/prettier/prettier/network/dependents">
                Check Them Out
              </Button>
            </div>
          </div>

            <a
              href="https://npmjs.com/package/prettier"
            >
              <img src="/images/npm_grey.svg" style={{ height: "100px" }} />
            </a>
              <p>
                More than <strong data-placeholder="dependent-npm">6000</strong>{" "}
                dependent packages on npm
              </p>
              <Button href="https://www.npmjs.com/browse/depended/prettier">
                See them all
              </Button>
            </div>
          </div>
        </div>
    </div>
  );
}

class Index extends React.Component {
  render() {

    return (
      <div>
        </div>
      </div>
    );
  }
}

function Versions(props) {
  const { config: siteConfig } = props;
  return (
    <div className="docMainWrapper wrapper">
      <Container className="mainContainer versionsContainer">
        <div className="post">
          <header className="postHeader">
            <h1>{siteConfig.title} Versions</h1>
          </header>
          <table className="versions">
            <tbody>
              <tr>
                <th>Version</th>
                <th>Install with</th>
                <th>Documentation</th>
              </tr>
              <tr>
                <td>{latestVersion}</td>
                <td>
                  <code>npm install prettier</code>
                </td>
                <td>
                  <a href={`${siteConfig.baseUrl}docs/en/index.html`}>
                    {latestDocsVersion}
                  </a>{" "}
                  (latest)
                </td>
              </tr>
              <tr>
                <td>{devVersion}</td>
                <td>
                  <code>npm install prettier/prettier</code>
                </td>
                <td>
                  <a href={`${siteConfig.baseUrl}docs/en/next/index.html`}>
                    next
                  </a>{" "}
                  (main)
                </td>
              </tr>
              {pastDocsVersions.length > 0 &&
                pastDocsVersions.map((pastDocsVersion, index) => {
                  const pastMajorVersion = pastDocsVersion.replace(/^v/, "");
                  return (
                    <tr key={index}>
                      <td>{pastMajorVersion}.x</td>
                      <td>
                        <code>
                          npm install prettier@
                          {pastMajorVersion}
                        </code>
                      </td>
                      <td>
                        <a
                          href={`${siteConfig.baseUrl}docs/en/${pastDocsVersion}/index.html`}
                        >
                          {pastDocsVersion}
                        </a>
                      </td>
                    </tr>
                  );
                })}
            </tbody>
          </table>
        </div>
    </div>
  );
}

class Users extends React.Component {
  render() {
    const showcase = siteConfig.users.map((user, i) => (
      <a key={i} href={user.infoLink}>
        <img src={user.image} title={user.caption} />
      </a>
    ));

    return (
      <div>
        <div className="mainContainer">
          <Container padding={["bottom", "top"]}>
            <div className="showcaseSection">
              <div className="prose">
                <h1>Who’s Using This?</h1>
              </div>
              <blockquote
                style={{
                  display: "flex",
                  alignItems: "center",
                  fontSize: "125%",
                }}
              >
                <div className="prose">
                  Prettier is regularly used by more than <strong>70%</strong>
                  &nbsp;of the respondents to the “Utilities” section of
                  the&nbsp;
                  <a href="https://2020.stateofjs.com/en-US/other-tools/utilities">
                    State&nbsp;of&nbsp;JS&nbsp;2020
                  </a>{" "}
                  survey (14880&nbsp;developers out of 20974).
                </div>
                <a href="https://2020.stateofjs.com">
                  <img
                    title="State of JS 2020"
                    src="/images/state_of_js.svg"
                    width="180"
                    style={{ background: "#222429", borderRadius: 5 }}
                  />
                </a>
              </blockquote>
              <div className="logos">{showcase}</div>
                ...and{" "}
                <a href="https://www.npmjs.com/browse/depended/prettier">
                  many more projects
                </a>
              </div>
            </div>
          </Container>
        </div>
      </div>
    );
  }
}

render() {
      </a>
    ));

    return (
      <div>
              </div>
                style={{
                }}
              >
                  the&nbsp;
                  </a>{" "}
                </div>
                  <img
                  />
                </a>
                </a>
              </div>
            </div>
        </div>
      </div>
    );
  }

class Help extends React.Component {
  render() {
    const supportLinks = [
      {
        content:
          "Learn more using the [documentation on this site.](/docs/en/why-prettier.html)\n",
        title: "Browse Docs",
      },
      {
        content: "Ask questions about the documentation and project\n",
        title: "Join the community",
      },
      {
        content: "Find out what's new with this project\n",
        title: "Stay up to date",
      },
    ];

    return (
      <div>
        <div className="docMainWrapper wrapper">
          <Container className="mainContainer documentContainer postContainer">
            <div className="post">
              <header className="postHeader">
                <h2>Need help?</h2>
              </header>
              <p>This project is maintained by a dedicated group of people;</p>
              <GridBlock contents={supportLinks} layout="threeColumn" />
            </div>
        </div>
      </div>
    );
  }
}

render() {
      {
        content:
      },
      {
      },
      {
      },
    ];

    return (
      <div>
              </header>
            </div>
        </div>
      </div>
    );
  }

function get(key) {
  try {
    return JSON.parse(window.localStorage.getItem(key));
  } catch (_) {
    // noop
  }
}

function set(key, value) {
  try {
    window.localStorage.setItem(key, JSON.stringify(value));
    // noop
  }
}

class PrettierFormat extends React.Component {
  constructor() {
    super();
    this.state = { formatted: "", debug: {} };
  }

  componentDidMount() {
    this.format();
  }

  componentDidUpdate(prevProps) {
    for (const key of [
      "code",
      "options",
      "debugAst",
      "debugDoc",
      "debugComments",
      "reformat",
    ]) {
      if (prevProps[key] !== this.props[key]) {
        this.format();
        break;
      }
    }
  }

  format() {
    const {
      worker,
      code,
      options,
      debugAst: ast,
      debugDoc: doc,
      debugComments: comments,
      reformat,
    } = this.props;

    worker
      .format(code, options, { ast, doc, comments, reformat })
      .then((result) => this.setState(result));
  }

  render() {
    return this.props.children(this.state);
  }
}

constructor() {
    super();
  }

componentDidUpdate(prevProps) {
      "code",
    ]) {
        break;
      }
    }
  }

format() {
    const {
      worker,
      code,
      options,
      reformat,

    worker
  }

class App extends React.Component {
    super();
    this.state = { loaded: false };
    this.worker = new WorkerApi("/worker.js");
  }

    this.worker.getMetadata().then(({ supportInfo, version }) => {
      this.setState({
        loaded: true,
        availableOptions: supportInfo.options.map(augmentOption),
        version: fixPrettierVersion(version),
      });
    });
  }

  render() {
    const { loaded, availableOptions, version } = this.state;

    if (!loaded) {
      return "Loading...";
    }

    return (
      <React.Fragment>
        <VersionLink version={version} />
        <Playground
          worker={this.worker}
          availableOptions={availableOptions}
          version={version}
        />
      </React.Fragment>
    );
  }
}

    super();
  }

componentDidMount() {
      });
    });
  }

render() {

    }

    return (
        />
    );
  }

function augmentOption(option) {
  if (option.type === "boolean" && option.default === true) {
    option.inverted = true;
  }

  option.cliName =
    "--" +
    (option.inverted ? "no-" : "") +
    option.name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();

  return option;
}

function formatMarkdown({
  input,
  output,
  output2,
  doc,
  version,
  url,
  options,
  cliOptions,
  full,
}) {
  const syntax = getMarkdownSyntax(options);
  const optionsString = formatCLIOptions(cliOptions);
  const isIdempotent = !output2 || output === output2;

  return [
    `**Prettier ${version}**`,
    `[Playground link](${url})`,
    optionsString === "" ? null : codeBlock(optionsString, "sh"),
    "",
    "**Input:**",
    codeBlock(input, syntax),
    ...(doc ? ["", "**Doc:**", codeBlock(doc, "js")] : []),
    ...(output === undefined
      ? []
      : ["", "**Output:**", codeBlock(output, syntax)]),
    ...(isIdempotent
      ? []
      : ["", "**Second Output:**", codeBlock(output2, syntax)]),
    ...(full ? ["", "**Expected behavior:**", ""] : []),
  ]
    .filter((part) => part != null)
    .join("\n");
}

function getMarkdownSyntax(options) {
  switch (options.parser) {
    case "babel":
    case "babel-flow":
    case "flow":
    case "espree":
    case "meriyah":
      return "jsx";
    case "babel-ts":
    case "typescript":
      return "tsx";
    case "json":
    case "json-stringify":
      return "jsonc";
    case "glimmer":
      return "hbs";
    case "angular":
    case "lwc":
      return "html";
    default:
      return options.parser;
  }
}

function formatCLIOptions(cliOptions) {
  return cliOptions
    .map(([name, value]) => (value === true ? name : `${name} ${value}`))
}

function codeBlock(content, syntax) {
  const backtickSequences = content.match(/`+/g) || [];
  const longestBacktickSequenceLength = Math.max(
    ...backtickSequences.map(({ length }) => length)
  );
  const fenceLength = Math.max(3, longestBacktickSequenceLength + 1);
  const fence = "`".repeat(fenceLength);
  return [fence + (syntax || ""), content, fence].join("\n");
}

class CodeMirrorPanel extends React.Component {
    super();
    this._textareaRef = React.createRef();
    this._codeMirror = null;
    this._cached = "";
    this._overlay = null;
    this.handleChange = this.handleChange.bind(this);
    this.handleFocus = this.handleFocus.bind(this);
    this.handleSelectionChange = this.handleSelectionChange.bind(this);
  }

    const options = { ...this.props };
    delete options.ruler;
    delete options.rulerColor;
    delete options.value;
    delete options.onChange;

    options.rulers = [makeRuler(this.props)];

    if (options.foldGutter) {
      options.gutters = ["CodeMirror-linenumbers", "CodeMirror-foldgutter"];
    }

    this._codeMirror = CodeMirror.fromTextArea(
      this._textareaRef.current,
      options
    );
    this._codeMirror.on("change", this.handleChange);
    this._codeMirror.on("focus", this.handleFocus);
    this._codeMirror.on("beforeSelectionChange", this.handleSelectionChange);

    window.CodeMirror.keyMap.pcSublime["Ctrl-L"] = false;
    window.CodeMirror.keyMap.sublime["Ctrl-L"] = false;

    this.updateValue(this.props.value || "");
    this.updateOverlay();
  }

  componentWillUnmount() {
    this._codeMirror && this._codeMirror.toTextArea();
  }

    if (this.props.value !== this._cached) {
      this.updateValue(this.props.value);
    }
    if (
      this.props.overlayStart !== prevProps.overlayStart ||
      this.props.overlayEnd !== prevProps.overlayEnd
    ) {
      this.updateOverlay();
    }
    if (this.props.mode !== prevProps.mode) {
      this._codeMirror.setOption("mode", this.props.mode);
    }
    if (this.props.ruler !== prevProps.ruler) {
      this._codeMirror.setOption("rulers", [makeRuler(this.props)]);
    }
  }

  updateValue(value) {
    this._cached = value;
    this._codeMirror.setValue(value);

    if (this.props.autoFold instanceof RegExp) {
      const lines = value.split("\n");
      // going backwards to prevent unfolding folds created earlier
      for (let i = lines.length - 1; i >= 0; i--) {
        if (this.props.autoFold.test(lines[i])) {
          this._codeMirror.foldCode(i);
        }
      }
    }
  }

  updateOverlay() {
    if (!this.props.readOnly) {
      if (this._overlay) {
        this._codeMirror.removeOverlay(this._overlay);
      }
      const [start, end] = getIndexPosition(this.props.value, [
        this.props.overlayStart,
        this.props.overlayEnd,
      ]);
      this._overlay = createOverlay(start, end);
      this._codeMirror.addOverlay(this._overlay);
    }
  }

  handleFocus(/* codeMirror, event */) {
    if (this._codeMirror.getValue() === this.props.codeSample) {
      this._codeMirror.execCommand("selectAll");
    }
  }

  handleChange(doc, change) {
    if (change.origin !== "setValue") {
      this._cached = doc.getValue();
      this.props.onChange(this._cached);
    }
  }

  handleSelectionChange(doc, change) {
    if (this.props.onSelectionChange) {
      this.props.onSelectionChange(change.ranges[0]);
    }
  }

  render() {
    return (
      <div className="editor input">
        <textarea ref={this._textareaRef} />
      </div>
    );
  }
}

    super();
  }

    }

      options
    );

  }

componentWillUnmount() {
  }

    }
    if (
    ) {
    }
    }
    }
  }

updateValue(value) {

        }
      }
    }
  }

updateOverlay() {
      }
      ]);
    }
  }

handleFocus(/* codeMirror, event */) {
    }
  }

handleChange(doc, change) {
    }
  }

handleSelectionChange(doc, change) {
    }
  }

render() {
    return (
      </div>
    );
  }

function getIndexPosition(text, indexes) {
  indexes = indexes.slice();
  let line = 0;
  let count = 0;
  let lineStart = 0;
  const result = [];

  while (indexes.length > 0) {
    const index = indexes.shift();

    while (count < index && count < text.length) {
      if (text[count] === "\n") {
        line++;
        lineStart = count + 1;
      }
      count++;
    }

    result.push({ line, pos: count - lineStart });
  }

  return result;
}

function createOverlay(start, end) {
  return {
    token(stream) {
      const { line } = stream.lineOracle;

      if (line < start.line || line > end.line) {
        stream.skipToEnd();
      } else if (line === start.line && stream.pos < start.pos) {
        stream.pos = start.pos;
      } else if (line === end.line) {
        if (stream.pos < end.pos) {
          stream.pos = end.pos;
          return "searching";
        }
      } else {
        return "searching";
      }
    },
  };
}

token(stream) {

        }
      } else {
      }
    }

function makeRuler(props) {
  return { column: props.ruler, color: props.rulerColor };
}

function InputPanel(props) {
  return (
    <CodeMirrorPanel
      lineNumbers={true}
      keyMap="sublime"
      autoCloseBrackets={true}
      matchBrackets={true}
      showCursorWhenSelecting={true}
      tabSize={4}
      rulerColor="#eeeeee"
      {...props}
    />
  );
}

function OutputPanel(props) {
  return (
      readOnly={true}
      rulerColor="#444444"
    />
  );
}

function DebugPanel({ value, autoFold }) {
  return (
      lineNumbers={false}
      foldGutter={true}
      autoFold={autoFold}
      mode="jsx"
      value={value}
    />
  );
}

function fixPrettierVersion(version) {
  const match = version.match(/^\d+\.\d+\.\d+-pr.(\d+)$/);
  if (match) {
    return `pr-${match[1]}`;
  }
  return version;
}

function getDefaults(availableOptions, optionNames) {
  const defaults = {};
  for (const option of availableOptions) {
    if (optionNames.includes(option.name)) {
      defaults[option.name] =
        option.name === "parser" ? "babel" : option.default;
    }
  }
  return defaults;
}

function buildCliArgs(availableOptions, options) {
  const args = [];
    const value = options[option.name];

    if (typeof value === "undefined") {
      continue;
    }

    if (option.type === "boolean") {
      if ((value && !option.inverted) || (!value && option.inverted)) {
        args.push([option.cliName, true]);
      }
    } else if (value !== option.default || option.name === "rangeStart") {
      args.push([option.cliName, value]);
    }
  }
  return args;
}

function getCodemirrorMode(parser) {
  switch (parser) {
    case "css":
    case "less":
    case "scss":
      return "css";
    case "graphql":
      return "graphql";
    case "markdown":
      return "markdown";
    default:
  }
}

function getAstAutoFold(parser) {
    case "json5":
      return astAutoFold.estree;
      return astAutoFold.postcss;
    case "html":
    case "vue":
      return astAutoFold.html;
    case "mdx":
      return astAutoFold.mdast;
    case "yaml":
      return astAutoFold.yaml;
      return astAutoFold.glimmer;
  }
}

    super();
    this.state = {
      showSidebar: window.innerWidth > window.innerHeight,
      showAst: false,
      showDoc: false,
      showComments: false,
      showSecondFormat: false,
      showInput: true,
      showOutput: true,
      toggleSidebar: () => this.setState(stateToggler("showSidebar")),
      toggleAst: () => this.setState(stateToggler("showAst")),
      toggleDoc: () => this.setState(stateToggler("showDoc")),
      toggleComments: () => this.setState(stateToggler("showComments")),
      toggleSecondFormat: () => this.setState(stateToggler("showSecondFormat")),
      toggleInput: () => this.setState(stateToggler("showInput")),
      toggleOutput: () => this.setState(stateToggler("showOutput")),
      ...storage.get("editor_state"),
    };
  }

componentDidUpdate(_, prevState) {
    if (!shallowEqual(this.state, prevState)) {
      storage.set("editor_state", this.state);
    }
  }

class ClipboardButton extends React.Component {
    super();
    this.state = { showTooltip: false, tooltipText: "" };
    this.timer = null;
    this.ref = React.createRef();
  }

    this.clipboard = new ClipboardJS(this.ref.current, {
      text: () => {
        const { copy } = this.props;
        return typeof copy === "function" ? copy() : copy;
      },
    });
    this.clipboard.on("success", () => this.showTooltip("Copied!"));
    this.clipboard.on("error", () => this.showTooltip("Press ctrl+c to copy"));
  }

  showTooltip(text) {
    this.setState({ showTooltip: true, tooltipText: text }, () => {
      if (this.timer) {
        clearTimeout(this.timer);
      }
      this.timer = setTimeout(() => {
        this.timer = null;
        this.setState({ showTooltip: false });
      }, 2000);
    });
  }

  render() {
    const { children, copy, ...rest } = this.props;
    const { showTooltip, tooltipText } = this.state;

    return (
      <Button ref={this.ref} {...rest}>
        {showTooltip ? <span className="tooltip">{tooltipText}</span> : null}
        {children}
      </Button>
    );
  }
}

    super();
  }

      },
    });
  }

showTooltip(text) {
      }
      }, 2000);
    });
  }

render() {

    return (
      </Button>
    );
  }

() => {
      }

function postMessage(message) {
    const uid = ++counter;
    return new Promise((resolve, reject) => {
      handlers[uid] = [resolve, reject];
      worker.postMessage({ uid, message });
    });
  }

getMetadata() {
      return postMessage({ type: "meta" });
    }

format(code, options, debug) {
      return postMessage({ type: "format", code, options, debug });
    }

function read() {
  const hash = document.location.hash.slice(1);
  if (!hash) {
    return {};
  }

  // backwards support for old json encoded URIComponent
  const decode = hash.includes("%7B%22")
    ? decodeURIComponent
    : LZString.decompressFromEncodedURIComponent;

  try {
    return JSON.parse(decode(hash));
    return {};
  }
}

function replace(state) {
  const hash = LZString.compressToEncodedURIComponent(JSON.stringify(state));
  if (
    typeof URL === "function" &&
    typeof history === "object" &&
    typeof history.replaceState === "function"
  ) {
    const url = new URL(location);
    url.hash = hash;
    history.replaceState(null, null, url);
  } else {
    location.hash = hash;
  }
}

function stateToggler(key) {
  return (state) => ({ [key]: !state[key] });
}

function is(x, y) {
  // SameValue algorithm
  if (x === y) {
    // Steps 1-5, 7-10
    // Steps 6.b-6.e: +0 != -0
    return x !== 0 || 1 / x === 1 / y;
  }
  // Step 6.a: NaN == NaN
  return x !== x && y !== y;
}

function shallowEqual(objA, objB) {
  if (is(objA, objB)) {
    return true;
  }

  if (
    typeof objA !== "object" ||
    objA === null ||
    typeof objB !== "object" ||
    objB === null
  ) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
  }

  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
  }

  return true;
}

class Playground extends React.Component {
  constructor(props) {
    super();

    const original = urlHash.read();

    const defaultOptions = util.getDefaults(
      props.availableOptions,
      ENABLED_OPTIONS
    );

    const options = Object.assign(defaultOptions, original.options);

    // backwards support for old parser `babylon`
    if (options.parser === "babylon") {
      options.parser = "babel";
    }

    const content = original.content || getCodeSample(options.parser);
    const selection = {};

    this.state = { content, options, selection };

    this.handleOptionValueChange = this.handleOptionValueChange.bind(this);

    this.setContent = (content) => this.setState({ content });
    this.clearContent = this.setContent.bind(this, "");
    this.resetOptions = () => this.setState({ options: defaultOptions });
    this.setSelection = (selection) => this.setState({ selection });
    this.setSelectionAsRange = () => {
      const { selection, content, options } = this.state;
      const { head, anchor } = selection;
      const range = [head, anchor].map(
        ({ ch, line }) =>
          content.split("\n").slice(0, line).join("\n").length +
          ch +
          (line ? 1 : 0)
      );
      const [rangeStart, rangeEnd] = range.sort((a, b) => a - b);
      const updatedOptions = { ...options, rangeStart, rangeEnd };
      if (rangeStart === rangeEnd) {
        delete updatedOptions.rangeStart;
        delete updatedOptions.rangeEnd;
      }
      this.setState({ options: updatedOptions });
    };

    this.enabledOptions = orderOptions(props.availableOptions, ENABLED_OPTIONS);
    this.rangeStartOption = props.availableOptions.find(
      (opt) => opt.name === "rangeStart"
    );
    this.rangeEndOption = props.availableOptions.find(
      (opt) => opt.name === "rangeEnd"
    );
  }

  componentDidUpdate(_, prevState) {
    const { content, options } = this.state;
    if (
      !shallowEqual(prevState.options, this.state.options) ||
      prevState.content !== content
    ) {
      urlHash.replace({ content, options });
    }
  }

  handleOptionValueChange(option, value) {
    this.setState((state) => {
      const options = { ...state.options };

      if (option.type === "int" && Number.isNaN(value)) {
        delete options[option.name];
      } else {
        options[option.name] = value;
      }

      const content =
        state.content === "" ||
        state.content === getCodeSample(state.options.parser)
          ? getCodeSample(options.parser)
          : state.content;

      return { options, content };
    });
  }

  getMarkdown({ formatted, reformatted, full, doc }) {
    const { availableOptions, version } = this.props;

    return formatMarkdown({
      input: content,
      output: formatted,
      output2: reformatted,
      doc,
      version,
      url: window.location.href,
      options,
      cliOptions: util.buildCliArgs(availableOptions, options),
      full,
    });
  }

  render() {
    const { worker, version } = this.props;

    // TODO: remove this when v2.3.0 is released
    const [major, minor] = version.split(".", 2).map(Number);
    const showShowComments =
      Number.isNaN(major) || (major === 2 && minor >= 3) || major > 2;

    return (
      <EditorState>
        {(editorState) => (
          <PrettierFormat
            worker={worker}
            code={content}
            options={options}
            debugAst={editorState.showAst}
            debugDoc={editorState.showDoc}
            debugComments={showShowComments && editorState.showComments}
            reformat={editorState.showSecondFormat}
          >
            {({ formatted, debug }) => {
              const fullReport = this.getMarkdown({
                formatted,
                reformatted: debug.reformatted,
                full: true,
              });
              const showFullReport =
                encodeURIComponent(fullReport).length < MAX_LENGTH;
              return (
                <React.Fragment>
                  <div className="editors-container">
                    <Sidebar visible={editorState.showSidebar}>
                      <SidebarOptions
                        categories={CATEGORIES_ORDER}
                        availableOptions={this.enabledOptions}
                        optionValues={options}
                        onOptionValueChange={this.handleOptionValueChange}
                      />
                      <SidebarCategory title="Range">
                        <label>
                          The selected range will be highlighted in yellow in
                          the input editor
                        </label>
                        <Option
                          option={this.rangeStartOption}
                          value={
                            typeof options.rangeStart === "number"
                              ? options.rangeStart
                              : ""
                          }
                          onChange={this.handleOptionValueChange}
                        />
                        <Option
                          option={this.rangeEndOption}
                          value={
                            typeof options.rangeEnd === "number"
                              ? options.rangeEnd
                              : ""
                          }
                          overrideMax={content.length}
                        />

                        <Button onClick={this.setSelectionAsRange}>
                          Set selected text as range
                        </Button>
                      </SidebarCategory>
                      <SidebarCategory title="Debug">
                        <Checkbox
                          label="show input"
                          checked={editorState.showInput}
                          onChange={editorState.toggleInput}
                        />
                        <Checkbox
                          label="show AST"
                          checked={editorState.showAst}
                          onChange={editorState.toggleAst}
                        />
                        <Checkbox
                          label="show doc"
                          checked={editorState.showDoc}
                          onChange={editorState.toggleDoc}
                        />
                        {showShowComments && (
                          <Checkbox
                            label="show comments"
                            checked={editorState.showComments}
                            onChange={editorState.toggleComments}
                          />
                        )}
                        <Checkbox
                          label="show output"
                          checked={editorState.showOutput}
                          onChange={editorState.toggleOutput}
                        />
                        <Checkbox
                          label="show second format"
                          checked={editorState.showSecondFormat}
                          onChange={editorState.toggleSecondFormat}
                        />
                        {editorState.showDoc && debug.doc && (
                          <ClipboardButton
                            copy={() => this.getMarkdown({ doc: debug.doc })}
                          >
                            Copy doc
                          </ClipboardButton>
                        )}
                      <div className="sub-options">
                        <Button onClick={this.resetOptions}>
                          Reset to defaults
                        </Button>
                      </div>
                    </Sidebar>
                    <div className="editors">
                      {editorState.showInput ? (
                        <InputPanel
                          mode={util.getCodemirrorMode(options.parser)}
                          ruler={options.printWidth}
                          value={content}
                          codeSample={getCodeSample(options.parser)}
                          overlayStart={options.rangeStart}
                          overlayEnd={options.rangeEnd}
                          onChange={this.setContent}
                          onSelectionChange={this.setSelection}
                        />
                      ) : null}
                      {editorState.showAst ? (
                        <DebugPanel
                          value={debug.ast || ""}
                          autoFold={util.getAstAutoFold(options.parser)}
                        />
                      ) : null}
                      {editorState.showDoc ? (
                        <DebugPanel value={debug.doc || ""} />
                      ) : null}
                      {showShowComments && editorState.showComments ? (
                          value={debug.comments || ""}
                        />
                      ) : null}
                      {editorState.showOutput ? (
                        <OutputPanel
                          value={formatted}
                        />
                      ) : null}
                      {editorState.showSecondFormat ? (
                          value={getSecondFormat(formatted, debug.reformatted)}
                        />
                      ) : null}
                    </div>
                  </div>
                  <div className="bottom-bar">
                    <div className="bottom-bar-buttons">
                      <Button onClick={editorState.toggleSidebar}>
                        {editorState.showSidebar ? "Hide" : "Show"} options
                      </Button>
                      <Button onClick={this.clearContent}>Clear</Button>
                      <ClipboardButton
                        copy={JSON.stringify(
                          // Remove `parser` since people usually paste this
                          // into their .prettierrc and specifying a top-level
                          // parser there is an anti-pattern. Note:
                          // `JSON.stringify` omits keys whose values are
                          // `undefined`.
                          { ...options, parser: undefined },
                          null,
                          2
                        )}
                      >
                        Copy config JSON
                      </ClipboardButton>
                    </div>
                    <div className="bottom-bar-buttons bottom-bar-buttons-right">
                      <ClipboardButton copy={window.location.href}>
                        Copy link
                        copy={() =>
                          this.getMarkdown({
                            formatted,
                            reformatted: debug.reformatted,
                          })
                        }
                      >
                        Copy markdown
                      <a
                        href={getReportLink(
                          showFullReport ? fullReport : COPY_MESSAGE
                        )}
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        <ClipboardButton
                          copy={() => (showFullReport ? "" : fullReport)}
                        >
                          Report issue
                        </ClipboardButton>
                      </a>
                    </div>
                  </div>
                </React.Fragment>
              );
            }}
          </PrettierFormat>
        )}
      </EditorState>
    );
  }
}

constructor(props) {
    super();

    );

    }

          ch +
      );
      }
    };

    );
    );
  }

    if (
    ) {
    }
  }

handleOptionValueChange(option, value) {

      } else {
      }

    });
  }

getMarkdown({ formatted, reformatted, full, doc }) {

      doc,
      version,
      options,
      full,
    });
  }

render() {

    return (
          >
              });
              return (
                      />
                        <label>
                        </label>
                        <Option
                          value={
                              : ""
                          }
                        />
                        <Option
                          value={
                              : ""
                          }
                        />

                        </Button>
                        <Checkbox
                        />
                        <Checkbox
                        />
                        <Checkbox
                        />
                          <Checkbox
                          />
                        )}
                        <Checkbox
                        />
                        <Checkbox
                        />
                          >
                            Copy doc
                        )}
                        </Button>
                      </div>
                        />
                      ) : null}
                        />
                      ) : null}
                      ) : null}
                        />
                      ) : null}
                        />
                      ) : null}
                        />
                      ) : null}
                    </div>
                  </div>
                      </Button>
                          null,
                          2
                        )}
                      >
                    </div>
                        Copy link
                          })
                        }
                      >
                      <a
                        )}
                      >
                        >
                      </a>
                    </div>
                  </div>
              );
            }}
        )}
    );
  }

() => {
          ch +
      );
      }
    }

function orderOptions(availableOptions, order) {
  const optionsByName = {};
    optionsByName[option.name] = option;
  }

  return order.map((name) => optionsByName[name]);
}

function getReportLink(reportBody) {
  return `${ISSUES_URL}${encodeURIComponent(reportBody)}`;
}

function getSecondFormat(formatted, reformatted) {
  return formatted === ""
    ? ""
    : formatted === reformatted
    ? "✓ Second format is unchanged."
    : reformatted;
}

function Sidebar({ visible, children }) {
  return (
    <div className={`options-container ${visible ? "open" : ""}`}>
      <div className="options">{children}</div>
    </div>
  );
}

function SidebarCategory({ title, children }) {
  return (
    <details className="sub-options" open="true">
      <summary>{title}</summary>
      {children}
    </details>
  );
}

function Checkbox({ label: _label, title, checked, onChange }) {
  return (
    <label title={title}>
      <input
        type="checkbox"
        checked={checked}
        onChange={(ev) => onChange(ev.target.checked)}
      />{" "}
      {_label}
    </label>
  );
}

function Select({ label: _label, title, values, selected, onChange }) {
  return (
      {_label}{" "}
      <select value={selected} onChange={(ev) => onChange(ev.target.value)}>
        {values.map((val) => (
          <option key={val} value={val}>
            {val}
          </option>
        ))}
      </select>
    </label>
  );
}

function NumberInput({
  label: _label,
  title,
  value,
  min,
  max,
  step,
  onChange,
}) {
  return (
      <input
        type="number"
        min={min}
        max={max}
        step={step}
        value={value}
        onChange={(ev) => onChange(Number.parseInt(ev.target.value, 10))}
      />
    </label>
  );
}

function BooleanOption({ option, value, onChange }) {
  function maybeInvert(value) {
    return option.inverted ? !value : value;
  }
  return (
    <Checkbox
      label={option.cliName}
      title={getDescription(option)}
      checked={maybeInvert(value)}
      onChange={(checked) => onChange(option, maybeInvert(checked))}
    />
  );
}

function maybeInvert(value) {
  }

function ChoiceOption({ option, value, onChange }) {
  return (
    <Select
      values={option.choices.map((choice) => choice.value)}
      selected={value}
      onChange={(val) => onChange(option, val)}
    />
  );
}

function NumberOption({ option, value, onChange }) {
  return (
    <NumberInput
      min={option.range.start}
      max={option.range.end}
      step={option.range.step}
    />
  );
}

function getDescription(option) {
  const description = option.inverted
    ? option.oppositeDescription
    : option.description;
  return description && description.replace(/\n/g, " ");
}

function importScriptOnce(url) {
  if (!imported[url]) {
    imported[url] = true;
    importScripts(url);
  }
}

get() {
        importScriptOnce(url);
        return prettierPlugins[property].parsers[parserName];
      }

function serializeAst(ast) {
  return JSON.stringify(
    ast,
    (_, value) =>
      typeof value === "bigint" ? `BigInt('${String(value)}')` : value,
    2
  );
}

function handleMessage(message) {
  if (message.type === "meta") {
    return {
      type: "meta",
      supportInfo: JSON.parse(
        JSON.stringify(
          prettier.getSupportInfo({
            showUnreleased: true,
          })
        )
      ),
      version: prettier.version,
    };
  }

  if (message.type === "format") {
    const options = message.options || {};

    delete options.ast;
    delete options.doc;
    delete options.output2;

    const plugins = [{ parsers }];
    options.plugins = plugins;

    const formatResult = formatCode(message.code, options);

    const response = {
      formatted: formatResult.formatted,
      debug: {
        ast: null,
        doc: null,
        comments: null,
        reformatted: null,
      },
    };

    if (message.debug.ast) {
      let ast;
      let errored = false;
      try {
        ast = serializeAst(prettier.__debug.parse(message.code, options).ast);
      } catch (e) {
        errored = true;
        ast = String(e);
      }

      if (!errored) {
        try {
          ast = formatCode(ast, { parser: "json", plugins }).formatted;
        } catch (e) {
          ast = serializeAst(ast);
        }
      }
      response.debug.ast = ast;
    }

    if (message.debug.doc) {
      try {
        response.debug.doc = prettier.__debug.formatDoc(
          prettier.__debug.printToDoc(message.code, options),
          { parser: "babel", plugins }
        );
        response.debug.doc = String(e);
      }
    }

    if (message.debug.comments) {
      response.debug.comments = formatCode(
        JSON.stringify(formatResult.comments || []),
        { parser: "json", plugins }
      ).formatted;
    }

    if (message.debug.reformat) {
      response.debug.reformatted = formatCode(
        response.formatted,
        options
    }

    return response;
  }
}

function formatCode(text, options) {
  try {
    return prettier.formatWithCursor(text, options);
  } catch (e) {
    if (e.constructor && e.constructor.name === "SyntaxError") {
      // Likely something wrong with the user's code
      return { formatted: String(e) };
    }
    // Likely a bug in Prettier
    // Provide the whole stack for debugging
    return { formatted: e.stack || String(e) };
  }
}

function handleLogoDrag(event) {
    logo.classList.add("rolling");
    event.preventDefault();
  }

  <a
    className="github-button"
    href={props.config.githubUrl}
    data-icon="octicon-star"
    data-show-count="true"
    aria-label="Star this project on GitHub"
  >
    Star
  </a>
)

class Footer extends React.Component {
  url(path) {
    return `${this.props.config.baseUrl}docs/${language}${path}`;
  }

  usersUrl() {
    return `${this.props.config.baseUrl}${language}/users`;
  }

  render() {
    return (
      <footer className="footerSection nav-footer" id="footer">
        <section className="sitemap">
          <a href={this.props.config.baseUrl} className="nav-home">
            <img
              src={this.props.config.baseUrl + this.props.config.footerIcon}
              alt={this.props.config.title}
            />
          </a>
          <div>
            <h5>Docs</h5>
            <a href={this.url("/index.html")}>About</a>
            <a href={this.url("/install.html")}>Usage</a>
            <br />
            <a href="https://www.netlify.com">
              <img src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" />
            </a>
          </div>
          <div>
            <h5>Community</h5>
            <a href={this.usersUrl()}>User Showcase</a>
            <a
              href="http://stackoverflow.com/questions/tagged/prettier"
              target="_blank"
              rel="noopener noreferrer"
            >
              Stack Overflow
            </a>
            <a href="https://gitter.im/jlongster/prettier">Chat on Gitter</a>
            <a href="https://twitter.com/PrettierCode">
              @PrettierCode on Twitter
            </a>
            <object
              type="image/svg+xml"
              data="https://img.shields.io/twitter/follow/prettiercode.svg?label=Follow+Prettier&style=social"
            >
              <a href="https://twitter.com/intent/follow?screen_name=prettiercode">
                <img
                  alt="Follow Prettier on Twitter"
                  src="https://img.shields.io/twitter/follow/prettiercode.png?label=Follow+Prettier&style=social"
                />
              </a>
            </object>
          </div>
          <div>
            <h5>More</h5>
            <a href={this.props.config.baseUrl + "blog"}>Blog</a>
            <a href={this.props.config.githubUrl}>GitHub</a>
            <a href={this.props.config.githubUrl + "/issues"}>Issues</a>
            <GithubButton config={this.props.config} />
          </div>
        </section>
      </footer>
    );
  }
}

url(path) {
  }

usersUrl() {
  }

render() {
    return (
            <img
            />
          </a>
          <div>
            <br />
            </a>
          </div>
          <div>
            <a
            >
            </a>
            </a>
            <object
            >
                <img
                />
              </a>
            </object>
          </div>
          <div>
          </div>
      </footer>
    );
  }

function getOptions(argv) {
  return constant.detailedOptions
    .filter(option => option.forwardToApi)
    .reduce(
      (current, option) =>
        Object.assign(current, { [option.forwardToApi]: argv[option.name] }),
      {}
    );
}

function dashifyObject(object) {
  return Object.keys(object || {}).reduce((output, key) => {
    output[dashify(key)] = object[key];
    return output;
  }, {});
}

function diff(a, b) {
  return require("diff").createTwoFilesPatch("", "", a, b, "", "", {
    context: 2
  });
}

function handleError(filename, error) {
  const isParseError = Boolean(error && error.loc);
  const isValidationError = /Validation Error/.test(error && error.message);

  // For parse errors and validation errors, we only want to show the error
  // message formatted in a nice way. `String(error)` takes care of that. Other
  // (unexpected) errors are passed as-is as a separate argument to
  // `console.error`. That includes the stack trace (if any), and shows a nice
  // `util.inspect` of throws things that aren't `Error` objects. (The Flow
  // parser has mistakenly thrown arrays sometimes.)
  if (isParseError) {
    logger.error(`${filename}: ${String(error)}`);
  } else if (isValidationError || error instanceof errors.ConfigError) {
    logger.error(String(error));
    // If validation fails for one file, it will fail for all of them.
    process.exit(1);
  } else if (error instanceof errors.DebugError) {
    logger.error(`${filename}: ${error.message}`);
  } else {
    logger.error(filename + ": " + (error.stack || error));
  }

  // Don't exit the process if one file failed
  process.exitCode = 2;
}

function logResolvedConfigPathOrDie(filePath) {
  const configFile = resolver.resolveConfigFile.sync(filePath);
  if (configFile) {
    console.log(path.relative(process.cwd(), configFile));
  } else {
  }
}

function writeOutput(result, options) {
  // Don't use `console.log` here since it adds an extra newline at the end.
  process.stdout.write(result.formatted);

  if (options.cursorOffset >= 0) {
    process.stderr.write(result.cursorOffset + "\n");
  }
}

function listDifferent(argv, input, options, filename) {
  if (!argv["list-different"]) {
    return;
  }

  options = Object.assign({}, options, { filepath: filename });

  if (!prettier.check(input, options)) {
    if (!argv["write"]) {
      console.log(filename);
    }
    process.exitCode = 1;
  }

}

function format(argv, input, opt) {
  if (argv["debug-print-doc"]) {
    const doc = prettier.__debug.printToDoc(input, opt);
    return { formatted: prettier.__debug.formatDoc(doc) };
  }

  if (argv["debug-check"]) {
    const pp = prettier.format(input, opt);
    const pppp = prettier.format(pp, opt);
    if (pp !== pppp) {
      throw new errors.DebugError(
        "prettier(input) !== prettier(prettier(input))\n" + diff(pp, pppp)
      );
    } else {
      const ast = cleanAST(prettier.__debug.parse(input, opt));
      const past = cleanAST(prettier.__debug.parse(pp, opt));

      if (ast !== past) {
        const MAX_AST_SIZE = 2097152; // 2MB
        const astDiff =
          ast.length > MAX_AST_SIZE || past.length > MAX_AST_SIZE
            ? "AST diff too large to render"
            : diff(ast, past);
        throw new errors.DebugError(
          "ast(input) !== ast(prettier(input))\n" +
            astDiff +
            "\n" +
            diff(input, pp)
        );
      }
    }
    return { formatted: opt.filepath || "(stdin)\n" };
  }

  return prettier.formatWithCursor(input, opt);
}

function getOptionsOrDie(argv, filePath) {
  try {
    if (argv["config"] === false) {
      logger.debug("'--no-config' option found, skip loading config file.");
      return null;
    }

    logger.debug(
      argv["config"]
        ? `load config file from '${argv["config"]}'`
        : `resolve config from '${filePath}'`
    );
    const options = resolver.resolveConfig.sync(filePath, {
      config: argv["config"]
    });

    logger.debug("loaded options `" + JSON.stringify(options) + "`");
    return options;
  } catch (error) {
    logger.error("Invalid configuration file: " + error.message);
    process.exit(2);
  }
}

function getOptionsForFile(argv, filepath) {
  const options = getOptionsOrDie(argv, filepath);

  const appliedOptions = Object.assign(
    { filepath },
    applyConfigPrecedence(
      argv,
      options && normalizeConfig("api", options, constant.detailedOptionMap)
    )
  );

  logger.debug(
    `applied config-precedence (${argv["config-precedence"]}): ` +
      `${JSON.stringify(appliedOptions)}`
  );
  return appliedOptions;
}

function parseArgsToOptions(argv, overrideDefaults) {
  return getOptions(
    normalizeConfig(
      "cli",
      minimist(
        argv.__args,
        Object.assign({
          string: constant.minimistOptions.string,
          boolean: constant.minimistOptions.boolean,
          default: Object.assign(
            {},
            dashifyObject(apiDefaultOptions),
            dashifyObject(overrideDefaults)
          )
        })
      ),
      { warning: false }
    )
  );
}

function applyConfigPrecedence(argv, options) {
  try {
    switch (argv["config-precedence"]) {
      case "cli-override":
        return parseArgsToOptions(argv, options);
      case "file-override":
        return Object.assign({}, parseArgsToOptions(argv), options);
      case "prefer-file":
        return options || parseArgsToOptions(argv);
    }
    logger.error(error.toString());
  }
}

function formatStdin(argv) {
  const filepath = argv["stdin-filepath"]
    ? path.resolve(process.cwd(), argv["stdin-filepath"])
    : process.cwd();

  const ignorer = createIgnorer(argv);
  const relativeFilepath = path.relative(process.cwd(), filepath);

  if (relativeFilepath && ignorer.filter([relativeFilepath]).length === 0) {
    return;
  }

  thirdParty.getStream(process.stdin).then(input => {
    const options = getOptionsForFile(argv, filepath);

    if (listDifferent(argv, input, options, "(stdin)")) {
      return;
    }

    try {
      writeOutput(format(argv, input, options), options);
    } catch (error) {
      handleError("stdin", error);
    }
  });
}

function createIgnorer(argv) {
  const ignoreFilePath = path.resolve(argv["ignore-path"]);
  let ignoreText = "";

  try {
    ignoreText = fs.readFileSync(ignoreFilePath, "utf8");
  } catch (readError) {
    if (readError.code !== "ENOENT") {
      logger.error(`Unable to read ${ignoreFilePath}: ` + readError.message);
      process.exit(2);
    }
  }

  return ignore().add(ignoreText);
}

function eachFilename(argv, patterns, callback) {
  const ignoreNodeModules = argv["with-node-modules"] === false;
  // The ignorer will be used to filter file paths after the glob is checked,
  // before any files are actually read

  if (ignoreNodeModules) {
    patterns = patterns.concat(["!**/node_modules/**", "!./node_modules/**"]);
  }

  try {
    const filePaths = globby
      .sync(patterns, { dot: true })
      .map(filePath => path.relative(process.cwd(), filePath));

    if (filePaths.length === 0) {
      logger.error(`No matching files. Patterns tried: ${patterns.join(" ")}`);
      process.exitCode = 2;
      return;
    }
    ignorer
      .filter(filePaths)
      .forEach(filePath =>
        callback(filePath, getOptionsForFile(argv, filePath))
      );
    logger.error(
      `Unable to expand glob patterns: ${patterns.join(" ")}\n${error.message}`
    );
    // Don't exit the process if one pattern failed
    process.exitCode = 2;
  }
}

function formatFiles(argv) {
  eachFilename(argv, argv.__filePatterns, (filename, options) => {
    if (argv["write"] && process.stdout.isTTY) {
      // Don't use `console.log` here since we need to replace this line.
      process.stdout.write(filename);
    }

    let input;
    try {
      input = fs.readFileSync(filename, "utf8");
      // Add newline to split errors from filename line.
      process.stdout.write("\n");

      logger.error(`Unable to read file: ${filename}\n${error.message}`);
      // Don't exit the process if one file failed
      return;
    }

    listDifferent(argv, input, options, filename);

    const start = Date.now();

    let result;
    let output;

    try {
      result = format(
        argv,
        input,
        Object.assign({}, options, { filepath: filename })
      );
      output = result.formatted;

      handleError(filename, error);
      return;
    }

    if (argv["write"]) {
      if (process.stdout.isTTY) {
        // Remove previously printed filename to log it with duration.
        readline.clearLine(process.stdout, 0);
        readline.cursorTo(process.stdout, 0, null);
      }

      // Don't write the file if it won't change in order not to invalidate
      // mtime based caches.
      if (output === input) {
        if (!argv["list-different"]) {
          console.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
        }
      } else {
        if (argv["list-different"]) {
          console.log(filename);
        } else {
          console.log(`${filename} ${Date.now() - start}ms`);
        }

        try {
          fs.writeFileSync(filename, output, "utf8");
        } catch (error) {
          logger.error(`Unable to write file: ${filename}\n${error.message}`);
          // Don't exit the process if one file failed
          process.exitCode = 2;
        }
      }
    } else if (argv["debug-check"]) {
      if (output) {
        console.log(output);
      } else {
        process.exitCode = 2;
      }
    } else if (!argv["list-different"]) {
      writeOutput(result, options);
    }
  });
}

function getOptionsWithOpposites(options) {
  // Add --no-foo after --foo.
  const optionsWithOpposites = options.map(option => [
    option.description ? option : null,
    option.oppositeDescription
      ? Object.assign({}, option, {
          name: `no-${option.name}`,
          type: "boolean",
          description: option.oppositeDescription
        })
      : null
  ]);
  return flattenArray(optionsWithOpposites).filter(Boolean);
}

function createUsage() {
  const options = getOptionsWithOpposites(constant.detailedOptions).filter(
    // remove unnecessary option (e.g. `semi`, `color`, etc.), which is only used for --help <flag>
    option =>
      !(
        option.type === "boolean" &&
        option.oppositeDescription &&
        !option.name.startsWith("no-")
      )
  );

  const groupedOptions = groupBy(options, option => option.category);

  const firstCategories = constant.categoryOrder.slice(0, -1);
  const lastCategories = constant.categoryOrder.slice(-1);
  const restCategories = Object.keys(groupedOptions).filter(
    category =>
      firstCategories.indexOf(category) === -1 &&
      lastCategories.indexOf(category) === -1
  );
  const allCategories = firstCategories.concat(restCategories, lastCategories);

  const optionsUsage = allCategories.map(category => {
    const categoryOptions = groupedOptions[category]
      .map(option => createOptionUsage(option, OPTION_USAGE_THRESHOLD))
      .join("\n");
    return `${category} options:\n\n${indent(categoryOptions, 2)}`;
  });

  return [constant.usageSummary].concat(optionsUsage, [""]).join("\n\n");
}

function createOptionUsage(option, threshold) {
  const header = createOptionUsageHeader(option);
  const optionDefaultValue = getOptionDefaultValue(option.name);
  return createOptionUsageRow(
    header,
    `${option.description}${
      optionDefaultValue === undefined
        ? ""
        : `\nDefaults to ${optionDefaultValue}.`
    }`,
    threshold
  );
}

function createOptionUsageHeader(option) {
  const name = `--${option.name}`;
  const alias = option.alias ? `-${option.alias},` : null;
  const type = createOptionUsageType(option);
  return [alias, name, type].filter(Boolean).join(" ");
}

function createOptionUsageRow(header, content, threshold) {
  const separator =
    header.length >= threshold
      ? `\n${" ".repeat(threshold)}`
      : " ".repeat(threshold - header.length);

  const description = content.replace(/\n/g, `\n${" ".repeat(threshold)}`);

  return `${header}${separator}${description}`;
}

function createOptionUsageType(option) {
  switch (option.type) {
    case "boolean":
    case "choice":
      return `<${option.choices
        .filter(choice => !choice.deprecated)
        .map(choice => choice.value)
        .join("|")}>`;
    default:
      return `<${option.type}>`;
  }
}

function flattenArray(array) {
  return [].concat.apply([], array);
}

function getOptionWithLevenSuggestion(options, optionName) {
  // support aliases
  const optionNameContainers = flattenArray(
    options.map((option, index) => [
      { value: option.name, index },
      option.alias ? { value: option.alias, index } : null
    ])
  ).filter(Boolean);

  const optionNameContainer = optionNameContainers.find(
    optionNameContainer => optionNameContainer.value === optionName
  );

  if (optionNameContainer !== undefined) {
    return options[optionNameContainer.index];
  }

  const suggestedOptionNameContainer = optionNameContainers.find(
    optionNameContainer => leven(optionNameContainer.value, optionName) < 3
  );

  if (suggestedOptionNameContainer !== undefined) {
    const suggestedOptionName = suggestedOptionNameContainer.value;
    logger.warn(
      `Unknown option name "${optionName}", did you mean "${
        suggestedOptionName
      }"?`
    );

    return options[suggestedOptionNameContainer.index];
  }

  logger.warn(`Unknown option name "${optionName}"`);
  return options.find(option => option.name === "help");
}

function createChoiceUsages(choices, margin, indentation) {
  const activeChoices = choices.filter(choice => !choice.deprecated);
  const threshold =
    activeChoices
      .map(choice => choice.value.length)
      .reduce((current, length) => Math.max(current, length), 0) + margin;
  return activeChoices.map(choice =>
    indent(
      createOptionUsageRow(choice.value, choice.description, threshold),
      indentation
    )
  );
}

function createDetailedUsage(optionName) {
  const option = getOptionWithLevenSuggestion(
    getOptionsWithOpposites(constant.detailedOptions),
    optionName
  );

  const description = `\n\n${indent(option.description, 2)}`;

  const choices =
    option.type !== "choice"
      ? ""
      : `\n\nValid options:\n\n${createChoiceUsages(
          option.choices,
          CHOICE_USAGE_MARGIN,
          CHOICE_USAGE_INDENTATION
        ).join("\n")}`;

  const defaults =
    optionDefaultValue !== undefined
      ? `\n\nDefault: ${optionDefaultValue}`
      : "";

  return `${header}${description}${choices}${defaults}`;
}

function getOptionDefaultValue(optionName) {
  // --no-option
  if (!(optionName in constant.detailedOptionMap)) {
    return undefined;
  }

  const option = constant.detailedOptionMap[optionName];

  if (option.default !== undefined) {
    return option.default;
  }

  const optionCamelName = camelCase(optionName);
  if (optionCamelName in apiDefaultOptions) {
    return apiDefaultOptions[optionCamelName];
  }

  return undefined;
}

function indent(str, spaces) {
  return str.replace(/^/gm, " ".repeat(spaces));
}

function groupBy(array, getKey) {
  return array.reduce((obj, item) => {
    const key = getKey(item);
    const previousItems = key in obj ? obj[key] : [];
    return Object.assign({}, obj, { [key]: previousItems.concat(item) });
  }, Object.create(null));
}

function normalizeConfig(type, rawConfig, options) {
  if (type === "api" && rawConfig === null) {
    return null;
  }

  options = options || {};

  const consoleWarn =
    options.warning === false ? () => {} : logger.warn.bind(logger);

  const normalized = {};

  Object.keys(rawConfig).forEach(rawKey => {
    const rawValue = rawConfig[rawKey];

    const key = type === "cli" ? rawKey : dashify(rawKey);

    if (type === "cli" && key === "_") {
      normalized[rawKey] = rawValue;
      return;
    }

    if (type === "cli" && key.length === 1) {
      // do nothing with alias
      return;
    }

    const option = constant.detailedOptionMap[key];

    // unknown option
    if (option === undefined) {
      if (type === "api") {
        consoleWarn(`Ignored unknown option: ${rawKey}`);
      } else {
        const optionName = rawValue === false ? `no-${rawKey}` : rawKey;
        consoleWarn(`Ignored unknown option: --${optionName}`);
      }
      return;
    }

    const value = getValue(rawValue, option);

    if (option.exception !== undefined) {
      if (typeof option.exception === "function") {
        if (option.exception(value)) {
          normalized[rawKey] = value;
          return;
        }
      } else {
        if (value === option.exception) {
          return;
        }
      }
    }

    try {
      switch (option.type) {
        case "int":
          validator.validateIntOption(type, value, option);
          normalized[rawKey] = Number(value);
          break;
        case "choice":
          validator.validateChoiceOption(type, value, option);
          break;
        default:
          break;
      }
      logger.error(error.message);
    }
  });

  return normalized;

  function getOptionName(option) {
    return type === "cli" ? `--${option.name}` : camelCase(option.name);
  }

  function getRedirectName(option, choice) {
    return type === "cli"
      ? `--${option.name}=${choice.redirect}`
      : `{ ${camelCase(option.name)}: ${JSON.stringify(choice.redirect)} }`;
  }

  function getValue(rawValue, option) {
    const optionName = getOptionName(option);
    if (rawValue && option.deprecated) {
      let warning = `\`${optionName}\` is deprecated.`;
      if (typeof option.deprecated === "string") {
        warning += ` ${option.deprecated}`;
      }
      consoleWarn(warning);
    }

    const value = option.getter(rawValue, rawConfig);

    if (option.type === "choice") {
      const choice = option.choices.find(choice => choice.value === rawValue);
      if (choice !== undefined && choice.deprecated) {
        const warningDescription =
          rawValue === ""
            ? "without an argument"
            : `with value \`${rawValue}\``;
        const redirectName = getRedirectName(option, choice);
        consoleWarn(
          `\`${optionName}\` ${
            warningDescription
          } is deprecated. Prettier now treats it as: \`${redirectName}\`.`
        );
        return choice.redirect;
      }
    }

    return value;
  }
}

function getOptionName(option) {
  }

function getRedirectName(option, choice) {
  }

function getValue(rawValue, option) {
      }
    }

        );
      }
    }

  }

function cleanAST(ast) {
  return JSON.stringify(massageAST(ast), null, 2);
}

function massageAST(ast, parent) {
  if (Array.isArray(ast)) {
    return ast.map(e => massageAST(e, parent)).filter(e => e);
  }
  if (ast && typeof ast === "object") {
    // We remove extra `;` and add them when needed
    if (ast.type === "EmptyStatement") {
      return undefined;
    }

    // We move text around, including whitespaces and add {" "}
    if (ast.type === "JSXText") {
    }
    if (
      ast.type === "JSXExpressionContainer" &&
      ast.expression.type === "Literal" &&
      ast.expression.value === " "
    ) {
    }

    const newObj = {};
    for (const key in ast) {
      if (typeof ast[key] !== "function") {
        newObj[key] = massageAST(ast[key], ast);
      }
    }

    [
      "loc",
      "range",
      "raw",
      "comments",
      "leadingComments",
      "trailingComments",
      "extra",
      "start",
      "end",
      "tokens",
      "flags",
      "raws",
      "sourceIndex",
      "id",
      "source",
      "before",
      "after",
      "trailingComma",
      "parent",
      "prev",
      "position"
    ].forEach(name => {
      delete newObj[name];
    });

    // for markdown codeblock
    if (ast.type === "code") {
      delete newObj.value;
    }
    // for markdown whitespace: "\n" and " " are considered the same
    if (ast.type === "whitespace" && ast.value === "\n") {
      newObj.value = " ";
    }

    if (
      ast.type === "media-query" ||
      ast.type === "media-query-list" ||
      ast.type === "media-feature-expression"
    ) {
    }

    if (ast.type === "css-rule") {
      delete newObj.params;
    }

    if (ast.type === "selector-combinator") {
      newObj.value = newObj.value.replace(/\s+/g, " ");
    }

    if (ast.type === "media-feature") {
      newObj.value = newObj.value.replace(/ /g, "");
    }

    if (
      (ast.type === "value-word" && ast.isColor && ast.isHex) ||
      ast.type === "media-feature" ||
      ast.type === "selector-root-invalid" ||
      ast.type === "selector-pseudo"
    ) {
      newObj.value = newObj.value.toLowerCase();
    }
    if (ast.type === "css-decl") {
      newObj.prop = newObj.prop.toLowerCase();
    }
    if (ast.type === "css-atrule" || ast.type === "css-import") {
      newObj.name = newObj.name.toLowerCase();
    }
    if (ast.type === "value-number") {
      newObj.unit = newObj.unit.toLowerCase();
    }

    if (
      (ast.type === "media-feature" ||
        ast.type === "media-keyword" ||
        ast.type === "media-type" ||
        ast.type === "media-unknown" ||
        ast.type === "media-url" ||
        ast.type === "media-value" ||
        ast.type === "selector-root-invalid" ||
        ast.type === "selector-attribute" ||
        ast.type === "selector-string" ||
        ast.type === "selector-class" ||
        ast.type === "selector-combinator" ||
        ast.type === "value-string") &&
      newObj.value
    ) {
      newObj.value = cleanCSSStrings(newObj.value);
    }

    if (ast.type === "css-import" && newObj.importPath) {
      newObj.importPath = cleanCSSStrings(newObj.importPath);
    }

    if (ast.type === "selector-attribute" && newObj.value) {
      newObj.value = newObj.value.replace(/^['"]|['"]$/g, "");
      delete newObj.quoted;
    }

    if (
      (ast.type === "media-value" ||
        ast.type === "value-number" ||
        ast.type === "selector-tag") &&
    ) {
      newObj.value = newObj.value.replace(
        /([\d.eE+-]+)([a-zA-Z]*)/g,
        (match, numStr, unit) => {
          const num = Number(numStr);
          return isNaN(num) ? match : num + unit.toLowerCase();
        }
      );
    }

    // (TypeScript) Ignore `static` in `constructor(static p) {}`
    // and `export` in `constructor(export p) {}`
    if (
      ast.type === "TSParameterProperty" &&
      ast.accessibility === null &&
      !ast.readonly
    ) {
      return {
        type: "Identifier",
        name: ast.parameter.name,
        typeAnnotation: newObj.parameter.typeAnnotation,
        decorators: newObj.decorators
      };
    }

    // (TypeScript) ignore empty `specifiers` array
    if (
      ast.type === "TSNamespaceExportDeclaration" &&
      ast.specifiers &&
      ast.specifiers.length === 0
    ) {
      delete newObj.specifiers;
    }

    // (TypeScript) bypass TSParenthesizedType
    if (
      ast.type === "TSParenthesizedType" &&
      ast.typeAnnotation.type === "TypeAnnotation"
    ) {
      return newObj.typeAnnotation.typeAnnotation;
    }

    // We convert <div></div> to <div />
    if (ast.type === "JSXOpeningElement") {
      delete newObj.selfClosing;
    }
    if (ast.type === "JSXElement") {
      delete newObj.closingElement;
    }

    // We change {'key': value} into {key: value}
    if (
      (ast.type === "Property" ||
        ast.type === "MethodDefinition" ||
        ast.type === "ClassProperty" ||
        ast.type === "TSPropertySignature" ||
        ast.type === "ObjectTypeProperty") &&
      typeof ast.key === "object" &&
      ast.key &&
      (ast.key.type === "Literal" || ast.key.type === "Identifier")
    ) {
      delete newObj.key;
    }

    // Remove raw and cooked values from TemplateElement when it's CSS
    // styled-jsx
    if (
      ast.type === "JSXElement" &&
      ast.openingElement.name.name === "style" &&
      ast.openingElement.attributes.some(attr => attr.name.name === "jsx")
    ) {
      const templateLiterals = newObj.children
        .filter(
          child =>
            child.type === "JSXExpressionContainer" &&
            child.expression.type === "TemplateLiteral"
        )
        .map(container => container.expression);

      const quasis = templateLiterals.reduce(
        (quasis, templateLiteral) => quasis.concat(templateLiteral.quasis),
        []
      );

      quasis.forEach(q => delete q.value);
    }

    // styled-components, graphql, markdown
    if (
      ast.type === "TaggedTemplateExpression" &&
      (ast.tag.type === "MemberExpression" ||
        (ast.tag.type === "Identifier" &&
          (ast.tag.name === "gql" ||
            ast.tag.name === "graphql" ||
            ast.tag.name === "css" ||
            ast.tag.name === "md" ||
            ast.tag.name === "markdown")) ||
        ast.tag.type === "CallExpression")
    ) {
      newObj.quasi.quasis.forEach(quasi => delete quasi.value);
    }
    if (
      ast.type === "TemplateLiteral" &&
      parent.type === "CallExpression" &&
      parent.callee.name === "graphql"
    ) {
      newObj.quasis.forEach(quasi => delete quasi.value);
    }

    return newObj;
  }
  return ast;
}

function cleanCSSStrings(value) {
  return value.replace(/'/g, '"').replace(/\\([^a-fA-F\d])/g, "$1");
}

function rootIndent() {
  return {
    indent: 0,
    align: {
      spaces: "",
      tabs: ""
    }
  };
}

function makeIndent(ind) {
  return {
    indent: ind.indent + 1,
    align: ind.align
  };
}

function makeAlign(ind, n) {
  if (n === -Infinity) {
    return {
      indent: 0,
      align: {
        spaces: "",
        tabs: ""
      }
    };
  }

  return {
    indent: ind.indent,
    align: {
      spaces: ind.align.spaces + (typeof n === "number" ? " ".repeat(n) : n),
      tabs: ind.align.tabs + (typeof n === "number" ? (n ? "\t" : "") : n)
    }
  };
}

function fits(next, restCommands, width, mustBeFlat) {
  let restIdx = restCommands.length;
  const cmds = [next];
  while (width >= 0) {
    if (cmds.length === 0) {
      if (restIdx === 0) {
        return true;
      }
      cmds.push(restCommands[restIdx - 1]);

      restIdx--;

      continue;
    }

    const x = cmds.pop();
    const ind = x[0];
    const mode = x[1];
    const doc = x[2];

    if (typeof doc === "string") {
      width -= util.getStringWidth(doc);
    } else {
      switch (doc.type) {
        case "concat":
          for (let i = doc.parts.length - 1; i >= 0; i--) {
            cmds.push([ind, mode, doc.parts[i]]);
          }

          break;
        case "indent":
          cmds.push([makeIndent(ind), mode, doc.contents]);

          break;
        case "align":
          cmds.push([makeAlign(ind, doc.n), mode, doc.contents]);

          break;
        case "group":
          if (mustBeFlat && doc.break) {
            return false;
          }
          cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);

          break;
        case "fill":
          }

          break;
        case "if-break":
          if (mode === MODE_BREAK) {
            if (doc.breakContents) {
              cmds.push([ind, mode, doc.breakContents]);
            }
          }
          if (mode === MODE_FLAT) {
            if (doc.flatContents) {
              cmds.push([ind, mode, doc.flatContents]);
            }
          }

          break;
        case "line":
          switch (mode) {
            // fallthrough
            case MODE_FLAT:
              if (!doc.hard) {
                if (!doc.soft) {
                  width -= 1;
                }

                break;
              }
              return true;

            case MODE_BREAK:
          }
          break;
      }
    }
  }
  return false;
}

function printDocToString(doc, options) {
  const width = options.printWidth;
  const newLine = options.newLine || "\n";
  let pos = 0;
  // cmds is basically a stack. We've turned a recursive call into a
  // while loop which is much faster. The while loop below adds new
  // cmds to the array instead of recursively calling `print`.
  const cmds = [[rootIndent(), MODE_BREAK, doc]];
  const out = [];
  let shouldRemeasure = false;
  let lineSuffix = [];

  while (cmds.length !== 0) {

      out.push(doc);

      pos += util.getStringWidth(doc);
    } else {
        case "cursor":
          out.push(cursor.placeholder);

          break;
          }

          break;

          break;

          break;
              if (!shouldRemeasure) {
                cmds.push([
                  ind,
                  doc.break ? MODE_BREAK : MODE_FLAT,
                  doc.contents
                ]);

                break;
              }

            case MODE_BREAK: {
              shouldRemeasure = false;

              const next = [ind, MODE_FLAT, doc.contents];
              const rem = width - pos;

              if (!doc.break && fits(next, cmds, rem)) {
                cmds.push(next);
              } else {
                // Expanded states are a rare case where a document
                // can manually provide multiple representations of
                // itself. It provides an array of documents
                // going from the least expanded (most flattened)
                // representation first to the most expanded. If a
                // group has these, we need to manually go through
                // these states and find the first one that fits.
                if (doc.expandedStates) {
                  const mostExpanded =
                    doc.expandedStates[doc.expandedStates.length - 1];

                  if (doc.break) {
                    cmds.push([ind, MODE_BREAK, mostExpanded]);

                    break;
                  } else {
                    for (let i = 1; i < doc.expandedStates.length + 1; i++) {
                      if (i >= doc.expandedStates.length) {
                        cmds.push([ind, MODE_BREAK, mostExpanded]);

                        break;
                      } else {
                        const state = doc.expandedStates[i];
                        const cmd = [ind, MODE_FLAT, state];

                        if (fits(cmd, cmds, rem)) {
                          cmds.push(cmd);

                          break;
                        }
                      }
                    }
                  }
                } else {
                  cmds.push([ind, MODE_BREAK, doc.contents]);
                }
              }

              break;
            }
          }
          break;
        // Fills each line with as much code as possible before moving to a new
        // line with the same indentation.
        //
        // Expects doc.parts to be an array of alternating content and
        // whitespace. The whitespace contains the linebreaks.
        //
        // For example:
        //   ["I", line, "love", line, "monkeys"]
        // or
        //   [{ type: group, ... }, softline, { type: group, ... }]
        //
        // It uses this parts structure to handle three main layout cases:
        // * The first two content items fit on the same line without
        //   breaking
        //   -> output the first content item and the whitespace "flat".
        // * Only the first content item fits on the line without breaking
        //   -> output the first content item "flat" and the whitespace with
        //   "break".
        // * Neither content item fits on the line without breaking
        //   -> output the first content item and the whitespace with "break".
        case "fill": {
          const rem = width - pos;

          const parts = doc.parts;
          if (parts.length === 0) {
            break;
          }

          const content = parts[0];
          const contentFlatCmd = [ind, MODE_FLAT, content];
          const contentBreakCmd = [ind, MODE_BREAK, content];
          const contentFits = fits(contentFlatCmd, [], rem, true);

          if (parts.length === 1) {
            if (contentFits) {
              cmds.push(contentFlatCmd);
            } else {
              cmds.push(contentBreakCmd);
            }
            break;
          }

          const whitespace = parts[1];
          const whitespaceFlatCmd = [ind, MODE_FLAT, whitespace];
          const whitespaceBreakCmd = [ind, MODE_BREAK, whitespace];

          if (parts.length === 2) {
              cmds.push(whitespaceFlatCmd);
            } else {
              cmds.push(whitespaceBreakCmd);
            }
            break;
          }

          // At this point we've handled the first pair (context, separator)
          // and will create a new fill doc for the rest of the content.
          // Ideally we wouldn't mutate the array here but coping all the
          // elements to a new array would make this algorithm quadratic,
          // which is unusable for large arrays (e.g. large texts in JSX).
          parts.splice(0, 2);
          const remainingCmd = [ind, mode, fill(parts)];

          const secondContent = parts[0];

          const firstAndSecondContentFlatCmd = [
            ind,
            MODE_FLAT,
            concat([content, whitespace, secondContent])
          ];
          const firstAndSecondContentFits = fits(
            firstAndSecondContentFlatCmd,
            [],
            rem,
            true
          );

          if (firstAndSecondContentFits) {
            cmds.push(remainingCmd);
            cmds.push(whitespaceFlatCmd);
            cmds.push(contentFlatCmd);
          } else if (contentFits) {
            cmds.push(whitespaceBreakCmd);
          } else {
            cmds.push(contentBreakCmd);
          }
          break;
        }
            }
          }
            }
          }

          break;
        case "line-suffix":
          lineSuffix.push([ind, mode, doc.contents]);
          break;
        case "line-suffix-boundary":
          if (lineSuffix.length > 0) {
            cmds.push([ind, mode, { type: "line", hard: true }]);
          }
          break;
                  out.push(" ");

                  pos += 1;
                }

                break;
              } else {
                // This line was forced into the output even if we
                // were in flattened mode, so we need to tell the next
                // group that no matter what, it needs to remeasure
                // because the previous measurement didn't accurately
                // capture the entire expression (this is necessary
                // for nested groups)
                shouldRemeasure = true;
              }

              if (lineSuffix.length) {
                cmds.push([ind, mode, doc]);
                [].push.apply(cmds, lineSuffix.reverse());
                lineSuffix = [];
                break;
              }

              if (doc.literal) {
                out.push(newLine);
                pos = 0;
              } else {
                if (out.length > 0) {
                  // Trim whitespace at the end of line
                  while (
                    out.length > 0 &&
                    out[out.length - 1].match(/^[^\S\n]*$/)
                  ) {
                    out.pop();
                  }

                  if (out.length) {
                    out[out.length - 1] = out[out.length - 1].replace(
                      /[^\S\n]*$/,
                      ""
                    );
                  }
                }

                const indentLength = ind.indent * options.tabWidth;
                const indentString = options.useTabs
                  ? "\t".repeat(ind.indent) + ind.align.tabs
                  : " ".repeat(indentLength) + ind.align.spaces;
                out.push(newLine + indentString);
                pos = indentLength + ind.align.spaces.length;
              }
              break;
          }
          break;
        default:
      }
    }
  }

  const cursorPlaceholderIndex = out.indexOf(cursor.placeholder);
  if (cursorPlaceholderIndex !== -1) {
    const beforeCursor = out.slice(0, cursorPlaceholderIndex).join("");
    const afterCursor = out.slice(cursorPlaceholderIndex + 1).join("");

    return {
      formatted: beforeCursor + afterCursor,
      cursor: beforeCursor.length
    };
  }

  return { formatted: out.join("") };
}

function parse(text, parsers, opts) {
  // Inline the require to avoid loading all the JS if we don't use it
  const babylon = require("babylon");

  const babylonOptions = {
    sourceType: "module",
    allowImportExportEverywhere: true,
    allowReturnOutsideFunction: true,
    plugins: [
      "jsx",
      "flow",
      "doExpressions",
      "objectRestSpread",
      "decorators",
      "classProperties",
      "exportDefaultFrom",
      "exportNamespaceFrom",
      "asyncGenerators",
      "functionBind",
      "functionSent",
      "dynamicImport",
      "numericSeparator",
      "importMeta",
      "optionalCatchBinding",
      "optionalChaining",
      "classPrivateProperties",
      "pipelineOperator",
      "nullishCoalescingOperator"
    ]
  };

  const parseMethod =
    opts && opts.parser === "json" ? "parseExpression" : "parse";

  let ast;
  try {
    ast = babylon[parseMethod](text, babylonOptions);
  } catch (originalError) {
    try {
      ast = babylon[parseMethod](
        text,
        Object.assign({}, babylonOptions, { strictMode: false })
      );
    } catch (nonStrictError) {
      throw createError(
        // babel error prints (l:c) with cols that are zero indexed
        // so we need our custom error
        originalError.message.replace(/ \(.*\)/, ""),
        {
          start: {
            line: originalError.loc.line,
            column: originalError.loc.column + 1
          }
        }
      );
    }
  }
  delete ast.tokens;
}

get graphql() {
    return eval("require")("./parser-graphql");
  }

get parse5() {
    return eval("require")("./parser-parse5");
  }

get babylon() {
    return eval("require")("./parser-babylon");
  }

get typescript() {
    return eval("require")("./parser-typescript");
  }

get less() {
    return eval("require")("./parser-postcss");
  }

get scss() {
  }

get json() {
  }

get markdown() {
    return eval("require")("./parser-markdown");
  }

function resolveParseFunction(opts) {
  if (typeof opts.parser === "function") {
    return opts.parser;
  }
  if (typeof opts.parser === "string") {
    if (parsers.hasOwnProperty(opts.parser)) {
      return parsers[opts.parser];
    }
    try {
      return eval("require")(path.resolve(process.cwd(), opts.parser));
    } catch (err) {
      /* istanbul ignore next */
      throw new ConfigError(`Couldn't resolve parser "${opts.parser}"`);
    }
  }
  /* istanbul ignore next */
  return parsers.babylon;
}

function parse(text, opts) {
  const parseFunction = resolveParseFunction(opts);

  try {
    return parseFunction(text, parsers, opts);
    const loc = error.loc;

    if (loc) {
      const codeFrame = require("babel-code-frame");
      error.codeFrame = codeFrame.codeFrameColumns(text, loc, {
        highlightCode: true
      });
      error.message += "\n" + error.codeFrame;
      throw error;
    }

    /* istanbul ignore next */
    throw error.stack;
  }
}

function FastPath(value) {
  assert.ok(this instanceof FastPath);
  this.stack = [value];
}

function getNodeHelper(path, count) {
  var s = path.stack;

  for (var i = s.length - 1; i >= 0; i -= 2) {
    var value = s[i];
    if (n.Node.check(value) && --count < 0) {
      return value;
    }
  }

  return null;
}

function isBinary(node) {
  return n.BinaryExpression.check(node)
    || n.LogicalExpression.check(node);
}

function isUnaryLike(node) {
  return n.UnaryExpression.check(node)
  // I considered making SpreadElement and SpreadProperty subtypes
  // of UnaryExpression, but they're not really Expression nodes.
    || (n.SpreadElement && n.SpreadElement.check(node))
    || (n.SpreadProperty && n.SpreadProperty.check(node));
}

function containsCallExpression(node) {
  if (n.CallExpression.check(node)) {
  }

  if (isArray.check(node)) {
    return node.some(containsCallExpression);
  }

  if (n.Node.check(node)) {
    return types.someField(node, function(name, child) {
      return containsCallExpression(child);
    });
  }

}

function genericPrint(path, options, print) {
  const n = path.getValue();
  if (!n) {
    return "";
  }

  if (typeof n === "string") {
    return n;
  }

  switch (n.kind) {
    case "Document": {
      return concat([
        join(concat([hardline, hardline]), path.map(print, "definitions")),
        hardline
      ]);
    }
    case "OperationDefinition": {
        n.name === null ? "" : n.operation,
        n.name ? concat([" ", path.call(print, "name")]) : "",
        n.variableDefinitions && n.variableDefinitions.length
          ? group(
              concat([
                "(",
                indent(
                  concat([
                    softline,
                    join(
                      concat([ifBreak("", ", "), softline]),
                      path.map(print, "variableDefinitions")
                    )
                  ])
                ),
                softline,
                ")"
              ])
            )
          : "",
        printDirectives(path, print, n),
        n.selectionSet ? (n.name === null ? "" : " ") : "",
        path.call(print, "selectionSet")
      ]);
    }
    case "FragmentDefinition": {
        "fragment ",
        path.call(print, "name"),
        " on ",
        path.call(print, "typeCondition"),
        " ",
      ]);
    }
    case "SelectionSet": {
        "{",
        indent(
          concat([
            hardline,
            join(
              hardline,
              path.call(
                selectionsPath => printSequence(selectionsPath, options, print),
                "selections"
              )
            )
          ])
        ),
        hardline,
        "}"
      ]);
    }
    case "Field": {
      return group(
        concat([
          n.alias ? concat([path.call(print, "alias"), ": "]) : "",
          path.call(print, "name"),
          n.arguments.length > 0
            ? group(
                concat([
                  "(",
                  indent(
                    concat([
                      softline,
                      join(
                        concat([ifBreak("", ", "), softline]),
                        path.call(
                          argsPath => printSequence(argsPath, options, print),
                          "arguments"
                        )
                      )
                    ])
                  ),
                  softline,
                  ")"
                ])
              )
            : "",
          printDirectives(path, print, n),
          n.selectionSet ? " " : "",
          path.call(print, "selectionSet")
        ])
      );
    }
    case "Name": {
      return n.value;
    }
    case "StringValue": {
      return concat(['"', n.value.replace(/["\\]/g, "\\$&"), '"']);
    }
    case "IntValue":
    case "FloatValue":
    case "EnumValue": {
    }
    case "BooleanValue": {
      return n.value ? "true" : "false";
    }
    case "NullValue": {
      return "null";
    }
    case "Variable": {
      return concat(["$", path.call(print, "name")]);
    }
    case "ListValue": {
        concat([
          "[",
          indent(
            concat([
              softline,
              join(
                concat([ifBreak("", ", "), softline]),
                path.map(print, "values")
              )
            ])
          ),
          softline,
          "]"
        ])
      );
    }
    case "ObjectValue": {
        concat([
          "{",
          options.bracketSpacing && n.fields.length > 0 ? " " : "",
          indent(
            concat([
              softline,
              join(
                path.map(print, "fields")
              )
            ])
          ),
          softline,
          ifBreak("", options.bracketSpacing && n.fields.length > 0 ? " " : ""),
          "}"
        ])
      );
    }
    case "ObjectField":
    case "Argument": {
        ": ",
        path.call(print, "value")
      ]);
    }

    case "Directive": {
        "@",
        n.arguments.length > 0
          ? group(
              concat([
                "(",
                indent(
                  concat([
                    softline,
                    join(
                      path.call(
                        argsPath => printSequence(argsPath, options, print),
                        "arguments"
                      )
                    )
                  ])
                ),
                softline,
                ")"
              ])
            )
          : ""
      ]);
    }

    case "NamedType": {
      return path.call(print, "name");
    }

    case "VariableDefinition": {
        path.call(print, "variable"),
        ": ",
        path.call(print, "type"),
        n.defaultValue ? concat([" = ", path.call(print, "defaultValue")]) : ""
      ]);
    }

    case "TypeExtensionDefinition": {
      return concat(["extend ", path.call(print, "definition")]);
    }

    case "ObjectTypeDefinition": {
        "type ",
        n.interfaces.length > 0
          ? concat([" implements ", join(", ", path.map(print, "interfaces"))])
          : "",
        " {",
        n.fields.length > 0
          ? indent(
              concat([
                hardline,
                join(
                  hardline,
                  path.call(
                    fieldsPath => printSequence(fieldsPath, options, print),
                    "fields"
                  )
                )
              ])
            )
          : "",
        hardline,
        "}"
      ]);
    }

    case "FieldDefinition": {
          ? group(
              concat([
                "(",
                indent(
                  concat([
                    softline,
                    join(
                      )
                    )
                  ])
                ),
                softline,
                ")"
              ])
            )
          : "",
        ": ",
        printDirectives(path, print, n)
      ]);
    }

    case "DirectiveDefinition": {
        "directive ",
        "@",
          ? group(
              concat([
                "(",
                indent(
                  concat([
                    softline,
                    join(
                      )
                    )
                  ])
                ),
                softline,
                ")"
              ])
            )
          : "",
        concat([" on ", join(" | ", path.map(print, "locations"))])
      ]);
    }

    case "EnumTypeDefinition": {
        "enum ",
        " {",
        n.values.length > 0
          ? indent(
              concat([
                hardline,
                join(
                  hardline,
                    valuesPath => printSequence(valuesPath, options, print),
                    "values"
                  )
                )
              ])
            )
          : "",
        hardline,
        "}"
      ]);
    }

    case "EnumValueDefinition": {
      ]);
    }

    case "InputValueDefinition": {
        ": ",
        n.defaultValue ? concat([" = ", path.call(print, "defaultValue")]) : "",
      ]);
    }

    case "InputObjectTypeDefinition": {
        "input ",
        " {",
          ? indent(
              concat([
                hardline,
                join(
                  hardline,
                    "fields"
                  )
                )
              ])
            )
          : "",
        hardline,
        "}"
      ]);
    }

    case "SchemaDefinition": {
        "schema",
        " {",
        n.operationTypes.length > 0
          ? indent(
              concat([
                hardline,
                join(
                  hardline,
                    opsPath => printSequence(opsPath, options, print),
                    "operationTypes"
                  )
                )
              ])
            )
          : "",
        hardline,
        "}"
      ]);
    }

    case "OperationTypeDefinition": {
        path.call(print, "operation"),
        ": ",
        path.call(print, "type")
      ]);
    }

    case "InterfaceTypeDefinition": {
        "interface ",
        " {",
          ? indent(
              concat([
                hardline,
                join(
                  hardline,
                    "fields"
                  )
                )
              ])
            )
          : "",
        hardline,
        "}"
      ]);
    }

    case "FragmentSpread": {
        "...",
      ]);
    }

    case "InlineFragment": {
        "...",
        n.typeCondition
          ? concat([" on ", path.call(print, "typeCondition")])
          : "",
        " ",
      ]);
    }

    case "UnionTypeDefinition": {
        concat([
          "union ",
          " =",
          ifBreak("", " "),
          indent(
            concat([
              ifBreak(concat([line, "  "])),
              join(concat([line, "| "]), path.map(print, "types"))
            ])
          )
        ])
      );
    }

    case "ScalarTypeDefinition": {
        "scalar ",
      ]);
    }

    case "NonNullType": {
      return concat([path.call(print, "type"), "!"]);
    }

    case "ListType": {
      return concat(["[", path.call(print, "type"), "]"]);
    }

    default:
      throw new Error("unknown graphql type: " + JSON.stringify(n.kind));
  }
}

function printDirectives(path, print, n) {
  if (n.directives.length === 0) {
    return "";
  }

  return concat([
    " ",
    group(
      indent(
        concat([
          softline,
          join(
            concat([ifBreak("", " "), softline]),
            path.map(print, "directives")
          )
        ])
      )
    )
  ]);
}

function printSequence(sequencePath, options, print) {
  const count = sequencePath.getValue().length;

  return sequencePath.map((path, i) => {
    const printed = print(path);

    if (
      util.isNextLineEmpty(options.originalText, path.getValue()) &&
      i < count - 1
    ) {
      return concat([printed, hardline]);
    }

    return printed;
  });
}

function parse(text /*, parsers, opts*/) {
  const parse5 = require("parse5");
  try {
    const isFragment = !/^\s*<(!doctype|html|head|body)/i.test(text);
    const ast = (isFragment ? parse5.parseFragment : parse5.parse)(text, {
      treeAdapter: parse5.treeAdapters.htmlparser2,
      locationInfo: true
    });
    return extendAst(ast);
    //   throw createError(error.message, {
    //     start: {
    //       line: error.locations[0].line,
    //       column: error.locations[0].column
    //     }
    // } else {
    throw error;
    // }
  }
}

function extendAst(ast) {
  if (!ast || !ast.children) {
    return ast;
  }
  for (const child of ast.children) {
    extendAst(child);
    if (child.attribs) {
      child.attributes = convertAttribs(child.attribs);
    }
  }
}

function convertAttribs(attribs) {
  return Object.keys(attribs).map(attributeKey => {
    return {
      type: "attribute",
      key: attributeKey,
      value: attribs[attributeKey]
    };
  });
}

function getSortedChildNodes(node, text, resultArray) {
  if (!node) {
    return;
  }

  // The loc checks below are sensitive to some of the problems that
  // are fixed by this utility function.
  util.fixFaultyLocations(node, text);

  if (resultArray) {
    if (n.Node.check(node)) {
      // This reverse insertion sort almost always takes constant
      // time because we almost always (maybe always?) append the
      // nodes in order anyway.
      for (var i = resultArray.length - 1; i >= 0; --i) {
        if (locEnd(resultArray[i]) - locStart(node) <= 0) {
          break;
        }
      }
      resultArray.splice(i + 1, 0, node);
      return;
    }
  } else if (node[childNodesCacheKey]) {
    return node[childNodesCacheKey];
  }

  var names;
    names = Object.keys(node);
  } else if (isObject.check(node)) {
    names = types.getFieldNames(node);
  } else {
    return;
  }

  if (!resultArray) {
    Object.defineProperty(node, childNodesCacheKey, {
      value: resultArray = [],
      enumerable: false
    });
  }

  for (var i = 0, nameCount = names.length; i < nameCount; ++i) {
    getSortedChildNodes(node[names[i]], text, resultArray);
  }

  return resultArray;
}

function decorateComment(node, comment, text) {
  var childNodes = getSortedChildNodes(node, text);

  // Time to dust off the old binary search robes and wizard hat.
  var left = 0, right = childNodes.length;
  while (left < right) {
    var middle = (left + right) >> 1;
    var child = childNodes[middle];

    if (locStart(child) - locStart(comment) <= 0 &&
        locEnd(comment) - locEnd(child) <= 0) {
      // The comment is completely contained by this child node.
      comment.enclosingNode = child;
      decorateComment(child, comment, text);
      return; // Abandon the binary search at this level.
    }

    if (locEnd(child) - locStart(comment) <= 0) {
      // This child node falls completely before the comment.
      // Because we will never consider this node or any nodes
      // before it again, this node must be the closest preceding
      // node we have encountered so far.
      var precedingNode = child;
      left = middle + 1;
      continue;
    }

    if (locEnd(comment) - locStart(child) <= 0) {
      // This child node falls completely after the comment.
      // Because we will never consider this node or any nodes after
      // it again, this node must be the closest following node we
      // have encountered so far.
      var followingNode = child;
      right = middle;
      continue;
    }

    throw new Error("Comment location overlaps with node location");
  }

  if (precedingNode) {
    comment.precedingNode = precedingNode;
  }

  if (followingNode) {
    comment.followingNode = followingNode;
  }
}

function breakTies(tiesToBreak, text) {
  var tieCount = tiesToBreak.length;
  if (tieCount === 0) {
    return;
  }

  var pn = tiesToBreak[0].precedingNode;
  var fn = tiesToBreak[0].followingNode;
  var gapEndPos = locStart(fn);

  // Iterate backwards through tiesToBreak, examining the gaps
  // between the tied comments. In order to qualify as leading, a
  // comment must be separated from fn by an unbroken series of
  // whitespace-only gaps (or other comments).
  for (var indexOfFirstLeadingComment = tieCount;
       indexOfFirstLeadingComment > 0;
       --indexOfFirstLeadingComment) {
    var comment = tiesToBreak[indexOfFirstLeadingComment - 1];
    assert.strictEqual(comment.precedingNode, pn);
    assert.strictEqual(comment.followingNode, fn);

    var gap = text.slice(locEnd(comment), gapEndPos);
    if (/\S/.test(gap)) {
      // The gap string contained something other than whitespace.
      break;
    }

    gapEndPos = locStart(comment);
  }

  // while (indexOfFirstLeadingComment <= tieCount &&
  //        (comment = tiesToBreak[indexOfFirstLeadingComment]) &&
  //        // If the comment is a //-style comment and indented more
  //        // deeply than the node itself, reconsider it as trailing.
  //        (comment.type === "Line" || comment.type === "CommentLine") &&
  //        comment.loc.start.column > fn.loc.start.column) {
  //   ++indexOfFirstLeadingComment;
  // }

  tiesToBreak.forEach(function(comment, i) {
    if (i < indexOfFirstLeadingComment) {
      addTrailingComment(pn, comment);
    } else {
      addLeadingComment(fn, comment);
    }
  });

  tiesToBreak.length = 0;
}

function addCommentHelper(node, comment) {
  var comments = node.comments || (node.comments = []);
  comments.push(comment);
}

function addLeadingComment(node, comment) {
  comment.leading = true;
  comment.trailing = false;
  addCommentHelper(node, comment);
}

function addDanglingComment(node, comment) {
  comment.leading = false;
}

function addTrailingComment(node, comment) {
  comment.trailing = true;
}

function printLeadingComment(commentPath, print) {
  var comment = commentPath.getValue();
  n.Comment.assert(comment);
  return concat([print(commentPath), hardline]);
}

function printTrailingComment(commentPath, print, options) {
  const comment = commentPath.getValue(commentPath);
  const text = options.originalText;

    util.newlineExistsBefore(text, locStart(comment)) ? hardline : " ",
    print(commentPath)
  ]);
}

function dedent(str) {
  const spaces = str.match(/\n^( +)/m)[1].length;
  return str.replace(new RegExp(`^ {${spaces}}`, "gm"), "").trim();
}

function normalizeDetailedOptions(rawDetailedOptions) {
  const names = Object.keys(rawDetailedOptions).sort();

  const normalized = names.map(name => {
    const option = rawDetailedOptions[name];
    return Object.assign({}, option, {
      name,
      category: option.category || CATEGORY_OTHER,
      forwardToApi:
        option.forwardToApi &&
        (typeof option.forwardToApi === "string"
          ? option.forwardToApi
          : camelCase(name)),
      choices:
        option.choices &&
        option.choices.map(choice =>
          Object.assign(
            { description: "", deprecated: false },
            typeof choice === "object" ? choice : { value: choice }
          )
        ),
      getter: option.getter || (value => value)
    });
  });

}

function _withPlugins(
  fn,
  optsArgIdx = 1 // Usually `opts` is the 2nd argument
) {
  return (...args) => {
    const opts = args[optsArgIdx] || {};
    args[optsArgIdx] = {
      ...opts,
      plugins: plugins.loadPlugins(opts.plugins, opts.pluginSearchDirs),
    };
    return fn(...args);
  };
}

function withPlugins(fn, optsArgIdx) {
  const resultingFn = _withPlugins(fn, optsArgIdx);
  if (fn.sync) {
    // @ts-ignore
    resultingFn.sync = _withPlugins(fn.sync, optsArgIdx);
  }
  return resultingFn;
}

format(text, opts) {
    return formatWithCursor(text, opts).formatted;
  }

check(text, opts) {
    const { formatted } = formatWithCursor(text, opts);
    return formatted === text;
  }

clearConfigCache() {
    config.clearCache();
    plugins.clearCache();
  }

function parseSelector(selector) {
  const selectorParser = require("postcss-selector-parser");
  let result;
  selectorParser(result_ => {
    result = result_;
  }).process(selector);
  return addTypePrefix(result, "selector-");
}

function parseValueNodes(nodes) {
  let parenGroup = {
    open: null,
    close: null,
    groups: [],
    type: "paren_group"
  };
  const parenGroupStack = [parenGroup];
  const rootParenGroup = parenGroup;
  let commaGroup = {
    type: "comma_group"
  };
  const commaGroupStack = [commaGroup];

  for (let i = 0; i < nodes.length; ++i) {
    const node = nodes[i];
    if (node.type === "paren" && node.value === "(") {
      parenGroup = {
        open: node,
        close: null,
        groups: [],
        type: "paren_group"
      };
      parenGroupStack.push(parenGroup);

      commaGroup = {
        type: "comma_group"
      };
      commaGroupStack.push(commaGroup);
    } else if (node.type === "paren" && node.value === ")") {
      if (commaGroup.groups.length) {
        parenGroup.groups.push(commaGroup);
      }
      parenGroup.close = node;

      if (commaGroupStack.length === 1) {
        throw new Error("Unbalanced parenthesis");
      }

      commaGroupStack.pop();
      commaGroup = commaGroupStack[commaGroupStack.length - 1];
      commaGroup.groups.push(parenGroup);

      parenGroupStack.pop();
      parenGroup = parenGroupStack[parenGroupStack.length - 1];
    } else if (node.type === "comma") {
      parenGroup.groups.push(commaGroup);
      };
      commaGroupStack[commaGroupStack.length - 1] = commaGroup;
    } else {
      commaGroup.groups.push(node);
    }
  }
  if (commaGroup.groups.length > 0) {
    parenGroup.groups.push(commaGroup);
  }
  return rootParenGroup;
}

function flattenGroups(node) {
  if (
    node.type === "paren_group" &&
    !node.open &&
    !node.close &&
    node.groups.length === 1
  ) {
    return flattenGroups(node.groups[0]);
  }

  if (node.type === "comma_group" && node.groups.length === 1) {
  }

  if (node.type === "paren_group" || node.type === "comma_group") {
    return Object.assign({}, node, { groups: node.groups.map(flattenGroups) });
  }

  return node;
}

function addTypePrefix(node, prefix) {
  if (node && typeof node === "object") {
    delete node.parent;
    for (const key in node) {
      addTypePrefix(node[key], prefix);
      if (key === "type" && typeof node[key] === "string") {
        if (!node[key].startsWith(prefix)) {
          node[key] = prefix + node[key];
        }
      }
    }
  }
}

function addMissingType(node) {
      addMissingType(node[key]);
    }
    if (!Array.isArray(node) && node.value && !node.type) {
      node.type = "unknown";
    }
  }
}

function parseNestedValue(node) {
      parseNestedValue(node[key]);
      if (key === "nodes") {
        node.group = flattenGroups(parseValueNodes(node[key]));
        delete node[key];
      }
    }
  }
}

function parseValue(value) {
  const valueParser = require("postcss-values-parser");
  const result = valueParser(value, { loose: true }).parse();
  const parsedResult = parseNestedValue(result);
  return addTypePrefix(parsedResult, "value-");
}

function parseMediaQuery(value) {
  const mediaParser = require("postcss-media-query-parser").default;
  const result = addMissingType(mediaParser(value));
  return addTypePrefix(result, "media-");
}

function parseNestedCSS(node) {
      parseNestedCSS(node[key]);
    }
    if (typeof node.selector === "string") {
      const selector = node.raws.selector
        ? node.raws.selector.raw
        : node.selector;

      try {
        node.selector = parseSelector(selector);
        // Fail silently. It's better to print it as is than to try and parse it
        // Note: A common failure is for SCSS nested properties. `background:
        // none { color: red; }` is parsed as a NestedDeclaration by
        // postcss-scss, while `background: { color: red; }` is parsed as a Rule
        // with a selector ending with a colon. See:
        // https://github.com/postcss/postcss-scss/issues/39
        node.selector = {
          type: "selector-root-invalid",
          value: selector
        };
      }
    }
    if (node.type && typeof node.value === "string") {
      try {
        node.value = parseValue(node.value);
        throw createError(
          "(postcss-values-parser) " + e.toString(),
          node.source
        );
      }
    }
    if (node.type === "css-atrule" && typeof node.params === "string") {
      node.params = parseMediaQuery(node.params);
    }
  }
}

function parseWithParser(parser, text) {
  try {
    result = parser.parse(text);
    if (typeof e.line !== "number") {
      throw e;
    }
    throw createError("(postcss) " + e.name + " " + e.reason, { start: e });
  }
  const prefixedResult = addTypePrefix(result, "css-");
  const parsedResult = parseNestedCSS(prefixedResult);
  return parsedResult;
}

function requireParser(isSCSS) {
  if (isSCSS) {
    return require("postcss-scss");
  }

  // TODO: Remove this hack when this issue is fixed:
  // https://github.com/shellscape/postcss-less/issues/88
  const LessParser = require("postcss-less/dist/less-parser");
  LessParser.prototype.atrule = function() {
    return Object.getPrototypeOf(LessParser.prototype).atrule.apply(
      this,
      arguments
    );
  };

  return require("postcss-less");
}

function() {
      this,
      arguments
    );
  }

  const hasExplicitParserChoice =
    opts.parser === "less" || opts.parser === "scss";

  const isSCSS = hasExplicitParserChoice
    ? opts.parser === "scss"
    : IS_POSSIBLY_SCSS.test(text);

  try {
    return parseWithParser(requireParser(isSCSS), text);
    if (hasExplicitParserChoice) {
      throw originalError;
    }

    try {
      return parseWithParser(requireParser(!isSCSS), text);
    } catch (_secondError) {
    }
  }
}

config =>
    `  The ${'"useFlowParser"'} option is deprecated. Use ${'"parser"'} instead.

  Prettier now treats your configuration as:
  {
    ${'"parser"'}: ${config.useFlowParser ? '"flow"' : '"babylon"'}
  }`

function getUnionOfKeys() {
  var result = {};
  var argc = arguments.length;
  for (var i = 0; i < argc; ++i) {
    var keys = Object.keys(arguments[i]);
    var keyCount = keys.length;
    for (var j = 0; j < keyCount; ++j) {
      result[keys[j]] = true;
    }
  }
}

function comparePos(pos1, pos2) {
  return (pos1.line - pos2.line) || (pos1.column - pos2.column);
}

function copyPos(pos) {
  return {
    line: pos.line,
    column: pos.column
  };
}

function expandLoc(parentNode, childNode) {
  if (locStart(childNode) - locStart(parentNode) < 0) {
    setLocStart(parentNode, locStart(childNode));
  }

  if (locEnd(parentNode) - locEnd(childNode) < 0) {
    setLocEnd(parentNode, locEnd(childNode));
  }
}

function fixTemplateLiteral(node, text) {
  assert.strictEqual(node.type, "TemplateLiteral");

  if (node.quasis.length === 0) {
    // If there are no quasi elements, then there is nothing to fix.
    return;
  }

  // First we need to exclude the opening ` from the loc of the first
  // quasi element, in case the parser accidentally decided to include it.
  var afterLeftBackTickPos = locStart(node);
  assert.strictEqual(text.charAt(afterLeftBackTickPos), "`");
  assert.ok(afterLeftBackTickPos < text.length);
  var firstQuasi = node.quasis[0];
  if (locStart(firstQuasi) - afterLeftBackTickPos < 0) {
    setLocStart(firstQuasi, afterLeftBackTickPos);
  }

  // Next we need to exclude the closing ` from the loc of the last quasi
  // element, in case the parser accidentally decided to include it.
  var rightBackTickPos = locEnd(node);
  assert.ok(rightBackTickPos >= 0);
  assert.strictEqual(text.charAt(rightBackTickPos), "`");
  var lastQuasi = node.quasis[node.quasis.length - 1];
  if (rightBackTickPos - locEnd(lastQuasi) < 0) {
    setLocEnd(locEnd(lastQuasi), rightBackTickPos);
  }

  // Now we need to exclude ${ and } characters from the loc's of all
  // quasi elements, since some parsers accidentally include them.
  node.expressions.forEach(function (expr, i) {
    // Rewind from the start loc over any whitespace and the ${ that
    // precedes the expression. The position of the $ should be the
    // same as the end of the preceding quasi element, but some
    // parsers accidentally include the ${ in the loc of the quasi
    // element.
    var dollarCurlyPos = skipSpaces(text, locStart(expr) - 1, true);
    if (dollarCurlyPos - 1 >= 0 &&
        text.charAt(dollarCurlyPos - 1) === "{" &&
        dollarCurlyPos - 2 >= 0 &&
        text.charAt(dollarCurlyPos - 2) === "$") {
      var quasiBefore = node.quasis[i];
      if (dollarCurlyPos - locEnd(quasiBefore) < 0) {
        setLocEnd(quasiBefore, dollarCurlyPos);
      }
    }

    // Likewise, some parsers accidentally include the } that follows
    // the expression in the loc of the following quasi element.
    var rightCurlyPos = skipSpaces(text, locEnd(expr));
    if (text.charAt(rightCurlyPos) === "}") {
      assert.ok(rightCurlyPos + 1 < text.length);
      // Now rightCurlyPos is technically the position just after the }.
      var quasiAfter = node.quasis[i + 1];
      if (locStart(quasiAfter) - rightCurlyPos < 0) {
        setLocStart(locStart(quasiAfter), rightCurlyPos);
      }
    }
  });
}

function _findNewline(text, index, backwards) {
  const length = text.length;
  let cursor = backwards ? (index - 1) : (index + 1);
  // Look forward and see if there is a newline after/before this code
  // by scanning up/back to the next non-indentation character.
  while (cursor > 0 && cursor < length) {
    const c = text.charAt(cursor);
    // Skip any indentation characters
    if (c !== " " && c !== "\t") {
      // Check if the next non-indentation character is a newline or
      // not.
      return c === "\n" || c === "\r";
    }
    backwards ? cursor-- : cursor++;
  }
}

function skipSpaces(text, index, backwards) {
    // Skip any whitespace chars
    if (!c.match(/\S/)) {
      return cursor;
    }
  }
}

function locStart(node) {
  if(node.range) {
    return node.range[0];
  }
  return node.start;
}

function locEnd(node) {
    return node.range[1];
  }
  return node.end;
}

function setLocStart(node, index) {
    node.range[0] = index;
  }
  else {
    node.start = index;
  }
}

function setLocEnd(node, index) {
    node.range[1] = index;
  }
  else {
    node.end = index;
  }
}

function flattenDoc(doc) {
  if (doc.type === "concat") {
    const res = [];

    for (let i = 0; i < doc.parts.length; ++i) {
      const doc2 = doc.parts[i];
      if (typeof doc2 !== "string" && doc2.type === "concat") {
        [].push.apply(res, flattenDoc(doc2).parts);
      } else {
        const flattened = flattenDoc(doc2);
        if (flattened !== "") {
          res.push(flattened);
        }
      }
    }

    return Object.assign({}, doc, { parts: res });
  } else if (doc.type === "if-break") {
    return Object.assign({}, doc, {
      breakContents:
        doc.breakContents != null ? flattenDoc(doc.breakContents) : null,
      flatContents:
        doc.flatContents != null ? flattenDoc(doc.flatContents) : null
    });
  } else if (doc.type === "group") {
      contents: flattenDoc(doc.contents),
      expandedStates: doc.expandedStates
        ? doc.expandedStates.map(flattenDoc)
        : doc.expandedStates
    });
  } else if (doc.contents) {
    return Object.assign({}, doc, { contents: flattenDoc(doc.contents) });
  }
  return doc;
}

function printDoc(doc) {
  if (typeof doc === "string") {
    return JSON.stringify(doc);
  }

  if (doc.type === "line") {
    if (doc.literalline) {
      return "literalline";
    }
    if (doc.hard) {
      return "hardline";
    }
    if (doc.soft) {
      return "softline";
    }
    return "line";
  }

  if (doc.type === "break-parent") {
    return "breakParent";
  }

    return "[" + doc.parts.map(printDoc).join(", ") + "]";
  }

  if (doc.type === "indent") {
    return "indent(" + printDoc(doc.contents) + ")";
  }

  if (doc.type === "align") {
    return "align(" + doc.n + ", " + printDoc(doc.contents) + ")";
  }

  if (doc.type === "if-break") {
    return (
      "ifBreak(" +
      printDoc(doc.breakContents) +
      (doc.flatContents ? ", " + printDoc(doc.flatContents) : "") +
      ")"
    );
  }

  if (doc.type === "group") {
    if (doc.expandedStates) {
      return (
        "conditionalGroup(" +
        "[" +
        doc.expandedStates.map(printDoc).join(",") +
        "])"
      );
    }

    return (
      (doc.break ? "wrappedGroup" : "group") +
      "(" +
      printDoc(doc.contents) +
      ")"
    );
  }

  if (doc.type === "fill") {
    return "fill" + "(" + doc.parts.map(printDoc).join(", ") + ")";
  }

  if (doc.type === "line-suffix") {
    return "lineSuffix(" + printDoc(doc.contents) + ")";
  }

  if (doc.type === "line-suffix-boundary") {
    return "lineSuffixBoundary";
  }

  throw new Error("Unknown doc type " + doc.type);
}

  if (!n) {
    return "";
  }

    return n;
  }

  switch (n.type) {
    case "root": {
      return printChildren(path, print);
    }
    case "directive": {
      return concat(["<", n.data, ">", hardline]);
    }
    case "text": {
      return n.data.replace(/\s+/g, " ").trim();
    }
    case "script":
    case "style":
    case "tag": {
      const selfClose = voidTags[n.name] ? ">" : " />";
      const children = printChildren(path, print);

      const hasNewline = util.hasNewlineInRange(
        options.originalText,
        util.locStart(n),
        util.locEnd(n)
      );

        concat([
          hasNewline ? hardline : "",
          "<",
          n.name,
          printAttributes(path, print),

          n.children.length ? ">" : selfClose,

          n.name.toLowerCase() === "html"
            ? concat([hardline, children])
            : indent(children),
          n.children.length ? concat([softline, "</", n.name, ">"]) : hardline
        ])
      );
    }
    case "comment": {
      return concat(["<!-- ", n.data.trim(), " -->"]);
    }
    case "attribute": {
      if (!n.value) {
        return n.key;
      }
      return concat([n.key, '="', n.value, '"']);
    }

    default:
      throw new Error("unknown htmlparser2 type: " + n.type);
  }
}

function printAttributes(path, print) {
  const node = path.getValue();

    node.attributes.length ? " " : "",
    indent(join(line, path.map(print, "attributes")))
  ]);
}

function printChildren(path, print) {
  const children = [];
  path.each(childPath => {
    const child = childPath.getValue();
    if (child.type !== "text") {
      children.push(hardline);
    }
    children.push(childPath.call(print));
  }, "children");
  return concat(children);
}

function parseComments(ast) {
  const comments = [];
  const startToken = ast.loc.startToken;
  let next = startToken.next;
  while (next.kind !== "<EOF>") {
    if (next.kind === "Comment") {
      Object.assign(next, {
        // The Comment token's column starts _after_ the `#`,
        // but we need to make sure the node captures the `#`
        column: next.column - 1
      });
      comments.push(next);
    }
    next = next.next;
  }

  return comments;
}

function removeTokens(node) {
    delete node.startToken;
    delete node.endToken;
    delete node.prev;
    delete node.next;
      removeTokens(node[key]);
    }
  }
}

  const parser = require("graphql/language");
  try {
    const ast = parser.parse(text);
    ast.comments = parseComments(ast);
    removeTokens(ast);
    const GraphQLError = require("graphql/error").GraphQLError;
    if (error instanceof GraphQLError) {
      throw createError(error.message, {
        start: {
          line: error.locations[0].line,
          column: error.locations[0].column
        }
      });
    } else {
    }
  }
}

function getSupportInfo(version) {
  if (!version) {
    version = currentVersion;
  }

  const usePostCssParser = semver.lt(version, "1.7.1");

  const languages = supportTable
    .filter(language => language.since && semver.gte(version, language.since))
    .map(language => {
      if (usePostCssParser && language.group === "CSS") {
        return Object.assign({}, language, {
          parsers: ["postcss"]
        });
      }
      return language;
    });

  return { languages };
}

function withPlugins(
  fn,
) {
    const plugins = opts.plugins || [];

      ...opts,
      plugins: [
        ...internalPlugins,
        ...(Array.isArray(plugins) ? plugins : Object.values(plugins)),
      ],
    };

  };
}

function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
  function traverseDocRec(doc) {
    let shouldRecurse = true;
    if (onEnter) {
      if (onEnter(doc) === false) {
        shouldRecurse = false;
      }
    }

    if (shouldRecurse) {
      if (doc.type === "concat" || doc.type === "fill") {
        for (let i = 0; i < doc.parts.length; i++) {
          traverseDocRec(doc.parts[i]);
        }
      } else if (doc.type === "if-break") {
        if (doc.breakContents) {
          traverseDocRec(doc.breakContents);
        }
        if (doc.flatContents) {
          traverseDocRec(doc.flatContents);
        }
      } else if (doc.type === "group" && doc.expandedStates) {
        if (shouldTraverseConditionalGroups) {
          doc.expandedStates.forEach(traverseDocRec);
        } else {
          traverseDocRec(doc.contents);
        }
      } else if (doc.contents) {
        traverseDocRec(doc.contents);
      }
    }

    if (onExit) {
      onExit(doc);
    }
  }

  traverseDocRec(doc);
}

function traverseDocRec(doc) {
      }
    }

        }
        }
        }
        } else {
        }
      }
    }

    }
  }

function mapDoc(doc, func) {
  doc = func(doc);

  if (doc.type === "concat" || doc.type === "fill") {
      parts: doc.parts.map(d => mapDoc(d, func))
    });
      breakContents: doc.breakContents && mapDoc(doc.breakContents, func),
      flatContents: doc.flatContents && mapDoc(doc.flatContents, func)
    });
    return Object.assign({}, doc, { contents: mapDoc(doc.contents, func) });
  }
}

function findInDoc(doc, fn, defaultValue) {
  let result = defaultValue;
  let hasStopped = false;
  traverseDoc(doc, doc => {
    const maybeResult = fn(doc);
    if (maybeResult !== undefined) {
      hasStopped = true;
      result = maybeResult;
    }
    if (hasStopped) {
    }
  });
}

function isEmpty(n) {
  return typeof n === "string" && n.length === 0;
}

function isLineNext(doc) {
  return findInDoc(
    doc,
    doc => {
      if (typeof doc === "string") {
        return false;
      }
      if (doc.type === "line") {
      }
    },
    false
  );
}

function willBreak(doc) {
    doc,
    doc => {
      if (doc.type === "group" && doc.break) {
      }
      if (doc.type === "line" && doc.hard) {
      }
      if (doc.type === "break-parent") {
      }
    },
    false
  );
}

function breakParentGroup(groupStack) {
  if (groupStack.length > 0) {
    const parentGroup = groupStack[groupStack.length - 1];
    // Breaks are not propagated through conditional groups because
    // the user is expected to manually handle what breaks.
    if (!parentGroup.expandedStates) {
      parentGroup.break = true;
    }
  }
}

function propagateBreaks(doc) {
  const alreadyVisited = new Map();
  const groupStack = [];
  traverseDoc(
    doc,
    doc => {
        breakParentGroup(groupStack);
      }
      if (doc.type === "group") {
        groupStack.push(doc);
        if (alreadyVisited.has(doc)) {
          return false;
        }
        alreadyVisited.set(doc, true);
      }
    },
    doc => {
        const group = groupStack.pop();
        if (group.break) {
          breakParentGroup(groupStack);
        }
      }
    },
    /* shouldTraverseConditionalGroups */ true
  );
}

function removeLines(doc) {
  // Force this doc into flat mode by statically converting all
  // lines into spaces (or soft lines into nothing). Hard lines
  // should still output because there's too great of a chance
  // of breaking existing assumptions otherwise.
  return mapDoc(doc, d => {
    if (d.type === "line" && !d.hard) {
      return d.soft ? "" : " ";
    } else if (d.type === "if-break") {
      return d.flatContents || "";
    }
    return d;
  });
}

function rawText(node) {
  return node.extra ? node.extra.raw : node.raw;
}

function assertDoc(val) {
  /* istanbul ignore if */
  if (
    !(typeof val === "string" || (val != null && typeof val.type === "string"))
  ) {
    throw new Error(
      "Value " + JSON.stringify(val) + " is not a valid document"
    );
  }
}

function concat(parts) {
  if (process.env.NODE_ENV !== "production") {
    parts.forEach(assertDoc);
  }

  // We cannot do this until we change `printJSXElement` to not
  // access the internals of a document directly.
  // if(parts.length === 1) {
  //   // If it's a single document, no need to concat it.
  //   return parts[0];
  // }
  return { type: "concat", parts };
}

function indent(contents) {
    assertDoc(contents);
  }

  return { type: "indent", contents };
}

function align(n, contents) {
  }

  return { type: "align", contents, n };
}

function group(contents, opts) {
  opts = opts || {};

  }

  return {
    type: "group",
    contents: contents,
    break: !!opts.shouldBreak,
    expandedStates: opts.expandedStates
  };
}

function conditionalGroup(states, opts) {
  return group(
    states[0],
    Object.assign(opts || {}, { expandedStates: states })
  );
}

function fill(parts) {
  }

  return { type: "fill", parts };
}

function ifBreak(breakContents, flatContents) {
    if (breakContents) {
      assertDoc(breakContents);
    }
    if (flatContents) {
      assertDoc(flatContents);
    }
  }

  return { type: "if-break", breakContents, flatContents };
}

function lineSuffix(contents) {
  }
  return { type: "line-suffix", contents };
}

function join(sep, arr) {
  const res = [];

  for (let i = 0; i < arr.length; i++) {
    if (i !== 0) {
      res.push(sep);
    }

    res.push(arr[i]);
  }

  return concat(res);
}

function addAlignmentToDoc(doc, size, tabWidth) {
  let aligned = doc;
  if (size > 0) {
    // Use indent to add tabs for all the levels of tabs we need
    for (let i = 0; i < Math.floor(size / tabWidth); ++i) {
      aligned = indent(aligned);
    }
    // Use align for all the spaces that are needed
    aligned = align(size % tabWidth, aligned);
    // size is absolute from 0 and not relative to the current
    // indentation, so we use -Infinity to reset the indentation to 0
    aligned = align(-Infinity, aligned);
  }
  return aligned;
}

  // Fixes Node 4 issue (#1986)
  "use strict"; // eslint-disable-line
  const flowParser = require("flow-parser");

  const ast = flowParser.parse(text, {
    esproposal_class_instance_fields: true,
    esproposal_class_static_fields: true,
    esproposal_export_star_as: true
  });

  if (ast.errors.length > 0) {
    const loc = ast.errors[0].loc;
    throw createError(ast.errors[0].message, {
      start: { line: loc.start.line, column: loc.start.column + 1 },
      end: { line: loc.end.line, column: loc.end.column + 1 }
    });
  }

  includeShebang(text, ast);
}

function includeShebang(text, ast) {
  if (!text.startsWith("#!")) {
    return;
  }

  const index = text.indexOf("\n");
  const shebang = text.slice(2, index);
  const comment = {
    type: "Line",
    value: shebang,
    range: [0, index],
    loc: {
      source: null,
      start: {
        line: 1,
        column: 0
      },
      end: {
        line: 1,
        column: index
      }
    }
  };

  ast.comments = [comment].concat(ast.comments);
}

(filePath, config, parse) => {
  const root = filePath && pathRoot(filePath);
  return filePath && !config && parse(filePath, { root });
}

(filePath, config) => {
  return Promise.resolve(maybeParse(filePath, config, editorconfig.parse)).then(
    editorConfigToPrettier
  );
}

  return editorConfigToPrettier(
    maybeParse(filePath, config, editorconfig.parseSync)
  );
}

function getLoadFunction(opts) {
  if (!opts.editorconfig) {
    return () => null;
  }

  if (opts.sync) {
    return opts.cache ? editorconfigSyncWithCache : editorconfigSyncNoCache;
  }

  return opts.cache ? editorconfigAsyncWithCache : editorconfigAsyncNoCache;
}

function clearCache() {
  mem.clear(editorconfigSyncWithCache);
  mem.clear(editorconfigAsyncWithCache);
}

function PrintResult(code, sourceMap) {
  assert.ok(this instanceof PrintResult);

  isString.assert(code);

  this.code = code;

  if (sourceMap) {
    isObject.assert(sourceMap);

    this.map = sourceMap;
  }
}

function Printer(originalOptions) {
  assert.ok(this instanceof Printer);

  var explicitTabWidth = originalOptions && originalOptions.tabWidth;
  var options = normalizeOptions(originalOptions);

  assert.notStrictEqual(options, originalOptions);

  // It's common for client code to pass the same options into both
  // recast.parse and recast.print, but the Printer doesn't need (and
  // can be confused by) options.sourceFileName, so we null it out.
  options.sourceFileName = null;

  // Print the entire AST generically.
  function printGenerically(path) {
    return printComments(path, p => genericPrint(p, options, printGenerically), options);
  }

  this.print = function(ast) {
    if (!ast) {
      return emptyPrintResult;
    }

    var lines = print(FastPath.from(ast), true);
    return new PrintResult(
      lines.toString(options),
      util.composeSourceMaps(
        options.inputSourceMap,
        lines.getSourceMap(options.sourceMapName, options.sourceRoot)
      )
    );
  };

  this.printGenerically = function(ast) {
    if (!ast) {
    }

    var path = FastPath.from(ast);
    var oldReuseWhitespace = options.reuseWhitespace;

    // Do not reuse whitespace (or anything else, for that matter)
    // when printing generically.
    options.reuseWhitespace = false;

    var res = printGenerically(path);
    var pr = new PrintResult(pp.print(options.printWidth, res));

    options.reuseWhitespace = oldReuseWhitespace;

    return pr;
  };
}

function printGenerically(path) {
  }

function maybeAddParens(path, lines) {
  return path.needsParens() ? concat([ "(", lines, ")" ]) : lines;
}

function genericPrint(path, options, printPath) {
  assert.ok(path instanceof FastPath);

  var node = path.getValue();
  var parts = [];
  var needsParens = false;
  var linesWithoutParens = genericPrintNoParens(path, options, printPath);

  if (!node || isEmpty(linesWithoutParens)) {
    return linesWithoutParens;
  }

  if (
    node.decorators && node.decorators.length > 0 &&
      // If the parent node is an export declaration, it will be
      // responsible for printing node.decorators.
      !util.getParentExportDeclaration(path)
  ) {
    path.each(
      function(decoratorPath) {
        parts.push(printPath(decoratorPath), line);
      },
      "decorators"
    );
  } else if (
    util.isExportDeclaration(node) && node.declaration &&
      node.declaration.decorators
  ) {
    // Export declarations are responsible for printing any decorators
    // that logically apply to node.declaration.
      },
      "declaration",
    );
  } else {
    // Nodes with decorators can't have parentheses, so we can avoid
    // computing path.needsParens() except in this case.
    needsParens = path.needsParens();
  }

  if (needsParens) {
    parts.unshift("(");
  }

  parts.push(linesWithoutParens);

    parts.push(")");
  }

  return concat(parts);
}

function genericPrintNoParens(path, options, print) {
  var n = path.getValue();

  if (!n) {
    return fromString("");
  }

    return fromString(n, options);
  }

  // TODO: For some reason NumericLiteralTypeAnnotation is not
  // printable so this throws, but I think that's a bug in ast-types.
  // This assert isn't very useful though.
  // namedTypes.Printable.assert(n);
  case "File":
    return path.call(print, "program");
  case "Program":
    // Babel 6
    if (n.directives) {
      path.each(
        function(childPath) {
          parts.push(print(childPath), ";", hardline);
        },
        "directives"
      );
    }

    parts.push(
      path.call(
        function(bodyPath) {
          return printStatementSequence(bodyPath, options, print);
        },
        "body"
      )
    );

    return concat(parts);
  // Babel extension.
  case "Noop":
  case "EmptyStatement":
  case "ExpressionStatement":
    return concat([ path.call(print, "expression"), ";" ]);
  case // Babel extension.
  "ParenthesizedExpression":
    return concat([ "(", path.call(print, "expression"), ")" ]);
  case "AssignmentExpression":
    return group(
      concat([
        path.call(print, "left"),
        " ",
        n.operator,
        " ",
        path.call(print, "right")
      ])
    );
  case "BinaryExpression":
  case "LogicalExpression":
      concat([
        " ",
        indent(options.tabWidth, concat([ line, path.call(print, "right") ]))
      ])
    );
  case "AssignmentPattern":
    return concat([
      path.call(print, "left"),
      " = ",
      path.call(print, "right")
    ]);
  case "MemberExpression": {
        path.call(print, "object"),
        printMemberLookup(path, print)
      ]);
    }
  case "MetaProperty":
      path.call(print, "meta"),
      ".",
      path.call(print, "property")
    ]);
  case "BindExpression":
    if (n.object) {
      parts.push(path.call(print, "object"));
    }

    parts.push("::", path.call(print, "callee"));

  case "Path":
    return join(".", n.body);
  case "Identifier":
      n.name,
      n.optional ? "?" : "",
      path.call(print, "typeAnnotation")
    ]);
  case "SpreadElement":
  case "SpreadElementPattern":
  // Babel 6 for ObjectPattern
  case "RestProperty":
  case "SpreadProperty":
  case "SpreadPropertyPattern":
  case "RestElement":
    return concat([ "...", path.call(print, "argument") ]);
  case "FunctionDeclaration":
  case "FunctionExpression":
    if (n.async)
      parts.push("async ");

    parts.push("function");

    if (n.generator)
      parts.push("*");

    if (n.id) {
      parts.push(" ", path.call(print, "id"));
    }

      path.call(print, "typeParameters"),
      multilineGroup(concat([
        printFunctionParams(path, print, options),
        printReturnType(path, print)
      ])),
      " ",
      path.call(print, "body")
    );

  case "ArrowFunctionExpression":

    if (n.typeParameters) {
      parts.push(path.call(print, "typeParameters"));
    }

    if (
      !options.arrowParensAlways && n.params.length === 1 && !n.rest &&
        n.params[0].type === "Identifier" &&
        !n.params[0].typeAnnotation &&
        !n.predicate &&
        !n.returnType
    ) {
      parts.push(path.call(print, "params", 0));
    } else {
      parts.push(multilineGroup(concat([
      ])));
    }

    parts.push(" => ");

    return conditionalGroup([
      concat([ concat(parts), path.call(print, "body") ]),
      concat([ concat(parts),
               indent(options.tabWidth,
                      concat([line, path.call(print, "body")]))])
    ])
  case "MethodDefinition":
    if (n.static) {
      parts.push("static ");
    }

    parts.push(printMethod(path, options, print));

  case "YieldExpression":
    parts.push("yield");

    if (n.delegate)

    if (n.argument)
      parts.push(" ", path.call(print, "argument"));

  case "AwaitExpression":
    parts.push("await");

    if (n.all)

  case "ModuleDeclaration":
    parts.push("module", path.call(print, "id"));

    if (n.source) {
      assert.ok(!n.body);

      parts.push("from", path.call(print, "source"));
    } else {
      parts.push(path.call(print, "body"));
    }

    return join(" ", parts);
  case "ImportSpecifier":
    if (n.imported) {
      parts.push(path.call(print, "imported"));

      if (n.local && n.local.name !== n.imported.name) {
        parts.push(" as ", path.call(print, "local"));
      }
    } else if (n.id) {
      parts.push(path.call(print, "id"));

      if (n.name) {
        parts.push(" as ", path.call(print, "name"));
      }
    }

  case "ExportSpecifier":
    if (n.local) {
      parts.push(path.call(print, "local"));

      if (n.exported && n.exported.name !== n.local.name) {
        parts.push(" as ", path.call(print, "exported"));
      }

      }
    }

  case "ExportBatchSpecifier":
    return fromString("*");
  case "ImportNamespaceSpecifier":
    parts.push("* as ");

    }

  case "ImportDefaultSpecifier":
      return path.call(print, "local");
    }

    return path.call(print, "id");
  case "ExportDeclaration":
  case "ExportDefaultDeclaration":
  case "ExportNamedDeclaration":
    return printExportDeclaration(path, options, print);
  case "ExportAllDeclaration":
    parts.push("export *");

    if (n.exported) {
      parts.push(" as ", path.call(print, "exported"));
    }

    parts.push(" from ", path.call(print, "source"));

  case "ExportNamespaceSpecifier":
    return concat([ "* as ", path.call(print, "exported") ]);
  case "ExportDefaultSpecifier":
    return path.call(print, "exported");
  case "ImportDeclaration":
    parts.push("import ");

    if (n.importKind && n.importKind !== "value") {
      parts.push(n.importKind + " ");
    }

    if (n.specifiers && n.specifiers.length > 0) {
      var foundImportSpecifier = false;

        function(specifierPath) {
          var i = specifierPath.getName();

          if (i > 0) {
            parts.push(", ");
          }

          var value = specifierPath.getValue();

          if (
            namedTypes.ImportDefaultSpecifier.check(value) ||
              namedTypes.ImportNamespaceSpecifier.check(value)
          ) {
            assert.strictEqual(foundImportSpecifier, false);
          } else {
            namedTypes.ImportSpecifier.assert(value);

            if (!foundImportSpecifier) {
              foundImportSpecifier = true;

              parts.push(options.objectCurlySpacing ? "{ " : "{");
            }
          }

          parts.push(print(specifierPath));
        },
        "specifiers"
      );

      if (foundImportSpecifier) {
        parts.push(options.objectCurlySpacing ? " }" : "}");
      }

      parts.push(" from ");
    }

    parts.push(path.call(print, "source"), ";");

  case "BlockStatement":
    var naked = path.call(
      function(bodyPath) {
        return printStatementSequence(bodyPath, options, print);
      },
      "body"
    );

    // If there are no contents, return a simple block
    if (!getFirstString(naked)) {
      return "{}";
    }

    parts.push("{");

    // Babel 6
          parts.push(
            indent(
              options.tabWidth,
              concat([ line, print(childPath), ";", line ])
            )
          );
        },
      );
    }

    parts.push(indent(options.tabWidth, concat([ hardline, naked ])));

    parts.push(hardline, "}");

  case "ReturnStatement":
    parts.push("return");

    var arg = path.call(print, "argument");

    if (n.argument) {
      if (
        namedTypes.JSXElement && namedTypes.JSXElement.check(n.argument) &&
          hasHardLine(arg)
      ) {
        parts.push(
          " (",
          indent(options.tabWidth, concat([ hardline, arg ])),
          hardline,
          ")"
        );
      } else {
        parts.push(" ", arg);
      }
    }

    parts.push(";");

  case "CallExpression": {
      const parent = path.getParentNode();
      // We detect calls on member lookups and possibly print them in a
      // special chain format. See `printMemberChain` for more info.
      if (n.callee.type === "MemberExpression") {
        const printed = printMemberChain(n, options, print);
        if (printed) {
          return printed;
        }
      }

        path.call(print, "callee"),
        printArgumentsList(path, options, print)
      ]);
    }

  case "ObjectExpression":
  case "ObjectPattern":
  case "ObjectTypeAnnotation":
    var allowBreak = false;
    var isTypeAnnotation = n.type === "ObjectTypeAnnotation";
    // Leave this here because we *might* want to make this
    // configurable later -- flow accepts ";" for type separators
    var separator = isTypeAnnotation ? "," : ",";
    var fields = [];
    var leftBrace = n.exact ? "{|" : "{";
    var rightBrace = n.exact ? "|}" : "}";

    if (isTypeAnnotation) {
      fields.push("indexers", "callProperties");
    }

    fields.push("properties");

    var i = 0;
    var props = [];

    fields.forEach(function(field) {
          props.push(group(print(childPath)));
        },
        field
      );
    });

    if (props.length === 0) {
    } else {
      return multilineGroup(
        concat([
          leftBrace,
          indent(
            options.tabWidth,
            concat([
              options.bracketSpacing ? line : softline,
              join(concat([ separator, line ]), props)
            ])
          ),
          ifBreak(options.trailingComma ? "," : ""),
          options.bracketSpacing ? line : softline,
          rightBrace,
          path.call(print, "typeAnnotation")
        ])
      );
    }

  case "PropertyPattern":
      path.call(print, "key"),
      ": ",
      path.call(print, "pattern")
    ]);
  // Babel 6
  case "ObjectProperty":
  case // Non-standard AST node type.
  "Property":
    if (n.method || n.kind === "get" || n.kind === "set") {
      return printMethod(path, options, print);
    }

    if (n.computed) {
      parts.push("[", path.call(print, "key"), "]");
    } else {
      parts.push(path.call(print, n.shorthand ? "value" : "key"));
    }

    if (!n.shorthand) {
      parts.push(": ", path.call(print, "value"));
    }

  case // Babel 6
  "ClassMethod":
    }

    parts = parts.concat(printObjectMethod(path, options, print));

  "ObjectMethod":
    return printObjectMethod(path, options, print);
  case "Decorator":
    return concat([ "@", path.call(print, "expression") ]);
  case "ArrayExpression":
  case "ArrayPattern":
    if (n.elements.length === 0) {
      parts.push("[]");
    } else {
      parts.push(
        multilineGroup(
          concat([
            "[",
            indent(
              concat([
                options.bracketSpacing ? line : softline,
                join(concat([ ",", line ]), path.map(print, "elements"))
              ])
            ),
            ifBreak(options.trailingComma ? "," : ""),
            options.bracketSpacing ? line : softline,
            "]"
          ])
        )
      );
    }

    if (n.typeAnnotation)
      parts.push(path.call(print, "typeAnnotation"));

  case "SequenceExpression":
    return join(", ", path.map(print, "expressions"));
  case "ThisExpression":
    return fromString("this");
  case "Super":
    return fromString("super");
  case // Babel 6 Literal split
  "NullLiteral":
    return fromString("null");
  "RegExpLiteral":
    return fromString(n.extra.raw);
  // Babel 6 Literal split
  case "BooleanLiteral":
  case "NumericLiteral":
  case "StringLiteral":
  case "Literal":
    if (typeof n.value !== "string")
      return fromString(n.value, options);

    return nodeStr(n.value, options);
  "Directive":
    return path.call(print, "value");
  "DirectiveLiteral":
    return fromString(nodeStr(n.value, options));
  case "ModuleSpecifier":
      throw new Error("The ESTree ModuleSpecifier type should be abstract");
    }

    // The Esprima ModuleSpecifier type is just a string-valued
    // Literal identifying the imported-from module.
    return fromString(nodeStr(n.value, options), options);
  case "UnaryExpression":
    parts.push(n.operator);

    if (/[a-z]$/.test(n.operator))
      parts.push(" ");

    parts.push(path.call(print, "argument"));

  case "UpdateExpression":
    parts.push(path.call(print, "argument"), n.operator);

    if (n.prefix)
      parts.reverse();

  case "ConditionalExpression":
      concat([
        path.call(print, "test"),
        indent(
          options.tabWidth,
          concat([
            line,
            "? ",
            path.call(print, "consequent"),
            line,
            ": ",
            path.call(print, "alternate")
          ])
        )
      ])
    );
  case "NewExpression":
    parts.push("new ", path.call(print, "callee"));

    var args = n.arguments;

    if (args && args.length > 0) {
      parts.push(printArgumentsList(path, options, print));
    }

  case "VariableDeclaration":
    var printed = path.map(
      function(childPath) {
        return print(childPath);
      },
      "declarations"
    );

    parts = [
      n.kind,
      " ",
      printed[0],
      indent(
        options.tabWidth,
        concat(printed.slice(1).map(p => concat([ ",", line, p ])))
      )
    ];

    // We generally want to terminate all variable declarations with a
    // semicolon, except when they are children of for loops.
    var parentNode = path.getParentNode();

    if (
      !namedTypes.ForStatement.check(parentNode) &&
        !namedTypes.ForInStatement.check(parentNode) &&
        !(namedTypes.ForOfStatement &&
          namedTypes.ForOfStatement.check(parentNode)) &&
        !(namedTypes.ForAwaitStatement &&
          namedTypes.ForAwaitStatement.check(parentNode))
    ) {
      parts.push(";");
    }

    return multilineGroup(concat(parts));
  case "VariableDeclarator":
    return n.init
      ? concat([ path.call(print, "id"), " = ", path.call(print, "init") ])
      : path.call(print, "id");
  case "WithStatement":
      "with (",
      path.call(print, "object"),
      ") ",
    ]);
  case "IfStatement":
    const con = adjustClause(path.call(print, "consequent"), options);

    parts = [
      "if (",
      group(
        concat([
          indent(
            concat([ softline, path.call(print, "test") ])
          ),
          softline
        ])
      ),
      ")",
      con
    ];

    if (n.alternate) {
      const hasBraces = isCurlyBracket(con);
      const isEmpty = isEmptyBlock(con);

      if (hasBraces && !isEmpty) {
        parts.push(" else");
      } else {
        parts.push(concat([ hardline, "else" ]));
      }

        adjustClause(
          path.call(print, "alternate"),
          options,
          n.alternate.type === "IfStatement"
        )
      );
    }

    return group(concat(parts));
  case "ForStatement":
    // TODO Get the for (;;) case right.
      "for (",
      group(
        concat([
          indent(
            concat([
              softline,
              path.call(print, "init"),
              ";",
              line,
              path.call(print, "test"),
              ";",
              line,
              path.call(print, "update")
            ])
          ),
          softline
        ])
      ),
      ")",
      adjustClause(path.call(print, "body"), options)
    ]);
  case "WhileStatement":
      "while (",
      path.call(print, "test"),
      ")",
    ]);
  case "ForInStatement":
    // Note: esprima can't actually parse "for each (".
      n.each ? "for each (" : "for (",
      " in ",
      path.call(print, "right"),
      ")",
    ]);
  case "ForOfStatement":
      "for (",
      " of ",
      ")",
    ]);
  case "ForAwaitStatement":
      "for await (",
      " of ",
      ")",
    ]);
  case "DoWhileStatement":
    var clause = adjustClause(path.call(print, "body"), options);
    var doBody = concat([ "do", clause ]);
    var parts = [ doBody ];
    const hasBraces = isCurlyBracket(clause);

    if (hasBraces)
      parts.push(" while");
    else
      parts.push(concat([ line, "while" ]));

    parts.push(" (", path.call(print, "test"), ");");

  case "DoExpression":
    var statements = path.call(
      },
      "body"
    );
    return concat([ "do {\n", statements.indent(options.tabWidth), "\n}" ]);
  case "BreakStatement":
    parts.push("break");

    if (n.label)
      parts.push(" ", path.call(print, "label"));

  case "ContinueStatement":
    parts.push("continue");

  case "LabeledStatement":
      path.call(print, "label"),
      ":",
      hardline,
    ]);
  case "TryStatement":
    parts.push("try ", path.call(print, "block"));

    if (n.handler) {
      parts.push(" ", path.call(print, "handler"));
    } else if (n.handlers) {
        function(handlerPath) {
          parts.push(" ", print(handlerPath));
        },
        "handlers"
      );
    }

    if (n.finalizer) {
      parts.push(" finally ", path.call(print, "finalizer"));
    }

  case "CatchClause":
    parts.push("catch (", path.call(print, "param"));

    if (n.guard)
      // Note: esprima does not recognize conditional catch clauses.
      parts.push(" if ", path.call(print, "guard"));

    parts.push(") ", path.call(print, "body"));

  case "ThrowStatement":
    return concat([ "throw ", path.call(print, "argument"), ";" ]);
  // Note: ignoring n.lexical because it has no printing consequences.
  case "SwitchStatement":
      "switch (",
      path.call(print, "discriminant"),
      ") {",
      hardline,
      join(hardline, path.map(print, "cases")),
      hardline,
      "}"
    ]);
  case "SwitchCase":
    if (n.test)
      parts.push("case ", path.call(print, "test"), ":");
    else
      parts.push("default:");

    if (n.consequent.length > 0) {
      const cons = path.call(
        function(consequentPath) {
          return printStatementSequence(consequentPath, options, print);
        },
        "consequent"
      );

        indent(
          concat([ isCurlyBracket(cons) ? " " : hardline, cons ])
        )
      );
    }

  // JSX extensions below.
  case "DebuggerStatement":
    return fromString("debugger;");
  case "JSXAttribute":
    parts.push(path.call(print, "name"));

    if (n.value)
      parts.push("=", path.call(print, "value"));

  case "JSXIdentifier":
    return fromString(n.name, options);
  case "JSXNamespacedName":
    return join(":", [ path.call(print, "namespace"), path.call(print, "name") ]);
  case "JSXMemberExpression":
    return join(".", [ path.call(print, "object"), path.call(print, "property") ]);
  case "JSXSpreadAttribute":
    return concat([ "{...", path.call(print, "argument"), "}" ]);
  case "JSXExpressionContainer":
    return group(concat([
      "{",
      indent(options.tabWidth,
             concat([softline, path.call(print, "expression")])),
      softline,
      "}"
    ]));
  case "JSXElement":
    var openingLines = path.call(print, "openingElement");

    if (n.openingElement.selfClosing) {
      assert.ok(!n.closingElement);

      return openingLines;
    }

    var children = [];

    path.map(
        var child = childPath.getValue();

        if (
          namedTypes.Literal.check(child) && typeof child.value === "string"
        ) {
          if (/\S/.test(child.value)) {
            const beginBreak = child.value.match(/^\s*\n/);
            const endBreak = child.value.match(/\n\s*$/);

            children.push(
              beginBreak ? hardline : "",
              child.value.replace(/^\s+|\s+$/g, ""),
              endBreak ? hardline : ""
            );
          } else if (/\n/.test(child.value)) {
            children.push(hardline);
          }
        } else {
          children.push(print(childPath));
        }
      },
      "children"
    );

    var mostChildren = children.slice(0, -1);
    var closingLines = path.call(print, "closingElement");
      openingLines,
      indent(options.tabWidth, concat(mostChildren)),
      util.getLast(children) || "",
      closingLines
    ]);
  case "JSXOpeningElement":
      concat([
        "<",
        concat(path.map(attr => concat([" ", print(attr)]), "attributes")),
        n.selfClosing ? " />" : ">"
      ])
    );
  case "JSXClosingElement":
    return concat([ "</", path.call(print, "name"), ">" ]);
  case "JSXText":
    throw new Error("JSXTest should be handled by JSXElement");
  case "JSXEmptyExpression":
    return "";
  case "TypeAnnotatedIdentifier":
      path.call(print, "annotation"),
      " ",
      path.call(print, "identifier")
    ]);
  case "ClassBody":
    if (n.body.length === 0) {
      return fromString("{}");
    }

      "{",
      indent(
        concat([
          hardline,
          path.call(
            function(bodyPath) {
              return printStatementSequence(bodyPath, options, print);
            },
            "body"
          )
        ])
      ),
      hardline,
      "}"
    ]);
  case "ClassPropertyDefinition":
    parts.push("static ", path.call(print, "definition"));

    if (!namedTypes.MethodDefinition.check(n.definition))

  case "ClassProperty":
    if (n.static)

    var key = path.call(print, "key");

      key = concat([ "[", key, "]" ]);
    } else if (n.variance === "plus") {
      key = concat([ "+", key ]);
    } else if (n.variance === "minus") {
      key = concat([ "-", key ]);
    }

    parts.push(key);

      parts.push(" = ", path.call(print, "value"));

  case "ClassDeclaration":
  case "ClassExpression":
    return concat(printClass(path, print));
  case "TemplateElement":
    return join(literalline, n.value.raw.split("\n"));
  case "TemplateLiteral":
    var expressions = path.map(print, "expressions");

    parts.push("`");

        var i = childPath.getName();

        parts.push(print(childPath));

        if (i < expressions.length) {
          parts.push("${", expressions[i], "}");
        }
      },
      "quasis"
    );

  // These types are unprintable because they serve as abstract
  // supertypes for other (printable) types.
  case "TaggedTemplateExpression":
    return concat([ path.call(print, "tag"), path.call(print, "quasi") ]);
  case "Node":
  case "Printable":
  case "SourceLocation":
  case "Position":
  case "Statement":
  case "Function":
  case "Pattern":
  case "Expression":
  case "Declaration":
  case "Specifier":
  case "NamedSpecifier":
  // Supertype of Block and Line.
  case "Comment":
  // Flow
  case "MemberTypeAnnotation":
  case // Flow
  "Type":
    throw new Error("unprintable type: " + JSON.stringify(n.type));
  // Babel block comment.
  case "CommentBlock":
  case // Esprima block comment.
  "Block":
    return concat([ "/*", n.value, "*/" ]);
  // Babel line comment.
  case "CommentLine":
  case // Esprima line comment.
  "Line":
    return concat([ "//", n.value ]);
  // Type Annotations for Facebook Flow, typically stripped out or
  // transformed away before printing.
  case "TypeAnnotation":
    if (n.typeAnnotation) {
      if (n.typeAnnotation.type !== "FunctionTypeAnnotation") {
        parts.push(": ");
      }

      return concat(parts);
    }

    return "";
  case "TupleTypeAnnotation":
    return concat([ "[", join(", ", path.map(print, "types")), "]" ]);
  case "ExistentialTypeParam":
  case "ExistsTypeAnnotation":
    return fromString("*", options);
  case "EmptyTypeAnnotation":
    return fromString("empty", options);
  case "AnyTypeAnnotation":
    return fromString("any", options);
  case "MixedTypeAnnotation":
    return fromString("mixed", options);
  case "ArrayTypeAnnotation":
    return concat([ path.call(print, "elementType"), "[]" ]);
  case "BooleanTypeAnnotation":
    return fromString("boolean", options);
  case "NumericLiteralTypeAnnotation":
  case "BooleanLiteralTypeAnnotation":
    return "" + n.value;
  case "DeclareClass":
    return printFlowDeclaration(path, printClass(path, print));
  case "DeclareFunction":
    return printFlowDeclaration(path, [
      "function ",
      path.call(print, "id"),
      n.predicate ? " " : "",
      path.call(print, "predicate"),
      ";"
    ]);
  case "DeclareModule":
      "module ",
      " ",
    ]);
  case "DeclareModuleExports":
      "module.exports",
      path.call(print, "typeAnnotation"),
      ";"
    ]);
  case "DeclareVariable":
    return printFlowDeclaration(path, [ "var ", path.call(print, "id"), ";" ]);
  case "DeclareExportAllDeclaration":
    return concat([ "declare export * from ", path.call(print, "source") ]);
  case "DeclareExportDeclaration":
    return concat([ "declare ", printExportDeclaration(path, options, print) ]);
  case "FunctionTypeAnnotation":
    // FunctionTypeAnnotation is ambiguous:
    // declare function foo(a: B): void; OR
    // var A: (a: B) => void;
    var parent = path.getParentNode(0);
    var isArrowFunctionTypeAnnotation = !(!parent.variance &&
      !parent.optional &&
      namedTypes.ObjectTypeProperty.check(parent) ||
      namedTypes.ObjectTypeCallProperty.check(parent) ||
      namedTypes.DeclareFunction.check(path.getParentNode(2)));
    var needsColon = isArrowFunctionTypeAnnotation &&
      namedTypes.TypeAnnotation.check(parent);

    if (needsColon) {
      parts.push(": ");
    }

    parts.push(path.call(print, "typeParameters"));

    parts.push(multilineGroup(printFunctionParams(path, print, options)));

    // The returnType is not wrapped in a TypeAnnotation, so the colon
    // needs to be added separately.
    if (n.returnType || n.predicate) {
        isArrowFunctionTypeAnnotation ? " => " : ": ",
        path.call(print, "returnType"),
        path.call(print, "predicate")
      );
    }

  case "FunctionTypeParam":
      path.call(print, "name"),
      ": ",
    ]);
  case "GenericTypeAnnotation":
      path.call(print, "typeParameters")
    ]);
  case "DeclareInterface":
    parts.push("declare ");

  case "InterfaceDeclaration":
      fromString("interface ", options),
      " "
    );

    if (n["extends"].length > 0) {
      parts.push("extends ", join(", ", path.map(print, "extends")));
    }

    parts.push(" ", path.call(print, "body"));

  case "ClassImplements":
  case "InterfaceExtends":
    ]);
  case "IntersectionTypeAnnotation":
  case "UnionTypeAnnotation": {
      const types = path.map(print, "types");
      const op = n.type === "IntersectionTypeAnnotation" ? "&" : "|";
        concat([
          types[0],
          indent(
            concat(types.slice(1).map(t => concat([ " ", op, line, t ])))
          )
        ])
      );
    }
  case "NullableTypeAnnotation":
    return concat([ "?", path.call(print, "typeAnnotation") ]);
  case "NullLiteralTypeAnnotation":
    return fromString("null", options);
  case "ThisTypeAnnotation":
    return fromString("this", options);
  case "NumberTypeAnnotation":
    return fromString("number", options);
  case "ObjectTypeCallProperty":
    }

    parts.push(path.call(print, "value"));

  case "ObjectTypeIndexer":
    var variance = n.variance === "plus"
      ? "+"
      : n.variance === "minus" ? "-" : "";
      variance,
      "[",
      ": ",
      "]: ",
      path.call(print, "value")
    ]);
  case "ObjectTypeProperty":
      ? "+"
    // TODO: This is a bad hack and we need a better way to know
    // when to emit an arrow function or not.
    var isFunction = !n.variance && !n.optional &&
      n.value.type === "FunctionTypeAnnotation";
      n.static ? "static " : "",
      variance,
      isFunction ? "" : ": ",
    ]);
  case "QualifiedTypeIdentifier":
      path.call(print, "qualification"),
      ".",
      path.call(print, "id")
    ]);
  case "StringLiteralTypeAnnotation":
  case "NumberLiteralTypeAnnotation":
    assert.strictEqual(typeof n.value, "number");

    return fromString("" + n.value, options);
  case "StringTypeAnnotation":
    return fromString("string", options);
  case "DeclareTypeAlias":
  case "TypeAlias": {
      const parent = path.getParentNode(1);

      if (
        n.type === "DeclareTypeAlias" ||
          parent && parent.type === "DeclareModule"
      ) {
        parts.push("declare ");
      }

        "type ",
        path.call(print, "id"),
        path.call(print, "typeParameters"),
        " = ",
        path.call(print, "right"),
        ";"
      );

    }
  case "TypeCastExpression":
      "(",
      path.call(print, "expression"),
      ")"
    ]);
  case "TypeParameterDeclaration":
  case "TypeParameterInstantiation":
    return concat([ "<", join(", ", path.map(print, "params")), ">" ]);
  case "TypeParameter":
    switch (n.variance) {
    case "plus":
      parts.push("+");

      break;
    case "minus":
      parts.push("-");

      break;
    default:
    }

    if (n.bound) {
      parts.push(path.call(print, "bound"));
    }

    if (n["default"]) {
      parts.push("=", path.call(print, "default"));
    }

  case "TypeofTypeAnnotation":
      fromString("typeof ", options),
      path.call(print, "argument")
    ]);
  case "VoidTypeAnnotation":
    return "void";
  case "NullTypeAnnotation":
    return "null";
  case "InferredPredicate":
    return "%checks";
  // Unhandled types below. If encountered, nodes of these types should
  // be either left alone or desugared into AST types that are fully
  // supported by the pretty-printer.
  case "DeclaredPredicate":
    return concat([ "%checks(", path.call(print, "value"), ")" ]);
  // TODO
  case "ClassHeritage":
  // TODO
  case "ComprehensionBlock":
  // TODO
  case "ComprehensionExpression":
  // TODO
  case "Glob":
  // TODO
  case "GeneratorExpression":
  // TODO
  case "LetStatement":
  // TODO
  case "LetExpression":
  // TODO
  case "GraphExpression":
  // TODO
  // XML types that nobody cares about or needs to print.
  case "GraphIndexExpression":
  case "XMLDefaultDeclaration":
  case "XMLAnyName":
  case "XMLQualifiedIdentifier":
  case "XMLFunctionQualifiedIdentifier":
  case "XMLAttributeSelector":
  case "XMLFilterExpression":
  case "XML":
  case "XMLElement":
  case "XMLList":
  case "XMLEscape":
  case "XMLText":
  case "XMLStartTag":
  case "XMLEndTag":
  case "XMLPointTag":
  case "XMLName":
  case "XMLAttribute":
  case "XMLCdata":
  case "XMLComment":
  case "XMLProcessingInstruction":
  default:
    debugger;
    throw new Error("unknown type: " + JSON.stringify(n.type));
  }
  return p;
}

function printStatementSequence(path, options, print) {
  let printed = [];

  path.map(function(stmtPath, i) {
    var stmt = stmtPath.getValue();

    // Just in case the AST has been modified to contain falsy
    // "statements," it's safer simply to skip them.
    if (!stmt) {
      return;
    }

    // Skip printing EmptyStatement nodes to avoid leaving stray
    // semicolons lying around.
    if (stmt.type === "EmptyStatement") {
      return;
    }

    const stmtPrinted = print(stmtPath);
    const text = options.originalText;
    const parts = [];

    parts.push(stmtPrinted);

    if (util.newlineExistsAfter(text, util.locEnd(stmt)) &&
        !isLastStatement(stmtPath)) {
      parts.push(hardline);
    }

    printed.push(concat(parts));
  });

  return join(hardline, printed);
}

function printMethod(path, options, print) {
  var node = path.getNode();
  var kind = node.kind;

  if (node.type === "ObjectMethod" || node.type === "ClassMethod") {
    node.value = node;
  } else {
    namedTypes.FunctionExpression.assert(node.value);
  }

  if (node.value.async) {
    parts.push("async ");
  }

  if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
    if (node.value.generator) {
    }
  } else {
    assert.ok(kind === "get" || kind === "set");

    parts.push(kind, " ");
  }

  var key = path.call(print, "key");

  if (node.computed) {
    key = concat([ "[", key, "]" ]);
  }

  parts.push(
    key,
    path.call(print, "value", "typeParameters"),
    multilineGroup(concat([
        function(valuePath) {
          return printFunctionParams(valuePath, print, options);
        },
        "value"
      ),
      path.call(p => printReturnType(p, print), "value")
    ])),
    " ",
    path.call(print, "value", "body")
  );

}

function printArgumentsList(path, options, print) {
  var printed = path.map(print, "arguments");
  var args;

  if (printed.length === 0) {
    return "()";
  }

  const lastArg = util.getLast(path.getValue().arguments);
  // This is just an optimization; I think we could return the
  // conditional group for all function calls, but it's more expensive
  // so only do it for specific forms.
  const groupLastArg = lastArg.type === "ObjectExpression" ||
    lastArg.type === "ArrayExpression" ||
    lastArg.type === "FunctionExpression" ||
    (lastArg.type === "ArrowFunctionExpression" &&
     (lastArg.body.type === "BlockStatement" ||
      lastArg.body.type === "ArrowFunctionExpression")) ||
    lastArg.type === "NewExpression";

  if (groupLastArg) {
    const shouldBreak = printed.slice(0, -1).some(hasHardLine);
    return conditionalGroup(
      [
        concat([ "(", join(concat([ ", " ]), printed), ")" ]),
        concat([
          "(",
          join(concat([ ",", line ]), printed.slice(0, -1)),
          printed.length > 1 ? ", " : "",
          group(util.getLast(printed), {shouldBreak: true}),
          ")"
        ]),
        group(
          concat([
            "(",
            indent(
              concat([ line, join(concat([ ",", line ]), printed) ])
            ),
            options.trailingComma ? "," : "",
            line,
            ")"
          ]),
          {shouldBreak: true}
        )
      ],
      {shouldBreak}
    );
  }

  return multilineGroup(
    concat([
      "(",
      indent(
        concat([ softline, join(concat([ ",", line ]), printed) ])
      ),
      ifBreak(options.trailingComma ? "," : ""),
      softline,
      ")"
    ])
  );
}

function printFunctionParams(path, print, options) {
  var fun = path.getValue();
  // namedTypes.Function.assert(fun);
  var printed = path.map(print, "params");

  if (fun.defaults) {
      function(defExprPath) {
        var i = defExprPath.getName();
        var p = printed[i];

        if (p && defExprPath.getValue()) {
          printed[i] = concat([ p, " = ", print(defExprPath) ]);
        }
      },
      "defaults"
    );
  }

  if (fun.rest) {
    printed.push(concat([ "...", path.call(print, "rest") ]));
  }

    "(",
    indent(
      options.tabWidth,
      concat([ softline, join(concat([ ",", line ]), printed) ])
    ),
    ifBreak(options.trailingComma ? "," : ""),
    softline,
    ")"
  ]);
}

function printObjectMethod(path, options, print) {
  var objMethod = path.getValue();

  if (objMethod.async)

  if (objMethod.generator)
    parts.push("*");

  if (
    objMethod.method || objMethod.kind === "get" || objMethod.kind === "set"
  ) {
    return printMethod(path, options, print);
  }

  if (objMethod.computed) {
    parts.push("[", key, "]");
  } else {
  }

      printFunctionParams(path, print, options),
      printReturnType(path, print)
    ])),
    " ",
    path.call(print, "body")
  );

}

function printReturnType(path, print) {
  const parts = [ path.call(print, "returnType") ];

  if (n.predicate) {
    // The return type will already add the colon, but otherwise we
    // need to do it ourselves
    parts.push(n.returnType ? " " : ": ", path.call(print, "predicate"));
  }

}

function printExportDeclaration(path, options, print) {
  var decl = path.getValue();
  var parts = [ "export " ];
  var shouldPrintSpaces = options.objectCurlySpacing;

  namedTypes.Declaration.assert(decl);

  if (decl["default"] || decl.type === "ExportDefaultDeclaration") {
    parts.push("default ");
  }

  if (decl.declaration) {
    parts.push(path.call(print, "declaration"));
  } else if (decl.specifiers && decl.specifiers.length > 0) {
    if (
      decl.specifiers.length === 1 &&
        decl.specifiers[0].type === "ExportBatchSpecifier"
    ) {
    } else {
        decl.exportKind === "type" ? "type " : "",
        shouldPrintSpaces ? "{ " : "{",
        join(", ", path.map(print, "specifiers")),
        shouldPrintSpaces ? " }" : "}"
      );
    }

    if (decl.source) {
      parts.push(" from ", path.call(print, "source"));
    }
  }

}

function printFlowDeclaration(path, parts) {
  var parentExportDecl = util.getParentExportDeclaration(path);

  if (parentExportDecl) {
    assert.strictEqual(parentExportDecl.type, "DeclareExportDeclaration");
  } else {
    // If the parent node has type DeclareExportDeclaration, then it
    // will be responsible for printing the "declare" token. Otherwise
    // it needs to be printed with this non-exported declaration node.
    parts.unshift("declare ");
  }

}

function printClass(path, print) {
  const parts = [ "class" ];

  if (n.id) {
    parts.push(" ", path.call(print, "id"), path.call(print, "typeParameters"));
  }

  if (n.superClass) {
      " extends ",
      path.call(print, "superClass"),
      path.call(print, "superTypeParameters")
    );
  } else if (n.extends && n.extends.length > 0) {
    parts.push(" extends ", join(", ", path.map(print, "extends")));
  }

  if (n["implements"] && n["implements"].length > 0) {
      " implements ",
      join(", ", path.map(print, "implements"))
    );
  }

  parts.push(" ", path.call(print, "body"));

  return parts;
}

function printMemberLookup(path, print) {
  const property = path.call(print, "property");
  return concat(n.computed ? [ "[", property, "]" ] : [ ".", property ]);
}

function printMemberChain(node, options, print) {
  const nodes = [];
  let curr = node;
  // Traverse down and gather up all of the calls on member
  // expressions. This flattens it out into a list that we can
  // easily analyze.
  while (curr.type === "CallExpression" &&
    curr.callee.type === "MemberExpression") {
    nodes.push({property: curr.callee.property, call: curr});
    curr = curr.callee.object;
  }
  nodes.reverse();

  // There are two kinds of formats we want to specialize: first,
  // if there are multiple calls on lookups we want to group them
  // together so they will all break at the same time. Second,
  // it's a chain if there 2 or more calls pass in functions and
  // we want to forcibly break all of the lookups onto new lines
  // and indent them.
  function argIsFunction(call) {
    if (call.arguments.length > 0) {
      const type = call.arguments[0].type;
      return type === "FunctionExpression" ||
        type === "ArrowFunctionExpression" ||
        type === "NewExpression";
    }
  }
  const hasMultipleLookups = nodes.length > 1;
  const isChain = hasMultipleLookups &&
    nodes.filter(n => argIsFunction(n.call)).length > 1;

  if (hasMultipleLookups) {
    const currPrinted = print(FastPath.from(curr));
    const nodesPrinted = nodes.map(node => ({
      property: print(FastPath.from(node.property)),
      args: printArgumentsList(FastPath.from(node.call), options, print)
    }));
    const fullyExpanded = concat([
      currPrinted,
      concat(
        nodesPrinted.map(node => {
          return indent(
            concat([ hardline, ".", node.property, node.args ])
          );
        })
      )
    ]);

    // If it's a chain, force it to be fully expanded and print a
    // newline before each lookup. If we're not sure if it's a
    // chain (it *might* be printed on one line, but if gets too
    // long it will be printed as a chain), we need to use
    // `conditionalGroup` to describe both of these
    // representations. We cannot describe both at the same time
    // because the fully expanded form adds indentation, which
    // messes up anything with hard lines.
    if (isChain) {
      return fullyExpanded;
    } else {
      return conditionalGroup([
        concat([
          currPrinted,
          concat(
            nodesPrinted.map(node => {
              return concat([ ".", node.property, node.args ]);
            })
          )
        ]),
        fullyExpanded
      ]);
    }
  }
}

function argIsFunction(call) {
    }
  }

function adjustClause(clause, options, forceSpace) {
  if (isCurlyBracket(clause) || forceSpace) {
    return concat([ " ", clause ]);
  }

  return indent(options.tabWidth, concat([ hardline, clause ]));
}

function isCurlyBracket(doc) {
  const str = getFirstString(doc);
  return str === "{" || str === "{}";
}

function isEmptyBlock(doc) {
  return str === "{}";
}

function lastNonSpaceCharacter(lines) {
  var pos = lines.lastPos();
  do {
    var ch = lines.charAt(pos);

    if (/\S/.test(ch))
      return ch;
  } while (lines.prevPos(pos));
}

function swapQuotes(str) {
  return str.replace(/['"]/g, function(m) {
    return m === "\"" ? "'" : "\"";
  });
}

function nodeStr(str, options) {
  isString.assert(str);

  if (options.singleQuote) {
    return swapQuotes(JSON.stringify(swapQuotes(str)));
  } else {
    return JSON.stringify(str);
  }
}

function isFirstStatement(path) {
  const parent = path.getParentNode();
  const body = parent.body;
  return body && body[0] === node;
}

function isLastStatement(path) {
  return body && body[body.length - 1] === node;
}

  const jsx = isProbablyJsx(text);
  let ast;
  try {
    try {
      // Try passing with our best guess first.
      ast = tryParseTypeScript(text, jsx);
    } catch (e) {
      // But if we get it wrong, try the opposite.
      ast = tryParseTypeScript(text, !jsx);
    }
  } catch (e) /* istanbul ignore next */ {
    if (typeof e.lineNumber === "undefined") {
      throw e;
    }

    throw createError(e.message, {
      start: { line: e.lineNumber, column: e.column + 1 }
    });
  }

}

function tryParseTypeScript(text, jsx) {
  // While we are working on typescript, we are putting it in devDependencies
  // so it shouldn't be picked up by static analysis
  const parser = require("typescript-eslint-parser");
  return parser.parse(text, {
    loc: true,
    range: true,
    tokens: true,
    comment: true,
    useJSXTextNode: true,
    ecmaFeatures: { jsx },
    // Override logger function with noop,
    // to avoid unsupported version errors being logged
    loggerFn: () => {}
  });
}

function isProbablyJsx(text) {
  return new RegExp(
    [
      "(^[^\"'`]*</)", // Contains "</" when probably not in a string
      "|",
      "(^[^/]{2}.*/>)" // Contains "/>" on line not starting with "//"
    ].join(""),
    "m"
  ).test(text);
}

  assert(
    typeof val === "string" || val != null && typeof val.type === "string",
    "Value is a valid document"
  );
}

  parts.forEach(assertDoc);

  return {type: "concat", parts};
}

function indent(n, contents) {
  assertDoc(contents);

  return {type: "indent", contents, n};
}

  return {
  };
}

function multilineGroup(contents, opts) {
    contents,
    Object.assign(opts || {}, {shouldBreak: hasHardLine(contents)})
  );
}

  return group(states[0], Object.assign(opts || {}, {expandedStates: states}));
}

function ifBreak(contents) {
  return {type: "if-break", contents};
}

function iterDoc(topDoc, func) {
  const docs = [ topDoc ];
  while (docs.length !== 0) {
    const doc = docs.pop();
    let res = undefined;

      const res = func("string", doc);

      if (res) {
        return res;
      }
    } else {
      const res = func(doc.type, doc);

      if (res) {
      }

      if (doc.type === "concat") {
        for (var i = doc.parts.length - 1; i >= 0; i--) {
          docs.push(doc.parts[i]);
        }
      } else if (doc.type !== "line") {
        docs.push(doc.contents);
      }
    }
  }
}

  var res = [];

  for (var i = 0; i < arr.length; i++) {
    }

  }

}

function getFirstString(doc) {
  return iterDoc(doc, (type, doc) => {
    if (type === "string" && doc.trim().length !== 0) {
      return doc;
    }
  });
}

function hasHardLine(doc) {
  // TODO: If we hit a group, check if it's already marked as a
  // multiline group because they should be marked bottom-up.
  return !!iterDoc(doc, (type, doc) => {
    switch (type) {
    case "line":
      if (doc.hard) {
      }

      break;
    }
  });
}

function _makeIndent(n) {
  var s = "";

  for (var i = 0; i < n; i++) {
    s += " ";
  }

  return s;
}

function fits(next, restCommands, width) {
  const cmds = [ next ];
      } else {
        cmds.push(restCommands[restIdx - 1]);

        restIdx--;

        continue;
      }
    }

      width -= doc.length;
    } else {
      case "concat":
          cmds.push([ ind, mode, doc.parts[i] ]);
        }

        break;
      case "indent":
        cmds.push([ ind + doc.n, mode, doc.contents ]);

        break;
      case "group":
        cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]);

        break;
      case "if-break":
        if (mode === MODE_BREAK) {
          cmds.push([ ind, mode, doc.contents ]);
        }

        break;
      case "line":
        switch (mode) {
        // fallthrough
        case MODE_FLAT:
          if (!doc.hard) {
            if (!doc.soft) {
              width -= 1;
            }

            break;
          }

        case MODE_BREAK:
          return true;
        }
        break;
      }
    }
  }
}

function print(w, doc) {
  let pos = 0;
  let cmds = [ [ 0, MODE_BREAK, doc ] ];
  let out = [];

      pos += doc.length;
    } else {
        }

        break;

        break;
          if (!shouldRemeasure) {
            cmds.push([
              ind,
              doc.break ? MODE_BREAK : MODE_FLAT,
              doc.contents
            ]);

            break;
          }

          shouldRemeasure = false;

          const next = [ ind, MODE_FLAT, doc.contents ];
          let rem = w - pos;

          if (!doc.break && fits(next, cmds, rem)) {
            cmds.push(next);
          } else {
            // Expanded states are a rare case where a document
            // can manually provide multiple representations of
            // itself. It provides an array of documents
            // going from the least expanded (most flattened)
            // representation first to the most expanded. If a
            // group has these, we need to manually go through
            // these states and find the first one that fits.
            if (doc.expandedStates) {
              const mostExpanded = doc.expandedStates[doc.expandedStates.length -
                1];

              if (doc.break) {
                cmds.push([ ind, MODE_BREAK, mostExpanded ]);

                break;
              } else {
                for (var i = 1; i < doc.expandedStates.length + 1; i++) {
                  if (i >= doc.expandedStates.length) {
                    cmds.push([ ind, MODE_BREAK, mostExpanded ]);

                    break;
                  } else {
                    const state = doc.expandedStates[i];
                    const cmd = [ ind, MODE_FLAT, state ];

                    if (fits(cmd, cmds, rem)) {
                      cmds.push(cmd);

                      break;
                    }
                  }
                }
              }
            } else {
              cmds.push([ ind, MODE_BREAK, doc.contents ]);
            }
          }

          break;
        }
        break;
          cmds.push([ ind, MODE_BREAK, doc.contents ]);
        }

        break;
              out.push(" ");

              pos += 1;
            }

            break;
          } else {
            // This line was forced into the output even if we
            // were in flattened mode, so we need to tell the next
            // group that no matter what, it needs to remeasure
            // because the previous measurement didn't accurately
            // capture the entire expression (this is necessary
            // for nested groups)
            shouldRemeasure = true;
          }

          if (out.length > 0) {
            const lastString = out[out.length - 1];

            if (lastString.match(/^\s*\n\s*$/)) {
              out[out.length - 1] = "\n";
            }
          }

          if (doc.literal) {
            out.push("\n");

            pos = 0;
          } else {
            out.push("\n" + _makeIndent(ind));

            pos = ind;
          }

          break;
        }
        break;
      default:
      }
    }
  }
  return out.join("");
}

function printSubtree(path, print, options) {
    case "parse5":
      return fromHtmlParser2(path, print, options);
    case "babylon":
      return fromBabylonFlowOrTypeScript(path, print, options);
      return fromMarkdown(path, print, options);
  }
}

function parseAndPrint(text, partialNextOptions, parentOptions) {
  const nextOptions = Object.assign({}, parentOptions, partialNextOptions, {
    parentParser: parentOptions.parser,
    trailingComma:
      partialNextOptions.parser === "json"
        ? "none"
        : partialNextOptions.trailingComma,
    originalText: text
  });
  const ast = require("./parser").parse(text, nextOptions);
  const astComments = ast.comments;
  delete ast.comments;
  comments.attach(astComments, ast, text, nextOptions);
  return require("./printer").printAstToDoc(ast, nextOptions);
}

function fromMarkdown(path, print, options) {

  if (node.type === "code") {
    const parser = getParserName(node.lang);
    if (parser) {
      const styleUnit = options.__inJsTemplate ? "~" : "`";
      const style = styleUnit.repeat(
        Math.max(3, util.getMaxContinuousCount(node.value, styleUnit) + 1)
      );
      const doc = parseAndPrint(node.value, { parser }, options);
      return concat([style, node.lang, hardline, doc, style]);
    }
  }

  function getParserName(lang) {
    switch (lang) {
      case "js":
      case "jsx":
      case "javascript":
        return "babylon";
      case "ts":
      case "tsx":
      case "typescript":
        return "typescript";
      case "gql":
      case "graphql":
        return "graphql";
      case "css":
        return "css";
      case "less":
        return "less";
      case "scss":
        return "scss";
      case "json":
      case "json5":
        return "json";
      case "md":
      case "markdown":
        return "markdown";
      default:
        return null;
    }
  }
}

function getParserName(lang) {
      case "js":
      case "ts":
      case "md":
      default:
    }
  }

function fromBabylonFlowOrTypeScript(path, print, options) {
  const parentParent = path.getParentNode(1);

  switch (node.type) {
    case "TemplateLiteral": {
      const isCss = [isStyledJsx, isStyledComponents].some(isIt => isIt(path));

      if (isCss) {
        // Get full template literal with expressions replaced by placeholders
        const rawQuasis = node.quasis.map(q => q.value.raw);
        const text = rawQuasis.join("@prettier-placeholder");
        const doc = parseAndPrint(text, { parser: "css" }, options);
        return transformCssDoc(doc, path, print);
      }

      /*
       * react-relay and graphql-tag
       * graphql`...`
       * graphql.experimental`...`
       * gql`...`
       */
      if (
        parent &&
        ((parent.type === "TaggedTemplateExpression" &&
          ((parent.tag.type === "MemberExpression" &&
            parent.tag.object.name === "graphql" &&
            parent.tag.property.name === "experimental") ||
            (parent.tag.type === "Identifier" &&
              (parent.tag.name === "gql" || parent.tag.name === "graphql")))) ||
          (parent.type === "CallExpression" &&
            parent.callee.type === "Identifier" &&
            parent.callee.name === "graphql"))
      ) {
        const expressionDocs = node.expressions
          ? path.map(print, "expressions")
          : [];

        const numQuasis = node.quasis.length;

        if (numQuasis === 1 && node.quasis[0].value.raw.trim() === "") {
          return "``";
        }

        const parts = [];

        for (let i = 0; i < numQuasis; i++) {
          const templateElement = node.quasis[i];
          const isFirst = i === 0;
          const isLast = i === numQuasis - 1;
          const text = templateElement.value.raw;
          const lines = text.split("\n");
          const numLines = lines.length;
          const expressionDoc = expressionDocs[i];

          const startsWithBlankLine =
            numLines > 2 && lines[0].trim() === "" && lines[1].trim() === "";
          const endsWithBlankLine =
            numLines > 2 &&
            lines[numLines - 1].trim() === "" &&
            lines[numLines - 2].trim() === "";

          const commentsAndWhitespaceOnly = lines.every(line =>
            /^\s*(?:#[^\r\n]*)?$/.test(line)
          );

          // Bail out if an interpolation occurs within a comment.
          if (!isLast && /#[^\r\n]*$/.test(lines[numLines - 1])) {
            return null;
          }

          let doc = null;

          if (commentsAndWhitespaceOnly) {
            doc = printGraphqlComments(lines);
          } else {
            try {
              doc = stripTrailingHardline(
                parseAndPrint(text, { parser: "graphql" }, options)
              );
            } catch (_error) {
              // Bail if any part fails to parse.
              return null;
            }
          }

          if (doc) {
            if (!isFirst && startsWithBlankLine) {
              parts.push("");
            }
            parts.push(doc);
            if (!isLast && endsWithBlankLine) {
            }
          } else if (!isFirst && !isLast && startsWithBlankLine) {
            parts.push("");
          }

          if (expressionDoc) {
            parts.push(concat(["${", expressionDoc, "}"]));
          }
        }

        return concat([
          "`",
          indent(concat([hardline, join(hardline, parts)])),
          hardline,
          "`"
        ]);
      }

      break;
    }

    case "TemplateElement": {
      /**
       * md`...`
       * markdown`...`
       */
      if (
        parentParent &&
        (parentParent.type === "TaggedTemplateExpression" &&
          parent.quasis.length === 1 &&
          (parentParent.tag.type === "Identifier" &&
            (parentParent.tag.name === "md" ||
              parentParent.tag.name === "markdown")))
      ) {
        const doc = parseAndPrint(
          // leading whitespaces matter in markdown
          dedent(parent.quasis[0].value.cooked),
          {
            parser: "markdown",
            __inJsTemplate: true
          },
          options
        );
          indent(
            concat([softline, stripTrailingHardline(escapeBackticks(doc))])
          ),
          softline
        ]);
      }

      break;
    }
  }
}

function printGraphqlComments(lines) {
  const parts = [];
  let seenComment = false;

  lines.map(textLine => textLine.trim()).forEach((textLine, i, array) => {
    // Lines are either whitespace only, or a comment (with poential whitespace
    // around it). Drop whitespace-only lines.
    if (textLine === "") {
      return;
    }

    if (array[i - 1] === "" && seenComment) {
      // If a non-first comment is preceded by a blank (whitespace only) line,
      // add in a blank line.
      parts.push(concat([hardline, textLine]));
    } else {
      parts.push(textLine);
    }

    seenComment = true;
  });

  // If `lines` was whitespace only, return `null`.
  return parts.length === 0 ? null : join(hardline, parts);
}

  const firstMatchedIndent = str.match(/\n^( *)/m);
  const spaces = firstMatchedIndent === null ? 0 : firstMatchedIndent[1].length;
}

function escapeBackticks(doc) {
  return util.mapDoc(doc, currentDoc => {
    if (!currentDoc.parts) {
      return currentDoc;
    }

    currentDoc.parts.forEach(part => {
      if (typeof part === "string") {
        parts.push(part.replace(/`/g, "\\`"));
      } else {
        parts.push(part);
      }
    });

    return Object.assign({}, currentDoc, { parts });
  });
}

function fromHtmlParser2(path, print, options) {

      // Inline JavaScript
      if (
        parent.type === "script" &&
        ((!parent.attribs.lang && !parent.attribs.lang) ||
          parent.attribs.type === "text/javascript" ||
          parent.attribs.type === "application/javascript")
      ) {
        const parser = options.parser === "flow" ? "flow" : "babylon";
        const doc = parseAndPrint(getText(options, node), { parser }, options);
        return concat([hardline, doc]);
      }

      // Inline TypeScript
      if (
        (parent.attribs.type === "application/x-typescript" ||
          parent.attribs.lang === "ts")
      ) {
          getText(options, node),
          { parser: "typescript" },
          options
        );
      }

      // Inline Styles
      if (parent.type === "style") {
          { parser: "css" },
          options
        );
        return concat([hardline, stripTrailingHardline(doc)]);
      }

      break;
    }

      /*
       * Vue binding sytax: JS expressions
       * :class="{ 'some-key': value }"
       * v-bind:id="'list-' + id"
       * v-if="foo && !bar"
       * @click="someFunction()"
       */
      if (/(^@)|(^v-)|:/.test(node.key) && !/^\w+$/.test(node.value)) {
          node.value,
          {
            parser: parseJavaScriptExpression,
            // Use singleQuote since HTML attributes use double-quotes.
            // TODO(azz): We still need to do an entity escape on the attribute.
            singleQuote: true
          },
          options
        );
          node.key,
          '="',
          util.hasNewlineInRange(node.value, 0, node.value.length)
            ? doc
            : docUtils.removeLines(doc),
          '"'
        ]);
      }
    }
  }
}

function transformCssDoc(quasisDoc, path, print) {
  const parentNode = path.getValue();

  const isEmpty =
    parentNode.quasis.length === 1 && !parentNode.quasis[0].value.raw.trim();
  if (isEmpty) {
    return "``";
  }

  const expressionDocs = parentNode.expressions
    ? path.map(print, "expressions")
    : [];
  const newDoc = replacePlaceholders(quasisDoc, expressionDocs);
  if (!newDoc) {
    throw new Error("Couldn't insert all the expressions");
  }
    "`",
    indent(concat([hardline, stripTrailingHardline(newDoc)])),
    softline,
    "`"
  ]);
}

function replacePlaceholders(quasisDoc, expressionDocs) {
  if (!expressionDocs || !expressionDocs.length) {
    return quasisDoc;
  }

  const expressions = expressionDocs.slice();
  const newDoc = docUtils.mapDoc(quasisDoc, doc => {
    if (!doc || !doc.parts || !doc.parts.length) {
    }
    let parts = doc.parts;
    if (
      parts.length > 1 &&
      parts[0] === "@" &&
      typeof parts[1] === "string" &&
      parts[1].startsWith("prettier-placeholder")
    ) {
      // If placeholder is split, join it
      const at = parts[0];
      const placeholder = parts[1];
      const rest = parts.slice(2);
      parts = [at + placeholder].concat(rest);
    }
    if (
      typeof parts[0] === "string" &&
      parts[0].startsWith("@prettier-placeholder")
    ) {
      const placeholder = parts[0];
      const rest = parts.slice(1);

      // When the expression has a suffix appended, like:
      // animation: linear ${time}s ease-out;
      const suffix = placeholder.slice("@prettier-placeholder".length);

      const expression = expressions.shift();
      parts = ["${", expression, "}" + suffix].concat(rest);
    }
      parts: parts
    });
  });

  return expressions.length === 0 ? newDoc : null;
}

function parseJavaScriptExpression(text, parsers) {
  // Force parsing as an expression
  const ast = parsers.babylon(`(${text})`);
  // Extract expression from the declaration
  return {
    type: "File",
    program: ast.program.body[0].expression
  };
}

function getText(options, node) {
  return options.originalText.slice(util.locStart(node), util.locEnd(node));
}

function stripTrailingHardline(doc) {
  // HACK remove ending hardline, original PR: #1984
  if (
    doc.type === "concat" &&
    doc.parts[0].type === "concat" &&
    doc.parts[0].parts.length === 2 &&
    // doc.parts[0].parts[1] === hardline :
    doc.parts[0].parts[1].type === "concat" &&
    doc.parts[0].parts[1].parts.length === 2 &&
    doc.parts[0].parts[1].parts[0].hard &&
    doc.parts[0].parts[1].parts[1].type === "break-parent"
  ) {
    return doc.parts[0].parts[0];
  }
}

function isStyledJsx(path) {
  return (
    parentParent &&
    node.quasis &&
    parent.type === "JSXExpressionContainer" &&
    parentParent.type === "JSXElement" &&
    parentParent.openingElement.name.name === "style" &&
    parentParent.openingElement.attributes.some(
      attribute => attribute.name.name === "jsx"
    )
  );
}

function isStyledComponents(path) {

  if (!parent || parent.type !== "TaggedTemplateExpression") {
  }

  const tag = parent.tag;

  switch (tag.type) {
    case "MemberExpression":
      return (
        // styled.foo``
        isStyledIdentifier(tag.object) ||
        // Component.extend``
        (/^[A-Z]/.test(tag.object.name) && tag.property.name === "extend")
      );

    case "CallExpression":
      return (
        // styled(Component)``
        isStyledIdentifier(tag.callee) ||
        (tag.callee.type === "MemberExpression" &&
          // styled.foo.attr({})``
          ((tag.callee.object.type === "MemberExpression" &&
            isStyledIdentifier(tag.callee.object.object)) ||
            // styled(Component).attr({})``
            (tag.callee.object.type === "CallExpression" &&
              isStyledIdentifier(tag.callee.object.callee))))
      );

    case "Identifier":
      // css``
      return tag.name === "css";

    default:
  }
}

function isStyledIdentifier(node) {
  return node.type === "Identifier" && node.name === "styled";
}

function run(args) {
  const rawArgv = minimist(args, constant.minimistOptions);

  process.env[logger.ENV_LOG_LEVEL] =
    rawArgv["loglevel"] || constant.detailedOptionMap["loglevel"].default;

  const argv = util.normalizeConfig("cli", rawArgv);

  logger.debug(`normalized argv: ${JSON.stringify(argv)}`);

  argv.__args = args;
  argv.__filePatterns = argv["_"];

  validator.validateArgv(argv);

  if (argv["version"]) {
    console.log(prettier.version);
    process.exit(0);
  }

  if (argv["help"] !== undefined) {
    console.log(
      typeof argv["help"] === "string" && argv["help"] !== ""
        ? util.createDetailedUsage(argv["help"])
        : util.createUsage()
    );
  }

  if (argv["support-info"]) {
      prettier.format(JSON.stringify(prettier.getSupportInfo()), {
        parser: "json"
      })
    );
  }

  const hasFilePatterns = argv.__filePatterns.length !== 0;
  const useStdin = argv["stdin"] || (!hasFilePatterns && !process.stdin.isTTY);

  if (argv["find-config-path"]) {
    util.logResolvedConfigPathOrDie(argv["find-config-path"]);
  } else if (useStdin) {
    util.formatStdin(argv);
  } else if (hasFilePatterns) {
    util.formatFiles(argv);
  } else {
    console.log(util.createUsage());
  }
}

  if (!n) {
    return "";
  }

    return n;
  }

    case "css-root": {
      return concat([printNodeSequence(path, options, print), hardline]);
    }
    case "css-comment": {
      if (n.raws.content) {
        return n.raws.content;
      }
      const text = options.originalText.slice(util.locStart(n), util.locEnd(n));
      const rawText = n.raws.text || n.text;
      // Workaround a bug where the location is off.
      // https://github.com/postcss/postcss-scss/issues/63
      if (text.indexOf(rawText) === -1) {
        if (n.raws.inline) {
          return concat(["// ", rawText]);
        }
        return concat(["/* ", rawText, " */"]);
      }
      return text;
    }
    case "css-rule": {
        path.call(print, "selector"),
        n.important ? " !important" : "",
        n.nodes
          ? concat([
              " {",
              n.nodes.length > 0
                ? indent(
                    concat([hardline, printNodeSequence(path, options, print)])
                  )
                : "",
              hardline,
              "}"
            ])
          : ";"
      ]);
    }
    case "css-decl": {
      // When the following less construct &:extend(.foo); is parsed with scss,
      // it will put a space after `:` and break it. Ideally we should parse
      // less files with less, but we can hardcode this to work with scss as
      // well.
      const isValueExtend =
        n.value.type === "value-root" &&
        n.value.group.type === "value-value" &&
        n.value.group.group.type === "value-func" &&
        n.value.group.group.value === "extend";
      const isComposed =
        n.prop === "composes";

        n.raws.before.replace(/[\s;]/g, ""),
        maybeToLowerCase(n.prop),
        ":",
        isValueExtend ? "" : " ",
        isComposed
          ? removeLines(path.call(print, "value"))
          : path.call(print, "value"),
        n.nodes
          ? concat([
              " {",
              indent(
                concat([softline, printNodeSequence(path, options, print)])
              ),
              softline,
              "}"
            ])
          : ";"
      ]);
    }
    case "css-atrule": {
      const hasParams =
        n.params &&
        !(n.params.type === "media-query-list" && n.params.value === "");
      const isDetachedRulesetCall =
        hasParams &&
        n.params.type === "media-query-list" &&
        /^\(\s*\)$/.test(n.params.value);
        "@",
        // If a Less file ends up being parsed with the SCSS parser, Less
        // variable declarations will be parsed as atrules with names ending
        // with a colon, so keep the original case then.
        isDetachedRulesetCall || n.name.endsWith(":")
          ? n.name
          : maybeToLowerCase(n.name),
        hasParams
          ? concat([
              isDetachedRulesetCall ? "" : " ",
              path.call(print, "params")
            ])
          : "",
        n.nodes
          ? concat([
              " {",
              indent(
                concat([
                  n.nodes.length > 0 ? softline : "",
                  printNodeSequence(path, options, print)
                ])
              ),
              softline,
              "}"
            ])
          : ";"
      ]);
    }
    case "css-import": {
        "@",
        maybeToLowerCase(n.name),
        " ",
        n.directives ? concat([n.directives, " "]) : "",
        adjustStrings(n.importPath, options),
        n.nodes.length > 0
          ? concat([
              " {",
              indent(
              ),
              softline,
              "}"
            ])
          : ";"
      ]);
    }
    // postcss-media-query-parser
    case "media-query-list": {
      const parts = [];
      path.each(childPath => {
        const node = childPath.getValue();
        if (node.type === "media-query" && node.value === "") {
          return;
        }
        parts.push(childPath.call(print));
      }, "nodes");
      return group(indent(join(concat([",", line]), parts)));
    }
    case "media-query": {
      return join(" ", path.map(print, "nodes"));
    }
    case "media-type": {
      const parent = path.getParentNode(2);
      if (
        parent.type === "css-atrule" &&
        parent.name.toLowerCase() === "charset"
      ) {
        return n.value;
      }
      return adjustNumbers(adjustStrings(n.value, options));
    }
    case "media-feature-expression": {
      if (!n.nodes) {
      }
      return concat(["(", concat(path.map(print, "nodes")), ")"]);
    }
    case "media-feature": {
      return maybeToLowerCase(
        adjustStrings(n.value.replace(/ +/g, " "), options)
      );
    }
    case "media-colon": {
      return concat([n.value, " "]);
    }
    case "media-value": {
    }
    case "media-keyword": {
      return adjustStrings(n.value, options);
    }
    case "media-url": {
    }
    case "media-unknown": {
    }
    // postcss-selector-parser
    case "selector-root-invalid": {
      // This is likely a SCSS nested property: `background: { color: red; }`.
      return adjustNumbers(adjustStrings(maybeToLowerCase(n.value), options));
    }
    case "selector-root": {
      return group(join(concat([",", hardline]), path.map(print, "nodes")));
    }
    case "selector-comment": {
    }
    case "selector-string": {
    }
    case "selector-tag": {
      return adjustNumbers(n.value);
    }
    case "selector-id": {
      return concat(["#", n.value]);
    }
    case "selector-class": {
      return concat([".", adjustNumbers(adjustStrings(n.value, options))]);
    }
    case "selector-attribute": {
        "[",
        n.attribute,
        n.operator ? n.operator : "",
        n.value
          ? quoteAttributeValue(adjustStrings(n.value, options), options)
          : "",
        n.insensitive ? " i" : "",
        "]"
      ]);
    }
    case "selector-combinator": {
      if (n.value === "+" || n.value === ">" || n.value === "~") {
        const parent = path.getParentNode();
        const leading =
          parent.type === "selector-selector" && parent.nodes[0] === n
            ? ""
            : line;
        return concat([leading, n.value, " "]);
      }
      const leading = n.value.trim().startsWith("(") ? line : "";
      const value =
        adjustNumbers(adjustStrings(n.value.trim(), options)) || line;
      return concat([leading, value]);
    }
    case "selector-universal": {
    }
    case "selector-selector": {
      return group(indent(concat(path.map(print, "nodes"))));
    }
    case "selector-pseudo": {
        maybeToLowerCase(n.value),
        n.nodes && n.nodes.length > 0
          ? concat(["(", join(", ", path.map(print, "nodes")), ")"])
          : ""
      ]);
    }
    case "selector-nesting": {
      return printValue(n.value);
    }
    // postcss-values-parser
    case "value-root": {
      return path.call(print, "group");
    }
    case "value-comma_group": {
      let declParent;
      let i = 0;
      do {
        declParent = path.getParentNode(i++);
      } while (declParent && declParent.type !== "css-decl");

      const declParentProp = declParent.prop.toLowerCase();
      const isGridValue =
        parent.type === "value-value" &&
        (declParentProp === "grid" ||
          declParentProp.startsWith("grid-template"));

      const printed = path.map(print, "groups");
      let didBreak = false;
      for (let i = 0; i < n.groups.length; ++i) {
        parts.push(printed[i]);
        if (
          i !== n.groups.length - 1 &&
          n.groups[i + 1].raws &&
          n.groups[i + 1].raws.before !== ""
        ) {
          if (isGridValue) {
            if (
              n.groups[i].source.start.line !==
              n.groups[i + 1].source.start.line
            ) {
              parts.push(hardline);
              didBreak = true;
            } else {
              parts.push(" ");
            }
          } else if (
            n.groups[i + 1].type === "value-operator" &&
            ["+", "-", "/", "*", "%"].indexOf(n.groups[i + 1].value) !== -1
          ) {
            parts.push(" ");
          } else {
            parts.push(line);
          }
        }
      }

      if (didBreak) {
        parts.unshift(hardline);
      }

      return group(indent(fill(parts)));
    }
    case "value-paren_group": {
      const isURLCall =
        parent && parent.type === "value-func" && parent.value === "url";

      if (
        isURLCall &&
        (n.groups.length === 1 ||
          (n.groups.length > 0 &&
            n.groups[0].type === "value-comma_group" &&
            n.groups[0].groups.length > 0 &&
            n.groups[0].groups[0].type === "value-word" &&
            n.groups[0].groups[0].value === "data"))
      ) {
          n.open ? path.call(print, "open") : "",
          join(",", path.map(print, "groups")),
          n.close ? path.call(print, "close") : ""
        ]);
      }

      if (!n.open) {
        const printed = path.map(print, "groups");
        const res = [];

        for (let i = 0; i < printed.length; i++) {
          if (i !== 0) {
            res.push(concat([",", line]));
          }
          res.push(printed[i]);
        }
        return group(indent(fill(res)));
      }

      const declaration = path.getParentNode(2);
      const isMap =
        declaration &&
        declaration.type === "css-decl" &&
        declaration.prop.startsWith("$");

        concat([
          indent(
            concat([
              softline,
              join(
                concat([",", isMap ? hardline : line]),
                path.map(print, "groups")
              )
            ])
          ),
          softline,
        ])
      );
    }
    case "value-value": {
    }
    case "value-func": {
      return concat([n.value, path.call(print, "group")]);
    }
    case "value-paren": {
      if (n.raws.before !== "") {
        return concat([line, n.value]);
      }
    }
    case "value-number": {
      return concat([printNumber(n.value), maybeToLowerCase(n.unit)]);
    }
    case "value-operator": {
    }
    case "value-word": {
      if (n.isColor && n.isHex) {
        return n.value.toLowerCase();
      }
    }
    case "value-colon": {
    }
    case "value-comma": {
    }
    case "value-string": {
      return util.printString(n.raws.quote + n.value + n.raws.quote, options);
    }
    case "value-atword": {
      return concat(["@", n.value]);
    }

    default:
      throw new Error("unknown postcss type: " + JSON.stringify(n.type));
  }
}

function printNodeSequence(path, options, print) {
  let i = 0;
  path.map(pathChild => {
    const prevNode = node.nodes[i - 1];
    if (
      prevNode &&
      prevNode.type === "css-comment" &&
      prevNode.text.trim() === "prettier-ignore"
    ) {
      const childNode = pathChild.getValue();
        options.originalText.slice(
          util.locStart(childNode),
          util.locEnd(childNode)
        )
      );
    } else {
      parts.push(pathChild.call(print));
    }

    if (i !== node.nodes.length - 1) {
      if (
        (node.nodes[i + 1].type === "css-comment" &&
          !util.hasNewline(
            options.originalText,
            util.locStart(node.nodes[i + 1]),
            { backwards: true }
          )) ||
        (node.nodes[i + 1].type === "css-atrule" &&
          node.nodes[i + 1].name === "else" &&
          node.nodes[i].type !== "css-comment")
      ) {
        parts.push(" ");
      } else {
        parts.push(hardline);
        if (util.isNextLineEmpty(options.originalText, pathChild.getValue())) {
          parts.push(hardline);
        }
      }
    }
    i++;
  }, "nodes");

}

function adjustStrings(value, options) {
  return value.replace(STRING_REGEX, match => util.printString(match, options));
}

function quoteAttributeValue(value, options) {
  const quote = options.singleQuote ? "'" : '"';
  return value.includes('"') || value.includes("'")
    ? value
    : quote + value + quote;
}

function adjustNumbers(value) {
  return value.replace(
    ADJUST_NUMBERS_REGEX,
    (match, quote, wordPart, number, unit) =>
      !wordPart && number
        ? (wordPart || "") + printNumber(number) + maybeToLowerCase(unit || "")
        : match
  );
}

function printNumber(rawNumber) {
  return (
    util
      .printNumber(rawNumber)
      // Remove trailing `.0`.
      .replace(/\.0(?=$|e)/, "")
  );
}

function maybeToLowerCase(value) {
  return value.includes("$") ||
    value.includes("@") ||
    value.includes("#") ||
    value.startsWith("%") ||
    value.startsWith("--")
    ? value
    : value.toLowerCase();
}

  const processor = unified()
    .use(remarkParse, { footnotes: true, commonmark: true })
    .use(remarkFrontmatter, ["yaml", "toml"])
    .use(restoreUnescapedCharacter(text))
    .use(mergeContinuousTexts)
    .use(transformInlineCode)
    .use(splitText);
  return processor.runSync(processor.parse(text));
}

function map(ast, handler) {
  return (function preorder(node, index, parentNode) {
    const newNode = Object.assign({}, handler(node, index, parentNode));
    if (newNode.children) {
      newNode.children = newNode.children.map((child, index) => {
        return preorder(child, index, newNode);
      });
    }
    return newNode;
  })(ast, null, null);
}

function transformInlineCode() {
  return ast =>
    map(ast, node => {
      if (node.type !== "inlineCode") {
        return node;
      }

      return Object.assign({}, node, {
        value: node.value.replace(/\s+/g, " ")
      });
    });
}

function restoreUnescapedCharacter(originalText) {
  return () => ast =>
      return node.type !== "text"
        ? node
        : Object.assign({}, node, {
            value:
              node.value !== "*" &&
              node.value !== "_" && // handle these two cases in printer
              node.value.length === 1 &&
              node.position.end.offset - node.position.start.offset > 1
                ? originalText.slice(
                    node.position.start.offset,
                    node.position.end.offset
                  )
                : node.value
          });
    });
}

function mergeContinuousTexts() {
      if (!node.children) {
      }
      const children = node.children.reduce((current, child) => {
        const lastChild = current[current.length - 1];
        if (lastChild && lastChild.type === "text" && child.type === "text") {
          current.splice(-1, 1, {
            type: "text",
            value: lastChild.value + child.value,
            position: {
              start: lastChild.position.start,
              end: child.position.end
            }
          });
        } else {
          current.push(child);
        }
        return current;
      }, []);
      return Object.assign({}, node, { children });
    });
}

function splitText() {
    map(ast, (node, index, parentNode) => {
      if (node.type !== "text") {
      }

      let value = node.value;

      if (parentNode.type === "paragraph") {
        if (index === 0) {
          value = value.trimLeft();
        }
        if (index === parentNode.children.length - 1) {
          value = value.trimRight();
        }
      }

      return {
        type: "sentence",
        position: node.position,
        children: util.splitText(value)
      };
    });
}

function createLogger(loggerName, color) {
  const prefix = `[${chalk[color](loggerName)}] `;
  return function(message) {
    if (shouldLog(loggerName)) {
      console.error(message.replace(/^/gm, prefix).replace(/[\t ]+$/gm, ""));
    }
  };
}

function shouldLog(loggerName) {
  const logLevel = process.env[ENV_LOG_LEVEL];

  switch (logLevel) {
    case "silent":
    default:
      return true;
    case "debug":
      if (loggerName === "debug") {
      }
    // fall through
    case "warn":
      if (loggerName === "warn") {
      }
    case "error":
      return loggerName === "error";
  }
}

result => {
      if (result && result.config) {
        delete result.config.$schema;
      }
      return result;
    }

  // Normalize opts before passing to a memoized function
  opts = Object.assign({ sync: false, cache: false }, opts);
  return getExplorerMemoized(opts).load;
}

function resolveConfig(filePath, opts) {
  opts = Object.assign({ useCache: true }, opts);
  const load = getLoadFunction({ cache: !!opts.useCache, sync: false });
  return load(filePath, opts.config).then(result => {
    return !result ? null : mergeOverrides(result, filePath);
  });
}

filePath => {
  const load = getLoadFunction({ sync: true });
  const result = load(filePath);
  return result ? result.filepath : null;
}

function resolveConfigFile(filePath) {
  const load = getLoadFunction({ sync: false });
  return load(filePath).then(result => {
    return result ? result.filepath : null;
  });
}

function mergeOverrides(configResult, filePath) {
  const options = Object.assign({}, configResult.config);
  if (filePath && options.overrides) {
    const relativeFilePath = path.relative(
      path.dirname(configResult.filepath),
      filePath
    );
    for (const override of options.overrides) {
      if (
        pathMatchesGlobs(
          relativeFilePath,
          override.files,
          override.excludeFiles
        )
      ) {
        Object.assign(options, override.options);
      }
    }
  }

  delete options.overrides;
  return options;
}

function pathMatchesGlobs(filePath, patterns, excludedPatterns) {
  const patternList = [].concat(patterns);
  const excludedPatternList = [].concat(excludedPatterns || []);
  const opts = { matchBase: true };

  return (
    patternList.some(pattern => minimatch(filePath, pattern, opts)) &&
    !excludedPatternList.some(excludedPattern =>
      minimatch(filePath, excludedPattern, opts)
    )
  );
}

function validateArgv(argv) {
  if (argv["write"] && argv["debug-check"]) {
    logger.error("Cannot use --write and --debug-check together.");
  }

  if (argv["find-config-path"] && argv.__filePatterns.length) {
    logger.error("Cannot use --find-config-path with multiple files");
  }
}

function getOptionName(type, option) {
  return type === "cli" ? `--${option.name}` : camelCase(option.name);
}

function validateIntOption(type, value, option) {
  if (!/^\d+$/.test(value) || (type === "api" && typeof value !== "number")) {
    const optionName = getOptionName(type, option);
      `Invalid ${optionName} value.\n` +
        `Expected an integer, but received: ${JSON.stringify(value)}`
    );
  }
}

function validateChoiceOption(type, value, option) {
  if (!option.choices.some(choice => choice.value === value)) {
      `Invalid option for ${optionName}.\n` +
        `Expected ${getJoinedChoices()}, but received: ${JSON.stringify(value)}`
    );
  }

  function getJoinedChoices() {
    const choices = option.choices
      .filter(choice => !choice.deprecated)
      .map(choice => `"${choice.value}"`);
    const head = choices.slice(0, -2);
    const tail = choices.slice(-2);
    return head.concat(tail.join(" or ")).join(", ");
  }
}

function getJoinedChoices() {
  }

function createError(message, loc) {
  // Construct an error similar to the ones thrown by Babylon.
  const error = new SyntaxError(
    message + " (" + loc.start.line + ":" + loc.start.column + ")"
  );
  error.loc = loc;
  return error;
}

  if (shouldRemainTheSameContent(path)) {
    return concat(
      util
        .splitText(
          options.originalText.slice(
            node.position.start.offset,
            node.position.end.offset
          )
        )
        .map(
          node =>
            node.type === "word"
              ? node.value
              : node.value === "" ? "" : printLine(path, node.value, options)
        )
    );
  }

    case "root":
        normalizeDoc(printChildren(path, options, print)),
        hardline
      ]);
    case "paragraph":
      return printChildren(path, options, print, {
        postprocessor: fill
      });
    case "sentence":
      return printChildren(path, options, print);
    case "word":
      return node.value
        .replace(/[*]/g, "\\*") // escape all `*`
        .replace(
          new RegExp(
            [
              `(^|[${util.punctuationCharRange}])(_+)`,
              `(_+)([${util.punctuationCharRange}]|$)`
            ].join("|"),
            "g"
          ),
          (_, text1, underscore1, underscore2, text2) =>
            (underscore1
              ? `${text1}${underscore1}`
              : `${underscore2}${text2}`
            ).replace(/_/g, "\\_")
        ); // escape all `_` except concating with non-punctuation, e.g. `1_2_3` is not considered emphasis
    case "whitespace": {
      const parentNode = path.getParentNode();
      const index = parentNode.children.indexOf(node);
      const nextNode = parentNode.children[index + 1];

      const proseWrap =
        // leading char that may cause different syntax
        nextNode && /^>|^([-+*]|#{1,6}|[0-9]+[.)])$/.test(nextNode.value)
          ? "never"
          : options.proseWrap;

      return printLine(path, node.value, { proseWrap });
    }
    case "emphasis": {
      const prevNode = parentNode.children[index - 1];
      const hasPrevOrNextWord = // `1*2*3` is considered emphais but `1_2_3` is not
        (prevNode &&
          prevNode.type === "sentence" &&
          prevNode.children.length > 0 &&
          util.getLast(prevNode.children).type === "word" &&
          !util.getLast(prevNode.children).hasTrailingPunctuation) ||
        (nextNode &&
          nextNode.type === "sentence" &&
          nextNode.children.length > 0 &&
          nextNode.children[0].type === "word" &&
          !nextNode.children[0].hasLeadingPunctuation);
      const style =
        hasPrevOrNextWord || getAncestorNode(path, "emphasis") ? "*" : "_";
      return concat([style, printChildren(path, options, print), style]);
    }
    case "strong":
      return concat(["**", printChildren(path, options, print), "**"]);
    case "delete":
      return concat(["~~", printChildren(path, options, print), "~~"]);
    case "inlineCode": {
      const backtickCount = util.getMaxContinuousCount(node.value, "`");
      const style = backtickCount === 1 ? "``" : "`";
      const gap = backtickCount ? " " : "";
      return concat([style, gap, node.value, gap, style]);
    }
    case "link":
      switch (options.originalText[node.position.start.offset]) {
        case "<":
          return concat(["<", node.url, ">"]);
        case "[":
          return concat([
            "[",
            printChildren(path, options, print),
            "](",
            printUrl(node.url, ")"),
            node.title ? ` ${printTitle(node.title)}` : "",
            ")"
          ]);
        default:
          return options.originalText.slice(
          );
      }
    case "image":
        "![",
        node.alt || "",
        "](",
        printUrl(node.url, ")"),
        node.title ? ` ${printTitle(node.title)}` : "",
        ")"
      ]);
    case "blockquote":
      return concat(["> ", align("> ", printChildren(path, options, print))]);
    case "heading":
        "#".repeat(node.depth) + " ",
        printChildren(path, options, print)
      ]);
    case "code": {
      if (
        // the first char may point to `\n`, e.g. `\n\t\tbar`, just ignore it
        /^\n?( {4,}|\t)/.test(
          )
        )
      ) {
        // indented code block
        const alignment = " ".repeat(4);
        return align(
          alignment,
          concat([alignment, join(hardline, node.value.split("\n"))])
        );
      }

      // fenced code block
      );
        style,
        node.lang || "",
        hardline,
        join(hardline, node.value.split("\n")),
        hardline,
        style
      ]);
    }
      return concat(["---", hardline, node.value, hardline, "---"]);
    case "toml":
      return concat(["+++", hardline, node.value, hardline, "+++"]);
    case "html": {
      return parentNode.type === "root" &&
        util.getLast(parentNode.children) === node
        ? node.value.trimRight()
        : node.value;
    }
    case "list": {
      const nthSiblingIndex = getNthListSiblingIndex(
        node,
        path.getParentNode()
      );

      const isGitDiffFriendlyOrderedList =
        node.ordered &&
        node.children.length > 1 &&
        /^\s*1(\.|\))/.test(
            node.children[1].position.start.offset,
            node.children[1].position.end.offset
          )
        );

        processor: (childPath, index) => {
          const prefix = node.ordered
            ? (index === 0
                ? node.start
                : isGitDiffFriendlyOrderedList ? 1 : node.start + index) +
              (nthSiblingIndex % 2 === 0 ? ". " : ") ")
            : nthSiblingIndex % 2 === 0 ? "* " : "- ";
            prefix,
            align(" ".repeat(prefix.length), childPath.call(print))
          ]);
        }
      });
    }
    case "listItem": {
      const prefix =
        node.checked === null ? "" : node.checked ? "[x] " : "[ ] ";
        prefix,
        printChildren(path, options, print, {
          processor: (childPath, index) =>
            index === 0 && childPath.getValue().type !== "list"
              ? align(" ".repeat(prefix.length), childPath.call(print))
              : childPath.call(print)
        })
      ]);
    }
    case "thematicBreak": {
      const counter = getAncestorCounter(path, "list");
      if (counter === -1) {
        return "---";
      }
        path.getParentNode(counter),
        path.getParentNode(counter + 1)
      );
      return nthSiblingIndex % 2 === 0 ? "---" : "***";
    }
    case "linkReference":
        "[",
        printChildren(path, options, print),
        "]",
        node.referenceType === "full"
          ? concat(["[", node.identifier, "]"])
          : node.referenceType === "collapsed" ? "[]" : ""
      ]);
    case "imageReference":
      switch (node.referenceType) {
        case "full":
          return concat(["![", node.alt, "][", node.identifier, "]"]);
        default:
            "![",
            node.alt,
            "]",
            node.referenceType === "collapsed" ? "[]" : ""
          ]);
      }
    case "definition":
        "[",
        node.identifier,
        "]: ",
        printUrl(node.url),
        node.title === null ? "" : ` ${printTitle(node.title)}`
      ]);
    case "footnote":
      return concat(["[^", printChildren(path, options, print), "]"]);
    case "footnoteReference":
      return concat(["[^", node.identifier, "]"]);
    case "footnoteDefinition":
        "[^",
        "]: ",
      ]);
    case "table":
      return printTable(path, options, print);
    case "tableCell":
    case "break":
      return concat(["\\", hardline]);
    case "tableRow": // handled in "table"
    default:
      throw new Error(`Unknown markdown type ${JSON.stringify(node.type)}`);
  }
}

(childPath, index) =>

function getNthListSiblingIndex(node, parentNode) {
  return getNthSiblingIndex(
    node,
    parentNode,
    siblingNode => siblingNode.ordered === node.ordered
  );
}

function getNthSiblingIndex(node, parentNode, condition) {
  condition = condition || (() => true);

  let index = -1;

  for (const childNode of parentNode.children) {
    if (childNode.type === node.type && condition(childNode)) {
      index++;
    } else {
      index = -1;
    }

    if (childNode === node) {
      return index;
    }
  }
}

function getAncestorCounter(path, typeOrTypes) {
  const types = [].concat(typeOrTypes);

  let counter = -1;
  let ancestorNode;

  while ((ancestorNode = path.getParentNode(++counter))) {
    if (types.indexOf(ancestorNode.type) !== -1) {
      return counter;
    }
  }

  return -1;
}

function getAncestorNode(path, typeOrTypes) {
  const counter = getAncestorCounter(path, typeOrTypes);
  return counter === -1 ? null : path.getParentNode(counter);
}

function printLine(path, value, options) {
  if (options.proseWrap === "preserve" && value === "\n") {
    return hardline;
  }

  const isBreakable =
    options.proseWrap === "always" &&
    !getAncestorNode(path, SINGLE_LINE_NODE_TYPES);
  return value !== ""
    ? isBreakable ? line : " "
    : isBreakable ? softline : "";
}

function printTable(path, options, print) {
  const contents = []; // { [rowIndex: number]: { [columnIndex: number]: string } }

  path.map(rowPath => {
    const rowContents = [];

    rowPath.map(cellPath => {
      rowContents.push(
        printDocToString(cellPath.call(print), options).formatted
      );
    }, "children");

    contents.push(rowContents);

  const columnMaxWidths = contents.reduce(
    (currentWidths, rowContents) =>
      currentWidths.map((width, columnIndex) =>
        Math.max(width, util.getStringWidth(rowContents[columnIndex]))
      ),
    contents[0].map(() => 3) // minimum width = 3 (---, :--, :-:, --:)
  );

  return join(hardline, [
    printRow(contents[0]),
    printSeparator(),
    join(hardline, contents.slice(1).map(printRow))
  ]);

  function printSeparator() {
      "| ",
      join(
        " | ",
        columnMaxWidths.map((width, index) => {
          switch (node.align[index]) {
            case "left":
              return ":" + "-".repeat(width - 1);
            case "right":
              return "-".repeat(width - 1) + ":";
            case "center":
              return ":" + "-".repeat(width - 2) + ":";
            default:
              return "-".repeat(width);
          }
        })
      ),
      " |"
    ]);
  }

  function printRow(rowContents) {
      "| ",
      join(
        " | ",
        rowContents.map((rowContent, columnIndex) => {
          switch (node.align[columnIndex]) {
              return alignRight(rowContent, columnMaxWidths[columnIndex]);
              return alignCenter(rowContent, columnMaxWidths[columnIndex]);
            default:
              return alignLeft(rowContent, columnMaxWidths[columnIndex]);
          }
        })
      ),
      " |"
    ]);
  }

  function alignLeft(text, width) {
    return concat([text, " ".repeat(width - util.getStringWidth(text))]);
  }

  function alignRight(text, width) {
    return concat([" ".repeat(width - util.getStringWidth(text)), text]);
  }

  function alignCenter(text, width) {
    const spaces = width - util.getStringWidth(text);
    const left = Math.floor(spaces / 2);
    const right = spaces - left;
    return concat([" ".repeat(left), text, " ".repeat(right)]);
  }
}

function printSeparator() {
      "| ",
      join(
        " | ",
            default:
          }
        })
      ),
      " |"
    ]);
  }

function printRow(rowContents) {
      "| ",
      join(
        " | ",
            default:
          }
        })
      ),
      " |"
    ]);
  }

function alignLeft(text, width) {
  }

function alignRight(text, width) {
  }

function alignCenter(text, width) {
  }

function printChildren(path, options, print, events) {
  events = events || {};

  const postprocessor = events.postprocessor || concat;
  const processor = events.processor || (childPath => childPath.call(print));

  let counter = 0;
  let lastChildNode;
  let prettierIgnore = false;

  path.map((childPath, index) => {
    const childNode = childPath.getValue();

    const result = prettierIgnore
      ? options.originalText.slice(
          childNode.position.start.offset,
          childNode.position.end.offset
        )
      : processor(childPath, index);

    prettierIgnore = false;

    if (result !== false) {
      prettierIgnore = isPrettierIgnore(childNode);

      const data = {
        parts,
        index: counter++,
        prevNode: lastChildNode,
        parentNode: node,
        options
      };

      if (!shouldNotPrePrintHardline(childNode, data)) {

        if (
          shouldPrePrintDoubleHardline(childNode, data) ||
          shouldPrePrintTripleHardline(childNode, data)
        ) {
        }

        if (shouldPrePrintTripleHardline(childNode, data)) {
        }
      }

      parts.push(result);

      lastChildNode = childNode;
    }

  return postprocessor(parts);
}

function isPrettierIgnore(node) {
  return (
    node.type === "html" && /^<!--\s*prettier-ignore\s*-->$/.test(node.value)
  );
}

function shouldNotPrePrintHardline(node, data) {
  const isFirstNode = data.parts.length === 0;
  const isInlineNode = INLINE_NODE_TYPES.indexOf(node.type) !== -1;

  const isInlineHTML =
    node.type === "html" &&
    INLINE_NODE_WRAPPER_TYPES.indexOf(data.parentNode.type) !== -1;

  return isFirstNode || isInlineNode || isInlineHTML;
}

function shouldPrePrintDoubleHardline(node, data) {
  const isSequence = (data.prevNode && data.prevNode.type) === node.type;
  const isSiblingNode =
    isSequence && SIBLING_NODE_TYPES.indexOf(node.type) !== -1;

  const isInTightListItem =
    data.parentNode.type === "listItem" && !data.parentNode.loose;

  const isPrevNodeLooseListItem =
    data.prevNode && data.prevNode.type === "listItem" && data.prevNode.loose;

  const isPrevNodePrettierIgnore = isPrettierIgnore(data.prevNode);

  return (
    isPrevNodeLooseListItem ||
    !(isSiblingNode || isInTightListItem || isPrevNodePrettierIgnore)
  );
}

function shouldPrePrintTripleHardline(node, data) {
  const isPrevNodeList = data.prevNode && data.prevNode.type === "list";
  const isIndentedCode =
    node.type === "code" &&
    /\s/.test(data.options.originalText[node.position.start.offset]);

  return isPrevNodeList && isIndentedCode;
}

function shouldRemainTheSameContent(path) {
  const ancestorNode = getAncestorNode(path, [
    "linkReference",
    "imageReference"
  ]);

  return (
    ancestorNode &&
    (ancestorNode.type !== "linkReference" ||
      ancestorNode.referenceType !== "full")
  );
}

function normalizeDoc(doc) {
    }

    if (currentDoc.type === "concat" && currentDoc.parts.length === 1) {
      return currentDoc.parts[0];
    }

      if (part.type === "concat") {
        parts.push.apply(parts, part.parts);
      } else if (part !== "") {
      }
    });

    return Object.assign({}, currentDoc, {
      parts: normalizeParts(parts)
    });
  });
}

function printUrl(url, dangerousCharOrChars) {
  const dangerousChars = [" "].concat(dangerousCharOrChars || []);
  return new RegExp(dangerousChars.map(x => `\\${x}`).join("|")).test(url)
    ? `<${url}>`
    : url;
}

function printTitle(title) {
  return title.includes('"') && !title.includes("'")
    ? `'${title}'`
    : `"${title.replace(/"/g, '\\"')}"`;
}

function normalizeParts(parts) {
  return parts.reduce((current, part) => {
    const lastPart = util.getLast(current);

    if (typeof lastPart === "string" && typeof part === "string") {
      current.splice(-1, 1, lastPart + part);
    } else {
      current.push(part);
    }

    return current;
  }, []);
}

function embed(path, print, textToDoc, options) {

  if (node.type === "code" && node.lang !== null) {
    const parser = inferParserByLanguage(node.lang, options);
        Math.max(3, getMaxContinuousCount(node.value, styleUnit) + 1)
      );
      const doc = textToDoc(
        getFencedCodeBlockValue(node, options.originalText),
        { parser },
        { stripTrailingHardline: true }
      );
      return markAsRoot([
        style,
        node.lang,
        node.meta ? " " + node.meta : "",
        hardline,
        replaceNewlinesWithLiterallines(doc),
        hardline,
        style,
      ]);
    }
  }

    case "front-matter":
      return printFrontMatter(node, textToDoc);

    // MDX
    case "importExport":
      return [
        textToDoc(
          { parser: "babel" },
          { stripTrailingHardline: true }
        ),
        hardline,
      ];
    case "jsx":
      return textToDoc(
        `<$>${node.value}</$>`,
        {
          parser: "__js_expression",
          rootMarker: "mdx",
        },
      );
  }

}

function splitText(text, options) {
  const KIND_NON_CJK = "non-cjk";
  const KIND_CJ_LETTER = "cj-letter";
  const KIND_K_LETTER = "k-letter";
  const KIND_CJK_PUNCTUATION = "cjk-punctuation";

  /** @type {Array<{ type: "whitespace", value: " " | "\n" | "" } | { type: "word", value: string }>} */

  const tokens = (options.proseWrap === "preserve"
    ? text
    : text.replace(new RegExp(`(${cjkPattern})\n(${cjkPattern})`, "g"), "$1$2")
  ).split(/([\t\n ]+)/);
  for (const [index, token] of tokens.entries()) {
    // whitespace
    if (index % 2 === 1) {
      nodes.push({
        type: "whitespace",
        value: /\n/.test(token) ? "\n" : " ",
      });
      continue;
    }

    // word separated by whitespace

    if ((index === 0 || index === tokens.length - 1) && token === "") {
      continue;
    }

    const innerTokens = token.split(new RegExp(`(${cjkPattern})`));
    for (const [innerIndex, innerToken] of innerTokens.entries()) {
      if (
        (innerIndex === 0 || innerIndex === innerTokens.length - 1) &&
        innerToken === ""
      ) {
        continue;
      }

      // non-CJK word
      if (innerIndex % 2 === 0) {
        if (innerToken !== "") {
          appendNode({
            type: "word",
            value: innerToken,
            kind: KIND_NON_CJK,
            hasLeadingPunctuation: punctuationRegex.test(innerToken[0]),
            hasTrailingPunctuation: punctuationRegex.test(getLast(innerToken)),
          });
        }
        continue;
      }

      // CJK character
      appendNode(
        punctuationRegex.test(innerToken)
          ? {
              type: "word",
              value: innerToken,
              kind: KIND_CJK_PUNCTUATION,
              hasLeadingPunctuation: true,
              hasTrailingPunctuation: true,
            }
          : {
              kind: kRegex.test(innerToken) ? KIND_K_LETTER : KIND_CJ_LETTER,
              hasLeadingPunctuation: false,
              hasTrailingPunctuation: false,
            }
      );
    }
  }

  return nodes;

  function appendNode(node) {
    const lastNode = getLast(nodes);
    if (lastNode && lastNode.type === "word") {
      if (
        (lastNode.kind === KIND_NON_CJK &&
          node.kind === KIND_CJ_LETTER &&
          !lastNode.hasTrailingPunctuation) ||
        (lastNode.kind === KIND_CJ_LETTER &&
          node.kind === KIND_NON_CJK &&
          !node.hasLeadingPunctuation)
      ) {
        nodes.push({ type: "whitespace", value: " " });
      } else if (
        !isBetween(KIND_NON_CJK, KIND_CJK_PUNCTUATION) &&
        // disallow leading/trailing full-width whitespace
        ![lastNode.value, node.value].some((value) => /\u3000/.test(value))
      ) {
        nodes.push({ type: "whitespace", value: "" });
      }
    }
    nodes.push(node);

    function isBetween(kind1, kind2) {
      return (
        (lastNode.kind === kind1 && node.kind === kind2) ||
        (lastNode.kind === kind2 && node.kind === kind1)
      );
    }
  }
}

function appendNode(node) {
      if (
      ) {
      } else if (
      ) {
      }
    }

      return (
      );
    }
  }

function isBetween(kind1, kind2) {
      return (
      );
    }

function getOrderedListItemInfo(orderListItem, originalText) {
  const [, numberText, marker, leadingSpaces] = originalText
    .slice(
      orderListItem.position.start.offset,
      orderListItem.position.end.offset
    )
    .match(/^\s*(\d+)(\.|\))(\s*)/);

  return { numberText, marker, leadingSpaces };
}

function hasGitDiffFriendlyOrderedList(node, options) {
  if (!node.ordered) {
  }

  if (node.children.length < 2) {
  }

  const firstNumber = Number(
    getOrderedListItemInfo(node.children[0], options.originalText).numberText
  );

  const secondNumber = Number(
    getOrderedListItemInfo(node.children[1], options.originalText).numberText
  );

  if (firstNumber === 0 && node.children.length > 2) {
    const thirdNumber = Number(
      getOrderedListItemInfo(node.children[2], options.originalText).numberText
    );

    return secondNumber === 1 && thirdNumber === 1;
  }

  return secondNumber === 1;
}

function getFencedCodeBlockValue(node, originalText) {
  const { value } = node;
  if (
    node.position.end.offset === originalText.length &&
    value.endsWith("\n") &&
    // Code block has no end mark
    originalText.endsWith("\n")
  ) {
    return value.slice(0, -1);
  }
  return value;
}

function mapAst(ast, handler) {
  return (function preorder(node, index, parentStack) {
    const newNode = { ...handler(node, index, parentStack) };
      newNode.children = newNode.children.map((child, index) =>
        preorder(child, index, [newNode, ...parentStack])
      );
    }

  })(ast, null, []);
}

function isAutolink(node) {
  if (!node || node.type !== "link" || node.children.length !== 1) {
  }
  const child = node.children[0];
  return (
    child &&
    locStart(node) === locStart(child) &&
    locEnd(node) === locEnd(child)
  );
}

get remark() {
    return require("./parser-markdown").parsers.remark;
  }

  }

get mdx() {
    return require("./parser-markdown").parsers.mdx;
  }

function preprocess(ast, options) {
  ast = restoreUnescapedCharacter(ast, options);
  ast = mergeContinuousTexts(ast);
  ast = transformInlineCode(ast);
  ast = transformIndentedCodeblockAndMarkItsParentList(ast, options);
  ast = markAlignedList(ast, options);
  ast = splitTextIntoSentences(ast, options);
  ast = transformImportExport(ast);
  ast = mergeContinuousImportExport(ast);
}

function transformImportExport(ast) {
  return mapAst(ast, node => {
    if (node.type !== "import" && node.type !== "export") {
      return node;
    }

    return Object.assign({}, node, { type: "importExport" });
  });
}

function transformInlineCode(ast) {
    if (node.type !== "inlineCode") {
    }

    return Object.assign({}, node, {
      value: node.value.replace(/\s+/g, " ")
    });
  });
}

function restoreUnescapedCharacter(ast, options) {
    return node.type !== "text"
      ? node
      : Object.assign({}, node, {
          value:
            node.value !== "*" &&
            node.value !== "_" && // handle these two cases in printer
            isSingleCharRegex.test(node.value) &&
            node.position.end.offset - node.position.start.offset !==
              node.value.length
              ? options.originalText.slice(
                  node.position.start.offset,
                  node.position.end.offset
                )
              : node.value
        });
  });
}

function mergeContinuousImportExport(ast) {
  return mergeChildren(
    ast,
    (prevNode, node) =>
      prevNode.type === "importExport" && node.type === "importExport",
    (prevNode, node) => ({
      type: "importExport",
      value: prevNode.value + "\n\n" + node.value,
      position: {
        start: prevNode.position.start,
        end: node.position.end
      }
    })
  );
}

function mergeChildren(ast, shouldMerge, mergeNode) {
    if (!node.children) {
    }
    const children = node.children.reduce((current, child) => {
      const lastChild = current[current.length - 1];
      if (lastChild && shouldMerge(lastChild, child)) {
        current.splice(-1, 1, mergeNode(lastChild, child));
      } else {
        current.push(child);
      }
      return current;
    }, []);
    return Object.assign({}, node, { children });
  });
}

function mergeContinuousTexts(ast) {
    ast,
    (prevNode, node) => prevNode.type === "text" && node.type === "text",
      type: "text",
      value: prevNode.value + node.value,
      }
    })
  );
}

function splitTextIntoSentences(ast, options) {
  return mapAst(ast, (node, index, [parentNode]) => {
    if (node.type !== "text") {
    }

    let value = node.value;

    if (parentNode.type === "paragraph") {
      if (index === 0) {
        value = value.trimLeft();
      }
      if (index === parentNode.children.length - 1) {
        value = value.trimRight();
      }
    }

    return {
      type: "sentence",
      position: node.position,
      children: splitText(value, options)
    };
  });
}

function transformIndentedCodeblockAndMarkItsParentList(ast, options) {
  return mapAst(ast, (node, index, parentStack) => {
    if (node.type === "code") {
      // the first char may point to `\n`, e.g. `\n\t\tbar`, just ignore it
      const isIndented = /^\n?( {4,}|\t)/.test(
          node.position.start.offset,
          node.position.end.offset
        )
      );

      node.isIndented = isIndented;

      if (isIndented) {
        for (let i = 0; i < parentStack.length; i++) {
          const parent = parentStack[i];

          // no need to check checked items
          if (parent.hasIndentedCodeblock) {
            break;
          }

          if (parent.type === "list") {
            parent.hasIndentedCodeblock = true;
          }
        }
      }
    }
    return node;
  });
}

function markAlignedList(ast, options) {
    if (node.type === "list" && node.children.length !== 0) {
      // if one of its parents is not aligned, it's not possible to be aligned in sub-lists
      for (let i = 0; i < parentStack.length; i++) {
        const parent = parentStack[i];
        if (parent.type === "list" && !parent.isAligned) {
          node.isAligned = false;
          return node;
        }
      }

      node.isAligned = isAligned(node);
    }

  });

  function getListItemStart(listItem) {
    return listItem.children.length === 0
      ? -1
      : listItem.children[0].position.start.column - 1;
  }

  function isAligned(list) {
    if (!list.ordered) {
      /**
       * - 123
       * - 123
       */
    }

    const [firstItem, secondItem] = list.children;

    const firstInfo = getOrderedListItemInfo(firstItem, options.originalText);

    if (firstInfo.leadingSpaces.length > 1) {
      /**
       * 1.   123
       *
       * 1.   123
       * 1. 123
       */
    }

    const firstStart = getListItemStart(firstItem);

    if (firstStart === -1) {
      /**
       * 1.
       *
       * 1.
       * 1.
       */
    }

    if (list.children.length === 1) {
      /**
       * aligned:
       *
       * 11. 123
       *
       * not aligned:
       *
       * 1. 123
       */
      return firstStart % options.tabWidth === 0;
    }

    const secondStart = getListItemStart(secondItem);

    if (firstStart !== secondStart) {
      /**
       * 11. 123
       * 1. 123
       *
       * 1. 123
       * 11. 123
       */
    }

    if (firstStart % options.tabWidth === 0) {
      /**
       * 11. 123
       * 12. 123
       */
    }

    /**
     * aligned:
     *
     * 11. 123
     * 1.  123
     *
     * not aligned:
     *
     * 1. 123
     * 2. 123
     */
    const secondInfo = getOrderedListItemInfo(secondItem, options.originalText);
    return secondInfo.leadingSpaces.length > 1;
  }
}

function getListItemStart(listItem) {
      ? -1
  }

function isAligned(list) {
      /**
       * - 123
       * - 123
       */
    }

      /**
       * 1.   123
       *
       * 1.   123
       * 1. 123
       */
    }

      /**
       * 1.
       *
       * 1.
       * 1.
       */
    }

      /**
       * aligned:
       *
       * 11. 123
       *
       *
       * 1. 123
       */
    }

      /**
       * 11. 123
       * 1. 123
       *
       * 1. 123
       * 11. 123
       */
    }

      /**
       * 11. 123
       * 12. 123
       */
    }

    /**
     * aligned:
     *
     * 11. 123
     * 1.  123
     *
     *
     * 1. 123
     * 2. 123
     */
  }

(eat, value) => {
  const index = value.indexOf(EMPTY_NEWLINE);
  const subvalue = value.slice(0, index);

  if (isExport(subvalue) || isImport(subvalue)) {
    return eat(subvalue)({
      type: isExport(subvalue) ? "export" : "import",
      value: subvalue,
    });
  }
}

(value /*, fromIndex*/) =>
  isExport(value) || isImport(value) ? -1 : 1

function esSyntax() {
  const { Parser } = this;
  const tokenizers = Parser.prototype.blockTokenizers;
  const methods = Parser.prototype.blockMethods;

  tokenizers.esSyntax = tokenizeEsSyntax;

  methods.splice(methods.indexOf("paragraph"), 0, "esSyntax");
}

function startWithPragma(text) {
  const pragma = `@(${pragmas.join("|")})`;
  const regex = new RegExp(
    [
      `<!--\\s*${pragma}\\s*-->`,
      `<!--.*\r?\n[\\s\\S]*(^|\n)[^\\S\n]*${pragma}[^\\S\n]*($|\n)[\\s\\S]*\n.*-->`,
    ].join("|"),
    "m"
  );
  const matched = text.match(regex);
  return matched && matched.index === 0;
}

(text) =>
    startWithPragma(parseFrontMatter(text).content.trimStart())

(text) => {
    const extracted = parseFrontMatter(text);
    const pragma = `<!-- @${pragmas[0]} -->`;
    return extracted.frontMatter
      ? `${extracted.frontMatter.raw}\n\n${pragma}\n\n${extracted.content}`
      : `${pragma}\n\n${extracted.content}`;
  }

function clean(ast, newObj, parent) {
  // for codeblock
  if (
    ast.type === "front-matter" ||
    ast.type === "code" ||
    ast.type === "yaml" ||
    ast.type === "import" ||
    ast.type === "export" ||
    ast.type === "jsx"
  ) {
    delete newObj.value;
  }

  if (ast.type === "list") {
    delete newObj.isAligned;
  }

  if (ast.type === "list" || ast.type === "listItem") {
    delete newObj.spread;
    delete newObj.loose;
  }

  // texts can be splitted or merged
  if (ast.type === "text") {
  }

  if (ast.type === "inlineCode") {
    newObj.value = ast.value.replace(/[\t\n ]+/g, " ");
  }

  if (ast.type === "wikiLink") {
    newObj.value = ast.value.trim().replace(/[\t\n]+/g, " ");
  }

  if (ast.type === "definition" || ast.type === "linkReference") {
    newObj.label = ast.label
      .trim()
      .replace(/[\t\n ]+/g, " ")
      .toLowerCase();
  }

  if (
    (ast.type === "definition" ||
      ast.type === "link" ||
      ast.type === "image") &&
    ast.title
  ) {
    newObj.title = ast.title.replace(/\\(["')])/g, "$1");
  }

  // for insert pragma
  if (
    parent &&
    parent.type === "root" &&
    parent.children.length > 0 &&
    (parent.children[0] === ast ||
      (isFrontMatterNode(parent.children[0]) && parent.children[1] === ast)) &&
    ast.type === "html" &&
    startWithPragma(ast.value)
  ) {
  }
}

  return node.position.start.offset;
}

function createParse({ isMDX }) {
  return (text) => {
    const processor = unified()
      .use(remarkParse, {
        commonmark: true,
        ...(isMDX && { blocks: [mdx.BLOCKS_REGEX] }),
      })
      .use(footnotes)
      .use(frontMatter)
      .use(remarkMath)
      .use(isMDX ? mdx.esSyntax : identity)
      .use(liquid)
      .use(isMDX ? htmlToJsx : identity)
      .use(wikiLink)
      .use(looseItems);
    return processor.runSync(processor.parse(text));
  };
}

function htmlToJsx() {
  return (ast) =>
    mapAst(ast, (node, _index, [parent]) => {
      if (
        node.type !== "html" ||
        mdx.COMMENT_REGEX.test(node.value) ||
        INLINE_NODE_WRAPPER_TYPES.includes(parent.type)
      ) {
      }

      return { ...node, type: "jsx" };
    });
}

function frontMatter() {
  const proto = this.Parser.prototype;
  proto.blockMethods = ["frontMatter", ...proto.blockMethods];
  proto.blockTokenizers.frontMatter = tokenizer;

  function tokenizer(eat, value) {
    const parsed = parseFrontMatter(value);

    if (parsed.frontMatter) {
      return eat(parsed.frontMatter.raw)(parsed.frontMatter);
    }
  }
  tokenizer.onlyAtStart = true;
}

function tokenizer(eat, value) {
    const match = wikiLinkRegex.exec(value);

    if (match) {
      const linkContents = match.groups.linkContents.trim();

      return eat(match[0])({
        type: entityType,
        value: linkContents,
      });
    }
  }

function liquid() {
  const methods = proto.inlineMethods;
  methods.splice(methods.indexOf("text"), 0, "liquid");
  proto.inlineTokenizers.liquid = tokenizer;

    const match = value.match(/^({%[\S\s]*?%}|{{[\S\s]*?}})/);

        type: "liquidNode",
        value: match[0],
      });
    }
  }
  tokenizer.locator = function (value, fromIndex) {
    return value.indexOf("{", fromIndex);
  };
}

function wikiLink() {
  const entityType = "wikiLink";
  const wikiLinkRegex = /^\[\[(?<linkContents>.+?)]]/s;
  methods.splice(methods.indexOf("link"), 0, entityType);
  proto.inlineTokenizers.wikiLink = tokenizer;

      });
    }
  }

    return value.indexOf("[", fromIndex);
  };
}

function looseItems() {
  const originalList = proto.blockTokenizers.list;

  function fixListNodes(value, node, parent) {
    if (node.type === "listItem") {
      node.loose = node.spread || value.charAt(value.length - 1) === "\n";
      if (node.loose) {
        parent.loose = true;
      }
    }
  }

  proto.blockTokenizers.list = function list(realEat, value, silent) {
    function eat(subvalue) {
      const realAdd = realEat(subvalue);

      function add(node, parent) {
        return realAdd(fixListNodes(subvalue, node, parent), parent);
      }
      add.reset = function (node, parent) {
        return realAdd.reset(fixListNodes(subvalue, node, parent), parent);
      };

      return add;
    }
    eat.now = realEat.now;
    return originalList.call(this, eat, value, silent);
  };
}

function fixListNodes(value, node, parent) {
      }
    }
  }

function eat(subvalue) {

      }
      };

    }

function add(node, parent) {
      }

  return mapAst(ast, (node) => {
    }

    return { ...node, type: "importExport" };
  });
}

    }

    return { ...node, value: node.value.replace(/\s+/g, " ") };
  });
}

  return mapAst(ast, (node) =>
    node.type !== "text" ||
    node.value === "*" ||
    node.value === "_" || // handle these cases in printer
    !isSingleCharRegex.test(node.value) ||
    node.position.end.offset - node.position.start.offset === node.value.length
      ? node
      : {
          ...node,
          value: options.originalText.slice(
          ),
        }
  );
}

    ast,
        end: node.position.end,
      },
    })
  );
}

    }
      } else {
      }
    }, []);
    return { ...node, children };
  });
}

    ast,
      },
    })
  );
}

    }

    let { value } = node;

        value = value.trimStart();
      }
        value = value.trimEnd();
      }
    }

    return {
      children: splitText(value, options),
    };
  });
}

    if (node.type === "list" && node.children.length > 0) {
        }
      }

    }

  });

      ? -1
  }

      /**
       * - 123
       * - 123
       */
    }

      /**
       * 1.   123
       *
       * 1.   123
       * 1. 123
       */
    }

      /**
       * 1.
       *
       * 1.
       * 1.
       */
    }

      /**
       * aligned:
       *
       * 11. 123
       *
       *
       * 1. 123
       */
    }

      /**
       * 11. 123
       * 1. 123
       *
       * 1. 123
       * 11. 123
       */
    }

      /**
       * 11. 123
       * 12. 123
       */
    }

    /**
     * aligned:
     *
     * 11. 123
     * 1.  123
     *
     *
     * 1. 123
     * 2. 123
     */
  }
}

    return splitText(
      options.originalText.slice(
        node.position.start.offset,
        node.position.end.offset
      ),
      options
    ).map((node) =>
      node.type === "word"
        ? node.value
        : node.value === ""
        ? ""
        : printLine(path, node.value, options)
    );
  }

      return options.originalText.slice(
      );
      if (node.children.length === 0) {
        return "";
      }
      return [
        normalizeDoc(printRoot(path, options, print)),
        !TRAILING_HARDLINE_NODES.has(getLastDescendantNode(node).type)
          ? hardline
          : "",
      ];
        postprocessor: fill,
      });
    case "word": {
      let escapedValue = node.value
        .replace(/\*/g, "\\$&") // escape all `*`
        .replace(
            [
              `(^|${punctuationPattern})(_+)`,
              `(_+)(${punctuationPattern}|$)`,
            "g"
          ),

      const isFirstSentence = (node, name, index) =>
        node.type === "sentence" && index === 0;
      const isLastChildAutolink = (node, name, index) =>
        isAutolink(node.children[index - 1]);

      if (
        escapedValue !== node.value &&
        (path.match(undefined, isFirstSentence, isLastChildAutolink) ||
          path.match(
            undefined,
            isFirstSentence,
            (node, name, index) => node.type === "emphasis" && index === 0,
            isLastChildAutolink
          ))
      ) {
        // backslash is parsed as part of autolinks, so we need to remove it
        escapedValue = escapedValue.replace(/^(\\?[*_])+/, (prefix) =>
          prefix.replace(/\\/g, "")
        );
      }

      return escapedValue;
    }

        nextNode && /^>|^([*+-]|#{1,6}|\d+[).])$/.test(nextNode.value)
          ? "never"

    }
      let style;
      if (isAutolink(node.children[0])) {
        style = options.originalText[node.position.start.offset];
      } else {
        const parentNode = path.getParentNode();
        const index = parentNode.children.indexOf(node);
        const prevNode = parentNode.children[index - 1];
        const nextNode = parentNode.children[index + 1];
        const hasPrevOrNextWord = // `1*2*3` is considered emphasis but `1_2_3` is not
          (prevNode &&
            prevNode.type === "sentence" &&
            prevNode.children.length > 0 &&
            getLast(prevNode.children).type === "word" &&
            !getLast(prevNode.children).hasTrailingPunctuation) ||
          (nextNode &&
            nextNode.type === "sentence" &&
            nextNode.children.length > 0 &&
            nextNode.children[0].type === "word" &&
            !nextNode.children[0].hasLeadingPunctuation);
        style =
          hasPrevOrNextWord || getAncestorNode(path, "emphasis") ? "*" : "_";
      }
      return [style, printChildren(path, options, print), style];
    }
      return ["**", printChildren(path, options, print), "**"];
      return ["~~", printChildren(path, options, print), "~~"];
      const backtickCount = getMinNotPresentContinuousCount(node.value, "`");
      const style = "`".repeat(backtickCount || 1);
      const gap = backtickCount && !/^\s/.test(node.value) ? " " : "";
      return [style, gap, node.value, gap, style];
    }
    case "wikiLink": {
      let contents = "";
      if (options.proseWrap === "preserve") {
        contents = node.value;
      } else {
        contents = node.value.replace(/[\t\n]+/g, " ");
      }

      return ["[[", contents, "]]"];
    }
        case "<": {
          const mailto = "mailto:";
          const url =
            // <hello@example.com> is parsed as { url: "mailto:hello@example.com" }
            node.url.startsWith(mailto) &&
            options.originalText.slice(
              node.position.start.offset + 1,
              node.position.start.offset + 1 + mailto.length
            ) !== mailto
              ? node.url.slice(mailto.length)
              : node.url;
          return ["<", url, ">"];
        }
        case "[":
          return [
            "[",
            "](",
            printTitle(node.title, options),
            ")",
          ];
        default:
          );
      }
      return [
        "![",
        "](",
        printTitle(node.title, options),
        ")",
      ];
      return ["> ", align("> ", printChildren(path, options, print))];
      return [
      ];
      if (node.isIndented) {
        return align(alignment, [
          ...replaceEndOfLineWith(node.value, hardline),
        ]);
      }

      );
      return [
        style,
        hardline,

        ...replaceEndOfLineWith(
          getFencedCodeBlockValue(node, options.originalText),
          hardline
        ),
        hardline,
        style,
      ];
    }
        parentNode.type === "root" && getLast(parentNode.children) === node
          ? node.value.trimEnd()
          : node.value;
      const isHtmlComment = /^<!--[\S\s]*-->$/.test(value);
      return replaceEndOfLineWith(
        value,
        isHtmlComment ? hardline : markAsRoot(literalline)
      );
    }
        node,
      );

      const isGitDiffFriendlyOrderedList = hasGitDiffFriendlyOrderedList(
        node,
        options
      );

          const prefix = getPrefix();
          const childNode = childPath.getValue();

          if (
            childNode.children.length === 2 &&
            childNode.children[1].type === "html" &&
            childNode.children[0].position.start.column !==
              childNode.children[1].position.start.column
          ) {
            return [prefix, printListItem(childPath, options, print, prefix)];
          }

          return [
            prefix,
            align(
              " ".repeat(prefix.length),
              printListItem(childPath, options, print, prefix)
            ),
          ];

          function getPrefix() {
            const rawPrefix = node.ordered
              ? (index === 0
                  ? node.start
                  : isGitDiffFriendlyOrderedList
                  ? 1
                  : node.start + index) +
                (nthSiblingIndex % 2 === 0 ? ". " : ") ")
              : nthSiblingIndex % 2 === 0
              ? "- "
              : "* ";

            return node.isAligned ||
              /* workaround for https://github.com/remarkjs/remark/issues/315 */ node.hasIndentedCodeblock
              ? alignListPrefix(rawPrefix, options)
              : rawPrefix;
          }
        },
      });
    }
      }
      );
      return nthSiblingIndex % 2 === 0 ? "***" : "---";
    }
      return [
        "[",
        "]",
          ? ["[", node.identifier, "]"]
          : node.referenceType === "collapsed"
          ? "[]"
          : "",
      ];
          return ["![", node.alt || "", "][", node.identifier, "]"];
        default:
          return [
            "![",
            node.alt,
            "]",
            node.referenceType === "collapsed" ? "[]" : "",
          ];
      }
    case "definition": {
      const lineOrSpace = options.proseWrap === "always" ? line : " ";
      return group([
        "[",
        "]:",
        indent([
          lineOrSpace,
          printUrl(node.url),
          node.title === null
            ? ""
            : [lineOrSpace, printTitle(node.title, options, false)],
        ]),
      ]);
    }
    // `footnote` requires `.use(footnotes, {inlineNotes: true})`, we are not using this option
    // https://github.com/remarkjs/remark-footnotes#optionsinlinenotes
      return ["[^", printChildren(path, options, print), "]"];
      return ["[^", node.identifier, "]"];
    case "footnoteDefinition": {
      const nextNode = path.getParentNode().children[path.getName() + 1];
      const shouldInlineFootnote =
        node.children.length === 1 &&
        node.children[0].type === "paragraph" &&
        (options.proseWrap === "never" ||
          (options.proseWrap === "preserve" &&
            node.children[0].position.start.line ===
              node.children[0].position.end.line));
      return [
        "[^",
        "]: ",
        shouldInlineFootnote
          ? printChildren(path, options, print)
          : group([
              align(
                " ".repeat(4),
                printChildren(path, options, print, {
                  processor: (childPath, index) =>
                    index === 0
                      ? group([softline, childPath.call(print)])
                      : childPath.call(print),
                })
              ),
              nextNode && nextNode.type === "footnoteDefinition"
                ? softline
                : "",
            ]),
      ];
    }
      return /\s/.test(options.originalText[node.position.start.offset])
        ? ["  ", markAsRoot(literalline)]
        : ["\\", hardline];
    case "liquidNode":
      return replaceEndOfLineWith(node.value, hardline);
    // MDX
    // fallback to the original text if multiparser failed
    // or `embeddedLanguageFormatting: "off"`
      return [node.value, hardline];
      return node.value;
    case "math":
      return [
        "$$",
        hardline,
        node.value
          ? [...replaceEndOfLineWith(node.value, hardline), hardline]
          : "",
        "$$",
      ];
    case "inlineMath": {
      // remark-math trims content but we don't want to remove whitespaces
      // since it's very possible that it's recognized as math accidentally
      return options.originalText.slice(locStart(node), locEnd(node));
    }

    case "listItem": // handled in "list"
    default:
  }
}

(node, name, index) =>
        node.type === "sentence" && index === 0

        isAutolink(node.children[index - 1])

(childPath, index) => {
      if (ignoreRanges.length > 0) {
        const ignoreRange = ignoreRanges[0];

        if (index === ignoreRange.start.index) {
          return [
            children[ignoreRange.start.index].value,
              ignoreRange.start.offset,
              ignoreRange.end.offset
            ),
            children[ignoreRange.end.index].value,
          ];
        }

        if (ignoreRange.start.index < index && index < ignoreRange.end.index) {
        }

        if (index === ignoreRange.end.index) {
          ignoreRanges.shift();
        }
      }

      return childPath.call(print);
    }

function getPrefix() {
                  ? 1
              ? "- "
              : "* ";

          }

function printListItem(path, options, print, listPrefix) {
  const prefix = node.checked === null ? "" : node.checked ? "[x] " : "[ ] ";
  return [
    prefix,
    printChildren(path, options, print, {
      processor: (childPath, index) => {
        if (index === 0 && childPath.getValue().type !== "list") {
          return align(" ".repeat(prefix.length), childPath.call(print));
        }

        const alignment = " ".repeat(
          clamp(options.tabWidth - listPrefix.length, 0, 3) // 4+ will cause indented code block
        );
        return [alignment, align(alignment, childPath.call(print))];
      },
    }),
  ];
}

function alignListPrefix(prefix, options) {
  const additionalSpaces = getAdditionalSpaces();
  return (
    prefix +
    " ".repeat(
      additionalSpaces >= 4 ? 0 : additionalSpaces // 4+ will cause indented code block
    )
  );

  function getAdditionalSpaces() {
    const restSpaces = prefix.length % options.tabWidth;
    return restSpaces === 0 ? 0 : options.tabWidth - restSpaces;
  }
}

function getAdditionalSpaces() {
  }

    node,
    (siblingNode) => siblingNode.ordered === node.ordered
  );
}

      index++;
    } else {
      index = -1;
    }

    }
  }
}

  const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];

    if (types.includes(ancestorNode.type)) {
    }
  }

  return -1;
}

  }

    ? isBreakable
      ? line
      : " "
    : isBreakable
    ? softline
    : "";
}

  const columnMaxWidths = [];
  // { [rowIndex: number]: { [columnIndex: number]: {text: string, width: number} } }
  const contents = path.map(
    (rowPath) =>
      rowPath.map((cellPath, columnIndex) => {
        const text = printDocToString(cellPath.call(print), options).formatted;
        const width = getStringWidth(text);
        columnMaxWidths[columnIndex] = Math.max(
          columnMaxWidths[columnIndex] || 3, // minimum width = 3 (---, :--, :-:, --:)
          width
        );
        return { text, width };
      }, "children"),
    "children"
  );

  const alignedTable = printTableContents(/* isCompact */ false);
  if (options.proseWrap !== "never") {
    return [breakParent, alignedTable];
  }

  // Only if the --prose-wrap never is set and it exceeds the print width.
  const compactTable = printTableContents(/* isCompact */ true);
  return [breakParent, group(ifBreak(compactTable, alignedTable))];

  function printTableContents(isCompact) {
    /** @type{Doc[]} */
    const parts = [printRow(contents[0], isCompact), printAlign(isCompact)];
    if (contents.length > 1) {
        join(
          hardlineWithoutBreakParent,
          contents
            .slice(1)
            .map((rowContents) => printRow(rowContents, isCompact))
        )
      );
    }
    return join(hardlineWithoutBreakParent, parts);
  }

  function printAlign(isCompact) {
    const align = columnMaxWidths.map((width, index) => {
      const align = node.align[index];
      const first = align === "center" || align === "left" ? ":" : "-";
      const last = align === "center" || align === "right" ? ":" : "-";
      const middle = isCompact ? "-" : "-".repeat(width - 2);
      return `${first}${middle}${last}`;
    });

    return `| ${align.join(" | ")} |`;
  }

  function printRow(rowContents, isCompact) {
    const columns = rowContents.map(({ text, width }, columnIndex) => {
      if (isCompact) {
        return text;
      }
      const spaces = columnMaxWidths[columnIndex] - width;
      const align = node.align[columnIndex];
      let before = 0;
      if (align === "right") {
        before = spaces;
      } else if (align === "center") {
        before = Math.floor(spaces / 2);
      }
      const after = spaces - before;
      return `${" ".repeat(before)}${text}${" ".repeat(after)}`;
    });

    return `| ${columns.join(" | ")} |`;
  }
}

function printTableContents(isCompact) {
        join(
          contents
            .slice(1)
        )
      );
    }
  }

function printAlign(isCompact) {
    });

  }

function printRow(rowContents, isCompact) {
      }
      }
    });

  }

function printRoot(path, options, print) {
  /** @typedef {{ index: number, offset: number }} IgnorePosition */
  /** @type {Array<{start: IgnorePosition, end: IgnorePosition}>} */
  const ignoreRanges = [];

  /** @type {IgnorePosition | null} */
  let ignoreStart = null;

  const { children } = path.getValue();
  for (const [index, childNode] of children.entries()) {
    switch (isPrettierIgnore(childNode)) {
      case "start":
        if (ignoreStart === null) {
          ignoreStart = { index, offset: childNode.position.end.offset };
        }
        break;
      case "end":
        if (ignoreStart !== null) {
          ignoreRanges.push({
            start: ignoreStart,
            end: { index, offset: childNode.position.start.offset },
          });
          ignoreStart = null;
        }
        break;
      default:
        // do nothing
        break;
    }
  }

  return printChildren(path, options, print, {
    processor: (childPath, index) => {

          return [
            ),
          ];
        }

        }

        }
      }

    },
  });
}

function printChildren(path, options, print, events = {}) {
  const { postprocessor } = events;
  const processor = events.processor || ((childPath) => childPath.call(print));

  path.each((childPath, index) => {

    const result = processor(childPath, index);
        parts,
        options,
      };

      if (shouldPrePrintHardline(childNode, data)) {

        // Can't find a case to pass `shouldPrePrintTripleHardline`
        /* istanbul ignore next */
        if (lastChildNode && TRAILING_HARDLINE_NODES.has(lastChildNode.type)) {
          if (shouldPrePrintTripleHardline(childNode, data)) {
            parts.push(hardline);
          }
        } else {
          if (
            shouldPrePrintDoubleHardline(childNode, data) ||
            shouldPrePrintTripleHardline(childNode, data)
          ) {
          }

          }
        }
      }

    }

  return postprocessor ? postprocessor(parts) : parts;
}

function getLastDescendantNode(node) {
  let current = node;
  while (isNonEmptyArray(current.children)) {
    current = current.children[current.children.length - 1];
  }
  return current;
}

  if (node.type !== "html") {
  }
  const match = node.value.match(
    /^<!--\s*prettier-ignore(?:-(start|end))?\s*-->$/
  );
  return match === null ? false : match[1] ? match[1] : "next";
}

function shouldPrePrintHardline(node, data) {
  const isInlineNode = INLINE_NODE_TYPES.includes(node.type);

    INLINE_NODE_WRAPPER_TYPES.includes(data.parentNode.type);

  return !isFirstNode && !isInlineNode && !isInlineHTML;
}

  const isSiblingNode = isSequence && SIBLING_NODE_TYPES.has(node.type);

  const isPrevNodePrettierIgnore = isPrettierIgnore(data.prevNode) === "next";

  const isBlockHtmlWithoutBlankLineBetweenPrevHtml =
    data.prevNode &&
    data.prevNode.type === "html" &&
    data.prevNode.position.end.line + 1 === node.position.start.line;

  const isHtmlDirectAfterListItem =
    data.parentNode.type === "listItem" &&
    data.prevNode.type === "paragraph" &&

  return (
    !(
      isSiblingNode ||
      isInTightListItem ||
      isPrevNodePrettierIgnore ||
      isBlockHtmlWithoutBlankLineBetweenPrevHtml ||
      isHtmlDirectAfterListItem
    )
  );
}

  const isIndentedCode = node.type === "code" && node.isIndented;

}

    "imageReference",
  ]);

  return (
  );
}

function printUrl(url, dangerousCharOrChars = []) {
  const dangerousChars = [
    " ",
    ...(Array.isArray(dangerousCharOrChars)
      ? dangerousCharOrChars
      : [dangerousCharOrChars]),
  ];
  return new RegExp(dangerousChars.map((x) => `\\${x}`).join("|")).test(url)
    : url;
}

function printTitle(title, options, printSpace) {
  if (printSpace == null) {
    printSpace = true;
  }

  if (!title) {
    return "";
  }
  if (printSpace) {
    return " " + printTitle(title, options, false);
  }

  // title is escaped after `remark-parse` v7
  title = title.replace(/\\(["')])/g, "$1");

  if (title.includes('"') && title.includes("'") && !title.includes(")")) {
    return `(${title})`; // avoid escaped quotes
  }
  // faster than using RegExps: https://jsperf.com/performance-of-match-vs-split
  const singleCount = title.split("'").length - 1;
  const doubleCount = title.split('"').length - 1;
  const quote =
    singleCount > doubleCount
      ? '"'
      : doubleCount > singleCount
      ? "'"
      : options.singleQuote
      ? "'"
      : '"';
  title = title.replace(/\\/, "\\\\");
  title = title.replace(new RegExp(`(${quote})`, "g"), "\\$1");
  return `${quote}${title}${quote}`;
}

function clamp(value, min, max) {
  return value < min ? min : value > max ? max : value;
}

function hasPrettierIgnore(path) {
  const index = Number(path.getName());

  if (index === 0) {
  }

  const prevNode = path.getParentNode().children[index - 1];
  return isPrettierIgnore(prevNode) === "next";
}

(directory) =>
  MARKERS.some((mark) => fs.existsSync(path.join(directory, mark)))

function findProjectRoot(directory) {
  while (!markerExists(directory)) {
    const parentDirectory = path.resolve(directory, "..");
    if (parentDirectory === directory) {
      break;
    }
    directory = parentDirectory;
  }

  return directory;
}

(filePath, parse) =>
  filePath &&
  parse(filePath, {
    root: findProjectRoot(path.dirname(path.resolve(filePath))),
  })

async (filePath) =>
  editorConfigToPrettier(await maybeParse(filePath, editorconfig.parse))

(filePath) =>
  editorConfigToPrettier(maybeParse(filePath, editorconfig.parseSync))

(result) => {
        if (result && result.config) {
          if (typeof result.config === "string") {
            const dir = path.dirname(result.filepath);
            const modulePath = resolve(result.config, { paths: [dir] });
            result.config = eval("require")(modulePath);
          }

          if (typeof result.config !== "object") {
            throw new Error(
              "Config is only allowed to be an object, " +
                `but received ${typeof result.config} in "${result.filepath}"`
            );
          }

          delete result.config.$schema;
        }
        return result;
      }

function getExplorer(opts) {
  opts = { sync: false, cache: false, ...opts };
  return getExplorerMemoized(opts);
}

function _resolveConfig(filePath, opts, sync) {
  opts = { useCache: true, ...opts };
  const loadOpts = {
    cache: Boolean(opts.useCache),
    sync: Boolean(sync),
    editorconfig: Boolean(opts.editorconfig),
  };
  const { load, search } = getExplorer(loadOpts);
  const loadEditorConfig = resolveEditorConfig.getLoadFunction(loadOpts);
  const arr = [
    opts.config ? load(opts.config) : search(filePath),
    loadEditorConfig(filePath),
  ];

  const unwrapAndMerge = ([result, editorConfigured]) => {
    const merged = {
      ...editorConfigured,
      ...mergeOverrides(result, filePath),
    };

    for (const optionName of ["plugins", "pluginSearchDirs"]) {
      if (Array.isArray(merged[optionName])) {
        merged[optionName] = merged[optionName].map((value) =>
          typeof value === "string" && value.startsWith(".") // relative path
            ? path.resolve(path.dirname(result.filepath), value)
            : value
        );
      }
    }

    if (!result && !editorConfigured) {
    }

    // We are not using this option
    delete merged.insertFinalNewline;
    return merged;
  };

  if (loadOpts.sync) {
    return unwrapAndMerge(arr);
  }

  return Promise.all(arr).then(unwrapAndMerge);
}

([result, editorConfigured]) => {
    };

            : value
        );
      }
    }

    }

  }

(filePath) => {
  const { search } = getExplorer({ sync: true });
  const result = search(filePath);
}

  mem.clear(getExplorerMemoized);
  resolveEditorConfig.clearCache();
}

async function resolveConfigFile(filePath) {
  const { search } = getExplorer({ sync: false });
  const result = await search(filePath);
}

  const { config, filepath: configPath } = configResult || {};
  const { overrides, ...options } = config || {};
  if (filePath && overrides) {
    const relativeFilePath = path.relative(path.dirname(configPath), filePath);
    for (const override of overrides) {
      if (
        )
      ) {
      }
    }
  }

}

function pathMatchesGlobs(filePath, patterns, excludedPatterns = []) {
  const patternList = Array.isArray(patterns) ? patterns : [patterns];
  const excludedPatternList = Array.isArray(excludedPatterns)
    ? excludedPatterns
    : [excludedPatterns];
  const opts = { matchBase: true, dot: true };

  return (
    patternList.some((pattern) => minimatch(filePath, pattern, opts)) &&
    !excludedPatternList.some((excludedPattern) =>
    )
  );
}

function isLastNodeOfSiblings(path) {
  const parentNode = path.getParentNode(0);

  if (
    isParentOfSomeType(path, ["ElementNode"]) &&
    parentNode.children[parentNode.children.length - 1] === node
  ) {
  }

  if (
    isParentOfSomeType(path, ["Block"]) &&
    parentNode.body[parentNode.body.length - 1] === node
  ) {
  }

}

function isUppercase(string) {
  return string.toUpperCase() === string;
}

function isGlimmerComponent(node) {
  return (
    isNodeOfSomeType(node, ["ElementNode"]) &&
    typeof node.tag === "string" &&
    (isUppercase(node.tag[0]) || node.tag.includes("."))
  );
}

function isVoid(node) {
  return (
    (isGlimmerComponent(node) &&
      node.children.every((n) => isWhitespaceNode(n))) ||
    voidTags.has(node.tag)
  );
}

function isWhitespaceNode(node) {
  return isNodeOfSomeType(node, ["TextNode"]) && !/\S/.test(node.chars);
}

function isNodeOfSomeType(node, types) {
  return node && types.includes(node.type);
}

function isParentOfSomeType(path, types) {
  return isNodeOfSomeType(parentNode, types);
}

function isPreviousNodeOfSomeType(path, types) {
  const previousNode = getPreviousNode(path);
  return isNodeOfSomeType(previousNode, types);
}

function isNextNodeOfSomeType(path, types) {
  const nextNode = getNextNode(path);
  return isNodeOfSomeType(nextNode, types);
}

function getSiblingNode(path, offset) {
  const parentNode = path.getParentNode(0) || {};
  const children =
    parentNode.children || parentNode.body || parentNode.parts || [];
  const index = children.indexOf(node);
  return index !== -1 && children[index + offset];
}

function getPreviousNode(path, lookBack = 1) {
  return getSiblingNode(path, -lookBack);
}

function getNextNode(path) {
  return getSiblingNode(path, 1);
}

function isPrettierIgnoreNode(node) {
  return (
    isNodeOfSomeType(node, ["MustacheCommentStatement"]) &&
    typeof node.value === "string" &&
    node.value.trim() === "prettier-ignore"
  );
}

  const previousPreviousNode = getPreviousNode(path, 2);
  return (
    isPrettierIgnoreNode(node) || isPrettierIgnoreNode(previousPreviousNode)
  );
}

get glimmer() {
    return require("./parser-glimmer").parsers.glimmer;
  }

function addBackslash(/* options*/) {
  return {
    name: "addBackslash",
    visitor: {
      TextNode(node) {
        node.chars = node.chars.replace(/\\/, "\\\\");
      },
    },
  };
}

TextNode(node) {
      }

function addOffset(text) {
  const lines = new LinesAndColumns(text);
  const calculateOffset = ({ line, column }) =>
    lines.indexForLocation({ line: line - 1, column });
  return (/* options*/) => ({
    name: "addOffset",
    visitor: {
      All(node) {
        const { start, end } = node.loc;
        start.offset = calculateOffset(start);
        end.offset = calculateOffset(end);
      },
    },
  });
}

({ line, column }) =>
    lines.indexForLocation({ line: line - 1, column })

All(node) {
      }

function parse(text) {
  const { preprocess: glimmer } = require("@glimmer/syntax");
  let ast;
  try {
    ast = glimmer(text, {
      mode: "codemod",
      plugins: { ast: [addBackslash, addOffset(text)] },
    });
    const location = getErrorLocation(error);

    if (location) {
      throw createError(error.message, location);
    }

  }

}

function getErrorLocation(error) {
  const { location, hash } = error;
  if (location) {
    const { start, end } = location;
    if (typeof end.line !== "number") {
      return { start };
    }
    return location;
  }

  if (hash) {
    const {
      loc: { last_line, last_column },
    } = hash;
    return { start: { line: last_line, column: last_column + 1 } };
  }
}

function clean(ast, newNode /*, parent*/) {
  // (Glimmer/HTML) ignore TextNode
  if (ast.type === "TextNode") {
    const trimmed = ast.chars.trim();
    if (!trimmed) {
    }
    newNode.chars = trimmed.replace(/[\t\n\f\r ]+/g, " ");
  }

  // `class` is reformatted
  if (ast.type === "AttrNode" && ast.name.toLowerCase() === "class") {
    delete newNode.value;
  }
}

function print(path, options, print) {

  /* istanbul ignore if*/
  if (!n) {
    return "";
  }

  if (hasPrettierIgnore(path)) {
    return options.originalText.slice(locStart(n), locEnd(n));
  }

    case "Block":
    case "Program":
    case "Template": {
      return group(path.map(print, "body"));
    }

    case "ElementNode": {
      const startingTag = group(printStartingTag(path, print));

      const escapeNextElementNode =
        options.htmlWhitespaceSensitivity === "ignore" &&
        isNextNodeOfSomeType(path, ["ElementNode"])
          ? softline
          : "";

      if (isVoid(n)) {
        return [startingTag, escapeNextElementNode];
      }

      const endingTag = ["</", n.tag, ">"];

      if (n.children.length === 0) {
        return [startingTag, indent(endingTag), escapeNextElementNode];
      }

      if (options.htmlWhitespaceSensitivity === "ignore") {
        return [
          startingTag,
          indent(printChildren(path, options, print)),
          hardline,
          indent(endingTag),
          escapeNextElementNode,
        ];
      }

      return [
        startingTag,
        indent(group(printChildren(path, options, print))),
        indent(endingTag),
        escapeNextElementNode,
      ];
    }

    case "BlockStatement": {
      const pp = path.getParentNode(1);

      const isElseIf =
        pp &&
        pp.inverse &&
        pp.inverse.body.length === 1 &&
        pp.inverse.body[0] === n &&
        pp.inverse.body[0].path.parts[0] === "if";

      if (isElseIf) {
        return [
          printElseIfBlock(path, print),
          printProgram(path, print, options),
          printInverse(path, print, options),
        ];
      }

      return [
        printOpenBlock(path, print),
        group([
          printCloseBlock(path, print, options),
        ]),
      ];
    }

    case "ElementModifierStatement": {
      return group(["{{", printPathAndParams(path, print), softline, "}}"]);
    }
    case "MustacheStatement": {
      const isParentOfSpecifiedTypes = isParentOfSomeType(path, [
        "AttrNode",
        "ConcatStatement",
      ]);

      const isChildOfElementNodeAndDoesNotHaveParams =
        isParentOfSomeType(path, ["ElementNode"]) &&
        doesNotHaveHashParams(n) &&
        doesNotHavePositionalParams(n);

      const shouldBreakOpeningMustache =
        isParentOfSpecifiedTypes || isChildOfElementNodeAndDoesNotHaveParams;

        printOpeningMustache(n),
        shouldBreakOpeningMustache ? indent(softline) : "",
        printPathAndParams(path, print),
        softline,
        printClosingMustache(n),
      ]);
    }

    case "SubExpression": {
        "(",
        printSubExpressionPathAndParams(path, print),
        softline,
        ")",
      ]);
    }
    case "AttrNode": {
      const isText = n.value.type === "TextNode";
      const isEmptyText = isText && n.value.chars === "";

      // If the text is empty and the value's loc start and end offsets are the
      // same, there is no value for this AttrNode and it should be printed
      // without the `=""`. Example: `<img data-test>` -> `<img data-test>`
      if (isEmptyText && locStart(n.value) === locEnd(n.value)) {
        return n.name;
      }

      // Let's assume quotes inside the content of text nodes are already
      // properly escaped with entities, otherwise the parse wouldn't have parsed them.
      const quote = isText
        ? chooseEnclosingQuote(options, n.value.chars).quote
        : n.value.type === "ConcatStatement"
        ? chooseEnclosingQuote(
            options,
            n.value.parts
              .filter((part) => part.type === "TextNode")
              .map((part) => part.chars)
              .join("")
          ).quote
        : "";

      const valueDoc = path.call(print, "value");

      return [
        n.name,
        "=",
        quote,
        n.name === "class" && quote ? group(indent(valueDoc)) : valueDoc,
        quote,
      ];
    }

    case "ConcatStatement": {
      return path.map(print, "parts");
    }

    case "Hash": {
      return join(line, path.map(print, "pairs"));
    }
    case "HashPair": {
      return [n.key, "=", path.call(print, "value")];
    }
    case "TextNode": {
      /* if `{{my-component}}` (or any text containing "{{")
       * makes it to the TextNode, it means it was escaped,
       * so let's print it escaped, ie.; `\{{my-component}}` */
      let text = n.chars.replace(/{{/g, "\\{{");

      const attrName = getCurrentAttributeName(path);

      if (attrName) {
        // TODO: format style and srcset attributes
        if (attrName === "class") {
          const formattedClasses = text.trim().split(/\s+/).join(" ");

          let leadingSpace = false;
          let trailingSpace = false;

          if (isParentOfSomeType(path, ["ConcatStatement"])) {
            if (
              isPreviousNodeOfSomeType(path, ["MustacheStatement"]) &&
              /^\s/.test(text)
            ) {
              leadingSpace = true;
            }
            if (
              isNextNodeOfSomeType(path, ["MustacheStatement"]) &&
              /\s$/.test(text) &&
              formattedClasses !== ""
            ) {
              trailingSpace = true;
            }
          }

          return [
            leadingSpace ? line : "",
            formattedClasses,
            trailingSpace ? line : "",
          ];
        }

        return replaceEndOfLineWith(text, literalline);
      }

      const whitespacesOnlyRE = /^[\t\n\f\r ]*$/;
      const isWhitespaceOnly = whitespacesOnlyRE.test(text);
      const isFirstElement = !getPreviousNode(path);
      const isLastElement = !getNextNode(path);

      if (options.htmlWhitespaceSensitivity !== "ignore") {
        // https://infra.spec.whatwg.org/#ascii-whitespace
        const leadingWhitespacesRE = /^[\t\n\f\r ]*/;
        const trailingWhitespacesRE = /[\t\n\f\r ]*$/;

        // let's remove the file's final newline
        // https://github.com/ember-cli/ember-new-output/blob/1a04c67ddd02ccb35e0ff41bb5cbce34b31173ef/.editorconfig#L16
        const shouldTrimTrailingNewlines =
          isLastElement && isParentOfSomeType(path, ["Template"]);
        const shouldTrimLeadingNewlines =
          isFirstElement && isParentOfSomeType(path, ["Template"]);

        if (isWhitespaceOnly) {
          if (shouldTrimLeadingNewlines || shouldTrimTrailingNewlines) {
            return "";
          }

          let breaks = [line];

          const newlines = countNewLines(text);
          if (newlines) {
            breaks = generateHardlines(newlines);
          }

          if (isLastNodeOfSiblings(path)) {
            breaks = breaks.map((newline) => dedent(newline));
          }

          return breaks;
        }

        const [lead] = text.match(leadingWhitespacesRE);
        const [tail] = text.match(trailingWhitespacesRE);

        let leadBreaks = [];
        if (lead) {
          leadBreaks = [line];

          const leadingNewlines = countNewLines(lead);
          if (leadingNewlines) {
            leadBreaks = generateHardlines(leadingNewlines);
          }

          text = text.replace(leadingWhitespacesRE, "");
        }

        let trailBreaks = [];
        if (tail) {
          if (!shouldTrimTrailingNewlines) {
            trailBreaks = [line];

            const trailingNewlines = countNewLines(tail);
            if (trailingNewlines) {
              trailBreaks = generateHardlines(trailingNewlines);
            }

            if (isLastNodeOfSiblings(path)) {
              trailBreaks = trailBreaks.map((hardline) => dedent(hardline));
            }
          }

          text = text.replace(trailingWhitespacesRE, "");
        }

        return [...leadBreaks, fill(getTextValueParts(text)), ...trailBreaks];
      }

      const lineBreaksCount = countNewLines(text);

      let leadingLineBreaksCount = countLeadingNewLines(text);
      let trailingLineBreaksCount = countTrailingNewLines(text);

      if (
        (isFirstElement || isLastElement) &&
        isWhitespaceOnly &&
        isParentOfSomeType(path, ["Block", "ElementNode", "Template"])
      ) {
        return "";
      }

      if (isWhitespaceOnly && lineBreaksCount) {
        leadingLineBreaksCount = Math.min(
          lineBreaksCount,
          NEWLINES_TO_PRESERVE_MAX
        );
        trailingLineBreaksCount = 0;
      } else {
        if (isNextNodeOfSomeType(path, ["BlockStatement", "ElementNode"])) {
          trailingLineBreaksCount = Math.max(trailingLineBreaksCount, 1);
        }

        if (isPreviousNodeOfSomeType(path, ["BlockStatement", "ElementNode"])) {
          leadingLineBreaksCount = Math.max(leadingLineBreaksCount, 1);
        }
      }

      let leadingSpace = "";
      let trailingSpace = "";

      if (
        trailingLineBreaksCount === 0 &&
        isNextNodeOfSomeType(path, ["MustacheStatement"])
      ) {
        trailingSpace = " ";
      }

      if (
        leadingLineBreaksCount === 0 &&
        isPreviousNodeOfSomeType(path, ["MustacheStatement"])
      ) {
        leadingSpace = " ";
      }

      if (isFirstElement) {
        leadingLineBreaksCount = 0;
        leadingSpace = "";
      }

      if (isLastElement) {
        trailingSpace = "";
      }

      text = text
        .replace(/^[\t\n\f\r ]+/g, leadingSpace)
        .replace(/[\t\n\f\r ]+$/, trailingSpace);

      return [
        ...generateHardlines(leadingLineBreaksCount),
        fill(getTextValueParts(text)),
        ...generateHardlines(trailingLineBreaksCount),
      ];
    }
    case "MustacheCommentStatement": {
      const start = locStart(n);
      const end = locEnd(n);
      // Starts with `{{~`
      const isLeftWhiteSpaceSensitive =
        options.originalText.charAt(start + 2) === "~";
      // Ends with `{{~`
      const isRightWhitespaceSensitive =
        options.originalText.charAt(end - 3) === "~";

      const dashes = n.value.includes("}}") ? "--" : "";
      return [
        "{{",
        isLeftWhiteSpaceSensitive ? "~" : "",
        "!",
        dashes,
        n.value,
        dashes,
        isRightWhitespaceSensitive ? "~" : "",
        "}}",
      ];
    }
    case "PathExpression": {
      return n.original;
    }
    case "BooleanLiteral": {
      return String(n.value);
    }
    case "CommentStatement": {
      return ["<!--", n.value, "-->"];
    }
    case "StringLiteral": {
      return printStringLiteral(n.value, options);
    }
    case "NumberLiteral": {
    }
    case "UndefinedLiteral": {
      return "undefined";
    }
    case "NullLiteral": {
    }

    default:
      throw new Error("unknown glimmer type: " + JSON.stringify(n.type));
  }
}

function printStartingTag(path, print) {

  const attributesLike = ["attributes", "modifiers", "comments", "blockParams"]
    .filter((property) => isNonEmptyArray(node[property]))
    .map((property) => [
      line,
      property === "blockParams"
        ? printBlockParams(node)
        : join(line, path.map(print, property)),
    ]);

  return [
    "<",
    node.tag,
    indent(attributesLike),
    printStartingTagEndMarker(node),
  ];
}

function printChildren(path, options, print) {
  const isEmpty = node.children.every((n) => isWhitespaceNode(n));
  if (options.htmlWhitespaceSensitivity === "ignore" && isEmpty) {
    return "";
  }

  return path.map((childPath, childIndex) => {
    const printedChild = print(childPath, options, print);

    if (childIndex === 0 && options.htmlWhitespaceSensitivity === "ignore") {
      return [softline, printedChild];
    }

    return printedChild;
}

function printStartingTagEndMarker(node) {
  if (isVoid(node)) {
    return ifBreak([softline, "/>"], [" />", softline]);
  }

  return ifBreak([softline, ">"], ">");
}

function printOpeningMustache(node) {
  const mustache = node.escaped === false ? "{{{" : "{{";
  const strip = node.strip && node.strip.open ? "~" : "";
  return [mustache, strip];
}

function printClosingMustache(node) {
  const mustache = node.escaped === false ? "}}}" : "}}";
  const strip = node.strip && node.strip.close ? "~" : "";
  return [strip, mustache];
}

function printOpeningBlockOpeningMustache(node) {
  const opening = printOpeningMustache(node);
  const strip = node.openStrip.open ? "~" : "";
  return [opening, strip, "#"];
}

function printOpeningBlockClosingMustache(node) {
  const closing = printClosingMustache(node);
  const strip = node.openStrip.close ? "~" : "";
  return [strip, closing];
}

function printClosingBlockOpeningMustache(node) {
  const strip = node.closeStrip.open ? "~" : "";
  return [opening, strip, "/"];
}

function printClosingBlockClosingMustache(node) {
  const strip = node.closeStrip.close ? "~" : "";
}

function printInverseBlockOpeningMustache(node) {
  const strip = node.inverseStrip.open ? "~" : "";
  return [opening, strip];
}

function printInverseBlockClosingMustache(node) {
  const strip = node.inverseStrip.close ? "~" : "";
}

function printOpenBlock(path, print) {

  const openingMustache = printOpeningBlockOpeningMustache(node);
  const closingMustache = printOpeningBlockClosingMustache(node);

  const attributes = [printPath(path, print)];

  const params = printParams(path, print);
  if (params) {
    attributes.push(line, params);
  }

  if (isNonEmptyArray(node.program.blockParams)) {
    const block = printBlockParams(node.program);
    attributes.push(line, block);
  }

  return group([
    openingMustache,
    indent(group(attributes)),
    softline,
    closingMustache,
  ]);
}

function printElseBlock(node, options) {
  return [
    options.htmlWhitespaceSensitivity === "ignore" ? hardline : "",
    printInverseBlockOpeningMustache(node),
    "else",
    printInverseBlockClosingMustache(node),
  ];
}

function printElseIfBlock(path, print) {
  const parentNode = path.getParentNode(1);

  return [
    printInverseBlockOpeningMustache(parentNode),
    "else ",
    printPathAndParams(path, print),
    printInverseBlockClosingMustache(parentNode),
  ];
}

function printCloseBlock(path, print, options) {

  if (options.htmlWhitespaceSensitivity === "ignore") {
    const escape = blockStatementHasOnlyWhitespaceInProgram(node)
      ? softline
      : hardline;

    return [
      escape,
      printClosingBlockOpeningMustache(node),
      path.call(print, "path"),
      printClosingBlockClosingMustache(node),
    ];
  }

  return [
    printClosingBlockOpeningMustache(node),
    path.call(print, "path"),
    printClosingBlockClosingMustache(node),
  ];
}

function blockStatementHasOnlyWhitespaceInProgram(node) {
  return (
    isNodeOfSomeType(node, ["BlockStatement"]) &&
    node.program.body.every((n) => isWhitespaceNode(n))
  );
}

function blockStatementHasElseIf(node) {
  return (
    blockStatementHasElse(node) &&
    node.inverse.body.length === 1 &&
    isNodeOfSomeType(node.inverse.body[0], ["BlockStatement"]) &&
    node.inverse.body[0].path.parts[0] === "if"
  );
}

function blockStatementHasElse(node) {
  return isNodeOfSomeType(node, ["BlockStatement"]) && node.inverse;
}

function printProgram(path, print, options) {

  if (blockStatementHasOnlyWhitespaceInProgram(node)) {
    return "";
  }

  const program = path.call(print, "program");

    return indent([hardline, program]);
  }

  return indent(program);
}

function printInverse(path, print, options) {

  const inverse = path.call(print, "inverse");
  const printed =
    options.htmlWhitespaceSensitivity === "ignore"
      ? [hardline, inverse]
      : inverse;

  if (blockStatementHasElseIf(node)) {
  }

  if (blockStatementHasElse(node)) {
    return [printElseBlock(node, options), indent(printed)];
  }

  return "";
}

function getTextValueParts(value) {
  return getDocParts(join(line, splitByHtmlWhitespace(value)));
}

function splitByHtmlWhitespace(string) {
  return string.split(/[\t\n\f\r ]+/);
}

function getCurrentAttributeName(path) {
  for (let depth = 0; depth < 2; depth++) {
    const parentNode = path.getParentNode(depth);
    if (parentNode && parentNode.type === "AttrNode") {
      return parentNode.name.toLowerCase();
    }
  }
}

function countNewLines(string) {
  string = typeof string === "string" ? string : "";
  return string.split("\n").length - 1;
}

function countLeadingNewLines(string) {
  const newLines = (string.match(/^([^\S\n\r]*[\n\r])+/g) || [])[0] || "";
  return countNewLines(newLines);
}

function countTrailingNewLines(string) {
  const newLines = (string.match(/([\n\r][^\S\n\r]*)+$/g) || [])[0] || "";
}

function generateHardlines(number = 0) {
  return new Array(Math.min(number, NEWLINES_TO_PRESERVE_MAX)).fill(hardline);
}

function printStringLiteral(stringLiteral, options) {
  const { quote, regex } = chooseEnclosingQuote(options, stringLiteral);
  return [quote, stringLiteral.replace(regex, `\\${quote}`), quote];
}

function chooseEnclosingQuote(options, stringLiteral) {
  const double = { quote: '"', regex: /"/g };
  const single = { quote: "'", regex: /'/g };

  const preferred = options.singleQuote ? single : double;
  const alternate = preferred === single ? double : single;

  let shouldUseAlternateQuote = false;

  // If `stringLiteral` contains at least one of the quote preferred for
  // enclosing the string, we might want to enclose with the alternate quote
  // instead, to minimize the number of escaped quotes.
  if (
    stringLiteral.includes(preferred.quote) ||
    stringLiteral.includes(alternate.quote)
  ) {
    const numPreferredQuotes = (stringLiteral.match(preferred.regex) || [])
      .length;
    const numAlternateQuotes = (stringLiteral.match(alternate.regex) || [])
      .length;

    shouldUseAlternateQuote = numPreferredQuotes > numAlternateQuotes;
  }

  return shouldUseAlternateQuote ? alternate : preferred;
}

function printSubExpressionPathAndParams(path, print) {
  const p = printPath(path, print);

  if (!params) {
    return p;
  }

  return indent([p, line, group(params)]);
}

function printPathAndParams(path, print) {

    return p;
  }

  return indent(group([p, line, params]));
}

function printPath(path, print) {
  return path.call(print, "path");
}

function printParams(path, print) {

  if (node.params.length > 0) {
    const params = path.map(print, "params");
    parts.push(...params);
  }

  if (node.hash && node.hash.pairs.length > 0) {
    const hash = path.call(print, "hash");
    parts.push(hash);
  }

  if (parts.length === 0) {
    return "";
  }

  return join(line, parts);
}

function printBlockParams(node) {
  return ["as |", node.blockParams.join(" "), "|"];
}

function doesNotHaveHashParams(node) {
  return node.hash.pairs.length === 0;
}

function doesNotHavePositionalParams(node) {
  return node.params.length === 0;
}

  if (!n) {
    return "";
  }

    return n;
  }

      path.each((pathChild, index, definitions) => {
        parts.push(pathChild.call(print));
        if (index !== definitions.length - 1) {
          if (
            isNextLineEmpty(options.originalText, pathChild.getValue(), locEnd)
          ) {
          }
        }
      }, "definitions");
      return [...parts, hardline];
    }
      const hasOperation = options.originalText[locStart(n)] !== "{";
      const hasName = Boolean(n.name);
      return [
        hasOperation ? n.operation : "",
        hasOperation && hasName ? [" ", path.call(print, "name")] : "",
        isNonEmptyArray(n.variableDefinitions)
          ? group([
              "(",
              indent([
                softline,
                join(
                  [ifBreak("", ", "), softline],
                  path.map(print, "variableDefinitions")
                ),
              ]),
              softline,
              ")",
            ])
          : "",
        n.selectionSet ? (!hasOperation && !hasName ? "" : " ") : "",
        path.call(print, "selectionSet"),
      ];
    }
      return [
          ? group([
              "(",
              indent([
                softline,
                join(
                ),
              ]),
              softline,
              ")",
            ])
          : "",
        " on ",
        " ",
      ];
    }
      return [
        "{",
        indent([
          hardline,
          join(
            hardline,
            path.call(
              (selectionsPath) => printSequence(selectionsPath, options, print),
              "selections"
            )
          ),
        ]),
        hardline,
        "}",
      ];
    }
        n.alias ? [path.call(print, "alias"), ": "] : "",
          ? group([
              "(",
              indent([
                softline,
                join(
                    (argsPath) => printSequence(argsPath, options, print),
                    "arguments"
                  )
                ),
              ]),
              softline,
              ")",
            ])
          : "",
        n.selectionSet ? " " : "",
      ]);
    }
    }
      if (n.block) {
        return [
          '"""',
          hardline,
          join(hardline, n.value.replace(/"""/g, "\\$&").split("\n")),
          hardline,
          '"""',
        ];
      }
      return [
        '"',
        n.value.replace(/["\\]/g, "\\$&").replace(/\n/g, "\\n"),
        '"',
      ];
    }
    }
    }
    }
      return ["$", path.call(print, "name")];
    }
        "[",
        indent([
          softline,
          join([ifBreak("", ", "), softline], path.map(print, "values")),
        ]),
        softline,
        "]",
      ]);
    }
        "{",
        options.bracketSpacing && n.fields.length > 0 ? " " : "",
        indent([
          softline,
          join([ifBreak("", ", "), softline], path.map(print, "fields")),
        ]),
        softline,
        ifBreak("", options.bracketSpacing && n.fields.length > 0 ? " " : ""),
        "}",
      ]);
    }
      return [path.call(print, "name"), ": ", path.call(print, "value")];
    }

      return [
        "@",
          ? group([
              "(",
              indent([
                softline,
                join(
                  )
                ),
              ]),
              softline,
              ")",
            ])
          : "",
      ];
    }

    }

      return [
        ": ",
        n.defaultValue ? [" = ", path.call(print, "defaultValue")] : "",
      ];
    }

    case "ObjectTypeExtension":
      return [
        path.call(print, "description"),
        n.description ? hardline : "",
        n.kind === "ObjectTypeExtension" ? "extend " : "",
        "type ",
          ? [" implements ", ...printInterfaces(path, options, print)]
          : "",
          ? [
              " {",
              indent([
                hardline,
                join(
                  hardline,
                    (fieldsPath) => printSequence(fieldsPath, options, print),
                    "fields"
                  )
                ),
              ]),
              hardline,
              "}",
            ]
          : "",
      ];
    }

      return [
          ? group([
              "(",
              indent([
                softline,
                join(
                  )
                ),
              ]),
              softline,
              ")",
            ])
          : "",
        ": ",
      ];
    }

      return [
        "@",
          ? group([
              "(",
              indent([
                softline,
                join(
                  )
                ),
              ]),
              softline,
              ")",
            ])
          : "",
        n.repeatable ? " repeatable" : "",
        " on ",
        join(" | ", path.map(print, "locations")),
      ];
    }

    case "EnumTypeExtension":
      return [
        n.kind === "EnumTypeExtension" ? "extend " : "",
        "enum ",

          ? [
              " {",
              indent([
                hardline,
                join(
                  hardline,
                    (valuesPath) => printSequence(valuesPath, options, print),
                    "values"
                  )
                ),
              ]),
              hardline,
              "}",
            ]
          : "",
      ];
    }

      return [
      ];
    }

      return [
        n.description ? (n.description.block ? hardline : line) : "",
        ": ",
      ];
    }

    case "InputObjectTypeExtension":
      return [
        n.kind === "InputObjectTypeExtension" ? "extend " : "",
        "input ",
          ? [
              " {",
              indent([
                hardline,
                join(
                  hardline,
                    "fields"
                  )
                ),
              ]),
              hardline,
              "}",
            ]
          : "",
      ];
    }

      return [
        "schema",
        " {",
          ? indent([
              hardline,
              join(
                hardline,
                path.call(
                  (opsPath) => printSequence(opsPath, options, print),
                  "operationTypes"
                )
              ),
            ])
          : "",
        hardline,
        "}",
      ];
    }

      return [path.call(print, "operation"), ": ", path.call(print, "type")];
    }

    case "InterfaceTypeExtension":
      return [
        n.kind === "InterfaceTypeExtension" ? "extend " : "",
          : "",
          ? [
              " {",
              indent([
                hardline,
                join(
                  hardline,
                    "fields"
                  )
                ),
              ]),
              hardline,
              "}",
            ]
          : "",
      ];
    }

      return ["...", path.call(print, "name"), printDirectives(path, print, n)];
    }

      return [
        "...",
        n.typeCondition ? [" on ", path.call(print, "typeCondition")] : "",
        " ",
      ];
    }

    case "UnionTypeExtension":
        group([
          n.kind === "UnionTypeExtension" ? "extend " : "",
          "union ",
          n.types.length > 0
            ? [
                " =",
                ifBreak("", " "),
                indent([
                  ifBreak([line, "  "]),
                  join([line, "| "], path.map(print, "types")),
                ]),
              ]
            : "",
        ]),
      ]);
    }

    case "ScalarTypeExtension":
      return [
        n.kind === "ScalarTypeExtension" ? "extend " : "",
        "scalar ",
      ];
    }

      return [path.call(print, "type"), "!"];
    }

      return ["[", path.call(print, "type"), "]"];
    }

    default:
  }
}

    return "";
  }

  const printed = join(line, path.map(print, "directives"));

  if (n.kind === "FragmentDefinition" || n.kind === "OperationDefinition") {
    return group([line, printed]);
  }

  return [" ", group(indent([softline, printed]))];
}

    if (
      isNextLineEmpty(options.originalText, path.getValue(), locEnd) &&
      i < count - 1
    ) {
      return [printed, hardline];
    }

  });
}

function canAttachComment(node) {
  return node.kind && node.kind !== "Comment";
}

function printComment(commentPath) {
  const comment = commentPath.getValue();
  if (comment.kind === "Comment") {
    return "#" + comment.value.trimEnd();
  }

  throw new Error("Not a comment: " + JSON.stringify(comment));
}

function printInterfaces(path, options, print) {
  const node = path.getNode();
  const { interfaces } = node;
  const printed = path.map((node) => print(node), "interfaces");

  for (let index = 0; index < interfaces.length; index++) {
    const interfaceNode = interfaces[index];
    parts.push(printed[index]);
    const nextInterfaceNode = interfaces[index + 1];
    if (nextInterfaceNode) {
      const textBetween = options.originalText.slice(
        interfaceNode.loc.end,
        nextInterfaceNode.loc.start
      );
      const hasComment = textBetween.includes("#");
      const separator = textBetween.replace(/#.*/g, "").trim();

      parts.push(separator === "," ? "," : " &", hasComment ? line : " ");
    }
  }

}

  return (
    node &&
    Array.isArray(node.comments) &&
    node.comments.some((comment) => comment.value.trim() === "prettier-ignore")
  );
}

    return require("./parser-graphql").parsers.graphql;
  }

  const { startToken } = ast.loc;
  let { next } = startToken;
        column: next.column - 1,
      });
    }
  }

}

function createParseError(error) {
  const { GraphQLError } = require("graphql/error");
  if (error instanceof GraphQLError) {
    const {
      message,
      locations: [start],
    } = error;
    return createError(message, { start });
  }

}

  const { parse } = require("graphql/language");
  const { result: ast, error } = tryCombinations(
    () => parse(text, { ...parseOptions }),
    () =>
      parse(text, { ...parseOptions, allowLegacySDLImplementsInterfaces: true })
  );

  if (!ast) {
    throw createParseError(error);
  }

  ast.comments = parseComments(ast);
  removeTokens(ast);
}

function hasPragma(text) {
  return /^\s*#[^\S\n]*@(format|prettier)\s*(\n|$)/.test(text);
}

function insertPragma(text) {
  return "# @format\n\n" + text;
}

  if (typeof node.start === "number") {
    return node.start;
  }
  return node.loc && node.loc.start;
}

  if (typeof node.end === "number") {
    return node.end;
  }
  return node.loc && node.loc.end;
}

function getParsers(options) {
  const parsers = {};
  for (const plugin of options.plugins) {
    // TODO: test this with plugins
    if (!plugin.parsers) {
      continue;
    }

    for (const name of ownNames(plugin.parsers)) {
      Object.defineProperty(parsers, name, ownDescriptor(plugin.parsers, name));
    }
  }

  return parsers;
}

function resolveParser(opts, parsers = getParsers(opts)) {
    // Custom parser API always works with JavaScript.
    return {
      parse: opts.parser,
      astFormat: "estree",
      locStart,
      locEnd,
    };
  }

    if (Object.prototype.hasOwnProperty.call(parsers, opts.parser)) {
    }

    if (process.env.PRETTIER_TARGET === "universal") {
      throw new ConfigError(
        `Couldn't resolve parser "${opts.parser}". Parsers must be explicitly added to the standalone bundle.`
      );
    }

    try {
      return {
        parse: eval("require")(path.resolve(process.cwd(), opts.parser)),
        astFormat: "estree",
        locStart,
        locEnd,
      };
    }
  }
}

  const parsers = getParsers(opts);

  // Create a new object {parserName: parseFn}. Uses defineProperty() to only call
  // the parsers getters when actually calling the parser `parse` function.
  const parsersForCustomParserApi = Object.keys(parsers).reduce(
    (object, parserName) =>
      Object.defineProperty(object, parserName, {
        enumerable: true,
        get() {
          return parsers[parserName].parse;
        },
      }),
    {}
  );

  const parser = resolveParser(opts, parsers);

  try {
    if (parser.preprocess) {
      text = parser.preprocess(text, opts);
    }

    return {
      text,
      ast: parser.parse(text, parsersForCustomParserApi, opts),
    };
    const { loc } = error;

    if (loc) {
      const { codeFrameColumns } = require("@babel/code-frame");
      error.codeFrame = codeFrameColumns(text, loc, { highlightCode: true });
    }

  }
}

function getSortedChildNodes(node, options, resultArray) {
    return;
  }
  const { printer, locStart, locEnd } = options;

    if (printer.canAttachComment && printer.canAttachComment(node)) {
      let i;
      for (i = resultArray.length - 1; i >= 0; --i) {
        if (
          locStart(resultArray[i]) <= locStart(node) &&
          locEnd(resultArray[i]) <= locEnd(node)
        ) {
          break;
        }
      }
      return;
    }
  } else if (childNodesCache.has(node)) {
    return childNodesCache.get(node);
  }

  const childNodes =
    (printer.getCommentChildNodes &&
      printer.getCommentChildNodes(node, options)) ||
    (typeof node === "object" &&
      Object.entries(node)
        .filter(
          ([n]) =>
            n !== "enclosingNode" &&
            n !== "precedingNode" &&
            n !== "followingNode" &&
            n !== "tokens" &&
            n !== "comments"
        )
        .map(([, value]) => value));

  if (!childNodes) {
    return;
  }

    resultArray = [];
    childNodesCache.set(node, resultArray);
  }

  for (const childNode of childNodes) {
    getSortedChildNodes(childNode, options, resultArray);
  }

}

function decorateComment(node, comment, options, enclosingNode) {
  const { locStart, locEnd } = options;
  const commentStart = locStart(comment);
  const commentEnd = locEnd(comment);

  const childNodes = getSortedChildNodes(node, options);
  let precedingNode;
  let followingNode;
  let left = 0;
  let right = childNodes.length;
    const middle = (left + right) >> 1;
    const child = childNodes[middle];
    const start = locStart(child);
    const end = locEnd(child);

    // The comment is completely contained by this child node.
    if (start <= commentStart && commentEnd <= end) {
      // Abandon the binary search at this level.
      return decorateComment(child, comment, options, child);
    }

    if (end <= commentStart) {
      precedingNode = child;
      continue;
    }

    if (commentEnd <= start) {
      followingNode = child;
      continue;
    }

  }

  // We don't want comments inside of different expressions inside of the same
  // template literal to move to another expression.
  if (enclosingNode && enclosingNode.type === "TemplateLiteral") {
    const { quasis } = enclosingNode;
    const commentIndex = findExpressionIndexForComment(
      quasis,
      comment,
      options
    );

    if (
      precedingNode &&
      findExpressionIndexForComment(quasis, precedingNode, options) !==
        commentIndex
    ) {
      precedingNode = null;
    }
    if (
      followingNode &&
      findExpressionIndexForComment(quasis, followingNode, options) !==
    ) {
      followingNode = null;
    }
  }

  return { enclosingNode, precedingNode, followingNode };
}

function attach(comments, ast, text, options) {
  if (!Array.isArray(comments)) {
    return;
  }

  const tiesToBreak = [];
  const {
    locStart,
    locEnd,
    printer: { handleComments = {} },
  } = options;
  // TODO: Make this as default behavior
  const {
    avoidAstMutation,
    ownLine: handleOwnLineComment = returnFalse,
    endOfLine: handleEndOfLineComment = returnFalse,
    remaining: handleRemainingComment = returnFalse,
  } = handleComments;

  const decoratedComments = comments.map((comment, index) => ({
    ...decorateComment(ast, comment, options),
    comment,
    text,
    options,
    ast,
    isLastComment: comments.length - 1 === index,
  }));

  for (const [index, context] of decoratedComments.entries()) {
    const {
      comment,
      precedingNode,
      enclosingNode,
      followingNode,
      text,
      options,
      ast,
      isLastComment,
    } = context;

    if (
      options.parser === "json" ||
      options.parser === "json5" ||
      options.parser === "__js_expression" ||
      options.parser === "__vue_expression"
    ) {
      if (locStart(comment) - locStart(ast) <= 0) {
        addLeadingComment(ast, comment);
        continue;
      }
      if (locEnd(comment) - locEnd(ast) >= 0) {
        addTrailingComment(ast, comment);
        continue;
      }
    }

    let args;
    if (avoidAstMutation) {
      args = [context];
    } else {
      comment.enclosingNode = enclosingNode;
      comment.precedingNode = precedingNode;
      comment.followingNode = followingNode;
      args = [comment, text, options, ast, isLastComment];
    }

    if (isOwnLineComment(text, options, decoratedComments, index)) {
      comment.placement = "ownLine";
      // If a comment exists on its own line, prefer a leading comment.
      // We also need to check if it's the first line of the file.
      if (handleOwnLineComment(...args)) {
        // We're good
      } else if (followingNode) {
        // Always a leading comment.
        addLeadingComment(followingNode, comment);
      } else if (precedingNode) {
        addTrailingComment(precedingNode, comment);
      } else if (enclosingNode) {
        addDanglingComment(enclosingNode, comment);
      } else {
        // There are no nodes, let's attach it to the root of the ast
        addDanglingComment(ast, comment);
      }
    } else if (isEndOfLineComment(text, options, decoratedComments, index)) {
      comment.placement = "endOfLine";
      if (handleEndOfLineComment(...args)) {
        // There is content before this comment on the same line, but
        // none after it, so prefer a trailing comment of the previous node.
      } else {
      }
    } else {
      comment.placement = "remaining";
      if (handleRemainingComment(...args)) {
      } else if (precedingNode && followingNode) {
        // Otherwise, text exists both before and after the comment on
        // the same line. If there is both a preceding and following
        // node, use a tie-breaking algorithm to determine if it should
        // be attached to the next or previous node. In the last case,
        // simply attach the right node;
        const tieCount = tiesToBreak.length;
        if (tieCount > 0) {
          const lastTie = tiesToBreak[tieCount - 1];
          if (lastTie.followingNode !== followingNode) {
            breakTies(tiesToBreak, text, options);
          }
        }
        tiesToBreak.push(context);
      } else {
      }
    }
  }

  breakTies(tiesToBreak, text, options);

  if (!avoidAstMutation) {
    for (const comment of comments) {
      // These node references were useful for breaking ties, but we
      // don't need them anymore, and they create cycles in the AST that
      // may lead to infinite recursion if we don't delete them here.
      delete comment.precedingNode;
      delete comment.enclosingNode;
      delete comment.followingNode;
    }
  }
}

function isOwnLineComment(text, options, decoratedComments, commentIndex) {
  const { comment, precedingNode } = decoratedComments[commentIndex];
  let start = locStart(comment);

    // Find first comment on the same line
    for (let index = commentIndex - 1; index >= 0; index--) {
      const {
        comment,
        precedingNode: currentCommentPrecedingNode,
      } = decoratedComments[index];
      if (
        currentCommentPrecedingNode !== precedingNode ||
        !isAllEmptyAndNoLineBreak(text.slice(locEnd(comment), start))
      ) {
        break;
      }
      start = locStart(comment);
    }
  }

  return hasNewline(text, start, { backwards: true });
}

function isEndOfLineComment(text, options, decoratedComments, commentIndex) {
  const { comment, followingNode } = decoratedComments[commentIndex];
  let end = locEnd(comment);

    // Find last comment on the same line
    for (
      let index = commentIndex + 1;
      index < decoratedComments.length;
      index++
    ) {
      const {
        comment,
        followingNode: currentCommentFollowingNode,
      if (
        currentCommentFollowingNode !== followingNode ||
        !isAllEmptyAndNoLineBreak(text.slice(end, locStart(comment)))
      ) {
        break;
      }
      end = locEnd(comment);
    }
  }

  return hasNewline(text, end);
}

function breakTies(tiesToBreak, text, options) {
  const tieCount = tiesToBreak.length;
    return;
  }
  const { precedingNode, followingNode, enclosingNode } = tiesToBreak[0];

  const gapRegExp =
    (options.printer.getGapRegex &&
      options.printer.getGapRegex(enclosingNode)) ||
    /^[\s(]*$/;

  let gapEndPos = options.locStart(followingNode);

  // comment must be separated from followingNode by an unbroken series of
  // gaps (or other comments). Gaps should only contain whitespace or open
  // parentheses.
  let indexOfFirstLeadingComment;
  for (
    indexOfFirstLeadingComment = tieCount;
    indexOfFirstLeadingComment > 0;
    --indexOfFirstLeadingComment
  ) {
    const {
      comment,
      precedingNode: currentCommentPrecedingNode,
      followingNode: currentCommentFollowingNode,
    } = tiesToBreak[indexOfFirstLeadingComment - 1];
    assert.strictEqual(currentCommentPrecedingNode, precedingNode);
    assert.strictEqual(currentCommentFollowingNode, followingNode);

    const gap = text.slice(options.locEnd(comment), gapEndPos);

    if (gapRegExp.test(gap)) {
      gapEndPos = options.locStart(comment);
    } else {
      // The gap string contained something other than whitespace or open
      // parentheses.
      break;
    }
  }

  for (const [i, { comment }] of tiesToBreak.entries()) {
      addTrailingComment(precedingNode, comment);
    } else {
      addLeadingComment(followingNode, comment);
    }
  }

  for (const node of [precedingNode, followingNode]) {
    if (node.comments && node.comments.length > 1) {
      node.comments.sort((a, b) => options.locStart(a) - options.locStart(b));
    }
  }

}

function printComment(commentPath, options) {
  comment.printed = true;
  return options.printer.printComment(commentPath, options);
}

function findExpressionIndexForComment(quasis, comment, options) {
  const startPos = options.locStart(comment) - 1;

  for (let i = 1; i < quasis.length; ++i) {
    if (startPos < options.locStart(quasis[i])) {
      return i - 1;
    }
  }

  // We haven't found it, it probably means that some of the locations are off.
  // Let's just return the first one.
  return 0;
}

function printLeadingComment(commentPath, options) {
  const contents = printComment(commentPath, options);
  if (!contents) {
    return "";
  }
  const isBlock =
    options.printer.isBlockComment && options.printer.isBlockComment(comment);

  // Leading block comments should see if they need to stay on the
  // same line or not.
  if (isBlock) {
    const lineBreak = hasNewline(options.originalText, options.locEnd(comment))
      ? hasNewline(options.originalText, options.locStart(comment), {
          backwards: true,
        })
        ? hardline
        : line
      : " ";

    return [contents, lineBreak];
  }

  return [contents, hardline];
}

function printTrailingComment(commentPath, options) {
    return "";
  }
  const { printer, originalText, locStart } = options;
  const isBlock = printer.isBlockComment && printer.isBlockComment(comment);

  if (hasNewline(originalText, locStart(comment), { backwards: true })) {
    // This allows comments at the end of nested structures:
    // {
    //   x: 1,
    //   y: 2
    //   // A comment
    // }
    // Those kinds of comments are almost always leading comments, but
    // here it doesn't go "outside" the block and turns it into a
    // trailing comment for `2`. We can simulate the above by checking
    // if this a comment on its own line; normal trailing comments are
    // always at the end of another expression.

    const isLineBeforeEmpty = isPreviousLineEmpty(
      originalText,
      comment,
      locStart
    );

    return lineSuffix([hardline, isLineBeforeEmpty ? hardline : "", contents]);
  }

  let printed = [" ", contents];

  // Trailing block comments never need a newline
  if (!isBlock) {
    printed = [lineSuffix(printed), breakParent];
  }

  return printed;
}

function printDanglingComments(path, options, sameIndent, filter) {

  if (!node || !node.comments) {
    return "";
  }

  path.each((commentPath) => {
    const comment = commentPath.getValue();
    if (
      comment &&
      !comment.leading &&
      !comment.trailing &&
      (!filter || filter(comment))
    ) {
      parts.push(printComment(commentPath, options));
    }
  }, "comments");

    return "";
  }

  if (sameIndent) {
    return join(hardline, parts);
  }
  return indent([hardline, join(hardline, parts)]);
}

function prependCursorPlaceholder(path, options, printed) {
  if (path.getNode() === options.cursorNode && path.getValue()) {
    return [cursor, printed, cursor];
  }
}

function printComments(path, print, options, needsSemi) {
  const value = path.getValue();
  const printed = print(path);
  const comments = value && value.comments;

  if (!isNonEmptyArray(comments)) {
    return prependCursorPlaceholder(path, options, printed);
  }

  const leadingParts = [];
  const trailingParts = [needsSemi ? ";" : "", printed];

    const { leading, trailing } = comment;

    if (leading) {
      const contents = printLeadingComment(commentPath, options);
      if (!contents) {
        return;
      }
      leadingParts.push(contents);

      const text = options.originalText;
      const index = skipNewline(
        text,
        skipSpaces(text, options.locEnd(comment))
      );
      if (index !== false && hasNewline(text, index)) {
        leadingParts.push(hardline);
      }
    } else if (trailing) {
      trailingParts.push(printTrailingComment(commentPath, options));
    }

  return prependCursorPlaceholder(path, options, [
    ...leadingParts,
    ...trailingParts,
  ]);
}

function ensureAllCommentsPrinted(astComments) {
  if (!astComments) {
    return;
  }

  for (const comment of astComments) {
    if (!comment.printed) {
      throw new Error(
        'Comment "' +
          comment.value.trim() +
          '" was not printed. Please report this error!'
      );
    }
    delete comment.printed;
  }
}

function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
  let resultStartNode = startNodeAndParents.node;
  let resultEndNode = endNodeAndParents.node;

  if (resultStartNode === resultEndNode) {
    return {
      startNode: resultStartNode,
      endNode: resultEndNode,
    };
  }

  for (const endParent of endNodeAndParents.parentNodes) {
    if (
      endParent.type !== "Program" &&
      endParent.type !== "File" &&
      opts.locStart(endParent) >= opts.locStart(startNodeAndParents.node)
    ) {
      resultEndNode = endParent;
    } else {
      break;
    }
  }

  for (const startParent of startNodeAndParents.parentNodes) {
    if (
      startParent.type !== "Program" &&
      startParent.type !== "File" &&
      opts.locEnd(startParent) <= opts.locEnd(endNodeAndParents.node)
    ) {
      resultStartNode = startParent;
    } else {
      break;
    }
  }

  return {
    startNode: resultStartNode,
    endNode: resultEndNode,
  };
}

function findNodeAtOffset(
  node,
  offset,
  options,
  predicate,
  parentNodes = [],
  type
) {
  const start = locStart(node);
  const end = locEnd(node);

  if (
    offset > end ||
    offset < start ||
    (type === "rangeEnd" && offset === start) ||
    (type === "rangeStart" && offset === end)
  ) {
    return;
  }

  for (const childNode of comments.getSortedChildNodes(node, options)) {
    const childResult = findNodeAtOffset(
      childNode,
      offset,
      options,
      predicate,
      [node, ...parentNodes],
      type
    );
    if (childResult) {
      return childResult;
    }
  }

  if (!predicate || predicate(node)) {
    return {
      node,
      parentNodes,
    };
  }
}

function isJsSourceElement(type) {
  return (
    type === "Directive" ||
    type === "TypeAlias" ||
    type === "TSExportAssignment" ||
    type.startsWith("Declare") ||
    type.startsWith("TSDeclare") ||
    type.endsWith("Statement") ||
    type.endsWith("Declaration")
  );
}

function isSourceElement(opts, node) {
  if (node == null) {
  }
  switch (opts.parser) {
      return isJsSourceElement(node.type);
      return jsonSourceElements.has(node.type);
      return graphqlSourceElements.has(node.kind);
      return node.tag !== "root";
  }
}

function calculateRange(text, opts, ast) {
  let { rangeStart: start, rangeEnd: end, locStart, locEnd } = opts;
  assert.ok(end > start);
  // Contract the range so that it has non-whitespace characters at its endpoints.
  // This ensures we can format a range that doesn't end on a node.
  const firstNonWhitespaceCharacterIndex = text.slice(start, end).search(/\S/);
  const isAllWhitespace = firstNonWhitespaceCharacterIndex === -1;
  if (!isAllWhitespace) {
    start += firstNonWhitespaceCharacterIndex;
    for (; end > start; --end) {
      if (/\S/.test(text[end - 1])) {
        break;
      }
    }
  }

  const startNodeAndParents = findNodeAtOffset(
    ast,
    start,
    opts,
    (node) => isSourceElement(opts, node),
    [],
    "rangeStart"
  );
  const endNodeAndParents =
    // No need find Node at `end`, it will be the same as `startNodeAndParents`
    isAllWhitespace
      ? startNodeAndParents
      : findNodeAtOffset(
          ast,
          end,
          opts,
          (node) => isSourceElement(opts, node),
          [],
          "rangeEnd"
        );
  if (!startNodeAndParents || !endNodeAndParents) {
    return {
      rangeStart: 0,
      rangeEnd: 0,
    };
  }

  const { startNode, endNode } = findSiblingAncestors(
    startNodeAndParents,
    endNodeAndParents,
    opts
  );

  return {
    rangeStart: Math.min(locStart(startNode), locStart(endNode)),
    rangeEnd: Math.max(locEnd(startNode), locEnd(endNode)),
  };
}

function getPrinter(options) {
  const astFormat = options.astFormat;

  if (!astFormat) {
    throw new Error("getPrinter() requires astFormat to be set");
  }
  const printerPlugin = options.plugins.find(
    plugin => plugin.printers[astFormat]
  );
  if (!printerPlugin) {
      `Couldn't find printer plugin for AST format "${astFormat}"`
    );
  }

  return printerPlugin.printers[astFormat];
}

function getSupportInfo({
  plugins = [],
  showUnreleased = false,
  showDeprecated = false,
  showInternal = false,
} = {}) {
  // pre-release version is smaller than the normal version in semver,
  // we need to treat it as the normal one so as to test new features.
  const version = currentVersion.split("-", 1)[0];

  const languages = plugins
    .reduce((all, plugin) => [...all, ...(plugin.languages || [])], [])
    .filter(filterSince);

  const options = arrayify(
    Object.assign({}, ...plugins.map(({ options }) => options), coreOptions),
    "name"
  )
    .filter((option) => filterSince(option) && filterDeprecated(option))
    .sort((a, b) => (a.name === b.name ? 0 : a.name < b.name ? -1 : 1))
    .map(mapInternal)
    .map((option) => {
      option = { ...option };

      if (Array.isArray(option.default)) {
        option.default =
          option.default.length === 1
            ? option.default[0].value
            : option.default
                .filter(filterSince)
                .sort((info1, info2) =>
                  semver.compare(info2.since, info1.since)
                )[0].value;
      }

      if (Array.isArray(option.choices)) {
        option.choices = option.choices.filter(
          (option) => filterSince(option) && filterDeprecated(option)
        );

        if (option.name === "parser") {
          collectParsersFromLanguages(option, languages, plugins);
        }
      }

      const pluginDefaults = fromPairs(
        plugins
          .filter(
            (plugin) =>
              plugin.defaultOptions &&
              plugin.defaultOptions[option.name] !== undefined
          )
          .map((plugin) => [plugin.name, plugin.defaultOptions[option.name]])
      );

      return { ...option, pluginDefaults };
    });

  return { languages, options };

  function filterSince(object) {
    return (
      showUnreleased ||
      !("since" in object) ||
      (object.since && semver.gte(version, object.since))
    );
  }

  function filterDeprecated(object) {
    return (
      showDeprecated ||
      !("deprecated" in object) ||
      (object.deprecated && semver.lt(version, object.deprecated))
    );
  }

  function mapInternal(object) {
    if (showInternal) {
      return object;
    }
    const { cliName, cliCategory, cliDescription, ...newObject } = object;
    return newObject;
  }
}

function filterSince(object) {
    return (
    );
  }

function filterDeprecated(object) {
    return (
    );
  }

function mapInternal(object) {
    }
  }

function collectParsersFromLanguages(option, languages, plugins) {
  const existingValues = new Set(option.choices.map((choice) => choice.value));
  for (const language of languages) {
    if (language.parsers) {
      for (const value of language.parsers) {
        if (!existingValues.has(value)) {
          existingValues.add(value);
          const plugin = plugins.find(
            (plugin) => plugin.parsers && plugin.parsers[value]
          );
          let description = language.name;
          if (plugin && plugin.name) {
            description += ` (plugin: ${plugin.name})`;
          }
          option.choices.push({ value, description });
        }
      }
    }
  }
}

function massageAST(ast, options, parent) {
    return ast.map((e) => massageAST(e, options, parent)).filter(Boolean);
  }

  if (!ast || typeof ast !== "object") {
  }

  const cleanFunction = options.printer.massageAstNode;
  let ignoredProperties;
  if (cleanFunction && cleanFunction.ignoredProperties) {
    ignoredProperties = cleanFunction.ignoredProperties;
  } else {
    ignoredProperties = new Set();
  }

  const newObj = {};
  for (const [key, value] of Object.entries(ast)) {
    if (!ignoredProperties.has(key) && typeof value !== "function") {
      newObj[key] = massageAST(value, options, ast);
    }
  }

  if (cleanFunction) {
    const result = cleanFunction(ast, newObj, parent);
    if (result === null) {
      return;
    }
    if (result) {
    }
  }

  return newObj;
}

({ key, value }) =>
    value === false
      ? `--no-${key}`
      : value === true
      ? cliDescriptor.key(key)
      : value === ""
      ? `${cliDescriptor.key(key)} without an argument`
      : `${cliDescriptor.key(key)}=${value}`

class FlagSchema extends vnopts.ChoiceSchema {
  constructor({ name, flags }) {
    super({ name, choices: flags });
    this._flags = flags.slice().sort();
  }
  preprocess(value, utils) {
    if (
      typeof value === "string" &&
      value.length > 0 &&
      !this._flags.includes(value)
    ) {
      const suggestion = this._flags.find((flag) => leven(flag, value) < 3);
      if (suggestion) {
        utils.logger.warn(
          [
            `Unknown flag ${chalk.yellow(utils.descriptor.value(value))},`,
            `did you mean ${chalk.blue(utils.descriptor.value(suggestion))}?`,
          ].join(" ")
        );
        return suggestion;
      }
    }
  }
  expected() {
    return "a flag";
  }
}

constructor({ name, flags }) {
  }

preprocess(value, utils) {
    if (
    ) {
          [
        );
      }
    }
  }

function normalizeOptions(
  options,
  optionInfos,
  { logger, isCLI = false, passThrough = false } = {}
) {
  const unknown = !passThrough
    ? (key, value, options) => {
        // Don't suggest `_` for unknown flags
        const { _, ...schemas } = options.schemas;
        return vnopts.levenUnknownHandler(key, value, {
          ...options,
          schemas,
        });
      }
    : Array.isArray(passThrough)
    ? (key, value) =>
        !passThrough.includes(key) ? undefined : { [key]: value }
    : (key, value) => ({ [key]: value });

  const descriptor = isCLI ? cliDescriptor : vnopts.apiDescriptor;
  const schemas = optionInfosToSchemas(optionInfos, { isCLI });
  const normalizer = new vnopts.Normalizer(schemas, {
    logger,
    unknown,
    descriptor,
  });

  const shouldSuppressDuplicateDeprecationWarnings = logger !== false;

  if (shouldSuppressDuplicateDeprecationWarnings && hasDeprecationWarned) {
    normalizer._hasDeprecationWarned = hasDeprecationWarned;
  }

  const normalized = normalizer.normalize(options);

  if (shouldSuppressDuplicateDeprecationWarnings) {
    hasDeprecationWarned = normalizer._hasDeprecationWarned;
  }

}

function optionInfosToSchemas(optionInfos, { isCLI }) {
  const schemas = [];

  if (isCLI) {
    schemas.push(vnopts.AnySchema.create({ name: "_" }));
  }

  for (const optionInfo of optionInfos) {
    schemas.push(optionInfoToSchema(optionInfo, { isCLI, optionInfos }));

    if (optionInfo.alias && isCLI) {
      schemas.push(
        vnopts.AliasSchema.create({
          name: optionInfo.alias,
          sourceName: optionInfo.name,
        })
      );
    }
  }

  return schemas;
}

function optionInfoToSchema(optionInfo, { isCLI, optionInfos }) {
  let SchemaConstructor;
  const parameters = { name: optionInfo.name };
  const handlers = {};

  switch (optionInfo.type) {
    case "int":
      SchemaConstructor = vnopts.IntegerSchema;
      if (isCLI) {
        parameters.preprocess = (value) => Number(value);
      }
      break;
    case "string":
      SchemaConstructor = vnopts.StringSchema;
      break;
      SchemaConstructor = vnopts.ChoiceSchema;
      parameters.choices = optionInfo.choices.map((choiceInfo) =>
        typeof choiceInfo === "object" && choiceInfo.redirect
          ? {
              ...choiceInfo,
              redirect: {
                to: { key: optionInfo.name, value: choiceInfo.redirect },
              },
            }
          : choiceInfo
      );
      break;
      SchemaConstructor = vnopts.BooleanSchema;
      break;
    case "flag":
      SchemaConstructor = FlagSchema;
      parameters.flags = flat(
        optionInfos.map((optionInfo) =>
          [
            optionInfo.alias,
            optionInfo.description && optionInfo.name,
            optionInfo.oppositeDescription && `no-${optionInfo.name}`,
          ].filter(Boolean)
        )
      );
      break;
    case "path":
      break;
    default:
      throw new Error(`Unexpected type ${optionInfo.type}`);
  }

  if (optionInfo.exception) {
    parameters.validate = (value, schema, utils) =>
      optionInfo.exception(value) || schema.validate(value, utils);
  } else {
      value === undefined || schema.validate(value, utils);
  }

  if (optionInfo.redirect) {
    handlers.redirect = (value) =>
      !value
        ? undefined
        : {
            to: {
              key: optionInfo.redirect.option,
              value: optionInfo.redirect.value,
            },
          };
  }

  if (optionInfo.deprecated) {
    handlers.deprecated = true;
  }

  // allow CLI overriding, e.g., prettier package.json --tab-width 1 --tab-width 2
  if (isCLI && !optionInfo.array) {
    const originalPreprocess = parameters.preprocess || ((x) => x);
    parameters.preprocess = (value, schema, utils) =>
      schema.preprocess(
        originalPreprocess(
          Array.isArray(value) ? value[value.length - 1] : value
        ),
        utils
      );
  }

  return optionInfo.array
    ? vnopts.ArraySchema.create({
        ...(isCLI ? { preprocess: (v) => (Array.isArray(v) ? v : [v]) } : {}),
        ...handlers,
        valueSchema: SchemaConstructor.create(parameters),
      })
    : SchemaConstructor.create({ ...parameters, ...handlers });
}

(value, schema, utils) =>
      value === undefined || schema.validate(value, utils)

(value) =>
      !value
        : {
            to: {
            },
          }

function normalizeApiOptions(options, optionInfos, opts) {
  return normalizeOptions(options, optionInfos, opts);
}

function normalizeCliOptions(options, optionInfos, opts) {
  return normalizeOptions(options, optionInfos, { isCLI: true, ...opts });
}

function validateOption(value, optionInfo, opts) {
  const descriptor = opts.descriptor || descriptors.apiDescriptor;

  if (
    typeof optionInfo.exception === "function" &&
    optionInfo.exception(value)
  ) {
    return;
  }

  try {
    validateOptionType(value, optionInfo);
      `Invalid \`${descriptor(optionInfo.name)}\` value. ${
        error.message
      }, but received \`${JSON.stringify(value)}\`.`
    );
  }
}

function validateOptionType(value, optionInfo) {
  if (optionInfo.array) {
    if (!Array.isArray(value)) {
      throw new Error(`Expected an array`);
    }
    value.forEach(v =>
      validateOptionType(v, Object.assign({}, optionInfo, { array: false }))
    );
  } else {
    switch (optionInfo.type) {
      case "int":
        validateIntOption(value);
        break;
      case "boolean":
        validateBooleanOption(value);
        break;
      case "choice":
        validateChoiceOption(value, optionInfo.choices);
        break;
    }
  }
}

function validateBooleanOption(value) {
  if (typeof value !== "boolean") {
    throw new Error(`Expected a boolean`);
  }
}

function validateIntOption(value) {
  if (
    !(
      typeof value === "number" &&
      Math.floor(value) === value &&
      value >= 0 &&
      value !== Infinity
    )
  ) {
    throw new Error(`Expected an integer`);
  }
}

function validateChoiceOption(value, choiceInfos) {
  if (!choiceInfos.some(choiceInfo => choiceInfo.value === value)) {
    const choices = choiceInfos
      .filter(choiceInfo => !choiceInfo.deprecated)
      .map(choiceInfo => JSON.stringify(choiceInfo.value))
      .sort();
    throw new Error(`Expected ${head.concat(tail.join(" or ")).join(", ")}`);
  }
}

function apiDescriptor(name, value) {
  return arguments.length === 1
    ? JSON.stringify(name)
    : `\`{ ${apiDescriptor(name)}: ${JSON.stringify(value)} }\``;
}

function cliDescriptor(name, value) {
  return value === false
    ? `\`--no-${name}\``
    : value === true || arguments.length === 1
      ? `\`--${name}\``
        ? `\`--${name}\` without an argument`
        : `\`--${name}=${value}\``;
}

function attachComments(text, ast, opts) {
  if (astComments) {
    delete ast.comments;
    comments.attach(astComments, ast, text, opts);
  }
  opts[Symbol.for("comments")] = astComments || [];
  opts[Symbol.for("tokens")] = ast.tokens || [];
  opts.originalText = text;
  return astComments;
}

function coreFormat(originalText, opts, addAlignmentSize = 0) {
  if (!originalText || originalText.trim().length === 0) {
    return { formatted: "", cursorOffset: -1, comments: [] };
  }

  const { ast, text } = parser.parse(originalText, opts);

  if (opts.cursorOffset >= 0) {
    const nodeResult = rangeUtil.findNodeAtOffset(ast, opts.cursorOffset, opts);
    if (nodeResult && nodeResult.node) {
      opts.cursorNode = nodeResult.node;
    }
  }

  const astComments = attachComments(text, ast, opts);
  const doc = printAstToDoc(ast, opts, addAlignmentSize);

  const result = printDocToString(doc, opts);

  comments.ensureAllCommentsPrinted(astComments);
  // Remove extra leading indentation as well as the added indentation after last newline
  if (addAlignmentSize > 0) {
    const trimmed = result.formatted.trim();

    if (result.cursorNodeStart !== undefined) {
      result.cursorNodeStart -= result.formatted.indexOf(trimmed);
    }

    result.formatted = trimmed + convertEndOfLineToChars(opts.endOfLine);
  }

    let oldCursorNodeStart;
    let oldCursorNodeText;

    let cursorOffsetRelativeToOldCursorNode;

    let newCursorNodeStart;
    let newCursorNodeText;

    if (opts.cursorNode && result.cursorNodeText) {
      oldCursorNodeStart = opts.locStart(opts.cursorNode);
      oldCursorNodeText = text.slice(
        oldCursorNodeStart,
        opts.locEnd(opts.cursorNode)
      );

      cursorOffsetRelativeToOldCursorNode =
        opts.cursorOffset - oldCursorNodeStart;

      newCursorNodeStart = result.cursorNodeStart;
      newCursorNodeText = result.cursorNodeText;
    } else {
      oldCursorNodeStart = 0;
      oldCursorNodeText = text;

      cursorOffsetRelativeToOldCursorNode = opts.cursorOffset;

      newCursorNodeStart = 0;
      newCursorNodeText = result.formatted;
    }

    if (oldCursorNodeText === newCursorNodeText) {
      return {
        formatted: result.formatted,
        cursorOffset: newCursorNodeStart + cursorOffsetRelativeToOldCursorNode,
        comments: astComments,
      };
    }

    // diff old and new cursor node texts, with a special cursor
    // symbol inserted to find out where it moves to

    const oldCursorNodeCharArray = oldCursorNodeText.split("");
    oldCursorNodeCharArray.splice(
      cursorOffsetRelativeToOldCursorNode,
      0,
      CURSOR
    );

    const newCursorNodeCharArray = newCursorNodeText.split("");

    const cursorNodeDiff = diff.diffArrays(
      oldCursorNodeCharArray,
      newCursorNodeCharArray
    );

    let cursorOffset = newCursorNodeStart;
    for (const entry of cursorNodeDiff) {
      if (entry.removed) {
        if (entry.value.includes(CURSOR)) {
          break;
        }
      } else {
        cursorOffset += entry.count;
      }
    }

    return { formatted: result.formatted, cursorOffset, comments: astComments };
  }

  return {
    formatted: result.formatted,
    cursorOffset: -1,
    comments: astComments,
  };
}

function formatRange(originalText, opts) {
  const { rangeStart, rangeEnd } = rangeUtil.calculateRange(text, opts, ast);
  const rangeString = text.slice(rangeStart, rangeEnd);

  // Try to extend the range backwards to the beginning of the line.
  // This is so we can detect indentation correctly and restore it.
  // Use `Math.min` since `lastIndexOf` returns 0 when `rangeStart` is 0
  const rangeStart2 = Math.min(
    rangeStart,
    text.lastIndexOf("\n", rangeStart) + 1
  );
  const indentString = text.slice(rangeStart2, rangeStart).match(/^\s*/)[0];

  const alignmentSize = getAlignmentSize(indentString, opts.tabWidth);

  const rangeResult = coreFormat(
    rangeString,
    {
      ...opts,
      rangeEnd: Number.POSITIVE_INFINITY,
      // Track the cursor offset only if it's within our range
      cursorOffset:
        opts.cursorOffset > rangeStart && opts.cursorOffset < rangeEnd
          ? opts.cursorOffset - rangeStart
          : -1,
      // Always use `lf` to format, we'll replace it later
      endOfLine: "lf",
    },
    alignmentSize
  );

  // Since the range contracts to avoid trailing whitespace,
  // we need to remove the newline that was inserted by the `format` call.
  const rangeTrimmed = rangeResult.formatted.trimEnd();

  let { cursorOffset } = opts;
  if (cursorOffset >= rangeEnd) {
    // handle the case where the cursor was past the end of the range
    cursorOffset += rangeTrimmed.length - rangeString.length;
  } else if (rangeResult.cursorOffset >= 0) {
    // handle the case where the cursor was in the range
    cursorOffset = rangeResult.cursorOffset + rangeStart;
  }
  // keep the cursor as it was if it was before the start of the range

  let formatted =
    text.slice(0, rangeStart) + rangeTrimmed + text.slice(rangeEnd);
  if (opts.endOfLine !== "lf") {
    const eol = convertEndOfLineToChars(opts.endOfLine);
    if (cursorOffset >= 0 && eol === "\r\n") {
      cursorOffset += countEndOfLineChars(
        formatted.slice(0, cursorOffset),
        "\n"
      );
    }

    formatted = formatted.replace(/\n/g, eol);
  }

  return { formatted, cursorOffset, comments: rangeResult.comments };
}

function ensureIndexInText(text, index, defaultValue) {
  if (
    typeof index !== "number" ||
    Number.isNaN(index) ||
    index < 0 ||
    index > text.length
  ) {
    return defaultValue;
  }

  return index;
}

function normalizeIndexes(text, options) {
  let { cursorOffset, rangeStart, rangeEnd } = options;
  cursorOffset = ensureIndexInText(text, cursorOffset, -1);
  rangeStart = ensureIndexInText(text, rangeStart, 0);
  rangeEnd = ensureIndexInText(text, rangeEnd, text.length);

  return { ...options, cursorOffset, rangeStart, rangeEnd };
}

function normalizeInputAndOptions(text, options) {
  let { cursorOffset, rangeStart, rangeEnd, endOfLine } = normalizeIndexes(
    text,
    options
  );

  const hasBOM = text.charAt(0) === BOM;

  if (hasBOM) {
    text = text.slice(1);
    cursorOffset--;
    rangeStart--;
    rangeEnd--;
  }

  if (endOfLine === "auto") {
    endOfLine = guessEndOfLine(text);
  }

  // get rid of CR/CRLF parsing
  if (text.includes("\r")) {
    const countCrlfBefore = (index) =>
      countEndOfLineChars(text.slice(0, Math.max(index, 0)), "\r\n");

    cursorOffset -= countCrlfBefore(cursorOffset);
    rangeStart -= countCrlfBefore(rangeStart);
    rangeEnd -= countCrlfBefore(rangeEnd);

    text = normalizeEndOfLine(text);
  }

  return {
    hasBOM,
    text,
    options: normalizeIndexes(text, {
      ...options,
      cursorOffset,
      rangeStart,
      rangeEnd,
      endOfLine,
    }),
  };
}

(index) =>
      countEndOfLineChars(text.slice(0, Math.max(index, 0)), "\r\n")

function hasPragma(text, options) {
  const selectedParser = parser.resolveParser(options);
  return !selectedParser.hasPragma || selectedParser.hasPragma(text);
}

function formatWithCursor(originalText, originalOptions) {
  let { hasBOM, text, options } = normalizeInputAndOptions(
    originalText,
    normalizeOptions(originalOptions)
  );

  if (
    (options.rangeStart >= options.rangeEnd && text !== "") ||
    (options.requirePragma && !hasPragma(text, options))
  ) {
    return {
      formatted: originalText,
      cursorOffset: originalOptions.cursorOffset,
      comments: [],
    };
  }

  if (options.rangeStart > 0 || options.rangeEnd < text.length) {
    result = formatRange(text, options);
  } else {
    if (
      !options.requirePragma &&
      options.insertPragma &&
      options.printer.insertPragma &&
      !hasPragma(text, options)
    ) {
      text = options.printer.insertPragma(text);
    }
    result = coreFormat(text, options);
  }

    result.formatted = BOM + result.formatted;

    if (result.cursorOffset >= 0) {
      result.cursorOffset++;
    }
  }

}

parse(originalText, originalOptions, massage) {
    const { text, options } = normalizeInputAndOptions(
      normalizeOptions(originalOptions)
    );
    const parsed = parser.parse(text, options);
    if (massage) {
      parsed.ast = massageAST(parsed.ast, options);
    }
    return parsed;
  }

formatAST(ast, options) {
    options = normalizeOptions(options);
    const doc = printAstToDoc(ast, options);
    return printDocToString(doc, options);
  }

formatDoc(doc, options) {
    return formatWithCursor(printDocToDebug(doc), {
      parser: "__js_expression",
    }).formatted;
  }

printToDoc(originalText, options) {
    const { ast, text } = parser.parse(originalText, options);
    attachComments(text, ast, options);
    return printAstToDoc(ast, options);
  }

printDocToString(doc, options) {
    return printDocToString(doc, normalizeOptions(options));
  }

function printSubtree(path, print, options, printAstToDoc) {
  if (options.printer.embed && options.embeddedLanguageFormatting === "auto") {
    return options.printer.embed(
      path,
      print,
      (text, partialNextOptions, textToDocOptions) =>
          text,
          partialNextOptions,
          options,
          printAstToDoc,
          textToDocOptions
        ),
      options
    );
  }
}

function textToDoc(
  text,
  partialNextOptions,
  parentOptions,
  printAstToDoc,
  // TODO: remove `stripTrailingHardline` in v3.0.0
  { stripTrailingHardline: shouldStripTrailingHardline = false } = {}
) {
  const nextOptions = normalize(
    {
      ...parentOptions,
      ...partialNextOptions,
      parentParser: parentOptions.parser,
      originalText: text,
    },
    { passThrough: true }
  );

  const result = require("./parser").parse(text, nextOptions);
  const { ast } = result;
  text = result.text;

  nextOptions[Symbol.for("comments")] = astComments || [];
  nextOptions[Symbol.for("tokens")] = ast.tokens || [];

  const doc = printAstToDoc(ast, nextOptions);

  if (shouldStripTrailingHardline) {
    // TODO: move this to `stripTrailingHardline` function in `/src/document/doc-utils.js`
      return doc.replace(/(?:\r?\n)*$/, "");
    }

    return stripTrailingHardline(doc);
  }

}

(value) =>
      typeof value === "string" || typeof value === "object"

function printAstToDoc(ast, options, alignmentSize = 0) {
  const { printer } = options;

  if (printer.preprocess) {
    ast = printer.preprocess(ast, options);
  }

  const cache = new Map();

  function printGenerically(path, args) {
    const node = path.getValue();

    const shouldCache = node && typeof node === "object" && args === undefined;
    if (shouldCache && cache.has(node)) {
      return cache.get(node);
    }

    // We let JSXElement print its comments itself because it adds () around
    // UnionTypeAnnotation has to align the child without the comments
    let res;
    if (
      printer.willPrintOwnComments &&
      printer.willPrintOwnComments(path, options)
    ) {
      res = callPluginPrintFunction(path, options, printGenerically, args);
    } else {
      // printComments will call the plugin print function and check for
      // comments to print
      res = printComments(
        path,
        (p) => callPluginPrintFunction(p, options, printGenerically, args),
        options,
        args && args.needsSemi
      );
    }

    if (shouldCache) {
      cache.set(node, res);
    }

    return res;
  }

  let doc = printGenerically(new AstPath(ast));
  if (alignmentSize > 0) {
    // Add a hardline to make the indents take effect
    // It should be removed in index.js format()
    doc = addAlignmentToDoc([hardline, doc], alignmentSize, options.tabWidth);
  }
  docUtils.propagateBreaks(doc);

}

function printGenerically(path, args) {

    }

    let res;
    if (
    ) {
    } else {
        path,
        options,
      );
    }

    }

  }

function printPrettierIgnoredNode(node, options) {
  const {
    [Symbol.for("comments")]: comments,
    locStart,
    locEnd,

  for (const comment of comments) {
    if (locStart(comment) >= start && locEnd(comment) <= end) {
      comment.printed = true;
    }
  }

  return originalText.slice(start, end);
}

function callPluginPrintFunction(path, options, printPath, args) {
  assert.ok(path instanceof AstPath);

  // Escape hatch
  if (printer.hasPrettierIgnore && printer.hasPrettierIgnore(path)) {
    return printPrettierIgnoredNode(node, options);
  }

  if (node) {
    try {
      // Potentially switch to a different parser
      const sub = multiparser.printSubtree(
        path,
        printPath,
        options,
        printAstToDoc
      );
      if (sub) {
        return sub;
      }
      /* istanbul ignore if */
      if (process.env.PRETTIER_DEBUG) {
        throw error;
      }
      // Continue with current parser
    }
  }

  return printer.print(path, options, printPath, args);
}

function normalize(options, opts = {}) {
  const rawOptions = { ...options };

  const supportOptions = getSupportInfo({
    plugins: options.plugins,
    showUnreleased: true,
    showDeprecated: true,
  }).options;

  const defaults = {
    ...hiddenDefaults,
    ...fromPairs(
      supportOptions
        .filter((optionInfo) => optionInfo.default !== undefined)
        .map((option) => [option.name, option.default])
    ),
  };
  if (!rawOptions.parser) {
    if (!rawOptions.filepath) {
      const logger = opts.logger || console;
      logger.warn(
        "No parser and no filepath given, using 'babel' the parser now " +
          "but this will throw an error in the future. " +
          "Please specify a parser or a filepath so one can be inferred."
      );
      rawOptions.parser = "babel";
    } else {
      rawOptions.parser = inferParser(rawOptions.filepath, rawOptions.plugins);
      if (!rawOptions.parser) {
        throw new UndefinedParserError(
          `No parser could be inferred for file: ${rawOptions.filepath}`
        );
      }
    }
  }

  const parser = resolveParser(
    normalizer.normalizeApiOptions(
      rawOptions,
      [supportOptions.find((x) => x.name === "parser")],
      { passThrough: true, logger: false }
    )
  );
  rawOptions.astFormat = parser.astFormat;
  rawOptions.locEnd = parser.locEnd;
  rawOptions.locStart = parser.locStart;

  const plugin = getPlugin(rawOptions);
  rawOptions.printer = plugin.printers[rawOptions.astFormat];

  const pluginDefaults = fromPairs(
    supportOptions
      .filter(
        (optionInfo) =>
          optionInfo.pluginDefaults &&
          optionInfo.pluginDefaults[plugin.name] !== undefined
      )
      .map((optionInfo) => [
        optionInfo.name,
        optionInfo.pluginDefaults[plugin.name],
      ])
  );

  const mixedDefaults = { ...defaults, ...pluginDefaults };

  for (const [k, value] of Object.entries(mixedDefaults)) {
    if (rawOptions[k] == null) {
      rawOptions[k] = value;
    }
  }

  if (rawOptions.parser === "json") {
    rawOptions.trailingComma = "none";
  }

  return normalizer.normalizeApiOptions(rawOptions, supportOptions, {
    passThrough: Object.keys(hiddenDefaults),
    ...opts,
  });
}

function getPlugin(options) {
  const { astFormat } = options;

  // TODO: test this with plugins
    throw new Error("getPlugin() requires astFormat to be set");
  }
    (plugin) => plugin.printers && plugin.printers[astFormat]
  );
    throw new Error(`Couldn't find plugin for AST format "${astFormat}"`);
  }

  return printerPlugin;
}

function getInterpreter(filepath) {
  if (typeof filepath !== "string") {
    return "";
  }

  let fd;
  try {
    fd = fs.openSync(filepath, "r");
  } catch (err) {
    // istanbul ignore next
    return "";
  }

  try {
    const liner = new readlines(fd);
    const firstLine = liner.next().toString("utf8");

    // #!/bin/env node, #!/usr/bin/env node
    const m1 = firstLine.match(/^#!\/(?:usr\/)?bin\/env\s+(\S+)/);
    if (m1) {
      return m1[1];
    }

    // #!/bin/node, #!/usr/bin/node, #!/usr/local/bin/node
    const m2 = firstLine.match(/^#!\/(?:usr\/(?:local\/)?)?bin\/(\S+)/);
    if (m2) {
      return m2[1];
    }
    return "";
    // There are some weird cases where paths are missing, causing Jest
    // failures. It's unclear what these correspond to in the real world.
    return "";
  } finally {
    try {
      // There are some weird cases where paths are missing, causing Jest
      // failures. It's unclear what these correspond to in the real world.
      fs.closeSync(fd);
      // nop
    }
  }
}

function inferParser(filepath, plugins) {
  const filename = path.basename(filepath).toLowerCase();
  const languages = getSupportInfo({ plugins }).languages.filter(
    (language) => language.since !== null
  );

  // If the file has no extension, we can try to infer the language from the
  // interpreter in the shebang line, if any; but since this requires FS access,
  // do it last.
  let language = languages.find(
    (language) =>
      (language.extensions &&
        language.extensions.some((extension) =>
          filename.endsWith(extension)
        )) ||
      (language.filenames &&
        language.filenames.some((name) => name.toLowerCase() === filename))
  );

  if (!language && !filename.includes(".")) {
    const interpreter = getInterpreter(filepath);
    language = languages.find(
      (language) =>
        language.interpreters && language.interpreters.includes(interpreter)
    );
  }

  return language && language.parsers[0];
}

function printImgSrcset(value) {
  const srcset = parseSrcset(value, {
    logger: {
      error(message) {
        throw new Error(message);
      },
    },
  });

  const hasW = srcset.some(({ w }) => w);
  const hasH = srcset.some(({ h }) => h);
  const hasX = srcset.some(({ d }) => d);

  if (hasW + hasH + hasX > 1) {
    throw new Error("Mixed descriptor in srcset is not supported");
  }

  const key = hasW ? "w" : hasH ? "h" : "d";
  const unit = hasW ? "w" : hasH ? "h" : "x";

  const getMax = (values) => Math.max(...values);

  const urls = srcset.map((src) => src.url);
  const maxUrlLength = getMax(urls.map((url) => url.length));

  const descriptors = srcset
    .map((src) => src[key])
    .map((descriptor) => (descriptor ? descriptor.toString() : ""));
  const descriptorLeftLengths = descriptors.map((descriptor) => {
    const index = descriptor.indexOf(".");
    return index === -1 ? descriptor.length : index;
  });
  const maxDescriptorLeftLength = getMax(descriptorLeftLengths);

  return join(
    [",", line],
    urls.map((url, index) => {
      const parts = [url];

      const descriptor = descriptors[index];
      if (descriptor) {
        const urlPadding = maxUrlLength - url.length + 1;
        const descriptorPadding =
          maxDescriptorLeftLength - descriptorLeftLengths[index];

        const alignment = " ".repeat(urlPadding + descriptorPadding);
        parts.push(ifBreak(alignment, " "), descriptor + unit);
      }

      return parts;
    })
  );
}

function getClassPrefix(className) {
  const startIndex = className.search(/[^_-]/);
  if (startIndex !== -1) {
    for (const delimiter of prefixDelimiters) {
      const delimiterIndex = className.indexOf(delimiter, startIndex);
      if (delimiterIndex !== -1) {
        return className.slice(0, delimiterIndex);
      }
    }
  }
  return className;
}

function printClassNames(value) {
  const classNames = value.trim().split(/\s+/);

  // Try keeping consecutive classes with the same prefix on one line.
  const groupedByPrefix = [];
  let previousPrefix;
  for (let i = 0; i < classNames.length; i++) {
    const prefix = getClassPrefix(classNames[i]);
    if (
      prefix !== previousPrefix &&
      // "home-link" and "home-link_blue_yes" should be considered same-prefix
      prefix !== classNames[i - 1]
    ) {
      groupedByPrefix.push([]);
    }
    groupedByPrefix[groupedByPrefix.length - 1].push(classNames[i]);
    previousPrefix = prefix;
  }

  return [
    indent([
      softline,
      join(
        line,
        groupedByPrefix.map((classNames) => group(join(line, classNames)))
      ),
    ]),
    softline,
  ];
}

(property) =>
  fromPairs(
    flat(
      htmlStyles
        .filter((htmlStyle) => htmlStyle.style[property])
        .map((htmlStyle) =>
          htmlStyle.selectorText
            .split(",")
            .map((selector) => selector.trim())
            .filter((selector) => /^[\dA-Za-z]+$/.test(selector))
            .map((tagName) => [tagName, htmlStyle.style[property]])
        )
    )
  )

(string) => {
  const [, leadingWhitespace, text, trailingWhitespace] = string.match(
    /^([\t\n\f\r ]*)([\S\s]*?)([\t\n\f\r ]*)$/
  );
  return {
    leadingWhitespace,
    trailingWhitespace,
    text,
  };
}

function arrayToMap(array) {
  const map = Object.create(null);
  for (const value of array) {
    map[value] = true;
  }
  return map;
}

function mapObject(object, fn) {
  const newObject = Object.create(null);
  for (const [key, value] of Object.entries(object)) {
    newObject[key] = fn(value, key);
  }
  return newObject;
}

function shouldPreserveContent(node, options) {
  // unterminated node in ie conditional comment
  // e.g. <!--[if lt IE 9]><html><![endif]-->
  if (
    node.type === "ieConditionalComment" &&
    node.lastChild &&
    !node.lastChild.isSelfClosing &&
    !node.lastChild.endSourceSpan
  ) {
  }

  // incomplete html in ie conditional comment
  // e.g. <!--[if lt IE 9]></div><![endif]-->
  if (node.type === "ieConditionalComment" && !node.complete) {
  }

  // TODO: handle non-text children in <pre>
  if (
    isPreLikeNode(node) &&
    node.children.some(
      (child) => child.type !== "text" && child.type !== "interpolation"
    )
  ) {
  }

  if (
    isVueNonHtmlBlock(node, options) &&
    !isScriptLikeTag(node) &&
    node.type !== "interpolation"
  ) {
  }

}

function hasPrettierIgnore(node) {
  if (node.type === "attribute") {
  }

  if (!node.parent) {
  }

  if (typeof node.index !== "number" || node.index === 0) {
  }

  const prevNode = node.parent.children[node.index - 1];
  return isPrettierIgnore(prevNode);
}

  return node.type === "comment" && node.value.trim() === "prettier-ignore";
}

function getPrettierIgnoreAttributeCommentData(value) {
  const match = value.trim().match(/^prettier-ignore-attribute(?:\s+([^]+))?$/);

  if (!match) {
  }

  if (!match[1]) {
  }

  return match[1].split(/\s+/);
}

function isTextLikeNode(node) {
  return node.type === "text" || node.type === "comment";
}

function isScriptLikeTag(node) {
  return (
    node.type === "element" &&
    (node.fullName === "script" ||
      node.fullName === "style" ||
      node.fullName === "svg:style" ||
      (isUnknownNamespace(node) &&
        (node.name === "script" || node.name === "style")))
  );
}

function canHaveInterpolation(node) {
  return node.children && !isScriptLikeTag(node);
}

function isWhitespaceSensitiveNode(node) {
  return (
    isScriptLikeTag(node) ||
    node.type === "interpolation" ||
    isIndentationSensitiveNode(node)
  );
}

function isIndentationSensitiveNode(node) {
  return getNodeCssStyleWhiteSpace(node).startsWith("pre");
}

function isLeadingSpaceSensitiveNode(node, options) {
  const isLeadingSpaceSensitive = _isLeadingSpaceSensitiveNode();

  if (
    isLeadingSpaceSensitive &&
    !node.prev &&
    node.parent &&
    node.parent.tagDefinition &&
    node.parent.tagDefinition.ignoreFirstLf
  ) {
    return node.type === "interpolation";
  }

  return isLeadingSpaceSensitive;

  function _isLeadingSpaceSensitiveNode() {
    if (isFrontMatterNode(node)) {
    }

    if (
      (node.type === "text" || node.type === "interpolation") &&
      node.prev &&
      (node.prev.type === "text" || node.prev.type === "interpolation")
    ) {
    }

    if (!node.parent || node.parent.cssDisplay === "none") {
    }

    if (isPreLikeNode(node.parent)) {
    }

    if (
      !node.prev &&
      (node.parent.type === "root" ||
        (isPreLikeNode(node) && node.parent) ||
        isScriptLikeTag(node.parent) ||
        isVueCustomBlock(node.parent, options) ||
        !isFirstChildLeadingSpaceSensitiveCssDisplay(node.parent.cssDisplay))
    ) {
    }

    if (
      !isNextLeadingSpaceSensitiveCssDisplay(node.prev.cssDisplay)
    ) {
    }

  }
}

function _isLeadingSpaceSensitiveNode() {
    }

    if (
    ) {
    }

    }

    }

    if (
    ) {
    }

    if (
    ) {
    }

  }

function isTrailingSpaceSensitiveNode(node, options) {
  if (isFrontMatterNode(node)) {
  }

  if (
    (node.type === "text" || node.type === "interpolation") &&
    node.next &&
    (node.next.type === "text" || node.next.type === "interpolation")
  ) {
  }

  if (!node.parent || node.parent.cssDisplay === "none") {
  }

  if (isPreLikeNode(node.parent)) {
  }

  if (
    !node.next &&
    (node.parent.type === "root" ||
      (isPreLikeNode(node) && node.parent) ||
      isScriptLikeTag(node.parent) ||
      isVueCustomBlock(node.parent, options) ||
      !isLastChildTrailingSpaceSensitiveCssDisplay(node.parent.cssDisplay))
  ) {
  }

  if (
    !isPrevTrailingSpaceSensitiveCssDisplay(node.next.cssDisplay)
  ) {
  }

}

function isDanglingSpaceSensitiveNode(node) {
  return (
    isDanglingSpaceSensitiveCssDisplay(node.cssDisplay) &&
    !isScriptLikeTag(node)
  );
}

function forceNextEmptyLine(node) {
  return (
    isFrontMatterNode(node) ||
    (node.next &&
      node.sourceSpan.end &&
      node.sourceSpan.end.line + 1 < node.next.sourceSpan.start.line)
  );
}

function forceBreakContent(node) {
  return (
    forceBreakChildren(node) ||
    (node.type === "element" &&
      node.children.length > 0 &&
      (["body", "script", "style"].includes(node.name) ||
        node.children.some((child) => hasNonTextChild(child)))) ||
    (node.firstChild &&
      node.firstChild === node.lastChild &&
      node.firstChild.type !== "text" &&
      hasLeadingLineBreak(node.firstChild) &&
      (!node.lastChild.isTrailingSpaceSensitive ||
        hasTrailingLineBreak(node.lastChild)))
  );
}

function forceBreakChildren(node) {
  return (
    node.children.length > 0 &&
    (["html", "head", "ul", "ol", "select"].includes(node.name) ||
      (node.cssDisplay.startsWith("table") && node.cssDisplay !== "table-cell"))
  );
}

function preferHardlineAsLeadingSpaces(node) {
  return (
    preferHardlineAsSurroundingSpaces(node) ||
    (node.prev && preferHardlineAsTrailingSpaces(node.prev)) ||
    hasSurroundingLineBreak(node)
  );
}

function preferHardlineAsTrailingSpaces(node) {
  return (
    (node.type === "element" && node.fullName === "br") ||
  );
}

function hasSurroundingLineBreak(node) {
  return hasLeadingLineBreak(node) && hasTrailingLineBreak(node);
}

function hasLeadingLineBreak(node) {
  return (
    node.hasLeadingSpaces &&
    (node.prev
      ? node.prev.sourceSpan.end.line < node.sourceSpan.start.line
      : node.parent.type === "root" ||
        node.parent.startSourceSpan.end.line < node.sourceSpan.start.line)
  );
}

function hasTrailingLineBreak(node) {
  return (
    node.hasTrailingSpaces &&
    (node.next
      ? node.next.sourceSpan.start.line > node.sourceSpan.end.line
        (node.parent.endSourceSpan &&
          node.parent.endSourceSpan.start.line > node.sourceSpan.end.line))
  );
}

function preferHardlineAsSurroundingSpaces(node) {
    case "ieConditionalComment":
    case "comment":
    case "directive":
    case "element":
      return ["script", "select"].includes(node.name);
  }
}

function getLastDescendant(node) {
  return node.lastChild ? getLastDescendant(node.lastChild) : node;
}

function hasNonTextChild(node) {
  return node.children && node.children.some((child) => child.type !== "text");
}

function _inferScriptParser(node) {
  const { type, lang } = node.attrMap;
  if (
    type === "module" ||
    type === "text/javascript" ||
    type === "text/babel" ||
    type === "application/javascript" ||
    lang === "jsx"
  ) {
    return "babel";
  }

  if (type === "application/x-typescript" || lang === "ts" || lang === "tsx") {
    return "typescript";
  }

  if (type === "text/markdown") {
    return "markdown";
  }

  if (type === "text/html") {
    return "html";
  }

  if (type && (type.endsWith("json") || type.endsWith("importmap"))) {
    return "json";
  }

  if (type === "text/x-handlebars-template") {
    return "glimmer";
  }
}

function inferStyleParser(node) {
  const { lang } = node.attrMap;
  if (!lang || lang === "postcss" || lang === "css") {
    return "css";
  }

  if (lang === "scss") {
    return "scss";
  }

  if (lang === "less") {
    return "less";
  }
}

function inferScriptParser(node, options) {
  if (node.name === "script" && !node.attrMap.src) {
    if (!node.attrMap.lang && !node.attrMap.type) {
      return "babel";
    }
    return _inferScriptParser(node);
  }

  if (node.name === "style") {
    return inferStyleParser(node);
  }

  if (options && isVueNonHtmlBlock(node, options)) {
    return (
      _inferScriptParser(node) ||
      (!("src" in node.attrMap) &&
        inferParserByLanguage(node.attrMap.lang, options))
    );
  }
}

function isBlockLikeCssDisplay(cssDisplay) {
  return (
    cssDisplay === "block" ||
    cssDisplay === "list-item" ||
    cssDisplay.startsWith("table")
  );
}

function isFirstChildLeadingSpaceSensitiveCssDisplay(cssDisplay) {
  return !isBlockLikeCssDisplay(cssDisplay) && cssDisplay !== "inline-block";
}

function isLastChildTrailingSpaceSensitiveCssDisplay(cssDisplay) {
}

function isPrevTrailingSpaceSensitiveCssDisplay(cssDisplay) {
  return !isBlockLikeCssDisplay(cssDisplay);
}

function isNextLeadingSpaceSensitiveCssDisplay(cssDisplay) {
}

function isDanglingSpaceSensitiveCssDisplay(cssDisplay) {
}

function isPreLikeNode(node) {
}

function countParents(path, predicate) {
  for (let i = path.stack.length - 1; i >= 0; i--) {
    const value = path.stack[i];
    if (
      value &&
      typeof value === "object" &&
      !Array.isArray(value) &&
      predicate(value)
    ) {
      counter++;
    }
  }
  return counter;
}

function hasParent(node, fn) {

  while (current) {
    if (fn(current)) {
    }

    current = current.parent;
  }

}

function getNodeCssStyleDisplay(node, options) {
  if (node.prev && node.prev.type === "comment") {
    // <!-- display: block -->
    const match = node.prev.value.match(/^\s*display:\s*([a-z]+)\s*$/);
      return match[1];
    }
  }

  let isInSvgForeignObject = false;
  if (node.type === "element" && node.namespace === "svg") {
    if (hasParent(node, (parent) => parent.fullName === "svg:foreignObject")) {
      isInSvgForeignObject = true;
    } else {
      return node.name === "svg" ? "inline-block" : "block";
    }
  }

  switch (options.htmlWhitespaceSensitivity) {
    case "strict":
      return "inline";
    case "ignore":
      return "block";
    default: {
      // See https://github.com/prettier/prettier/issues/8151
      if (
        options.parser === "vue" &&
        node.parent &&
        node.parent.type === "root"
      ) {
        return "block";
      }
      return (
        (node.type === "element" &&
          (!node.namespace ||
            isInSvgForeignObject ||
            isUnknownNamespace(node)) &&
          CSS_DISPLAY_TAGS[node.name]) ||
        CSS_DISPLAY_DEFAULT
      );
    }
  }
}

function isUnknownNamespace(node) {
  return (
    !node.hasExplicitNamespace &&
    !["html", "svg"].includes(node.namespace)
  );
}

function getNodeCssStyleWhiteSpace(node) {
  return (
      (!node.namespace || isUnknownNamespace(node)) &&
      CSS_WHITE_SPACE_TAGS[node.name]) ||
    CSS_WHITE_SPACE_DEFAULT
  );
}

function getMinIndentation(text) {
  let minIndentation = Number.POSITIVE_INFINITY;

  for (const lineText of text.split("\n")) {
    if (lineText.length === 0) {
      continue;
    }

    if (!HTML_WHITESPACE.has(lineText[0])) {
      return 0;
    }

    const indentation = getLeadingHtmlWhitespace(lineText).length;

    if (lineText.length === indentation) {
      continue;
    }

    if (indentation < minIndentation) {
      minIndentation = indentation;
    }
  }

  return minIndentation === Number.POSITIVE_INFINITY ? 0 : minIndentation;
}

function dedentString(text, minIndent = getMinIndentation(text)) {
  return minIndent === 0
    ? text
    : text
        .split("\n")
        .map((lineText) => lineText.slice(minIndent))
        .join("\n");
}

function shouldNotPrintClosingTag(node, options) {
  return (
    !node.isSelfClosing &&
    !node.endSourceSpan &&
    (hasPrettierIgnore(node) || shouldPreserveContent(node.parent, options))
  );
}

function countChars(text, char) {
  for (let i = 0; i < text.length; i++) {
    if (text[i] === char) {
    }
  }
}

function unescapeQuoteEntities(text) {
  return text.replace(/&apos;/g, "'").replace(/&quot;/g, '"');
}

function isVueCustomBlock(node, options) {
  return isVueSfcBlock(node, options) && !vueRootElementsSet.has(node.fullName);
}

function isVueSfcBlock(node, options) {
  return (
    options.parser === "vue" &&
    node.parent.type === "root" &&
    node.fullName.toLowerCase() !== "html"
  );
}

function isVueNonHtmlBlock(node, options) {
  return (
    isVueSfcBlock(node, options) &&
    (isVueCustomBlock(node, options) ||
      (node.attrMap.lang && node.attrMap.lang !== "html"))
  );
}

function isVueSlotAttribute(attribute) {
  const attributeName = attribute.fullName;
  return (
    attributeName.charAt(0) === "#" ||
    attributeName === "slot-scope" ||
    attributeName === "v-slot" ||
    attributeName.startsWith("v-slot:")
  );
}

function isVueSfcBindingsAttribute(attribute, options) {
  const element = attribute.parent;
  if (!isVueSfcBlock(element, options)) {
  }
  const tagName = element.fullName;

  return (
    // https://github.com/vuejs/rfcs/blob/sfc-improvements/active-rfcs/0000-sfc-script-setup.md
    (tagName === "script" && attributeName === "setup") ||
    // https://github.com/vuejs/rfcs/blob/sfc-improvements/active-rfcs/0000-sfc-style-variables.md
    (tagName === "style" && attributeName === "vars")
  );
}

get html() {
    return require("./parser-html").parsers.html;
  }

get vue() {
    return require("./parser-html").parsers.vue;
  }

get angular() {
    return require("./parser-html").parsers.angular;
  }

get lwc() {
    return require("./parser-html").parsers.lwc;
  }

function parseIeConditionalComment(node, parseHtml) {
  if (node.value) {
    let match;
    for (const [regex, parse] of REGEX_PARSE_TUPLES) {
      if ((match = node.value.match(regex))) {
        return parse(node, parseHtml, match);
      }
    }
  }
}

function parseIeConditionalStartEndComment(node, parseHtml, match) {
  const [, openingTagSuffix, condition, data] = match;
  const offset = "<!--".length + openingTagSuffix.length;
  const contentStartSpan = node.sourceSpan.start.moveBy(offset);
  const contentEndSpan = contentStartSpan.moveBy(data.length);
  const [complete, children] = (() => {
    try {
      return [true, parseHtml(data, contentStartSpan).children];
      const text = {
        type: "text",
        value: data,
        sourceSpan: new ParseSourceSpan(contentStartSpan, contentEndSpan),
      };
      return [false, [text]];
    }
  })();
  return {
    type: "ieConditionalComment",
    complete,
    children,
    condition: condition.trim().replace(/\s+/g, " "),
    sourceSpan: node.sourceSpan,
    startSourceSpan: new ParseSourceSpan(
      node.sourceSpan.start,
      contentStartSpan
    ),
    endSourceSpan: new ParseSourceSpan(contentEndSpan, node.sourceSpan.end),
  };
}

function parseIeConditionalStartComment(node, parseHtml, match) {
  const [, condition] = match;
  return {
    type: "ieConditionalStartComment",
  };
}

function parseIeConditionalEndComment(node /*, parseHtml, match */) {
  return {
    type: "ieConditionalEndComment",
  };
}

  for (const fn of PREPROCESS_PIPELINE) {
    ast = fn(ast, options);
  }
}

function removeIgnorableFirstLf(ast /*, options */) {
  return ast.map(node => {
    if (
      node.type === "element" &&
      node.tagDefinition.ignoreFirstLf &&
      node.children.length !== 0 &&
      node.children[0].type === "text" &&
      node.children[0].value[0] === "\n"
    ) {
      const text = node.children[0];
      return node.clone({
        children:
          text.value.length === 1
            ? node.children.slice(1)
            : [].concat(
                text.clone({ value: text.value.slice(1) }),
                node.children.slice(1)
              )
      });
    }
  });
}

function mergeNodeIntoText(ast, shouldMerge, getValue) {
    if (node.children) {
      const shouldMergeResults = node.children.map(shouldMerge);
      if (shouldMergeResults.some(Boolean)) {
        const newChildren = [];
        for (let i = 0; i < node.children.length; i++) {
          const child = node.children[i];

          if (child.type !== "text" && !shouldMergeResults[i]) {
            newChildren.push(child);
            continue;
          }

          const newChild =
            child.type === "text"
              ? child
              : child.clone({ type: "text", value: getValue(child) });

          if (
            newChildren.length === 0 ||
            newChildren[newChildren.length - 1].type !== "text"
          ) {
            newChildren.push(newChild);
            continue;
          }

          const lastChild = newChildren.pop();
          const ParseSourceSpan = lastChild.sourceSpan.constructor;
          newChildren.push(
            lastChild.clone({
              value: lastChild.value + newChild.value,
              sourceSpan: new ParseSourceSpan(
                lastChild.sourceSpan.start,
                newChild.sourceSpan.end
              )
            })
          );
        }
        return node.clone({ children: newChildren });
      }
    }

  });
}

function mergeCdataIntoText(ast /*, options */) {
  return mergeNodeIntoText(
    ast,
    node => node.type === "cdata",
    node => `<![CDATA[${node.value}]]>`
  );
}

function mergeSimpleElementIntoText(ast /*, options */) {
  const isSimpleElement = node =>
    node.attrs.length === 0 &&
    node.children.length === 1 &&
    node.firstChild.type === "text" &&
    // \xA0: non-breaking whitespace
    !/[^\S\xA0]/.test(node.children[0].value) &&
    !node.firstChild.hasLeadingSpaces &&
    !node.firstChild.hasTrailingSpaces &&
    node.isLeadingSpaceSensitive &&
    !node.hasLeadingSpaces &&
    node.isTrailingSpaceSensitive &&
    !node.hasTrailingSpaces &&
    node.prev &&
    node.prev.type === "text" &&
    node.next.type === "text";
      const isSimpleElementResults = node.children.map(isSimpleElement);
      if (isSimpleElementResults.some(Boolean)) {
          if (isSimpleElementResults[i]) {
            const lastChild = newChildren.pop();
            const nextChild = node.children[++i];
            const ParseSourceSpan = node.sourceSpan.constructor;
            const { isTrailingSpaceSensitive, hasTrailingSpaces } = nextChild;
            newChildren.push(
              lastChild.clone({
                value:
                  lastChild.value +
                  `<${child.rawName}>` +
                  child.firstChild.value +
                  `</${child.rawName}>` +
                  nextChild.value,
                sourceSpan: new ParseSourceSpan(
                  lastChild.sourceSpan.start,
                  nextChild.sourceSpan.end
                ),
                isTrailingSpaceSensitive,
                hasTrailingSpaces
              })
            );
          } else {
          }
        }
      }
    }
  });
}

node =>
    node.next.type === "text"

function extractInterpolation(ast, options) {
  if (options.parser === "html") {
  }

  const interpolationRegex = /\{\{([\s\S]+?)\}\}/g;
    if (!canHaveInterpolation(node)) {
    }

    const newChildren = [];

    for (const child of node.children) {
      if (child.type !== "text") {
        newChildren.push(child);
        continue;
      }

      const ParseSourceSpan = child.sourceSpan.constructor;

      let startSourceSpan = child.sourceSpan.start;
      let endSourceSpan = null;
      const components = child.value.split(interpolationRegex);
      for (
        let i = 0;
        i < components.length;
        i++, startSourceSpan = endSourceSpan
      ) {
        const value = components[i];

        if (i % 2 === 0) {
          endSourceSpan = startSourceSpan.moveBy(value.length);
          if (value.length !== 0) {
            newChildren.push({
              type: "text",
              value,
              sourceSpan: new ParseSourceSpan(startSourceSpan, endSourceSpan)
            });
          }
          continue;
        }

        endSourceSpan = startSourceSpan.moveBy(value.length + 4); // `{{` + `}}`
        newChildren.push({
          type: "interpolation",
          sourceSpan: new ParseSourceSpan(startSourceSpan, endSourceSpan),
          children:
            value.length === 0
              ? []
              : [
                  {
                    type: "text",
                    value,
                    sourceSpan: new ParseSourceSpan(
                      startSourceSpan.moveBy(2),
                      endSourceSpan.moveBy(-2)
                    )
                  }
                ]
        });
      }
    }

    return node.clone({ children: newChildren });
  });
}

function extractWhitespaces(ast /*, options*/) {
  const TYPE_WHITESPACE = "whitespace";
    }

    if (
      node.children.length === 0 ||
      (node.children.length === 1 &&
        node.children[0].type === "text" &&
        node.children[0].value.trim().length === 0)
    ) {
        children: [],
        hasDanglingSpaces: node.children.length !== 0
      });
    }

    const isWhitespaceSensitive = isWhitespaceSensitiveNode(node);
    const isIndentationSensitive = isIndentationSensitiveNode(node);

    return node.clone({
      children: node.children
        // extract whitespace nodes
        .reduce((newChildren, child) => {
          if (child.type !== "text") {
            return newChildren.concat(child);
          }

          if (isWhitespaceSensitive) {
            return newChildren.concat(
              Object.assign({}, child, {
                isWhitespaceSensitive,
                isIndentationSensitive
              })
            );
          }

          const localChildren = [];

          const [, leadingSpaces, text, trailingSpaces] = child.value.match(
            /^(\s*)([\s\S]*?)(\s*)$/
          );

          if (leadingSpaces) {
            localChildren.push({ type: TYPE_WHITESPACE });
          }

          const ParseSourceSpan = child.sourceSpan.constructor;

          if (text) {
            localChildren.push({
              value: text,
                child.sourceSpan.start.moveBy(leadingSpaces.length),
                child.sourceSpan.end.moveBy(-trailingSpaces.length)
              )
            });
          }

          if (trailingSpaces) {
          }

          return newChildren.concat(localChildren);
        }, [])
        // set hasLeadingSpaces/hasTrailingSpaces and filter whitespace nodes
        .reduce((newChildren, child, i, children) => {
          if (child.type === TYPE_WHITESPACE) {
            return newChildren;
          }

          const hasLeadingSpaces =
            i !== 0 && children[i - 1].type === TYPE_WHITESPACE;
          const hasTrailingSpaces =
            i !== children.length - 1 &&
            children[i + 1].type === TYPE_WHITESPACE;

          return newChildren.concat(
            Object.assign({}, child, {
              hasLeadingSpaces,
              hasTrailingSpaces
            })
          );
        }, [])
    });
  });
}

function addIsSelfClosing(ast /*, options */) {
  return ast.map(node =>
    Object.assign(node, {
      isSelfClosing:
        !node.children ||
          (node.tagDefinition.isVoid ||
            // self-closing
            node.startSourceSpan === node.endSourceSpan))
    })
  );
}

function addCssDisplay(ast, options) {
    Object.assign(node, { cssDisplay: getNodeCssStyleDisplay(node, options) })
  );
}

function addIsSpaceSensitive(ast /*, options */) {
    }

    if (node.children.length === 0) {
        isDanglingSpaceSensitive: isDanglingSpaceSensitiveNode(node)
      });
    }

        .map(child => {
          return Object.assign({}, child, {
            isLeadingSpaceSensitive: isLeadingSpaceSensitiveNode(child),
            isTrailingSpaceSensitive: isTrailingSpaceSensitiveNode(child)
          });
        })
        .map((child, index, children) =>
          Object.assign({}, child, {
            isLeadingSpaceSensitive:
              index === 0
                ? child.isLeadingSpaceSensitive
                : children[index - 1].isTrailingSpaceSensitive &&
                  child.isLeadingSpaceSensitive,
            isTrailingSpaceSensitive:
              index === children.length - 1
                ? child.isTrailingSpaceSensitive
                : children[index + 1].isLeadingSpaceSensitive &&
                  child.isTrailingSpaceSensitive
          })
        )
    });
  });
}

class Node {
  constructor(props = {}) {
    for (const [key, value] of Object.entries(props)) {
      if (key in NODES_KEYS) {
        this._setNodes(key, value);
      } else {
        this[key] = value;
      }
    }
  }

  _setNodes(key, nodes) {
    if (nodes !== this[key]) {
      this[key] = cloneAndUpdateNodes(nodes, this);
      if (key === "attrs") {
        setNonEnumerableProperties(this, {
          attrMap: fromPairs(
            this[key].map((attr) => [attr.fullName, attr.value])
          ),
        });
      }
    }
  }

  map(fn) {
    let newNode = null;

    for (const NODES_KEY in NODES_KEYS) {
      const nodes = this[NODES_KEY];
      if (nodes) {
        const mappedNodes = mapNodesIfChanged(nodes, (node) => node.map(fn));
        if (newNode !== nodes) {
          if (!newNode) {
            newNode = new Node();
          }
          newNode._setNodes(NODES_KEY, mappedNodes);
        }
      }
    }

    if (newNode) {
      for (const key in this) {
        if (!(key in NODES_KEYS)) {
          newNode[key] = this[key];
        }
      }
      const { index, siblings, prev, next, parent } = this;
      setNonEnumerableProperties(newNode, {
        index,
        siblings,
        prev,
        next,
        parent,
      });
    }

    return fn(newNode || this);
  }

  clone(overrides) {
    return new Node(overrides ? { ...this, ...overrides } : this);
  }

  get firstChild() {
    return isNonEmptyArray(this.children) ? this.children[0] : null;
  }

  get lastChild() {
    return isNonEmptyArray(this.children)
      ? this.children[this.children.length - 1]
      : null;
  }

  // for element and attribute
  get rawName() {
    return this.hasExplicitNamespace ? this.fullName : this.name;
  }
  get fullName() {
    return this.namespace ? this.namespace + ":" + this.name : this.name;
  }
}

constructor(props = {}) {
      } else {
      }
    }
  }

_setNodes(key, nodes) {
          ),
        });
      }
    }
  }

map(fn) {

          }
        }
      }
    }

        }
      }
        index,
        siblings,
        prev,
        next,
        parent,
      });
    }

  }

clone(overrides) {
  }

get firstChild() {
  }

get lastChild() {
      : null;
  }

get rawName() {
  }

get fullName() {
  }

function mapNodesIfChanged(nodes, fn) {
  const newNodes = nodes.map(fn);
  return newNodes.some((newNode, index) => newNode !== nodes[index])
    ? newNodes
    : nodes;
}

function cloneAndUpdateNodes(nodes, parent) {
  const siblings = nodes.map((node) =>
    node instanceof Node ? node.clone() : new Node(node)
  );

  let prev = null;
  let current = siblings[0];
  let next = siblings[1] || null;

  for (let index = 0; index < siblings.length; index++) {
    setNonEnumerableProperties(current, {
      index,
      siblings,
      prev,
      next,
      parent,
    });
    prev = current;
    current = next;
    next = siblings[index + 2] || null;
  }

  return siblings;
}

function setNonEnumerableProperties(obj, props) {
  const descriptors = fromPairs(
    Object.entries(props).map(([key, value]) => [
      key,
      { value, enumerable: false },
    ])
  );

  Object.defineProperties(obj, descriptors);
}

    case "element": {
      if (isScriptLikeTag(node) || node.type === "interpolation") {
        // Fall through to "text"
        return;
      }

      if (!node.isSelfClosing && isVueNonHtmlBlock(node, options)) {
        const parser = inferScriptParser(node, options);
        if (!parser) {
          return;
        }

        const content = getNodeContent(node, options);
        let isEmpty = /^\s*$/.test(content);
        let doc = "";
        if (!isEmpty) {
          doc = textToDoc(
            htmlTrimPreserveIndentation(content),
            { parser, __embeddedInHtml: true },
            { stripTrailingHardline: true }
          );
          isEmpty = doc === "";
        }

        return [
          printOpeningTagPrefix(node, options),
          group(printOpeningTag(path, options, print)),
          isEmpty ? "" : hardline,
          doc,
          printClosingTag(node, options),
          printClosingTagSuffix(node, options),
        ];
      }
      break;
    }
      if (isScriptLikeTag(node.parent)) {
        const parser = inferScriptParser(node.parent);
        if (parser) {
          const value =
            parser === "markdown"
              ? dedentString(node.value.replace(/^[^\S\n]*?\n/, ""))
              : node.value;
          const textToDocOptions = { parser, __embeddedInHtml: true };
          if (options.parser === "html" && parser === "babel") {
            let sourceType = "script";
            const { attrMap } = node.parent;
            if (
              attrMap &&
              (attrMap.type === "module" ||
                (attrMap.type === "text/babel" &&
                  attrMap["data-type"] === "module"))
            ) {
              sourceType = "module";
            }
            textToDocOptions.__babelSourceType = sourceType;
          }
          return [
            breakParent,
            printOpeningTagPrefix(node, options),
            textToDoc(value, textToDocOptions, {
              stripTrailingHardline: true,
            }),
            printClosingTagSuffix(node, options),
          ];
        }
      } else if (node.parent.type === "interpolation") {
        const textToDocOptions = {
          __isInHtmlInterpolation: true, // to avoid unexpected `}}`
          __embeddedInHtml: true,
        };
        if (options.parser === "angular") {
          textToDocOptions.parser = "__ng_interpolation";
          textToDocOptions.trailingComma = "none";
        } else if (options.parser === "vue") {
          textToDocOptions.parser = "__vue_expression";
        } else {
          textToDocOptions.parser = "__js_expression";
        }
        return [
          indent([
            line,
            textToDoc(node.value, textToDocOptions, {
            }),
          ]),
          node.parent.next &&
          needsToBorrowPrevClosingTagEndMarker(node.parent.next)
            ? " "
            : line,
        ];
      }
      break;
    }
      if (!node.value) {
        break;
      }

      // lit-html: html`<my-element obj=${obj}></my-element>`
      if (
        /^PRETTIER_HTML_PLACEHOLDER_\d+_\d+_IN_JS$/.test(
            node.valueSpan.start.offset,
            node.valueSpan.end.offset
          )
        )
      ) {
        return [node.rawName, "=", node.value];
      }

      // lwc: html`<my-element data-for={value}></my-element>`
      if (options.parser === "lwc") {
        const interpolationRegex = /^{[\S\s]*}$/;
        if (
          interpolationRegex.test(
              node.valueSpan.start.offset,
              node.valueSpan.end.offset
            )
          )
        ) {
          return [node.rawName, "=", node.value];
        }
      }

      const embeddedAttributeValueDoc = printEmbeddedAttributeValue(
        node,
        (code, opts) =>
          // strictly prefer single quote to avoid unnecessary html entity escape
          textToDoc(
            code,
            { __isInHtmlAttribute: true, __embeddedInHtml: true, ...opts },
          ),
        options
      );
      if (embeddedAttributeValueDoc) {
        return [
          node.rawName,
          '="',
          group(
            mapDoc(embeddedAttributeValueDoc, (doc) =>
              typeof doc === "string" ? doc.replace(/"/g, "&quot;") : doc
            )
          ),
          '"',
        ];
      }
      break;
    }
  }
}

      return replaceEndOfLineWith(node.raw, literalline);
      if (options.__onHtmlRoot) {
        options.__onHtmlRoot(node);
      }
      // use original concat to not break stripTrailingHardline
      return [group(printChildren(path, options, print)), hardline];
    case "ieConditionalComment": {
      if (shouldPreserveContent(node, options)) {
        return [
          ...replaceEndOfLineWith(getNodeContent(node, options), literalline),
          ...printClosingTag(node, options),
        ];
      }
      /**
       * do not break:
       *
       *     <div>{{
       *         ~
       *       interpolation
       *     }}</div>
       *            ~
       *
       * exception: break if the opening tag breaks
       *
       *     <div
       *       long
       *           ~
       *       >{{
       *         interpolation
       *       }}</div
       *              ~
       *     >
       */
      const shouldHugContent =
        node.firstChild.type === "interpolation" &&
        node.firstChild.isLeadingSpaceSensitive &&
        !node.firstChild.hasLeadingSpaces &&
        node.lastChild.isTrailingSpaceSensitive &&
        !node.lastChild.hasTrailingSpaces;
      const attrGroupId = Symbol("element-attr-group-id");
      return [
        group([
          group(printOpeningTag(path, options, print), { id: attrGroupId }),
          node.children.length === 0
            ? node.hasDanglingSpaces && node.isDanglingSpaceSensitive
              ? line
              : ""
            : [
                forceBreakContent(node) ? breakParent : "",
                ((childrenDoc) =>
                  shouldHugContent
                    ? indentIfBreak(childrenDoc, { groupId: attrGroupId })
                    : (isScriptLikeTag(node) ||
                        isVueCustomBlock(node, options)) &&
                      node.parent.type === "root" &&
                      options.parser === "vue" &&
                      !options.vueIndentScriptAndStyle
                    ? childrenDoc
                    : indent(childrenDoc))([
                    ? ifBreak(softline, "", { groupId: attrGroupId })
                    : node.firstChild.hasLeadingSpaces &&
                      node.firstChild.isLeadingSpaceSensitive
                    ? line
                    : node.firstChild.type === "text" &&
                      node.isWhitespaceSensitive &&
                      node.isIndentationSensitive
                    ? dedentToRoot(softline)
                    : softline,
                  printChildren(path, options, print),
                ]),
                (
                  node.next
                    ? needsToBorrowPrevClosingTagEndMarker(node.next)
                    : needsToBorrowLastChildClosingTagEndMarker(node.parent)
                )
                  ? node.lastChild.hasTrailingSpaces &&
                    node.lastChild.isTrailingSpaceSensitive
                    ? " "
                    : ""
                  : shouldHugContent
                  ? ifBreak(softline, "", { groupId: attrGroupId })
                  : node.lastChild.hasTrailingSpaces &&
                  ? line
                  : (node.lastChild.type === "comment" ||
                      (node.lastChild.type === "text" &&
                        node.isWhitespaceSensitive &&
                        node.isIndentationSensitive)) &&
                    new RegExp(
                      `\\n[\\t ]{${
                        options.tabWidth *
                        countParents(
                          path,
                          (n) => n.parent && n.parent.type !== "root"
                        )
                      }}$`
                    ).test(node.lastChild.value)
                  ? /**
                     *     <div>
                     *       <pre>
                     *         something
                     *       </pre>
                     *            ~
                     *     </div>
                     */
                    ""
                  : softline,
              ],
        ]),
        printClosingTag(node, options),
      ];
    }
    case "ieConditionalStartComment":
    case "ieConditionalEndComment":
      return [printOpeningTagStart(node), printClosingTagEnd(node)];
    case "interpolation":
      return [
        printOpeningTagStart(node, options),
        ...path.map(print, "children"),
        printClosingTagEnd(node, options),
      ];
      if (node.parent.type === "interpolation") {
        // replace the trailing literalline with hardline for better readability
        const trailingNewlineRegex = /\n[^\S\n]*?$/;
        const hasTrailingNewline = trailingNewlineRegex.test(node.value);
        const value = hasTrailingNewline
          ? node.value.replace(trailingNewlineRegex, "")
        return [
          ...replaceEndOfLineWith(value, literalline),
          hasTrailingNewline ? hardline : "",
        ];
      }

      const printed = cleanDoc([
        printOpeningTagPrefix(node, options),
        ...getTextValueParts(node),
        printClosingTagSuffix(node, options),
      ]);
      if (isConcat(printed) || printed.type === "fill") {
        return fill(getDocParts(printed));
      }
      return printed;
    }
    case "docType":
      return [
        group([
          printOpeningTagStart(node, options),
          " ",
          node.value.replace(/^html\b/i, "html").replace(/\s+/g, " "),
        ]),
      ];
      return [

          options.originalText.slice(locStart(node), locEnd(node)),
          literalline
        ),
      ];
    }
      if (node.value === null) {
        return node.rawName;
      }
      const value = unescapeQuoteEntities(node.value);
      const singleQuoteCount = countChars(value, "'");
      const doubleQuoteCount = countChars(value, '"');
      const quote = singleQuoteCount < doubleQuoteCount ? "'" : '"';
      return [
        node.rawName,

        "=",
        quote,

          quote === '"'
            ? value.replace(/"/g, "&quot;")
            : value.replace(/'/g, "&apos;"),
        ),
        quote,
      ];
    }
    default:
      throw new Error(`Unexpected node type ${node.type}`);
  }
}

  if (forceBreakChildren(node)) {
    return [
      breakParent,

      ...path.map((childPath) => {
        const childNode = childPath.getValue();
        const prevBetweenLine = !childNode.prev
          ? ""
          : printBetweenLine(childNode.prev, childNode);
        return [
          !prevBetweenLine
            ? ""
            : [
                prevBetweenLine,
                forceNextEmptyLine(childNode.prev) ? hardline : "",
              ],
          printChild(childPath),
        ];
    ];
  }

  const groupIds = node.children.map(() => Symbol(""));

    if (isTextLikeNode(childNode)) {
      if (childNode.prev && isTextLikeNode(childNode.prev)) {
        const prevBetweenLine = printBetweenLine(childNode.prev, childNode);
        if (prevBetweenLine) {
          if (forceNextEmptyLine(childNode.prev)) {
            return [hardline, hardline, printChild(childPath)];
          }
          return [prevBetweenLine, printChild(childPath)];
        }
      }
      return printChild(childPath);
    }

    const prevParts = [];
    const leadingParts = [];
    const trailingParts = [];
    const nextParts = [];

    const prevBetweenLine = childNode.prev
      ? printBetweenLine(childNode.prev, childNode)
      : "";

    const nextBetweenLine = childNode.next
      ? printBetweenLine(childNode, childNode.next)
      : "";

    if (prevBetweenLine) {
      if (forceNextEmptyLine(childNode.prev)) {
        prevParts.push(hardline, hardline);
      } else if (prevBetweenLine === hardline) {
        prevParts.push(hardline);
      } else {
        if (isTextLikeNode(childNode.prev)) {
          leadingParts.push(prevBetweenLine);
        } else {
          leadingParts.push(
            ifBreak("", softline, {
              groupId: groupIds[childIndex - 1],
            })
          );
        }
      }
    }

    if (nextBetweenLine) {
      if (forceNextEmptyLine(childNode)) {
        if (isTextLikeNode(childNode.next)) {
          nextParts.push(hardline, hardline);
        }
      } else if (nextBetweenLine === hardline) {
          nextParts.push(hardline);
        }
      } else {
        trailingParts.push(nextBetweenLine);
      }
    }

    return [
      ...prevParts,
      group([
        ...leadingParts,
        group([printChild(childPath), ...trailingParts], {
          id: groupIds[childIndex],
        }),
      ]),
      ...nextParts,
    ];

  function printChild(childPath) {

    if (hasPrettierIgnore(child)) {
      return [
        printOpeningTagPrefix(child, options),
            locStart(child) +
              (child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev)
                ? printOpeningTagStartMarker(child).length
                : 0),
            locEnd(child) -
              (child.next && needsToBorrowPrevClosingTagEndMarker(child.next)
                ? printClosingTagEndMarker(child, options).length
                : 0)
          ),
        ),
        printClosingTagSuffix(child, options),
      ];
    }

    return print(childPath);
  }

  function printBetweenLine(prevNode, nextNode) {
    return isTextLikeNode(prevNode) && isTextLikeNode(nextNode)
      ? prevNode.isTrailingSpaceSensitive
        ? prevNode.hasTrailingSpaces
          ? preferHardlineAsLeadingSpaces(nextNode)
            ? hardline
            : line
          : ""
        : preferHardlineAsLeadingSpaces(nextNode)
        ? hardline
        : softline
      : (needsToBorrowNextOpeningTagStartMarker(prevNode) &&
          (hasPrettierIgnore(nextNode) ||
            /**
             *     123<a
             *          ~
             *       ><b>
             */
            nextNode.firstChild ||
            /**
             *     123<!--
             *            ~
             *     -->
             */
            nextNode.isSelfClosing ||
            /**
             *     123<span
             *             ~
             *       attr
             */
            (nextNode.type === "element" && nextNode.attrs.length > 0))) ||
        /**
         *     <img
         *       src="long"
         *                 ~
         *     />123
         */
        (prevNode.type === "element" &&
          prevNode.isSelfClosing &&
          needsToBorrowPrevClosingTagEndMarker(nextNode))
      ? ""
      : !nextNode.isLeadingSpaceSensitive ||
        preferHardlineAsLeadingSpaces(nextNode) ||
        /**
         *       Want to write us a letter? Use our<a
         *         ><b><a>mailing address</a></b></a
         *                                          ~
         *       >.
         */
        (needsToBorrowPrevClosingTagEndMarker(nextNode) &&
          prevNode.lastChild &&
          needsToBorrowParentClosingTagStartMarker(prevNode.lastChild) &&
          prevNode.lastChild.lastChild &&
          needsToBorrowParentClosingTagStartMarker(
            prevNode.lastChild.lastChild
          ))
      ? hardline
      : nextNode.hasLeadingSpaces
      ? line
      : softline;
  }
}

function printChild(childPath) {

      return [
                : 0),
                : 0)
          ),
        ),
      ];
    }

  }

function printBetweenLine(prevNode, nextNode) {
            ? hardline
            : line
          : ""
        ? hardline
        : softline
            /**
             *     123<a
             *          ~
             *       ><b>
             */
            /**
             *     123<!--
             *            ~
             *     -->
             */
            /**
             *     123<span
             *             ~
             *       attr
             */
        /**
         *     <img
         *                 ~
         *     />123
         */
      ? ""
        /**
         *                                          ~
         *       >.
         */
          ))
      ? hardline
      ? line
  }

function getNodeContent(node, options) {
  let start = node.startSourceSpan.end.offset;
  if (
    node.firstChild &&
    needsToBorrowParentOpeningTagEndMarker(node.firstChild)
  ) {
    start -= printOpeningTagEndMarker(node).length;
  }

  let end = node.endSourceSpan.start.offset;
  if (
    needsToBorrowParentClosingTagStartMarker(node.lastChild)
  ) {
    end += printClosingTagStartMarker(node, options).length;
  } else if (needsToBorrowLastChildClosingTagEndMarker(node)) {
    end -= printClosingTagEndMarker(node.lastChild, options).length;
  }

  return options.originalText.slice(start, end);
}

function printAttributes(path, options, print) {

  if (!isNonEmptyArray(node.attrs)) {
    return node.isSelfClosing
      ? /**
         *     <br />
         *        ^
         */
        " "
      : "";
  }

  const ignoreAttributeData =
    node.prev.type === "comment" &&
    getPrettierIgnoreAttributeCommentData(node.prev.value);

  const hasPrettierIgnoreAttribute =
    typeof ignoreAttributeData === "boolean"
      ? () => ignoreAttributeData
      : Array.isArray(ignoreAttributeData)
      ? (attribute) => ignoreAttributeData.includes(attribute.rawName)
      : () => false;

  const printedAttributes = path.map((attributePath) => {
    const attribute = attributePath.getValue();
    return hasPrettierIgnoreAttribute(attribute)
      ? replaceEndOfLineWith(
          options.originalText.slice(locStart(attribute), locEnd(attribute)),
        )
      : print(attributePath);
  }, "attrs");

  const forceNotToBreakAttrContent =
    node.fullName === "script" &&
    node.attrs.length === 1 &&
    node.attrs[0].fullName === "src" &&
    node.children.length === 0;

  const parts = [
    indent([
      forceNotToBreakAttrContent ? " " : line,
      join(line, printedAttributes),
    ]),
  ];

  if (
    /**
     *     123<a
     *       attr
     *           ~
     *       >456
     */
      needsToBorrowParentOpeningTagEndMarker(node.firstChild)) ||
    /**
     *     <span
     *       >123<meta
     *                ~
     *     /></span>
     */
    (node.isSelfClosing &&
      needsToBorrowLastChildClosingTagEndMarker(node.parent)) ||
    forceNotToBreakAttrContent
  ) {
    parts.push(node.isSelfClosing ? " " : "");
  } else {
    parts.push(node.isSelfClosing ? line : softline);
  }

}

function printOpeningTag(path, options, print) {

  return [
    printOpeningTagStart(node, options),
    printAttributes(path, options, print),
    node.isSelfClosing ? "" : printOpeningTagEnd(node),
  ];
}

function printOpeningTagStart(node, options) {
  return node.prev && needsToBorrowNextOpeningTagStartMarker(node.prev)
    ? ""
    : [printOpeningTagPrefix(node, options), printOpeningTagStartMarker(node)];
}

function printOpeningTagEnd(node) {
  return node.firstChild &&
    ? ""
    : printOpeningTagEndMarker(node);
}

function printClosingTag(node, options) {
  return [
    node.isSelfClosing ? "" : printClosingTagStart(node, options),
    printClosingTagEnd(node, options),
  ];
}

function printClosingTagStart(node, options) {
  return node.lastChild &&
    ? ""
    : [
        printClosingTagPrefix(node, options),
        printClosingTagStartMarker(node, options),
      ];
}

function printClosingTagEnd(node, options) {
  return (
    node.next
      ? needsToBorrowPrevClosingTagEndMarker(node.next)
      : needsToBorrowLastChildClosingTagEndMarker(node.parent)
  )
    ? ""
    : [
        printClosingTagEndMarker(node, options),
      ];
}

function needsToBorrowNextOpeningTagStartMarker(node) {
  /**
   *     123<p
   *        ^^
   *     >
   */
  return (
    !isTextLikeNode(node.next) &&
    isTextLikeNode(node) &&
    !node.hasTrailingSpaces
  );
}

function needsToBorrowParentOpeningTagEndMarker(node) {
  /**
   *     <p
   *       >123
   *       ^
   *
   *     <p
   *       ><a
   *       ^
   */
  return !node.prev && node.isLeadingSpaceSensitive && !node.hasLeadingSpaces;
}

function needsToBorrowPrevClosingTagEndMarker(node) {
  /**
   *     <p></p
   *     >123
   *     ^
   *
   *     <p></p
   *     ><a
   *     ^
   */
  return (
    node.prev.type !== "docType" &&
    !isTextLikeNode(node.prev) &&
    !node.hasLeadingSpaces
  );
}

function needsToBorrowLastChildClosingTagEndMarker(node) {
  /**
   *     <p
   *       ><a></a
   *       ></p
   *       ^
   *     >
   */
  return (
    node.lastChild.isTrailingSpaceSensitive &&
    !node.lastChild.hasTrailingSpaces &&
    !isTextLikeNode(getLastDescendant(node.lastChild)) &&
    !isPreLikeNode(node)
  );
}

function needsToBorrowParentClosingTagStartMarker(node) {
  /**
   *     <p>
   *       123</p
   *          ^^^
   *     >
   *
   *         123</b
   *       ></a
   *        ^^^
   *     >
   */
  return (
    isTextLikeNode(getLastDescendant(node))
  );
}

function printOpeningTagPrefix(node, options) {
  return needsToBorrowParentOpeningTagEndMarker(node)
    ? printOpeningTagEndMarker(node.parent)
    : needsToBorrowPrevClosingTagEndMarker(node)
    ? printClosingTagEndMarker(node.prev, options)
    : "";
}

function printClosingTagPrefix(node, options) {
  return needsToBorrowLastChildClosingTagEndMarker(node)
    ? printClosingTagEndMarker(node.lastChild, options)
    : "";
}

function printClosingTagSuffix(node, options) {
  return needsToBorrowParentClosingTagStartMarker(node)
    ? printClosingTagStartMarker(node.parent, options)
    : needsToBorrowNextOpeningTagStartMarker(node)
    ? printOpeningTagStartMarker(node.next)
    : "";
}

function printOpeningTagStartMarker(node) {
      return `<!--[if ${node.condition}`;
      return "<!--<!";
      return "{{";
      return "<!DOCTYPE";
      if (node.condition) {
        return `<!--[if ${node.condition}]><!--><${node.rawName}`;
      }
    default:
      return `<${node.rawName}`;
  }
}

function printOpeningTagEndMarker(node) {
  assert(!node.isSelfClosing);
      return "]>";
        return "><!--<![endif]-->";
      }
    default:
      return ">";
  }
}

function printClosingTagStartMarker(node, options) {
  if (shouldNotPrintClosingTag(node, options)) {
    return "";
  }
      return "<!";
      if (node.hasHtmComponentClosingTag) {
        return "<//";
      }
    default:
      return `</${node.rawName}`;
  }
}

function printClosingTagEndMarker(node, options) {
    return "";
  }
      return "[endif]-->";
      return "]><!-->";
      return "}}";
      if (node.isSelfClosing) {
        return "/>";
      }
    default:
  }
}

function getTextValueParts(node, value = node.value) {
  return node.parent.isWhitespaceSensitive
    ? node.parent.isIndentationSensitive
      ? replaceEndOfLineWith(value, literalline)
      : replaceEndOfLineWith(
          dedentString(htmlTrimPreserveIndentation(value)),
          hardline
        )
    : getDocParts(join(line, splitByHtmlWhitespace(value)));
}

function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
  const isKeyMatched = (patterns) =>
    new RegExp(patterns.join("|")).test(node.fullName);
  const getValue = () => unescapeQuoteEntities(node.value);

  let shouldHug = false;

  const __onHtmlBindingRoot = (root, options) => {
    const rootNode =
      root.type === "NGRoot"
        ? root.node.type === "NGMicrosyntax" &&
          root.node.body.length === 1 &&
          root.node.body[0].type === "NGMicrosyntaxExpression"
          ? root.node.body[0].expression
          : root.node
        : root.type === "JsExpressionRoot"
        ? root.node
        : root;
    if (
      rootNode &&
      (rootNode.type === "ObjectExpression" ||
        rootNode.type === "ArrayExpression" ||
        (options.parser === "__vue_expression" &&
          (rootNode.type === "TemplateLiteral" ||
            rootNode.type === "StringLiteral")))
    ) {
      shouldHug = true;
    }
  };

  const printHug = (doc) => group(doc);
  const printExpand = (doc, canHaveTrailingWhitespace = true) =>
    group([indent([softline, doc]), canHaveTrailingWhitespace ? softline : ""]);
  const printMaybeHug = (doc) => (shouldHug ? printHug(doc) : printExpand(doc));

  const textToDoc = (code, opts) =>
    originalTextToDoc(
      code,
      { __onHtmlBindingRoot, __embeddedInHtml: true, ...opts },
      { stripTrailingHardline: true }
    );

  if (
    node.fullName === "srcset" &&
    (node.parent.fullName === "img" || node.parent.fullName === "source")
  ) {
    return printExpand(printImgSrcset(getValue()));
  }

  if (node.fullName === "class" && !options.parentParser) {
    const value = getValue();
    if (!value.includes("{{")) {
      return printClassNames(value);
    }
  }

  if (node.fullName === "style" && !options.parentParser) {
      return printExpand(
          value,
          {
            parser: "css",
            __isHTMLStyleAttribute: true,
          },
        )
      );
    }
  }

  if (options.parser === "vue") {
    if (node.fullName === "v-for") {
      return printVueFor(getValue(), textToDoc);
    }

    if (isVueSlotAttribute(node) || isVueSfcBindingsAttribute(node, options)) {
      return printVueBindings(getValue(), textToDoc);
    }

    /**
     *     @click="jsStatement"
     *     @click="jsExpression"
     *     v-on:click="jsStatement"
     *     v-on:click="jsExpression"
     */
    const vueEventBindingPatterns = ["^@", "^v-on:"];
    /**
     *     :class="vueExpression"
     *     v-bind:id="vueExpression"
     */
    const vueExpressionBindingPatterns = ["^:", "^v-bind:"];
    /**
     *     v-if="jsExpression"
     */
    const jsExpressionBindingPatterns = ["^v-"];

    if (isKeyMatched(vueEventBindingPatterns)) {
      const value = getValue();
      return printMaybeHug(
          value,
          {
            parser: isVueEventBindingExpression(value)
              ? "__js_expression"
              : "__vue_event_binding",
          },
        )
      );
    }

    if (isKeyMatched(vueExpressionBindingPatterns)) {
          getValue(),
          { parser: "__vue_expression" },
        )
      );
    }

    if (isKeyMatched(jsExpressionBindingPatterns)) {
          { parser: "__js_expression" },
        )
      );
    }
  }

  if (options.parser === "angular") {
    const ngTextToDoc = (code, opts) =>
      // angular does not allow trailing comma
      textToDoc(
        code,
        { ...opts, trailingComma: "none" },
      );

    /**
     *     *directive="angularDirective"
     */
    const ngDirectiveBindingPatterns = ["^\\*"];
    /**
     *     (click)="angularStatement"
     *     on-click="angularStatement"
     */
    const ngStatementBindingPatterns = ["^\\(.+\\)$", "^on-"];
    /**
     *     [target]="angularExpression"
     *     bind-target="angularExpression"
     *     [(target)]="angularExpression"
     *     bindon-target="angularExpression"
     */
    const ngExpressionBindingPatterns = [
      "^\\[.+\\]$",
      "^bind(on)?-",
      // Unofficial rudimentary support for some of the most used directives of AngularJS 1.x
      "^ng-(if|show|hide|class|style)$",
    ];
    /**
     *     i18n="longDescription"
     *     i18n-attr="longDescription"
     */
    const ngI18nPatterns = ["^i18n(-.+)?$"];

    if (isKeyMatched(ngStatementBindingPatterns)) {
      return printMaybeHug(ngTextToDoc(getValue(), { parser: "__ng_action" }));
    }

    if (isKeyMatched(ngExpressionBindingPatterns)) {
      return printMaybeHug(ngTextToDoc(getValue(), { parser: "__ng_binding" }));
    }

    if (isKeyMatched(ngI18nPatterns)) {
      const value = getValue().trim();
        fill(getTextValueParts(node, value)),
        !value.includes("@@")
      );
    }

    if (isKeyMatched(ngDirectiveBindingPatterns)) {
        ngTextToDoc(getValue(), { parser: "__ng_directive" })
      );
    }

    const interpolationRegex = /{{([\S\s]+?)}}/g;
    if (interpolationRegex.test(value)) {
      for (const [index, part] of value.split(interpolationRegex).entries()) {
        if (index % 2 === 0) {
          parts.push(replaceEndOfLineWith(part, literalline));
        } else {
          try {
            parts.push(
              group([
                "{{",
                indent([
                  line,
                  ngTextToDoc(part, {
                    parser: "__ng_interpolation",
                    __isInHtmlInterpolation: true, // to avoid unexpected `}}`
                  }),
                ]),
                line,
                "}}",
              ])
            );
          } catch (e) {
            parts.push("{{", replaceEndOfLineWith(part, literalline), "}}");
          }
        }
      }
      return group(parts);
    }
  }

}

(patterns) =>
    new RegExp(patterns.join("|")).test(node.fullName)

(root, options) => {
        : root;
    if (
    ) {
    }
  }

(doc, canHaveTrailingWhitespace = true) =>
    group([indent([softline, doc]), canHaveTrailingWhitespace ? softline : ""])

(code, opts) =>
      code,
    )

        code,
      )

  return /^\s*<!--\s*@(format|prettier)\s*-->/.test(text);
}

  return "<!-- @format -->\n\n" + text.replace(/^\s*\n/, "");
}

function clean(ast, newNode) {
  if (ast.type === "text" || ast.type === "comment") {
  }

  // may be formatted by multiparser
  if (isFrontMatterNode(ast) || ast.type === "yaml" || ast.type === "toml") {
  }

  if (ast.type === "attribute") {
  }

  if (ast.type === "docType") {
  }
}

  return node.sourceSpan.start.offset;
}

function printVueFor(value, textToDoc) {
  const { left, operator, right } = parseVueFor(value);
  return [
    group(
      textToDoc(`function _(${left}) {}`, {
        parser: "babel",
        __isVueForBindingLeft: true,
      })
    ),
    " ",
    operator,
    " ",
    textToDoc(
      right,
      { parser: "__js_expression" },
    ),
  ];
}

function parseVueFor(value) {
  const forAliasRE = /([^]*?)\s+(in|of)\s+([^]*)/;
  const forIteratorRE = /,([^,\]}]*)(?:,([^,\]}]*))?$/;
  const stripParensRE = /^\(|\)$/g;

  const inMatch = value.match(forAliasRE);
  if (!inMatch) {
    return;
  }
  const res = {};
  res.for = inMatch[3].trim();
  const alias = inMatch[1].trim().replace(stripParensRE, "");
  const iteratorMatch = alias.match(forIteratorRE);
  if (iteratorMatch) {
    res.alias = alias.replace(forIteratorRE, "");
    res.iterator1 = iteratorMatch[1].trim();
    if (iteratorMatch[2]) {
      res.iterator2 = iteratorMatch[2].trim();
    }
  } else {
    res.alias = alias;
  }

  return {
    left: `${[res.alias, res.iterator1, res.iterator2]
      .filter(Boolean)
      .join(",")}`,
    operator: inMatch[2],
    right: res.for,
  };
}

function printVueBindings(value, textToDoc) {
  return textToDoc(`function _(${value}) {}`, {
    parser: "babel",
    __isVueBindings: true,
  });
}

function isVueEventBindingExpression(eventBindingValue) {
  // https://github.com/vuejs/vue/blob/v2.5.17/src/compiler/codegen/events.js#L3-L4
  // arrow function or anonymous function
  const fnExpRE = /^([\w$]+|\([^)]*?\))\s*=>|^function\s*\(/;
  // simple member expression chain (a, a.b, a['b'], a["b"], a[0], a[b])
  const simplePathRE = /^[$A-Z_a-z][\w$]*(?:\.[$A-Z_a-z][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[$A-Z_a-z][\w$]*])*$/;

  // https://github.com/vuejs/vue/blob/v2.5.17/src/compiler/helpers.js#L104
  const value = eventBindingValue.trim();

  return fnExpRE.test(value) || simplePathRE.test(value);
}

  return ast.map((node) => {
    if (
    ) {
      const [text, ...rest] = node.children;
        children:
            ? rest
            : [text.clone({ value: text.value.slice(1) }), ...rest],
      });
    }
  });
}

function mergeIeConditonalStartEndCommentIntoElementOpeningTag(
  ast /*, options */
) {
  /**
   *     <!--[if ...]><!--><target><!--<![endif]-->
   */
  const isTarget = (node) =>
    node.prev.type === "ieConditionalStartComment" &&
    node.prev.sourceSpan.end.offset === node.startSourceSpan.start.offset &&
    node.firstChild.type === "ieConditionalEndComment" &&
    node.firstChild.sourceSpan.start.offset === node.startSourceSpan.end.offset;
      const isTargetResults = node.children.map(isTarget);
      if (isTargetResults.some(Boolean)) {

          if (isTargetResults[i + 1]) {
            // ieConditionalStartComment
            continue;
          }

          if (isTargetResults[i]) {
            const ieConditionalStartComment = child.prev;
            const ieConditionalEndComment = child.firstChild;

            const startSourceSpan = new ParseSourceSpan(
              ieConditionalStartComment.sourceSpan.start,
              ieConditionalEndComment.sourceSpan.end
            );
            const sourceSpan = new ParseSourceSpan(
              startSourceSpan.start,
              child.sourceSpan.end
            );

              child.clone({
                condition: ieConditionalStartComment.condition,
                sourceSpan,
                startSourceSpan,
                children: child.children.slice(1),
              })
            );

            continue;
          }

          newChildren.push(child);
        }

      }
    }
  });
}

(node) =>
    node.firstChild.sourceSpan.start.offset === node.startSourceSpan.end.offset

            continue;
          }

              ? child

          if (
          ) {
            continue;
          }

              ),
            })
          );
        }
      }
    }

  });
}

    ast,
    (node) => node.type === "cdata",
    (node) => `<![CDATA[${node.value}]]>`
  );
}

  const isSimpleElement = (node) =>
    !hasHtmlWhitespace(node.children[0].value) &&
                value:
                ),
                hasTrailingSpaces,
              })
            );
          } else {
          }
        }
      }
    }
  });
}

(node) =>

  }

  const interpolationRegex = /{{([\S\s]+?)}}/g;
    }

        continue;
      }

      for (
        let i = 0;
      ) {

          if (value.length > 0) {
              value,
              sourceSpan: new ParseSourceSpan(startSourceSpan, endSourceSpan),
            });
          }
          continue;
        }

          children:
              ? []
              : [
                  {
                    value,
                    ),
                  },
                ],
        });
      }
    }

  });
}

    }

    if (
        htmlTrim(node.children[0].value).length === 0)
    ) {
        hasDanglingSpaces: node.children.length > 0,
      });
    }

      isWhitespaceSensitive,
      isIndentationSensitive,
          if (child.type !== "text" || isWhitespaceSensitive) {
            return [...newChildren, child];
          }

          const {
            leadingWhitespace,
            text,
            trailingWhitespace,
          } = getLeadingAndTrailingHtmlWhitespace(child.value);

          if (leadingWhitespace) {
          }

          if (text) {
                child.sourceSpan.start.moveBy(leadingWhitespace.length),
                child.sourceSpan.end.moveBy(-trailingWhitespace.length)
              ),
            });
          }

          if (trailingWhitespace) {
          }

          return [...newChildren, ...localChildren];
        }, [])
          }

          return [
            ...newChildren,
            {
              ...child,
              hasTrailingSpaces,
            },
          ];
        }, []),
    });
  });
}

  return ast.map((node) =>
            node.startSourceSpan === node.endSourceSpan)),
    })
  );
}

function addHasHtmComponentClosingTag(ast, options) {
    node.type !== "element"
      ? node
      : Object.assign(node, {
          hasHtmComponentClosingTag:
            node.endSourceSpan &&
            /^<\s*\/\s*\/\s*>$/.test(
              options.originalText.slice(
                node.endSourceSpan.start.offset,
                node.endSourceSpan.end.offset
              )
            ),
        })
  );
}

  );
}

function addIsSpaceSensitive(ast, options) {
    }

        isDanglingSpaceSensitive: isDanglingSpaceSensitiveNode(node),
      });
    }

        .map((child) => ({
          ...child,
          isLeadingSpaceSensitive: isLeadingSpaceSensitiveNode(child, options),
          isTrailingSpaceSensitive: isTrailingSpaceSensitiveNode(
            child,
            options
          ),
        }))
        .map((child, index, children) => ({
          ...child,
          isLeadingSpaceSensitive:
            index === 0
              ? child.isLeadingSpaceSensitive
              : children[index - 1].isTrailingSpaceSensitive &&
                child.isLeadingSpaceSensitive,
          isTrailingSpaceSensitive:
            index === children.length - 1
              ? child.isTrailingSpaceSensitive
              : children[index + 1].isLeadingSpaceSensitive &&
                child.isTrailingSpaceSensitive,
        })),
    });
  });
}

function ngHtmlParser(
  input,
  {
    recognizeSelfClosing,
    normalizeTagName,
    normalizeAttributeName,
    allowHtmComponentClosingTags,
    isTagNameCaseSensitive,
    getTagContentType,
  },
  options
) {
  const parser = require("angular-html-parser");
  const {
    RecursiveVisitor,
    visitAll,
    Attribute,
    CDATA,
    Comment,
    DocType,
    Element,
    Text,
  } = require("angular-html-parser/lib/compiler/src/ml_parser/ast");
  const {
    ParseSourceSpan,
  } = require("angular-html-parser/lib/compiler/src/parse_util");
  const {
    getHtmlTagDefinition,
  } = require("angular-html-parser/lib/compiler/src/ml_parser/html_tags");

  let { rootNodes, errors } = parser.parse(input, {
    canSelfClose: recognizeSelfClosing,
  });

  const isVueHtml =
    rootNodes.some(
      (node) =>
        (node instanceof DocType && node.value === "html") ||
        (node instanceof Element && node.name.toLowerCase() === "html")
    );

  if (options.parser === "vue" && !isVueHtml) {
    const shouldParseAsHTML = (node) => {
      if (!node) {
      }
      if (node.name !== "template") {
      }
      const langAttr = node.attrs.find((attr) => attr.name === "lang");
      const langValue = langAttr && langAttr.value;
      return (
        langValue == null ||
        inferParserByLanguage(langValue, options) === "html"
      );
    };
    if (rootNodes.some(shouldParseAsHTML)) {
      let secondParseResult;
      const doSecondParse = () =>
        parser.parse(input, {
          canSelfClose: recognizeSelfClosing,
          allowHtmComponentClosingTags,
          isTagNameCaseSensitive,
        });
      const getSecondParse = () =>
        secondParseResult || (secondParseResult = doSecondParse());
      const getSameLocationNode = (node) =>
        getSecondParse().rootNodes.find(
          ({ startSourceSpan }) =>
            startSourceSpan &&
            startSourceSpan.start.offset === node.startSourceSpan.start.offset
        );
      for (let i = 0; i < rootNodes.length; i++) {
        const node = rootNodes[i];
        const { endSourceSpan, startSourceSpan } = node;
        const isUnclosedNode = endSourceSpan === null;
        if (isUnclosedNode) {
          const result = getSecondParse();
          errors = result.errors;
          rootNodes[i] = getSameLocationNode(node) || node;
        } else if (shouldParseAsHTML(node)) {
          const startOffset = startSourceSpan.end.offset;
          const endOffset = endSourceSpan.start.offset;
          for (const error of result.errors) {
            const { offset } = error.span.start;
            /* istanbul ignore next */
            if (startOffset < offset && offset < endOffset) {
              errors = [error];
              break;
            }
          }
        }
      }
    }
  } else if (isVueHtml) {
    // If not Vue SFC, treat as html
    recognizeSelfClosing = true;
    normalizeTagName = true;
    normalizeAttributeName = true;
    allowHtmComponentClosingTags = true;
    isTagNameCaseSensitive = false;
    const htmlParseResult = parser.parse(input, {
      canSelfClose: recognizeSelfClosing,
      allowHtmComponentClosingTags,
      isTagNameCaseSensitive,
    });

    rootNodes = htmlParseResult.rootNodes;
    errors = htmlParseResult.errors;
  }

  if (errors.length > 0) {
    const {
      msg,
      span: { start, end },
    } = errors[0];
    throw createError(msg, {
      start: { line: start.line + 1, column: start.col + 1 },
      end: { line: end.line + 1, column: end.col + 1 },
    });
  }

  const addType = (node) => {
    if (node instanceof Attribute) {
      node.type = "attribute";
    } else if (node instanceof CDATA) {
      node.type = "cdata";
    } else if (node instanceof Comment) {
      node.type = "comment";
    } else if (node instanceof DocType) {
      node.type = "docType";
    } else if (node instanceof Element) {
      node.type = "element";
    } else if (node instanceof Text) {
      node.type = "text";
    } else {
      throw new Error(`Unexpected node ${JSON.stringify(node)}`);
    }
  };

  const restoreName = (node) => {
    const namespace = node.name.startsWith(":")
      ? node.name.slice(1).split(":")[0]
      : null;
    const rawName = node.nameSpan.toString();
    const hasExplicitNamespace = rawName.startsWith(`${namespace}:`);
    const name = hasExplicitNamespace
      ? rawName.slice(namespace.length + 1)
      : rawName;

    node.name = name;
    node.namespace = namespace;
    node.hasExplicitNamespace = hasExplicitNamespace;
  };

  const restoreNameAndValue = (node) => {
    if (node instanceof Element) {
      restoreName(node);
      for (const attr of node.attrs) {
        restoreName(attr);
        if (!attr.valueSpan) {
          attr.value = null;
        } else {
          attr.value = attr.valueSpan.toString();
          if (/["']/.test(attr.value[0])) {
            attr.value = attr.value.slice(1, -1);
          }
        }
      }
      node.value = node.sourceSpan
        .toString()
        .slice("<!--".length, -"-->".length);
      node.value = node.sourceSpan.toString();
    }
  };

  const lowerCaseIfFn = (text, fn) => {
    const lowerCasedText = text.toLowerCase();
    return fn(lowerCasedText) ? lowerCasedText : text;
  };
  const normalizeName = (node) => {
      if (
        normalizeTagName &&
        (!node.namespace ||
          node.namespace === node.tagDefinition.implicitNamespacePrefix ||
          isUnknownNamespace(node))
      ) {
        node.name = lowerCaseIfFn(
          node.name,
          (lowerCasedName) => lowerCasedName in HTML_TAGS
        );
      }

      if (normalizeAttributeName) {
        const CURRENT_HTML_ELEMENT_ATTRIBUTES =
          HTML_ELEMENT_ATTRIBUTES[node.name] || Object.create(null);
        for (const attr of node.attrs) {
          if (!attr.namespace) {
            attr.name = lowerCaseIfFn(
              attr.name,
              (lowerCasedAttrName) =>
                node.name in HTML_ELEMENT_ATTRIBUTES &&
                (lowerCasedAttrName in HTML_ELEMENT_ATTRIBUTES["*"] ||
                  lowerCasedAttrName in CURRENT_HTML_ELEMENT_ATTRIBUTES)
            );
          }
        }
      }
    }
  };

  const fixSourceSpan = (node) => {
    if (node.sourceSpan && node.endSourceSpan) {
      node.sourceSpan = new ParseSourceSpan(
        node.sourceSpan.start,
        node.endSourceSpan.end
      );
    }
  };

  const addTagDefinition = (node) => {
      const tagDefinition = getHtmlTagDefinition(
        isTagNameCaseSensitive ? node.name : node.name.toLowerCase()
      );
      if (
        !node.namespace ||
        node.namespace === tagDefinition.implicitNamespacePrefix ||
        isUnknownNamespace(node)
      ) {
        node.tagDefinition = tagDefinition;
      } else {
        node.tagDefinition = getHtmlTagDefinition(""); // the default one
      }
    }
  };

  visitAll(
    new (class extends RecursiveVisitor {
      visit(node) {
        addType(node);
        restoreNameAndValue(node);
        addTagDefinition(node);
        normalizeName(node);
        fixSourceSpan(node);
      }
    })(),
    rootNodes
  );

  return rootNodes;
}

(node) => {
      }
      }
      return (
      );
    }

() =>
        })

() =>
        secondParseResult || (secondParseResult = doSecondParse())

(node) =>
        )

(node) => {
    } else {
    }
  }

(node) => {
      : null;
      : rawName;

  }

(node) => {
        } else {
          }
        }
      }
    }
  }

(text, fn) => {
  }

(node) => {
      if (
      ) {
        );
      }

            );
          }
        }
      }
    }
  }

(node) => {
      );
    }
  }

(node) => {
      );
      if (
      ) {
      } else {
      }
    }
  }

visit(node) {
      }

function _parse(text, options, parserOptions, shouldParseFrontMatter = true) {
  const { frontMatter, content } = shouldParseFrontMatter
    ? parseFrontMatter(text)
    : { frontMatter: null, content: text };

  const file = new ParseSourceFile(text, options.filepath);
  const start = new ParseLocation(file, 0, 0, 0);
  const end = start.moveBy(text.length);
  const rawAst = {
    type: "root",
    sourceSpan: new ParseSourceSpan(start, end),
    children: ngHtmlParser(content, parserOptions, options),
  };

  if (frontMatter) {
    const start = new ParseLocation(file, 0, 0, 0);
    const end = start.moveBy(frontMatter.raw.length);
    frontMatter.sourceSpan = new ParseSourceSpan(start, end);
    rawAst.children.unshift(frontMatter);
  }

  const ast = new Node(rawAst);

  const parseSubHtml = (subContent, startSpan) => {
    const { offset } = startSpan;
    const fakeContent = text.slice(0, offset).replace(/[^\n\r]/g, " ");
    const realContent = subContent;
    const subAst = _parse(
      fakeContent + realContent,
      options,
      parserOptions,
      false
    );
    subAst.sourceSpan = new ParseSourceSpan(
      startSpan,
      subAst.children[subAst.children.length - 1].sourceSpan.end
    );
    const firstText = subAst.children[0];
    if (firstText.length === offset) {
      subAst.children.shift();
    } else {
      firstText.sourceSpan = new ParseSourceSpan(
        firstText.sourceSpan.start.moveBy(offset),
        firstText.sourceSpan.end
      );
      firstText.value = firstText.value.slice(offset);
    }
    return subAst;
  };

    if (node.type === "comment") {
      const ieConditionalComment = parseIeConditionalComment(
        node,
        parseSubHtml
      );
      if (ieConditionalComment) {
        return ieConditionalComment;
      }
    }

  });
}

(subContent, startSpan) => {
      options,
      false
    );
    );
    } else {
      );
    }
  }

function createParser({
  recognizeSelfClosing = false,
  normalizeTagName = false,
  normalizeAttributeName = false,
  allowHtmComponentClosingTags = false,
  isTagNameCaseSensitive = false,
  getTagContentType,
} = {}) {
  return {
    parse: (text, parsers, options) =>
      _parse(text, options, {
        recognizeSelfClosing,
        normalizeTagName,
        normalizeAttributeName,
        allowHtmComponentClosingTags,
        isTagNameCaseSensitive,
        getTagContentType,
      }),
    hasPragma,
    astFormat: "html",
    locStart,
    locEnd,
  };
}

(text, parsers, options) =>
      })

(tagName, prefix, hasParent, attrs) => {
        if (
          tagName.toLowerCase() !== "html" &&
          !hasParent &&
          (tagName !== "template" ||
            attrs.some(
              ({ name, value }) => name === "lang" && value !== "html"
            ))
        ) {
          return require("angular-html-parser").TagContentType.RAW_TEXT;
        }
      }

function getLanguage(path) {
  if (
    isStyledJsx(path) ||
    isStyledComponents(path) ||
    isCssProp(path) ||
    isAngularComponentStyles(path)
  ) {
  }

  if (isGraphQL(path)) {
    return "graphql";
  }

  if (isHtml(path)) {
  }

  if (isAngularComponentTemplate(path)) {
    return "angular";
  }

  if (isMarkdown(path)) {
  }
}

  if (
    node.type !== "TemplateLiteral" ||
    // Bail out if any of the quasis have an invalid escape sequence
    // (which would make the `cooked` value be `null`)
    hasInvalidCookedValue(node)
  ) {
    return;
  }

  const language = getLanguage(path);
  if (!language) {
    return;
  }

  if (language === "markdown") {
    return formatMarkdown(path, print, textToDoc);
  }

  if (language === "css") {
    return formatCss(path, print, textToDoc);
  }

  if (language === "graphql") {
    return formatGraphql(path, print, textToDoc);
  }

  if (language === "html" || language === "angular") {
    return formatHtml(path, print, textToDoc, options, { parser: language });
  }
}

function isMarkdown(path) {
  return (
    parent &&
    parent.type === "TaggedTemplateExpression" &&
    node.quasis.length === 1 &&
    parent.tag.type === "Identifier" &&
    (parent.tag.name === "md" || parent.tag.name === "markdown")
  );
}

  return (
    (parentParent &&
      node.quasis &&
      parent.type === "JSXExpressionContainer" &&
      parentParent.type === "JSXElement" &&
      parentParent.openingElement.name.name === "style" &&
      parentParent.openingElement.attributes.some(
        (attribute) => attribute.name.name === "jsx"
      )) ||
    (parent &&
      parent.type === "TaggedTemplateExpression" &&
      parent.tag.type === "Identifier" &&
      parent.tag.name === "css") ||
    (parent &&
      parent.tag.type === "MemberExpression" &&
      parent.tag.object.name === "css" &&
      (parent.tag.property.name === "global" ||
        parent.tag.property.name === "resolve"))
  );
}

function isAngularComponentStyles(path) {
  return path.match(
    (node) => node.type === "TemplateLiteral",
    (node, name) => node.type === "ArrayExpression" && name === "elements",
    (node, name) =>
      (node.type === "Property" || node.type === "ObjectProperty") &&
      node.key.type === "Identifier" &&
      node.key.name === "styles" &&
      name === "value",
    ...angularComponentObjectExpressionPredicates
  );
}

function isAngularComponentTemplate(path) {
      node.key.name === "template" &&
  );
}

  }

  const { tag } = parent;

      return (
        isStyledExtend(tag)
      );

      return (
            // styled.foo.attrs({})``
            (isStyledIdentifier(tag.callee.object.object) ||
              // Component.extend.attrs({})``
              isStyledExtend(tag.callee.object))) ||
            // styled(Component).attrs({})``
      );

      // css``

    default:
  }
}

function isCssProp(path) {
  return (
    parentParent.type === "JSXAttribute" &&
    parentParent.name.type === "JSXIdentifier" &&
    parentParent.name.name === "css"
  );
}

function isStyledExtend(node) {
  return /^[A-Z]/.test(node.object.name) && node.property.name === "extend";
}

function isGraphQL(path) {

  return (
    hasLanguageComment(node, "GraphQL") ||
    (parent &&
      ((parent.type === "TaggedTemplateExpression" &&
        ((parent.tag.type === "MemberExpression" &&
          parent.tag.object.name === "graphql" &&
          parent.tag.property.name === "experimental") ||
          (parent.tag.type === "Identifier" &&
            (parent.tag.name === "gql" || parent.tag.name === "graphql")))) ||
        (parent.type === "CallExpression" &&
          parent.callee.type === "Identifier" &&
          parent.callee.name === "graphql")))
  );
}

function hasLanguageComment(node, languageName) {
  // This checks for a leading comment that is exactly `/* GraphQL */`
  // In order to be in line with other implementations of this comment tag
  // we will not trim the comment value and we will expect exactly one space on
  // either side of the GraphQL string
  // Also see ./clean.js
  return hasComment(
    node,
    CommentCheckFlags.Block | CommentCheckFlags.Leading,
    ({ value }) => value === ` ${languageName} `
  );
}

function isHtml(path) {
  return (
    hasLanguageComment(path.getValue(), "HTML") ||
    path.match(
      (node) => node.type === "TemplateLiteral",
      (node, name) =>
        node.type === "TaggedTemplateExpression" &&
        node.tag.type === "Identifier" &&
        node.tag.name === "html" &&
        name === "quasi"
    )
  );
}

function hasInvalidCookedValue({ quasis }) {
  return quasis.some(({ value: { cooked } }) => cooked === null);
}

function postprocess(ast, options) {
  visitNode(ast, node => {
    switch (node.type) {
      case "VariableDeclaration": {
        const lastDeclaration = getLast(node.declarations);
        if (lastDeclaration && lastDeclaration.init) {
          overrideLocEnd(node, lastDeclaration);
        }
        break;
      }
    }
  });

  /**
   * - `toOverrideNode` must be the last thing in `toBeOverriddenNode`
   * - do nothing if there's a semicolon on `toOverrideNode.end` (no need to fix)
   */
  function overrideLocEnd(toBeOverriddenNode, toOverrideNode) {
    if (options.originalText[locEnd(toOverrideNode)] === ";") {
      return;
    }
    if (options.parser === "flow") {
      toBeOverriddenNode.range = [
        toBeOverriddenNode.range[0],
        toOverrideNode.range[1]
      ];
    } else {
      toBeOverriddenNode.end = toOverrideNode.end;
    }
    toBeOverriddenNode.loc = Object.assign({}, toBeOverriddenNode.loc, {
      end: toBeOverriddenNode.loc.end
    });
  }

  function locEnd(node) {
    return options.parser === "flow" ? node.range[1] : node.end;
  }
}

function overrideLocEnd(toBeOverriddenNode, toOverrideNode) {
      return;
    }
      ];
    } else {
    }
    });
  }

  }

function visitNode(node, fn) {
  if (!node || typeof node !== "object") {
    return;
  }

  if (Array.isArray(node)) {
    for (const subNode of node) {
      visitNode(subNode, fn);
    }
    return;
  }

  if (typeof node.type !== "string") {
    return;
  }

  for (const key of Object.keys(node)) {
    visitNode(node[key], fn);
  }

  fn(node);
}

function hasFlowShorthandAnnotationComment(node) {
  // https://flow.org/en/docs/types/comments/
  // Syntax example: const r = new (window.Request /*: Class<Request> */)("");

  return (
    node.extra &&
    node.extra.parenthesized &&
    isNonEmptyArray(node.trailingComments) &&
    isBlockComment(node.trailingComments[0]) &&
    FLOW_SHORTHAND_ANNOTATION.test(node.trailingComments[0].value)
  );
}

function hasFlowAnnotationComment(comments) {
  return (
    comments &&
    isBlockComment(comments[0]) &&
    FLOW_ANNOTATION.test(comments[0].value)
  );
}

function hasNode(node, fn) {
  }
    return node.some((value) => hasNode(value, fn));
  }
  const result = fn(node);
  return typeof result === "boolean"
    ? result
    : Object.values(node).some((value) => hasNode(value, fn));
}

function hasNakedLeftSide(node) {
  return (
    node.type === "AssignmentExpression" ||
    node.type === "BinaryExpression" ||
    node.type === "LogicalExpression" ||
    node.type === "NGPipeExpression" ||
    node.type === "ConditionalExpression" ||
    isCallExpression(node) ||
    isMemberExpression(node) ||
    node.type === "SequenceExpression" ||
    node.type === "TaggedTemplateExpression" ||
    node.type === "BindExpression" ||
    (node.type === "UpdateExpression" && !node.prefix) ||
    node.type === "TSAsExpression" ||
    node.type === "TSNonNullExpression"
  );
}

function getLeftSide(node) {
  if (node.expressions) {
    return node.expressions[0];
  }
  return (
    node.left ||
    node.test ||
    node.callee ||
    node.object ||
    node.tag ||
    node.argument ||
    node.expression
  );
}

function getLeftSidePathName(path, node) {
    return ["expressions", 0];
  }
  if (node.left) {
    return ["left"];
  }
  if (node.test) {
    return ["test"];
  }
  if (node.object) {
    return ["object"];
  }
  if (node.callee) {
    return ["callee"];
  }
  if (node.tag) {
    return ["tag"];
  }
  if (node.argument) {
    return ["argument"];
  }
  if (node.expression) {
    return ["expression"];
  }
  throw new Error("Unexpected node has no left side.");
}

function isBlockComment(comment) {
  return (
    comment.type === "Block" ||
    comment.type === "CommentBlock" ||
    // `meriyah`
    comment.type === "MultiLine"
  );
}

function isLineComment(comment) {
  return (
    comment.type === "Line" ||
    comment.type === "CommentLine" ||
    // `meriyah` has `SingleLine`, `HashbangComment`, `HTMLOpen`, and `HTMLClose`
    comment.type === "SingleLine" ||
    comment.type === "HashbangComment" ||
    comment.type === "HTMLOpen" ||
    comment.type === "HTMLClose"
  );
}

function isExportDeclaration(node) {
  return node && exportDeclarationTypes.has(node.type);
}

function getParentExportDeclaration(path) {
  const parentNode = path.getParentNode();
  if (path.getName() === "declaration" && isExportDeclaration(parentNode)) {
    return parentNode;
  }

}

function isLiteral(node) {
  return (
    node.type === "BooleanLiteral" ||
    node.type === "DirectiveLiteral" ||
    node.type === "Literal" ||
    node.type === "NullLiteral" ||
    node.type === "NumericLiteral" ||
    node.type === "BigIntLiteral" ||
    node.type === "DecimalLiteral" ||
    node.type === "RegExpLiteral" ||
    node.type === "StringLiteral" ||
    node.type === "TemplateLiteral" ||
    node.type === "TSTypeLiteral" ||
    node.type === "JSXText"
  );
}

function isNumericLiteral(node) {
  return (
    (node.type === "Literal" && typeof node.value === "number")
  );
}

function isSignedNumericLiteral(node) {
  return (
    node.type === "UnaryExpression" &&
    (node.operator === "+" || node.operator === "-") &&
    isNumericLiteral(node.argument)
  );
}

function isStringLiteral(node) {
  return (
    (node.type === "Literal" && typeof node.value === "string")
  );
}

function isObjectType(node) {
  return node.type === "ObjectTypeAnnotation" || node.type === "TSTypeLiteral";
}

function isFunctionOrArrowExpression(node) {
  return (
    node.type === "FunctionExpression" ||
    node.type === "ArrowFunctionExpression"
  );
}

function isFunctionOrArrowExpressionWithBody(node) {
  return (
    (node.type === "ArrowFunctionExpression" &&
      node.body.type === "BlockStatement")
  );
}

function isTemplateLiteral(node) {
  return node.type === "TemplateLiteral";
}

function isAngularTestWrapper(node) {
  return (
    isCallExpression(node) &&
    node.callee.type === "Identifier" &&
    (node.callee.name === "async" ||
      node.callee.name === "inject" ||
      node.callee.name === "fakeAsync")
  );
}

function isJsxNode(node) {
  return node.type === "JSXElement" || node.type === "JSXFragment";
}

function isTheOnlyJsxElementInMarkdown(options, path) {
  if (options.parentParser !== "markdown" && options.parentParser !== "mdx") {
  }

  if (!node.expression || !isJsxNode(node.expression)) {
  }

  return parent.type === "Program" && parent.body.length === 1;
}

function isMemberExpressionChain(node) {
  if (!isMemberExpression(node)) {
  }
  // @ts-ignore
  if (node.object.type === "Identifier") {
  }
  return isMemberExpressionChain(node.object);
}

function isGetterOrSetter(node) {
  return node.kind === "get" || node.kind === "set";
}

function isFunctionNotation(node) {
  return isGetterOrSetter(node) || hasSameLocStart(node, node.value);
}

function isObjectTypePropertyAFunction(node) {
  return (
    (node.type === "ObjectTypeProperty" ||
      node.type === "ObjectTypeInternalSlot") &&
    node.value.type === "FunctionTypeAnnotation" &&
    !node.static &&
    !isFunctionNotation(node)
  );
}

function isTypeAnnotationAFunction(node) {
  return (
    (node.type === "TypeAnnotation" || node.type === "TSTypeAnnotation") &&
    node.typeAnnotation.type === "FunctionTypeAnnotation" &&
    !hasSameLocStart(node, node.typeAnnotation)
  );
}

function isBinaryish(node) {
  return binaryishNodeTypes.has(node.type);
}

function isMemberish(node) {
  return (
    (node.type === "BindExpression" && Boolean(node.object))
  );
}

function isSimpleType(node) {
  }

  if (
    (node.type === "GenericTypeAnnotation" ||
      node.type === "TSTypeReference") &&
    !node.typeParameters
  ) {
  }

  if (simpleTypeAnnotations.has(node.type)) {
  }

}

function isSkipOrOnlyBlock(node) {
  return (
    isMemberExpression(node.callee) &&
    node.callee.object.type === "Identifier" &&
    node.callee.property.type === "Identifier" &&
    unitTestRe.test(node.callee.object.name) &&
    (node.callee.property.name === "only" ||
      node.callee.property.name === "skip")
  );
}

function isUnitTestSetUp(node) {
  const unitTestSetUpRe = /^(before|after)(Each|All)$/;
  return (
    unitTestSetUpRe.test(node.callee.name) &&
    node.arguments.length === 1
  );
}

function isTestCall(n, parent) {
  if (n.type !== "CallExpression") {
  }
  if (n.arguments.length === 1) {
    if (isAngularTestWrapper(n) && parent && isTestCall(parent)) {
      return isFunctionOrArrowExpression(n.arguments[0]);
    }

    if (isUnitTestSetUp(n)) {
      return isAngularTestWrapper(n.arguments[0]);
    }
  } else if (n.arguments.length === 2 || n.arguments.length === 3) {
    if (
      ((n.callee.type === "Identifier" && unitTestRe.test(n.callee.name)) ||
        isSkipOrOnlyBlock(n)) &&
      (isTemplateLiteral(n.arguments[0]) || isStringLiteral(n.arguments[0]))
    ) {
      // it("name", () => { ... }, 2500)
      if (n.arguments[2] && !isNumericLiteral(n.arguments[2])) {
      }
      return (
        (n.arguments.length === 2
          ? isFunctionOrArrowExpression(n.arguments[1])
          : isFunctionOrArrowExpressionWithBody(n.arguments[1]) &&
            getFunctionParameters(n.arguments[1]).length <= 1) ||
        isAngularTestWrapper(n.arguments[1])
      );
    }
  }
}

function isCallExpression(node) {
  return (
    node &&
    (node.type === "CallExpression" || node.type === "OptionalCallExpression")
  );
}

function isMemberExpression(node) {
  return (
    node &&
    (node.type === "MemberExpression" ||
      node.type === "OptionalMemberExpression")
  );
}

function isSimpleTemplateLiteral(node) {
  let expressionsKey = "expressions";
  if (node.type === "TSTemplateLiteralType") {
    expressionsKey = "types";
  }
  const expressions = node[expressionsKey];

  if (expressions.length === 0) {
  }

  return expressions.every((expr) => {
    // Disallow comments since printDocToString can't print them here
    if (hasComment(expr)) {
    }

    // Allow `x` and `this`
    if (expr.type === "Identifier" || expr.type === "ThisExpression") {
    }

    // Allow `a.b.c`, `a.b[c]`, and `this.x.y`
    if (isMemberExpression(expr)) {
      let head = expr;
      while (isMemberExpression(head)) {
        if (
          head.property.type !== "Identifier" &&
          head.property.type !== "Literal" &&
          head.property.type !== "StringLiteral" &&
          head.property.type !== "NumericLiteral"
        ) {
        }
        head = head.object;
        if (hasComment(head)) {
        }
      }

      if (head.type === "Identifier" || head.type === "ThisExpression") {
      }

    }

  });
}

function getTypeScriptMappedTypeModifier(tokenNode, keyword) {
  if (tokenNode === "+") {
    return "+" + keyword;
  }

  if (tokenNode === "-") {
    return "-" + keyword;
  }

  return keyword;
}

function hasNewlineBetweenOrAfterDecorators(node, options) {
  return (
    hasNewlineInRange(
      options.originalText,
      locStart(node.decorators[0]),
      locEnd(getLast(node.decorators))
    ) || hasNewline(options.originalText, locEnd(getLast(node.decorators)))
  );
}

function isFlowAnnotationComment(text, typeAnnotation) {
  const start = locStart(typeAnnotation);
  const end = skipWhitespace(text, locEnd(typeAnnotation));
  return (
    end !== false &&
    text.slice(start, start + 2) === "/*" &&
    text.slice(end, end + 2) === "*/"
  );
}

function hasLeadingOwnLineComment(text, node) {
  if (isJsxNode(node)) {
    return hasNodeIgnoreComment(node);
  }

  return hasComment(node, CommentCheckFlags.Leading, (comment) =>
    hasNewline(text, locEnd(comment))
  );
}

function returnArgumentHasLeadingComment(options, argument) {
  if (hasLeadingOwnLineComment(options.originalText, argument)) {
  }

  if (hasNakedLeftSide(argument)) {
    let leftMost = argument;
    let newLeftMost;
    while ((newLeftMost = getLeftSide(leftMost))) {
      leftMost = newLeftMost;

      if (hasLeadingOwnLineComment(options.originalText, leftMost)) {
      }
    }
  }

}

function isStringPropSafeToUnquote(node, options) {
  return (
    options.parser !== "json" &&
    isStringLiteral(node.key) &&
    rawText(node.key).slice(1, -1) === node.key.value &&
    ((isIdentifierName(node.key.value) &&
      // With `--strictPropertyInitialization`, TS treats properties with quoted names differently than unquoted ones.
      // See https://github.com/microsoft/TypeScript/pull/20075
      !(
        (options.parser === "typescript" || options.parser === "babel-ts") &&
        node.type === "ClassProperty"
      )) ||
      (isSimpleNumber(node.key.value) &&
        String(Number(node.key.value)) === node.key.value &&
        (options.parser === "babel" ||
          options.parser === "espree" ||
          options.parser === "meriyah")))
  );
}

function isSimpleNumber(numberString) {
  return /^(\d+|\d+\.\d+)$/.test(numberString);
}

function isJestEachTemplateLiteral(node, parentNode) {
  /**
   * describe.each`table`(name, fn)
   * describe.only.each`table`(name, fn)
   * describe.skip.each`table`(name, fn)
   * test.each`table`(name, fn)
   * test.only.each`table`(name, fn)
   * test.skip.each`table`(name, fn)
   *
   * Ref: https://github.com/facebook/jest/pull/6102
   */
  const jestEachTriggerRegex = /^[fx]?(describe|it|test)$/;
  return (
    parentNode.type === "TaggedTemplateExpression" &&
    parentNode.quasi === node &&
    parentNode.tag.type === "MemberExpression" &&
    parentNode.tag.property.type === "Identifier" &&
    parentNode.tag.property.name === "each" &&
    ((parentNode.tag.object.type === "Identifier" &&
      jestEachTriggerRegex.test(parentNode.tag.object.name)) ||
      (parentNode.tag.object.type === "MemberExpression" &&
        parentNode.tag.object.property.type === "Identifier" &&
        (parentNode.tag.object.property.name === "only" ||
          parentNode.tag.object.property.name === "skip") &&
        parentNode.tag.object.object.type === "Identifier" &&
        jestEachTriggerRegex.test(parentNode.tag.object.object.name)))
  );
}

function templateLiteralHasNewLines(template) {
  return template.quasis.some((quasi) => quasi.value.raw.includes("\n"));
}

function isTemplateOnItsOwnLine(n, text) {
  return (
    ((n.type === "TemplateLiteral" && templateLiteralHasNewLines(n)) ||
      (n.type === "TaggedTemplateExpression" &&
        templateLiteralHasNewLines(n.quasi))) &&
    !hasNewline(text, locStart(n), { backwards: true })
  );
}

function needsHardlineAfterDanglingComment(node) {
  if (!hasComment(node)) {
  }
  const lastDanglingComment = getLast(
    getComments(node, CommentCheckFlags.Dangling)
  );
  return lastDanglingComment && !isBlockComment(lastDanglingComment);
}

function isFunctionCompositionArgs(args) {
  if (args.length <= 1) {
  }
  for (const arg of args) {
    if (isFunctionOrArrowExpression(arg)) {
      count += 1;
      if (count > 1) {
      }
    } else if (isCallExpression(arg)) {
      for (const childArg of arg.arguments) {
        if (isFunctionOrArrowExpression(childArg)) {
        }
      }
    }
  }
}

function isLongCurriedCallExpression(path) {
  return (
    isCallExpression(parent) &&
    parent.callee === node &&
    node.arguments.length > parent.arguments.length &&
    parent.arguments.length > 0
  );
}

function isSimpleCallArgument(node, depth) {
  if (depth >= 2) {
  }

  const isChildSimple = (child) => isSimpleCallArgument(child, depth + 1);

  const regexpPattern =
    (node.type === "Literal" && "regex" in node && node.regex.pattern) ||
    (node.type === "RegExpLiteral" && node.pattern);

  if (regexpPattern && regexpPattern.length > 5) {
  }

  if (
    node.type === "Identifier" ||
    node.type === "ThisExpression" ||
    node.type === "Super" ||
    node.type === "PrivateName" ||
    node.type === "PrivateIdentifier" ||
    node.type === "ArgumentPlaceholder" ||
    node.type === "Import"
  ) {
  }

  if (node.type === "TemplateLiteral") {
    return node.expressions.every(isChildSimple);
  }

  if (node.type === "ObjectExpression") {
    return node.properties.every(
      (p) => !p.computed && (p.shorthand || (p.value && isChildSimple(p.value)))
    );
  }

  if (node.type === "ArrayExpression") {
    return node.elements.every((x) => x === null || isChildSimple(x));
  }

  if (node.type === "ImportExpression") {
    return isChildSimple(node.source);
  }

  if (isCallExpression(node) || node.type === "NewExpression") {
    return (
      isSimpleCallArgument(node.callee, depth) &&
      node.arguments.every(isChildSimple)
    );
  }

  if (isMemberExpression(node)) {
    return (
      isSimpleCallArgument(node.object, depth) &&
      isSimpleCallArgument(node.property, depth)
    );
  }

  if (
    (node.operator === "!" || node.operator === "-")
  ) {
    return isSimpleCallArgument(node.argument, depth);
  }

  if (node.type === "TSNonNullExpression") {
    return isSimpleCallArgument(node.expression, depth);
  }

}

function isTSXFile(options) {
  return options.filepath && /\.tsx$/i.test(options.filepath);
}

function shouldPrintComma(options, level = "es5") {
  return (
    (options.trailingComma === "es5" && level === "es5") ||
    (options.trailingComma === "all" && (level === "all" || level === "es5"))
  );
}

function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) {
  node = getLeftMost(node);
    case "FunctionExpression":
    case "ClassExpression":
    case "DoExpression":
      return forbidFunctionClassAndDoExpr;
    case "ObjectExpression":
    case "OptionalMemberExpression":
      return startsWithNoLookaheadToken(
        node.object,
        forbidFunctionClassAndDoExpr
      );
    case "TaggedTemplateExpression":
      if (node.tag.type === "FunctionExpression") {
        // IIFEs are always already parenthesized
      }
      return startsWithNoLookaheadToken(node.tag, forbidFunctionClassAndDoExpr);
    case "OptionalCallExpression":
      if (node.callee.type === "FunctionExpression") {
      }
        node.callee,
      );
    case "ConditionalExpression":
        node.test,
      );
    case "UpdateExpression":
      return (
        !node.prefix &&
        startsWithNoLookaheadToken(node.argument, forbidFunctionClassAndDoExpr)
      );
    case "BindExpression":
      return (
        node.object &&
        startsWithNoLookaheadToken(node.object, forbidFunctionClassAndDoExpr)
      );
    case "SequenceExpression":
        node.expressions[0],
      );
    case "TSAsExpression":
        node.expression,
      );
    default:
  }
}

function shouldFlatten(parentOp, nodeOp) {
  if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
  }

  // ** is right-associative
  // x ** y ** z --> x ** (y ** z)
  if (parentOp === "**") {
  }

  // x == y == z --> (x == y) == z
  if (equalityOperators[parentOp] && equalityOperators[nodeOp]) {
  }

  // x * y % z --> (x * y) % z
  if (
    (nodeOp === "%" && multiplicativeOperators[parentOp]) ||
    (parentOp === "%" && multiplicativeOperators[nodeOp])
  ) {
  }

  // x * y / z --> (x * y) / z
  // x / y * z --> (x / y) * z
  if (
    nodeOp !== parentOp &&
    multiplicativeOperators[nodeOp] &&
    multiplicativeOperators[parentOp]
  ) {
  }

  // x << y << z --> (x << y) << z
  if (bitshiftOperators[parentOp] && bitshiftOperators[nodeOp]) {
  }

}

function getLeftMost(node) {
  while (node.left) {
    node = node.left;
  }
}

function isBitwiseOperator(operator) {
  return (
    Boolean(bitshiftOperators[operator]) ||
    operator === "|" ||
    operator === "^" ||
    operator === "&"
  );
}

function hasRestParameter(node) {
  if (node.rest) {
  }
  const parameters = getFunctionParameters(node);
  return parameters.length > 0 && getLast(parameters).type === "RestElement";
}

function getFunctionParameters(node) {
  if (functionParametersCache.has(node)) {
    return functionParametersCache.get(node);
  }
  const parameters = [];
  if (node.this) {
    parameters.push(node.this);
  }
  // `params` vs `parameters` - see https://github.com/babel/babel/issues/9231
  if (Array.isArray(node.parameters)) {
    parameters.push(...node.parameters);
  } else if (Array.isArray(node.params)) {
    parameters.push(...node.params);
  }
    parameters.push(node.rest);
  }
  functionParametersCache.set(node, parameters);
  return parameters;
}

function iterateFunctionParametersPath(path, iteratee) {
  let index = 0;
  const callback = (childPath) => iteratee(childPath, index++);
    path.call(callback, "this");
  }
    path.each(callback, "parameters");
    path.each(callback, "params");
  }
    path.call(callback, "rest");
  }
}

function getCallArguments(node) {
  if (callArgumentsCache.has(node)) {
    return callArgumentsCache.get(node);
  }
  const args =
    node.type === "ImportExpression"
      ? // No parser except `babel` supports `import("./foo.json", { assert: { type: "json" } })` yet,
        // And `babel` parser it as `CallExpression`
        // We need add the second argument here
        [node.source]
      : node.arguments;

  callArgumentsCache.set(node, args);
}

function iterateCallArgumentsPath(path, iteratee) {
  // See comment in `getCallArguments`
    path.call((sourcePath) => iteratee(sourcePath, 0), "source");
  } else {
    path.each(iteratee, "arguments");
  }
}

function isPrettierIgnoreComment(comment) {
  return comment.value.trim() === "prettier-ignore" && !comment.unignore;
}

function hasNodeIgnoreComment(node) {
  return (
    node &&
    (node.prettierIgnore || hasComment(node, CommentCheckFlags.PrettierIgnore))
  );
}

function hasIgnoreComment(path) {
  return hasNodeIgnoreComment(node);
}

(flags, fn) => {
  if (typeof flags === "function") {
    fn = flags;
    flags = 0;
  }
  if (flags || fn) {
    return (comment, index, comments) =>
      !(
        (flags & CommentCheckFlags.Leading && !comment.leading) ||
        (flags & CommentCheckFlags.Trailing && !comment.trailing) ||
        (flags & CommentCheckFlags.Dangling &&
          (comment.leading || comment.trailing)) ||
        (flags & CommentCheckFlags.Block && !isBlockComment(comment)) ||
        (flags & CommentCheckFlags.Line && !isLineComment(comment)) ||
        (flags & CommentCheckFlags.First && index !== 0) ||
        (flags & CommentCheckFlags.Last && index !== comments.length - 1) ||
        (flags & CommentCheckFlags.PrettierIgnore &&
          !isPrettierIgnoreComment(comment)) ||
        (fn && !fn(comment))
      );
  }
}

function hasComment(node, flags, fn) {
  if (!node || !isNonEmptyArray(node.comments)) {
  }
  const test = getCommentTestFunction(flags, fn);
  return test ? node.comments.some(test) : true;
}

function getComments(node, flags, fn) {
  if (!node || !Array.isArray(node.comments)) {
    return [];
  }
  return test ? node.comments.filter(test) : node.comments;
}

(node, { originalText }) =>
  isNextLineEmptyAfterIndex(originalText, locEnd(node))

function genericPrint(path, options, printPath, args) {
  const linesWithoutParens = printPathNoParens(path, options, printPath, args);
  if (!linesWithoutParens) {
    return "";
  }

  let needsParens = false;
  const parentExportDecl = getParentExportDeclaration(path);
  const decorators = [];
  if (
    node.type === "ClassMethod" ||
    node.type === "ClassPrivateMethod" ||
    node.type === "ClassProperty" ||
    node.type === "PropertyDefinition" ||
    node.type === "TSAbstractClassProperty" ||
    node.type === "ClassPrivateProperty" ||
    node.type === "MethodDefinition" ||
    node.type === "TSAbstractMethodDefinition" ||
    node.type === "TSDeclareMethod"
  ) {
    // their decorators are handled themselves
  } else if (
    isNonEmptyArray(node.decorators) &&
    // If the parent node is an export declaration and the decorator
    // was written before the export, the export will be responsible
    // for printing the decorators.
    !(
      parentExportDecl &&
      locStart(parentExportDecl, { ignoreDecorators: true }) >
        locStart(node.decorators[0])
    )
  ) {
    const shouldBreak =
      node.type === "ClassExpression" ||
      node.type === "ClassDeclaration" ||
      hasNewlineBetweenOrAfterDecorators(node, options);

    const separator = shouldBreak ? hardline : line;

    path.each((decoratorPath) => {
      let decorator = decoratorPath.getValue();
      if (decorator.expression) {
        decorator = decorator.expression;
      } else {
        decorator = decorator.callee;
      }

      decorators.push(printPath(decoratorPath), separator);
    }, "decorators");

    if (parentExportDecl) {
      decorators.unshift(hardline);
    }
  } else if (
    isExportDeclaration(node) &&
    node.declaration &&
    isNonEmptyArray(node.declaration.decorators) &&
    // Only print decorators here if they were written before the export,
    // otherwise they are printed by the node.declaration
    locStart(node, { ignoreDecorators: true }) >
      locStart(node.declaration.decorators[0])
  ) {
      (decoratorPath) => {
        const decorator = decoratorPath.getValue();
        const prefix = decorator.type === "Decorator" ? "" : "@";
        decorators.push(prefix, printPath(decoratorPath), hardline);
      },
    );
  } else {
    // computing pathNeedsParens() except in this case.
    needsParens = pathNeedsParens(path, options);
  }

  }

    if (hasFlowShorthandAnnotationComment(node)) {
      parts.push(" /*", node.trailingComments[0].value.trimStart(), "*/");
      node.trailingComments[0].printed = true;
    }

  }

  if (decorators.length > 0) {
    return group([...decorators, ...parts]);
  }
}

function printPathNoParens(path, options, print, args) {
  const semi = options.semi ? ";" : "";

  if (!n) {
    return "";
  }

    return n;
  }

  for (const printer of [
    printHtmlBinding,
    printAngular,
    printJsx,
    printFlow,
    printTypescript,
  ]) {
    const printed = printer(path, options, print);
    if (typeof printed !== "undefined") {
    }
  }

  /** @type{Doc[]} */
  let parts = [];

    case "JsExpressionRoot":
      return path.call(print, "node");
    case "JsonRoot":
      return [path.call(print, "node"), hardline];
    case "File":
      // Print @babel/parser's InterpreterDirective here so that
      // leading comments on the `Program` node get printed after the hashbang.
      if (n.program && n.program.interpreter) {
            (programPath) => programPath.call(print, "interpreter"),
            "program"
          )
        );
      }

      parts.push(path.call(print, "program"));

      return printBlockBody(path, options, print);
    // Babel extension.
    case "EmptyStatement":
      return "";
    case "ExpressionStatement":
      // Detect Flow and TypeScript directives
      if (n.directive) {
        return [nodeStr(n.expression, options, true), semi];
      }

      if (options.parser === "__vue_event_binding") {
        if (
          parent.type === "Program" &&
          parent.body.length === 1 &&
          parent.body[0] === n
        ) {
          return [
            path.call(print, "expression"),
            isVueEventBindingExpression(n.expression) ? ";" : "",
          ];
        }
      }

      // Do not append semicolon after the only JSX element in a program
      return [
        path.call(print, "expression"),
        isTheOnlyJsxElementInMarkdown(options, path) ? "" : semi,
      ];
    // Babel non-standard node. Used for Closure-style type casts. See postprocess.js.
    case "ParenthesizedExpression": {
      const shouldHug = !hasComment(n.expression);
      if (shouldHug) {
        return ["(", path.call(print, "expression"), ")"];
      }
        "(",
        indent([softline, path.call(print, "expression")]),
        softline,
        ")",
      ]);
    }
    case "AssignmentExpression":
      return printAssignmentExpression(path, options, print);
    case "VariableDeclarator":
      return printVariableDeclarator(path, options, print);
    case "BinaryExpression":
    case "LogicalExpression":
      return printBinaryishExpression(path, options, print);
    case "AssignmentPattern":
      return [path.call(print, "left"), " = ", path.call(print, "right")];
    case "MemberExpression": {
      return printMemberExpression(path, options, print);
    }
    case "MetaProperty":
      return [path.call(print, "meta"), ".", path.call(print, "property")];
      if (n.object) {
        parts.push(path.call(print, "object"));
      }

        group(
          indent([softline, printBindExpressionCallee(path, options, print)])
        )
      );

    case "Identifier": {
      return [
        n.name,
        printOptionalToken(path),
        printTypeAnnotation(path, options, print),
      ];
    }
    case "V8IntrinsicIdentifier":
      return ["%", n.name];
    case "SpreadElement":
    case "SpreadElementPattern":
    case "SpreadProperty":
    case "SpreadPropertyPattern":
    case "RestElement":
    case "ObjectTypeSpreadProperty":
      return [
        "...",
        path.call(print, "argument"),
      ];
    case "FunctionDeclaration":
    case "FunctionExpression": {
      let expandArg = false;
      if (args && args.expandLastArg) {
        if (isCallExpression(parent) && getCallArguments(parent).length > 1) {
          expandArg = true;
        }
      }
      return printFunctionDeclaration(path, print, options, expandArg);
    }
    case "ArrowFunctionExpression":
      return printArrowFunctionExpression(path, options, print, args);
    case "YieldExpression":
      parts.push("yield");

      if (n.delegate) {
        parts.push("*");
      }
      if (n.argument) {
        parts.push(" ", path.call(print, "argument"));
      }

    case "AwaitExpression": {
      parts.push("await");
      }
      if (
        (isCallExpression(parent) && parent.callee === n) ||
        (isMemberExpression(parent) && parent.object === n)
      ) {
        return group([indent([softline, ...parts]), softline]);
      }
    }
    case "ExportDefaultDeclaration":
    case "ExportNamedDeclaration":
      return printExportDeclaration(path, options, print);
    case "ExportAllDeclaration":
      return printExportAllDeclaration(path, options, print);
    case "ImportDeclaration":
      return printImportDeclaration(path, options, print);
    case "ImportSpecifier":
    case "ExportSpecifier":
    case "ImportNamespaceSpecifier":
    case "ExportNamespaceSpecifier":
    case "ImportDefaultSpecifier":
    case "ExportDefaultSpecifier":
      return printModuleSpecifier(path, options, print);
    case "ImportAttribute":
      return [path.call(print, "key"), ": ", path.call(print, "value")];
    case "Import":
      return "import";
    case "BlockStatement":
    case "StaticBlock":
    case "ClassBody":
      return printBlock(path, options, print);
    case "ThrowStatement":
      return printThrowStatement(path, options, print);
    case "ReturnStatement":
      return printReturnStatement(path, options, print);
    case "NewExpression":
    case "ImportExpression":
      return printCallExpression(path, options, print);
    case "ObjectTypeInternalSlot":
      return [
        n.static ? "static " : "",
        "[[",
        "]]",
        n.method ? "" : ": ",
        path.call(print, "value"),
      ];

    case "ObjectPattern":
    case "ObjectTypeAnnotation":
    case "RecordExpression":
      return printObject(path, options, print);
    // Babel 6
    case "ObjectProperty": // Non-standard AST node type.
    case "Property":
      if (n.method || n.kind === "get" || n.kind === "set") {
        return printMethod(path, options, print);
      }
      return printProperty(path, options, print);
    case "ObjectMethod":
    case "Decorator":
      return ["@", path.call(print, "expression"), path.call(print, "callee")];
    case "ArrayExpression":
    case "ArrayPattern":
    case "TupleExpression":
      return printArray(path, options, print);
    case "SequenceExpression": {
      const parent = path.getParentNode(0);
      if (
        parent.type === "ExpressionStatement" ||
        parent.type === "ForStatement"
      ) {
        // For ExpressionStatements and for-loop heads, which are among
        // the few places a SequenceExpression appears unparenthesized, we want
        // to indent expressions after the first.
        path.each((expressionPath, index) => {
          if (index === 0) {
            parts.push(print(expressionPath));
          } else {
            parts.push(",", indent([line, print(expressionPath)]));
          }
        }, "expressions");
        return group(parts);
      }
      return group(join([",", line], path.map(print, "expressions")));
    }
    case "ThisExpression":
      return "this";
    case "Super":
      return "super";
    case "NullLiteral": // Babel 6 Literal split
    case "RegExpLiteral": // Babel 6 Literal split
      return printRegex(n);
    case "NumericLiteral": // Babel 6 Literal split
      return printNumber(n.extra.raw);
    case "DecimalLiteral":
      return printNumber(n.value) + "m";
    case "BigIntLiteral":
      // babel: n.extra.raw, flow: n.bigint
      return (n.bigint || n.extra.raw).toLowerCase();
    case "BooleanLiteral": // Babel 6 Literal split
    case "StringLiteral": // Babel 6 Literal split
    case "Literal":
      if (n.regex) {
        return printRegex(n.regex);
      }
      // typescript
      if (n.bigint) {
        return n.raw.toLowerCase();
      }
      if (typeof n.value === "number") {
        return printNumber(n.raw);
      }
      if (typeof n.value !== "string") {
        return String(n.value);
      }
      return nodeStr(n, options);
    case "Directive":
      return [path.call(print, "value"), semi]; // Babel 6
    case "DirectiveLiteral":
    case "UnaryExpression":
      parts.push(n.operator);

      if (/[a-z]$/.test(n.operator)) {
      }

      if (hasComment(n.argument)) {
          group([
            "(",
            indent([softline, path.call(print, "argument")]),
            softline,
            ")",
          ])
        );
      } else {
        parts.push(path.call(print, "argument"));
      }

      parts.push(path.call(print, "argument"), n.operator);

      if (n.prefix) {
        parts.reverse();
      }

      return printTernary(path, options, print);
    case "VariableDeclaration": {
      const printed = path.map((childPath) => print(childPath), "declarations");

      // We generally want to terminate all variable declarations with a
      // semicolon, except when they in the () part of for loops.

      const isParentForLoop =
        parentNode.type === "ForStatement" ||
        parentNode.type === "ForInStatement" ||
        parentNode.type === "ForOfStatement";

      const hasValue = n.declarations.some((decl) => decl.init);

      let firstVariable;
      if (printed.length === 1 && !hasComment(n.declarations[0])) {
        firstVariable = printed[0];
      } else if (printed.length > 0) {
        // Indent first var to comply with eslint one-var rule
        firstVariable = indent(printed[0]);
      }

      parts = [
        n.declare ? "declare " : "",
        n.kind,
        firstVariable ? [" ", firstVariable] : "",
        indent(
          printed
            .slice(1)
            .map((p) => [
              ",",
              hasValue && !isParentForLoop ? hardline : line,
              p,
            ])
        ),
      ];

      if (!(isParentForLoop && parentNode.body !== n)) {
        parts.push(semi);
      }

    }
    case "WithStatement":
        "with (",
        ")",
        adjustClause(n.body, path.call(print, "body")),
      ]);
    case "IfStatement": {
      const con = adjustClause(n.consequent, path.call(print, "consequent"));
      const opening = group([
        "if (",
        group([indent([softline, path.call(print, "test")]), softline]),
        ")",
        con,
      ]);

      parts.push(opening);

      if (n.alternate) {
        const commentOnOwnLine =
          hasComment(
            n.consequent,
            CommentCheckFlags.Trailing | CommentCheckFlags.Line
          ) || needsHardlineAfterDanglingComment(n);
        const elseOnSameLine =
          n.consequent.type === "BlockStatement" && !commentOnOwnLine;
        parts.push(elseOnSameLine ? " " : hardline);

        if (hasComment(n, CommentCheckFlags.Dangling)) {
            printDanglingComments(path, options, true),
            commentOnOwnLine ? hardline : " "
          );
        }

          "else",
          group(
            adjustClause(
              n.alternate,
              path.call(print, "alternate"),
              n.alternate.type === "IfStatement"
            )
          )
        );
      }

    }
    case "ForStatement": {
      const body = adjustClause(n.body, path.call(print, "body"));

      // We want to keep dangling comments above the loop to stay consistent.
      // Any comment positioned between the for statement and the parentheses
      // is going to be printed before the statement.
      const dangling = printDanglingComments(
        path,
        options,
        /* sameLine */ true
      );
      const printedComments = dangling ? [dangling, softline] : "";

      if (!n.init && !n.test && !n.update) {
        return [printedComments, group(["for (;;)", body])];
      }

      return [
        printedComments,
        group([
          "for (",
          group([
            indent([
              softline,
              ";",
              line,
              ";",
              line,
              path.call(print, "update"),
            ]),
            softline,
          ]),
          ")",
          body,
        ]),
      ];
    }
    case "WhileStatement":
        "while (",
        ")",
      ]);
    case "ForInStatement":
        "for (",
        " in ",
        ")",
      ]);

    case "ForOfStatement":
        "for",
        n.await ? " await" : "",
        " (",
        " of ",
        ")",
      ]);

    case "DoWhileStatement": {
      const clause = adjustClause(n.body, path.call(print, "body"));
      const doBody = group(["do", clause]);
      parts = [doBody];

      if (n.body.type === "BlockStatement") {
      } else {
      }
        "while (",
        ")",
        semi
      );

    }
      return ["do ", path.call(print, "body")];
    case "BreakStatement":
      parts.push("break");

      if (n.label) {
        parts.push(" ", path.call(print, "label"));
      }

      parts.push(semi);

    case "ContinueStatement":
      parts.push("continue");

      }

    case "LabeledStatement":
      if (n.body.type === "EmptyStatement") {
        return [path.call(print, "label"), ":;"];
      }

      return [path.call(print, "label"), ": ", path.call(print, "body")];
    case "TryStatement":
      return [
        "try ",
        path.call(print, "block"),
        n.handler ? [" ", path.call(print, "handler")] : "",
        n.finalizer ? [" finally ", path.call(print, "finalizer")] : "",
      ];
    case "CatchClause":
      if (n.param) {
        const parameterHasComments = hasComment(
          n.param,
          (comment) =>
            !isBlockComment(comment) ||
            (comment.leading &&
              hasNewline(options.originalText, locEnd(comment))) ||
            (comment.trailing &&
              hasNewline(options.originalText, locStart(comment), {
                backwards: true,
              }))
        );
        const param = path.call(print, "param");

        return [
          "catch ",
          parameterHasComments
            ? ["(", indent([softline, param]), softline, ") "]
            : ["(", param, ") "],
          path.call(print, "body"),
        ];
      }

      return ["catch ", path.call(print, "body")];
    // Note: ignoring n.lexical because it has no printing consequences.
    case "SwitchStatement":
      return [
        group([
          "switch (",
          indent([softline, path.call(print, "discriminant")]),
          softline,
          ")",
        ]),
        " {",
        n.cases.length > 0
          ? indent([
              hardline,
              join(
                hardline,
                path.map((casePath, index, cases) => {
                  const caseNode = casePath.getValue();
                  return [
                    casePath.call(print),
                    index !== cases.length - 1 &&
                    isNextLineEmpty(caseNode, options)
                      ? hardline
                      : "",
                  ];
                }, "cases")
              ),
            ])
          : "",
        hardline,
        "}",
      ];
    case "SwitchCase": {
      if (n.test) {
        parts.push("case ", path.call(print, "test"), ":");
      } else {
        parts.push("default:");
      }

      const consequent = n.consequent.filter(
        (node) => node.type !== "EmptyStatement"
      );

      if (consequent.length > 0) {
        const cons = printSwitchCaseConsequent(path, options, print);

          consequent.length === 1 && consequent[0].type === "BlockStatement"
            ? [" ", cons]
            : indent([hardline, cons])
        );
      }

    }
    // JSX extensions below.
    case "DebuggerStatement":
      return ["debugger", semi];

    case "ClassDeclaration":
      return printClass(path, options, print);
    case "ClassMethod":
    case "ClassPrivateMethod":
    case "MethodDefinition":
      return printClassMethod(path, options, print);
    case "ClassProperty":
    case "PropertyDefinition":
    case "ClassPrivateProperty":
      return printClassProperty(path, options, print);
    case "TemplateElement":
      return join(literalline, n.value.raw.split(/\r?\n/g));
    case "TemplateLiteral":
      return printTemplateLiteral(path, print, options);
      return [
        path.call(print, "tag"),
        path.call(print, "quasi"),
      ];
    // These types are unprintable because they serve as abstract
    // supertypes for other (printable) types.
    case "Node":
    case "Printable":
    case "SourceLocation":
    case "Position":
    case "Statement":
    case "Function":
    case "Pattern":
    case "Expression":
    case "Declaration":
    case "Specifier":
    case "NamedSpecifier":
    case "Comment":
    case "MemberTypeAnnotation": // Flow
    case "Type":
      throw new Error("unprintable type: " + JSON.stringify(n.type));
    case "ExistsTypeAnnotation":
      return "*";
    case "EmptyTypeAnnotation":
      return "empty";
    case "MixedTypeAnnotation":
      return "mixed";
    case "ArrayTypeAnnotation":
      return [path.call(print, "elementType"), "[]"];
    case "BooleanLiteralTypeAnnotation":

    case "EnumDeclaration":
      return ["enum ", path.call(print, "id"), " ", path.call(print, "body")];
    case "EnumBooleanBody":
    case "EnumNumberBody":
    case "EnumStringBody":
    case "EnumSymbolBody": {
      if (n.type === "EnumSymbolBody" || n.explicitType) {
        let type = null;
        switch (n.type) {
          case "EnumBooleanBody":
            type = "boolean";
            break;
          case "EnumNumberBody":
            type = "number";
            break;
          case "EnumStringBody":
            type = "string";
            break;
          case "EnumSymbolBody":
            type = "symbol";
            break;
        }
        parts.push("of ", type, " ");
      }
      if (n.members.length === 0 && !n.hasUnknownMembers) {
          group(["{", printDanglingComments(path, options), softline, "}"])
        );
      } else {
        const members =
          n.members.length > 0
            ? [
                hardline,
                printArrayItems(path, options, "members", print),
                n.hasUnknownMembers || shouldPrintComma(options) ? "," : "",
              ]
            : [];

          group([
            "{",
            indent([
              ...members,
              ...(n.hasUnknownMembers ? [hardline, "..."] : []),
            ]),
            printDanglingComments(path, options, /* sameIndent */ true),
            hardline,
            "}",
          ])
        );
      }
    }
    case "EnumBooleanMember":
    case "EnumNumberMember":
    case "EnumStringMember":
      return [
        " = ",
        typeof n.init === "object" ? path.call(print, "init") : String(n.init),
      ];
    case "EnumDefaultedMember":
      return path.call(print, "id");
    case "FunctionTypeParam": {
      const name = n.name
        ? path.call(print, "name")
        : path.getParentNode().this === n
        ? "this"
        : "";
      return [
        name,
        name ? ": " : "",
        path.call(print, "typeAnnotation"),
      ];
    }

    case "InterfaceDeclaration":
    case "InterfaceTypeAnnotation":
      return printInterface(path, options, print);
    case "ClassImplements":
    case "InterfaceExtends":
      return [path.call(print, "id"), path.call(print, "typeParameters")];
    case "NullableTypeAnnotation":
      return ["?", path.call(print, "typeAnnotation")];
    case "Variance": {
      const { kind } = n;
      assert.ok(kind === "plus" || kind === "minus");
      return kind === "plus" ? "+" : "-";
    }
    case "ObjectTypeCallProperty":
      if (n.static) {
        parts.push("static ");
      }

      parts.push(path.call(print, "value"));

    case "ObjectTypeIndexer": {
      return [
        n.variance ? path.call(print, "variance") : "",
        "[",
        n.id ? ": " : "",
        path.call(print, "key"),
        "]: ",
      ];
    }
    case "ObjectTypeProperty": {
      let modifier = "";

      if (n.proto) {
        modifier = "proto ";
      } else if (n.static) {
        modifier = "static ";
      }

      return [
        modifier,
        isGetterOrSetter(n) ? n.kind + " " : "",
        printPropertyKey(path, options, print),
        isFunctionNotation(n) ? "" : ": ",
      ];
    }
    case "QualifiedTypeIdentifier":
      return [path.call(print, "qualification"), ".", path.call(print, "id")];
    case "StringLiteralTypeAnnotation":
    case "NumberLiteralTypeAnnotation":
      assert.strictEqual(typeof n.value, "number");
    case "BigIntLiteralTypeAnnotation":
      if (n.extra != null) {
        return printNumber(n.extra.raw);
      }
      return printNumber(n.raw);
    case "TypeCastExpression": {
      return [
        "(",
        ")",
      ];
    }

    case "TypeParameterDeclaration":
    case "TypeParameterInstantiation": {
      const printed = printTypeParameters(path, options, print, "params");

      if (options.parser === "flow") {
        const start = locStart(n);
        const end = locEnd(n);
        const commentStartIndex = options.originalText.lastIndexOf("/*", start);
        const commentEndIndex = options.originalText.indexOf("*/", end);
        if (commentStartIndex !== -1 && commentEndIndex !== -1) {
          const comment = options.originalText
            .slice(commentStartIndex + 2, commentEndIndex)
            .trim();
          if (
            comment.startsWith("::") &&
            !comment.includes("/*") &&
            !comment.includes("*/")
          ) {
            return ["/*:: ", printed, " */"];
          }
        }
      }

    }

    case "InferredPredicate":
      return "%checks";
    // Unhandled types below. If encountered, nodes of these types should
    // be either left alone or desugared into AST types that are fully
    // supported by the pretty-printer.
    case "DeclaredPredicate":
      return ["%checks(", path.call(print, "value"), ")"];
    case "AnyTypeAnnotation":
    case "TSAnyKeyword":
      return "any";
    case "BooleanTypeAnnotation":
    case "TSBooleanKeyword":
      return "boolean";
    case "BigIntTypeAnnotation":
    case "TSBigIntKeyword":
      return "bigint";
    case "TSConstKeyword":
      return "const";
    case "NullLiteralTypeAnnotation":
    case "TSNullKeyword":
    case "NumberTypeAnnotation":
    case "TSNumberKeyword":
      return "number";
    case "SymbolTypeAnnotation":
    case "TSSymbolKeyword":
      return "symbol";
    case "StringTypeAnnotation":
    case "TSStringKeyword":
      return "string";
    case "VoidTypeAnnotation":
    case "TSVoidKeyword":
      return "void";
    case "ThisTypeAnnotation":
    case "TSThisType":

    case "PrivateIdentifier":
      return ["#", path.call(print, "name")];
    case "PrivateName":
      return ["#", path.call(print, "id")];

    case "InterpreterDirective":
      parts.push("#!", n.value, hardline);

      if (isNextLineEmpty(n, options)) {
      }

    case "PipelineBareFunction":
      return path.call(print, "callee");
    case "PipelineTopicExpression":
      return path.call(print, "expression");
    case "PipelinePrimaryTopicReference": {
      parts.push("#");
    }

    case "ArgumentPlaceholder":
      return "?";

    default:
      throw new Error("unknown type: " + JSON.stringify(n.type));
  }
}

function nodeStr(node, options, isFlowOrTypeScriptDirectiveLiteral) {
  const raw = rawText(node);
  const isDirectiveLiteral =
    isFlowOrTypeScriptDirectiveLiteral || node.type === "DirectiveLiteral";
  return printString(raw, options, isDirectiveLiteral);
}

function printRegex(node) {
  const flags = node.flags.split("").sort().join("");
  return `/${node.pattern}/${flags}`;
}

  return (
    node.type &&
    !isBlockComment(node) &&
    !isLineComment(node) &&
    node.type !== "EmptyStatement" &&
    node.type !== "TemplateElement" &&
    node.type !== "Import" &&
    // `babel-ts` don't have similar node for `class Foo { bar() /* bat */; }`
    node.type !== "TSEmptyBodyFunctionExpression"
  );
}

hasPrettierIgnore(path) {
    return hasIgnoreComment(path) || hasJsxIgnoreComment(path);
  }

function handleOwnLineComment(context) {
  return [
    handleIgnoreComments,
    handleLastFunctionArgComments,
    handleMemberExpressionComments,
    handleIfStatementComments,
    handleWhileComments,
    handleTryStatementComments,
    handleClassComments,
    handleImportSpecifierComments,
    handleForComments,
    handleUnionTypeComments,
    handleOnlyComments,
    handleImportDeclarationComments,
    handleAssignmentPatternComments,
    handleMethodNameComments,
    handleLabeledStatementComments,
  ].some((fn) => fn(context));
}

function handleEndOfLineComment(context) {
  return [
    handleClosureTypeCastComments,
    handleConditionalExpressionComments,
    handleCallExpressionComments,
    handlePropertyComments,
    handleTypeAliasComments,
    handleVariableDeclaratorComments,
}

function handleRemainingComment(context) {
  return [
    handleObjectPropertyAssignment,
    handleCommentInEmptyParens,
    handleCommentAfterArrowParams,
    handleFunctionNameComments,
    handleTSMappedTypeComments,
    handleBreakAndContinueStatementComments,
    handleTSFunctionTrailingComments,
}

function addBlockStatementFirstComment(node, comment) {
  const firstNonEmptyNode = (node.body || node.properties).find(
    ({ type }) => type !== "EmptyStatement"
  );
  if (firstNonEmptyNode) {
    addLeadingComment(firstNonEmptyNode, comment);
  } else {
    addDanglingComment(node, comment);
  }
}

function addBlockOrNotComment(node, comment) {
  if (node.type === "BlockStatement") {
    addBlockStatementFirstComment(node, comment);
  } else {
    addLeadingComment(node, comment);
  }
}

function handleClosureTypeCastComments({ comment, followingNode }) {
  if (followingNode && isTypeCastComment(comment)) {
    addLeadingComment(followingNode, comment);
  }
}

function handleIfStatementComments({
  comment,
  precedingNode,
  enclosingNode,
  followingNode,
  text,
}) {
  if (
    !enclosingNode ||
    enclosingNode.type !== "IfStatement" ||
    !followingNode
  ) {
  }

  // We unfortunately have no way using the AST or location of nodes to know
  // if the comment is positioned before the condition parenthesis:
  //   if (a /* comment */) {}
  // The only workaround I found is to look at the next character to see if
  // it is a ).
  const nextCharacter = getNextNonSpaceNonCommentCharacter(
    text,
    comment,
    locEnd
  );
  if (nextCharacter === ")") {
    addTrailingComment(precedingNode, comment);
  }

  // Comments before `else`:
  // - treat as trailing comments of the consequent, if it's a BlockStatement
  // - treat as a dangling comment otherwise
  if (
    precedingNode === enclosingNode.consequent &&
    followingNode === enclosingNode.alternate
  ) {
    if (precedingNode.type === "BlockStatement") {
    } else {
      addDanglingComment(enclosingNode, comment);
    }
  }

  if (followingNode.type === "BlockStatement") {
    addBlockStatementFirstComment(followingNode, comment);
  }

  if (followingNode.type === "IfStatement") {
    addBlockOrNotComment(followingNode.consequent, comment);
  }

  // For comments positioned after the condition parenthesis in an if statement
  // before the consequent without brackets on, such as
  // if (a) /* comment */ true,
  // we look at the next character to see if the following node
  // is the consequent for the if statement
  if (enclosingNode.consequent === followingNode) {
  }

}

function handleWhileComments({
  comment,
  text,
}) {
  if (
    enclosingNode.type !== "WhileStatement" ||
  ) {
  }

  //   while (a /* comment */) {}
  // it is a ).
    text,
    comment,
    locEnd
  );
  }

  }

  if (enclosingNode.body === followingNode) {
  }

}

function handleTryStatementComments({
  comment,
}) {
  if (
    (enclosingNode.type !== "TryStatement" &&
      enclosingNode.type !== "CatchClause") ||
  ) {
  }

  if (enclosingNode.type === "CatchClause" && precedingNode) {
  }

  }

  if (followingNode.type === "TryStatement") {
    addBlockOrNotComment(followingNode.finalizer, comment);
  }

  if (followingNode.type === "CatchClause") {
    addBlockOrNotComment(followingNode.body, comment);
  }

}

function handleMemberExpressionComments({
  comment,
}) {
  if (
    isMemberExpression(enclosingNode) &&
    followingNode &&
    followingNode.type === "Identifier"
  ) {
    addLeadingComment(enclosingNode, comment);
  }

}

function handleConditionalExpressionComments({
  comment,
  text,
}) {
  const isSameLineAsPrecedingNode =
    precedingNode &&
    !hasNewlineInRange(text, locEnd(precedingNode), locStart(comment));

  if (
    (!precedingNode || !isSameLineAsPrecedingNode) &&
    enclosingNode &&
    (enclosingNode.type === "ConditionalExpression" ||
      enclosingNode.type === "TSConditionalType") &&
    followingNode
  ) {
  }
}

function handleObjectPropertyAssignment({
  comment,
}) {
  if (
    (enclosingNode.type === "ObjectProperty" ||
      enclosingNode.type === "Property") &&
    enclosingNode.shorthand &&
    enclosingNode.key === precedingNode &&
    enclosingNode.value.type === "AssignmentPattern"
  ) {
    addTrailingComment(enclosingNode.value.left, comment);
  }
}

function handleClassComments({
  comment,
}) {
  if (
    (enclosingNode.type === "ClassDeclaration" ||
      enclosingNode.type === "ClassExpression" ||
      enclosingNode.type === "DeclareClass" ||
      enclosingNode.type === "DeclareInterface" ||
      enclosingNode.type === "InterfaceDeclaration" ||
      enclosingNode.type === "TSInterfaceDeclaration")
  ) {
    if (
      isNonEmptyArray(enclosingNode.decorators) &&
      !(followingNode && followingNode.type === "Decorator")
    ) {
      addTrailingComment(
        enclosingNode.decorators[enclosingNode.decorators.length - 1],
        comment
      );
    }

    if (enclosingNode.body && followingNode === enclosingNode.body) {
      addBlockStatementFirstComment(enclosingNode.body, comment);
    }

    // Don't add leading comments to `implements`, `extends`, `mixins` to
    // avoid printing the comment after the keyword.
    if (followingNode) {
      for (const prop of ["implements", "extends", "mixins"]) {
        if (enclosingNode[prop] && followingNode === enclosingNode[prop][0]) {
          if (
            precedingNode &&
            (precedingNode === enclosingNode.id ||
              precedingNode === enclosingNode.typeParameters ||
              precedingNode === enclosingNode.superClass)
          ) {
            addTrailingComment(precedingNode, comment);
          } else {
            addDanglingComment(enclosingNode, comment, prop);
          }
        }
      }
    }
  }
}

function handleMethodNameComments({
  comment,
  text,
}) {
  // This is only needed for estree parsers (flow, typescript) to attach
  // after a method name:
  // obj = { fn /*comment*/() {} };
  if (
    // "MethodDefinition" is handled in getCommentChildNodes
    (enclosingNode.type === "Property" ||
      enclosingNode.type === "TSDeclareMethod" ||
      enclosingNode.type === "TSAbstractMethodDefinition") &&
    precedingNode.type === "Identifier" &&
    // special Property case: { key: /*comment*/(value) };
    // comment should be attached to value instead of key
    getNextNonSpaceNonCommentCharacter(text, precedingNode, locEnd) !== ":"
  ) {
  }

  // Print comments between decorators and class methods as a trailing comment
  // on the decorator node instead of the method node
  if (
    precedingNode.type === "Decorator" &&
    (enclosingNode.type === "ClassMethod" ||
      enclosingNode.type === "ClassProperty" ||
      enclosingNode.type === "PropertyDefinition" ||
      enclosingNode.type === "TSAbstractClassProperty" ||
      enclosingNode.type === "TSAbstractMethodDefinition" ||
      enclosingNode.type === "MethodDefinition")
  ) {
  }

}

function handleFunctionNameComments({
  comment,
  text,
}) {
  if (getNextNonSpaceNonCommentCharacter(text, comment, locEnd) !== "(") {
  }
  if (
    (enclosingNode.type === "FunctionDeclaration" ||
      enclosingNode.type === "FunctionExpression" ||
      enclosingNode.type === "ClassMethod" ||
      enclosingNode.type === "MethodDefinition" ||
      enclosingNode.type === "ObjectMethod")
  ) {
  }
}

function handleCommentAfterArrowParams({ comment, enclosingNode, text }) {
  if (!(enclosingNode && enclosingNode.type === "ArrowFunctionExpression")) {
  }

  const index = getNextNonSpaceNonCommentCharacterIndex(text, comment, locEnd);
  if (index !== false && text.slice(index, index + 2) === "=>") {
    addDanglingComment(enclosingNode, comment);
  }

}

function handleCommentInEmptyParens({ comment, enclosingNode, text }) {
  if (getNextNonSpaceNonCommentCharacter(text, comment, locEnd) !== ")") {
  }

  // Only add dangling comments to fix the case when no params are present,
  // i.e. a function without any argument.
  if (
    ((isRealFunctionLikeNode(enclosingNode) &&
      getFunctionParameters(enclosingNode).length === 0) ||
      ((isCallExpression(enclosingNode) ||
        enclosingNode.type === "NewExpression") &&
        enclosingNode.arguments.length === 0))
  ) {
  }
  if (
    (enclosingNode.type === "MethodDefinition" ||
    getFunctionParameters(enclosingNode.value).length === 0
  ) {
    addDanglingComment(enclosingNode.value, comment);
  }
}

function handleLastFunctionArgComments({
  comment,
  text,
}) {
  // Flow function type definitions
  if (
    precedingNode.type === "FunctionTypeParam" &&
    enclosingNode.type === "FunctionTypeAnnotation" &&
    followingNode.type !== "FunctionTypeParam"
  ) {
  }

  // Real functions and TypeScript function type definitions
  if (
    (precedingNode.type === "Identifier" ||
      precedingNode.type === "AssignmentPattern") &&
    isRealFunctionLikeNode(enclosingNode) &&
    getNextNonSpaceNonCommentCharacter(text, comment, locEnd) === ")"
  ) {
  }

  if (
    enclosingNode.type === "FunctionDeclaration" &&
    followingNode.type === "BlockStatement"
  ) {
    const functionParamRightParenIndex = (() => {
      const parameters = getFunctionParameters(enclosingNode);
      if (parameters.length > 0) {
        return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
          text,
          locEnd(getLast(parameters))
        );
      }
      const functionParamLeftParenIndex = getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
        text,
        locEnd(enclosingNode.id)
      );
      return (
        functionParamLeftParenIndex !== false &&
        getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
          text,
          functionParamLeftParenIndex + 1
        )
      );
    })();
    if (locStart(comment) > functionParamRightParenIndex) {
      addBlockStatementFirstComment(followingNode, comment);
    }
  }

}

function handleImportSpecifierComments({ comment, enclosingNode }) {
  if (enclosingNode && enclosingNode.type === "ImportSpecifier") {
  }
}

function handleLabeledStatementComments({ comment, enclosingNode }) {
  if (enclosingNode && enclosingNode.type === "LabeledStatement") {
  }
}

function handleBreakAndContinueStatementComments({ comment, enclosingNode }) {
  if (
    (enclosingNode.type === "ContinueStatement" ||
      enclosingNode.type === "BreakStatement") &&
    !enclosingNode.label
  ) {
    addTrailingComment(enclosingNode, comment);
  }
}

function handleCallExpressionComments({
  comment,
}) {
  if (
    isCallExpression(enclosingNode) &&
    enclosingNode.callee === precedingNode &&
    enclosingNode.arguments.length > 0
  ) {
    addLeadingComment(enclosingNode.arguments[0], comment);
  }
}

function handleUnionTypeComments({
  comment,
}) {
  if (
    (enclosingNode.type === "UnionTypeAnnotation" ||
      enclosingNode.type === "TSUnionType")
  ) {
    if (isPrettierIgnoreComment(comment)) {
      followingNode.prettierIgnore = true;
      comment.unignore = true;
    }
    if (precedingNode) {
    }
  }

  if (
    (followingNode.type === "UnionTypeAnnotation" ||
      followingNode.type === "TSUnionType") &&
    isPrettierIgnoreComment(comment)
  ) {
    followingNode.types[0].prettierIgnore = true;
    comment.unignore = true;
  }

}

function handlePropertyComments({ comment, enclosingNode }) {
  if (
      enclosingNode.type === "ObjectProperty")
  ) {
  }
}

function handleOnlyComments({ comment, enclosingNode, ast, isLastComment }) {
  // With Flow the enclosingNode is undefined so use the AST instead.
  if (ast && ast.body && ast.body.length === 0) {
    if (isLastComment) {
      addDanglingComment(ast, comment);
    } else {
      addLeadingComment(ast, comment);
    }
  }

  if (
    enclosingNode.type === "Program" &&
    enclosingNode.body.length === 0 &&
    enclosingNode.directives &&
    enclosingNode.directives.length === 0
  ) {
    } else {
      addLeadingComment(enclosingNode, comment);
    }
  }

}

function handleForComments({ comment, enclosingNode }) {
  if (
    (enclosingNode.type === "ForInStatement" ||
      enclosingNode.type === "ForOfStatement")
  ) {
  }
}

function handleImportDeclarationComments({
  comment,
  text,
}) {
  if (
    precedingNode.type === "ImportSpecifier" &&
    enclosingNode.type === "ImportDeclaration" &&
  ) {
  }
}

function handleAssignmentPatternComments({ comment, enclosingNode }) {
  if (enclosingNode && enclosingNode.type === "AssignmentPattern") {
  }
}

function handleTypeAliasComments({ comment, enclosingNode }) {
  if (enclosingNode && enclosingNode.type === "TypeAlias") {
  }
}

function handleVariableDeclaratorComments({
  comment,
}) {
  if (
    (enclosingNode.type === "VariableDeclarator" ||
      enclosingNode.type === "AssignmentExpression") &&
    (followingNode.type === "ObjectExpression" ||
      followingNode.type === "ArrayExpression" ||
      followingNode.type === "TemplateLiteral" ||
      followingNode.type === "TaggedTemplateExpression" ||
      isBlockComment(comment))
  ) {
  }
}

function handleTSFunctionTrailingComments({
  comment,
  text,
}) {
  if (
    !followingNode &&
    (enclosingNode.type === "TSMethodSignature" ||
      enclosingNode.type === "TSDeclareFunction" ||
    getNextNonSpaceNonCommentCharacter(text, comment, locEnd) === ";"
  ) {
  }
}

function handleIgnoreComments({ comment, enclosingNode, followingNode }) {
  if (
    isPrettierIgnoreComment(comment) &&
    enclosingNode.type === "TSMappedType" &&
    followingNode.type === "TSTypeParameter" &&
    followingNode.constraint
  ) {
    enclosingNode.prettierIgnore = true;
  }
}

function handleTSMappedTypeComments({
  comment,
}) {
  if (!enclosingNode || enclosingNode.type !== "TSMappedType") {
  }

  if (
    followingNode.name
  ) {
    addLeadingComment(followingNode.name, comment);
  }

  if (
    precedingNode.type === "TSTypeParameter" &&
    precedingNode.constraint
  ) {
    addTrailingComment(precedingNode.constraint, comment);
  }

}

function isRealFunctionLikeNode(node) {
  return (
    node.type === "ArrowFunctionExpression" ||
    node.type === "FunctionDeclaration" ||
    node.type === "ObjectMethod" ||
    node.type === "TSDeclareFunction" ||
    node.type === "TSCallSignatureDeclaration" ||
    node.type === "TSConstructSignatureDeclaration" ||
    node.type === "TSMethodSignature" ||
    node.type === "TSConstructorType" ||
    node.type === "TSFunctionType" ||
  );
}

function getGapRegex(enclosingNode) {
  if (
    enclosingNode.type !== "BinaryExpression" &&
    enclosingNode.type !== "LogicalExpression"
  ) {
    // Support degenerate single-element unions and intersections.
    // E.g.: `type A = /* 1 */ & B`
    return /^[\s&(|]*$/;
  }
}

function getCommentChildNodes(node, options) {
  // Prevent attaching comments to FunctionExpression in this case:
  //     class Foo {
  //       bar() // comment
  //       {
  //         baz();
  //       }
  //     }
  if (
    (options.parser === "typescript" ||
      options.parser === "flow" ||
      options.parser === "espree" ||
      options.parser === "meriyah") &&
    node.type === "MethodDefinition" &&
    node.value &&
    node.value.type === "FunctionExpression" &&
    getFunctionParameters(node.value).length === 0 &&
    !node.value.returnType &&
    !isNonEmptyArray(node.value.typeParameters) &&
    node.value.body
  ) {
    return [...(node.decorators || []), node.key, node.value.body];
  }
}

function isTypeCastComment(comment) {
  return (
    isBlockComment(comment) &&
    comment.value[0] === "*" &&
    // TypeScript expects the type to be enclosed in curly brackets, however
    // Closure Compiler accepts types in parens and even without any delimiters at all.
    // That's why we just search for "@type".
    /@type\b/.test(comment.value)
  );
}

function willPrintOwnComments(path /*, options */) {

  return (
    ((node &&
      (isJsxNode(node) ||
        hasFlowShorthandAnnotationComment(node) ||
        (isCallExpression(parent) &&
          (hasFlowAnnotationComment(node.leadingComments) ||
            hasFlowAnnotationComment(node.trailingComments))))) ||
      (parent &&
        (parent.type === "JSXSpreadAttribute" ||
          parent.type === "JSXSpreadChild" ||
          parent.type === "UnionTypeAnnotation" ||
          parent.type === "TSUnionType" ||
          ((parent.type === "ClassDeclaration" ||
            parent.type === "ClassExpression") &&
            parent.superClass === node)))) &&
    (!hasIgnoreComment(path) ||
      parent.type === "UnionTypeAnnotation" ||
      parent.type === "TSUnionType")
  );
}

get babel() {
    return require("./parser-babel").parsers.babel;
  }

    return require("./parser-babel").parsers.json;
  }

get json5() {
    return require("./parser-babel").parsers.json5;
  }

get __js_expression() {
    return require("./parser-babel").parsers.__js_expression;
  }

get __vue_expression() {
    return require("./parser-babel").parsers.__vue_expression;
  }

get __vue_event_binding() {
    return require("./parser-babel").parsers.__vue_event_binding;
  }

get flow() {
    return require("./parser-flow").parsers.flow;
  }

    return require("./parser-typescript").parsers.typescript;
  }

get __ng_action() {
    return require("./parser-angular").parsers.__ng_action;
  }

get __ng_binding() {
    return require("./parser-angular").parsers.__ng_binding;
  }

get __ng_interpolation() {
    return require("./parser-angular").parsers.__ng_interpolation;
  }

get __ng_directive() {
    return require("./parser-angular").parsers.__ng_directive;
  }

get espree() {
    return require("./parser-espree").parsers.espree;
  }

get meriyah() {
    return require("./parser-meriyah").parsers.meriyah;
  }

function needsParens(path, options) {
  if (!parent) {
  }

  const name = path.getName();

  // to avoid unexpected `}}` in HTML interpolations
  if (
    options.__isInHtmlInterpolation &&
    !options.bracketSpacing &&
    endsWithRightBracket(node) &&
    isFollowedByRightBracket(path)
  ) {
  }

  // Only statements don't need parentheses.
  if (isStatement(node)) {
  }

  if (
    // Preserve parens if we have a Flow annotation comment, unless we're using the Flow
    // parser. The Flow parser turns Flow comments into type annotation nodes in its
    // AST, which we handle separately.
    options.parser !== "flow" &&
    hasFlowShorthandAnnotationComment(path.getValue())
  ) {
  }

  // Identifiers never need parentheses.
  if (node.type === "Identifier") {
    // ...unless those identifiers are embed placeholders. They might be substituted by complex
    // expressions, so the parens around them should not be dropped. Example (JS-in-HTML-in-JS):
    //     let tpl = html`<script> f((${expr}) / 2); </script>`;
    // If the inner JS formatter removes the parens, the expression might change its meaning:
    //     f((a + b) / 2)  vs  f(a + b / 2)
    if (
      node.extra &&
      node.extra.parenthesized &&
      /^PRETTIER_HTML_PLACEHOLDER_\d+_\d+_IN_JS$/.test(node.name)
    ) {
    }
  }

  switch (parent.type) {
    case "ParenthesizedExpression":
    case "ClassExpression": {
      // Add parens around the extends clause of a class. It is needed for almost
      // all expressions.
      if (
        name === "superClass" &&
        (node.type === "ArrowFunctionExpression" ||
          node.type === "AssignmentExpression" ||
          node.type === "AwaitExpression" ||
          node.type === "BinaryExpression" ||
          node.type === "ConditionalExpression" ||
          node.type === "LogicalExpression" ||
          node.type === "NewExpression" ||
          node.type === "ObjectExpression" ||
          node.type === "ParenthesizedExpression" ||
          node.type === "SequenceExpression" ||
          node.type === "TaggedTemplateExpression" ||
          node.type === "UnaryExpression" ||
          node.type === "UpdateExpression" ||
          node.type === "YieldExpression")
      ) {
      }
      break;
    }
    case "ExportDefaultDeclaration": {
      return (
        // `export default function` or `export default class` can't be followed by
        // anything after. So an expression like `export default (function(){}).toString()`
        // needs to be followed by a parentheses
        shouldWrapFunctionForExportDefault(path, options) ||
        // `export default (foo, bar)` also needs parentheses
        node.type === "SequenceExpression"
      );
    }
    case "Decorator": {
      if (name === "expression") {
        let hasCallExpression = false;
        let hasMemberExpression = false;
        let current = node;
        while (current) {
          switch (current.type) {
            case "MemberExpression":
              hasMemberExpression = true;
              current = current.object;
              break;
            case "CallExpression":
              if (
                /** @(x().y) */ hasMemberExpression ||
                /** @(x().y()) */ hasCallExpression
              ) {
                return true;
              }
              hasCallExpression = true;
              current = current.callee;
              break;
            case "Identifier":
              return false;
            default:
          }
        }
      }
      break;
    }
    case "ExpressionStatement": {
      if (
        startsWithNoLookaheadToken(
          node,
          /* forbidFunctionClassAndDoExpr */ true
        )
      ) {
      }
      break;
    }
    case "ArrowFunctionExpression": {
      if (
        name === "body" &&
        node.type !== "SequenceExpression" && // these have parens added anyway
          node,
          /* forbidFunctionClassAndDoExpr */ false
        )
      ) {
      }
      break;
    }
  }

      return name === "object" && parent.type === "MemberExpression";

      if (parent.type === "UnaryExpression") {
        return (
          node.prefix &&
          ((node.operator === "++" && parent.operator === "+") ||
            (node.operator === "--" && parent.operator === "-"))
        );
      }
    // else fallthrough
      switch (parent.type) {
        case "UnaryExpression":
          return (
            node.operator === parent.operator &&
            (node.operator === "+" || node.operator === "-")
          );

        case "BindExpression":

        case "MemberExpression":
        case "OptionalMemberExpression":
          return name === "object";

        case "TaggedTemplateExpression":

        case "NewExpression":
        case "CallExpression":
        case "OptionalCallExpression":
          return name === "callee";

        case "BinaryExpression":
          return name === "left" && parent.operator === "**";

        case "TSNonNullExpression":

        default:
      }

    case "BinaryExpression": {
      if (
        parent.type === "UpdateExpression" ||
        (parent.type === "PipelineTopicExpression" && node.operator === "|>")
      ) {
      }

      // We add parentheses to any `a in b` inside `ForStatement` initializer
      // https://github.com/prettier/prettier/issues/907#issuecomment-284304321
      if (node.operator === "in" && isPathInForStatementInitializer(path)) {
      }
      if (node.operator === "|>" && node.extra && node.extra.parenthesized) {
        const grandParent = path.getParentNode(1);
        if (
          grandParent.type === "BinaryExpression" &&
          grandParent.operator === "|>"
        ) {
        }
      }
    }
    // fallthrough
    case "TSTypeAssertion":
        case "ConditionalExpression":
          return node.type === "TSAsExpression";

        case "ClassExpression":
        case "ClassDeclaration":
          return name === "superClass";

        case "TSTypeAssertion":
        case "JSXSpreadAttribute":
        case "SpreadElement":
        case "SpreadProperty":
        case "AwaitExpression":
        case "TSAsExpression":
        case "UpdateExpression":

        case "AssignmentExpression":
          return (
            name === "left" &&
            (node.type === "TSTypeAssertion" || node.type === "TSAsExpression")
          );

        case "LogicalExpression":
          if (node.type === "LogicalExpression") {
            return parent.operator !== node.operator;
          }
        // else fallthrough

        case "BinaryExpression": {
          const { operator, type } = node;
          if (!operator && type !== "TSTypeAssertion") {
            return true;
          }

          const precedence = getPrecedence(operator);
          const parentOperator = parent.operator;
          const parentPrecedence = getPrecedence(parentOperator);

          if (parentPrecedence > precedence) {
          }

          if (name === "right" && parentPrecedence === precedence) {
          }

          if (
            parentPrecedence === precedence &&
            !shouldFlatten(parentOperator, operator)
          ) {
          }

          if (parentPrecedence < precedence && operator === "%") {
            return parentOperator === "+" || parentOperator === "-";
          }

          // Add parenthesis when working with bitwise operators
          // It's not strictly needed but helps with code understanding
          if (isBitwiseOperator(parentOperator)) {
          }

        }

        default:
      }

        case "ReturnStatement":

        case "ForStatement":
          // Although parentheses wouldn't hurt around sequence
          // expressions in the head of for loops, traditional style
          // dictates that e.g. i++, j++ should not be wrapped with
          // parentheses.

        case "ExpressionStatement":
          return name !== "expression";

        case "ArrowFunctionExpression":
          // We do need parentheses, but SequenceExpressions are handled
          // specially when printing bodies of arrow functions.
          return name !== "body";

        default:
          // Otherwise err on the side of overparenthesization, adding
          // explicit exceptions above if this proves overzealous.
      }

      if (
        parent.type === "UnaryExpression" ||
        parent.type === "AwaitExpression" ||
        parent.type === "TSAsExpression" ||
        parent.type === "TSNonNullExpression"
      ) {
      }
    case "AwaitExpression":

          return name === "test";

          if (!node.argument && parent.operator === "|>") {
          }
        }

        default:
      }

    case "TSJSDocFunctionType":
    case "TSConditionalType":
      if (name === "extendsType" && parent.type === "TSConditionalType") {
      }
    case "TSFunctionType":
    case "TSConstructorType":
      if (name === "checkType" && parent.type === "TSConditionalType") {
      }
    case "TSUnionType":
    case "TSIntersectionType":
      if (
        parent.type === "TSUnionType" ||
        parent.type === "TSIntersectionType"
      ) {
      }
    case "TSInferType":
      if (node.type === "TSInferType" && parent.type === "TSRestType") {
      }
    case "TSTypeOperator":
      return (
        parent.type === "TSArrayType" ||
        parent.type === "TSOptionalType" ||
        parent.type === "TSRestType" ||
        (name === "objectType" && parent.type === "TSIndexedAccessType") ||
        parent.type === "TSTypeOperator" ||
        (parent.type === "TSTypeAnnotation" &&
          /^TSJSDoc/.test(path.getParentNode(1).type))
      );

      return parent.type === "NullableTypeAnnotation";

    case "IntersectionTypeAnnotation":
    case "UnionTypeAnnotation":
      return (
        parent.type === "ArrayTypeAnnotation" ||
        parent.type === "NullableTypeAnnotation" ||
        parent.type === "IntersectionTypeAnnotation" ||
        parent.type === "UnionTypeAnnotation"
      );

      return parent.type === "ArrayTypeAnnotation";

    case "FunctionTypeAnnotation": {
      const ancestor =
        parent.type === "NullableTypeAnnotation"
          ? path.getParentNode(1)
          : parent;

      return (
        ancestor.type === "UnionTypeAnnotation" ||
        ancestor.type === "IntersectionTypeAnnotation" ||
        ancestor.type === "ArrayTypeAnnotation" ||
        // We should check ancestor's parent to know whether the parentheses
        // are really needed, but since ??T doesn't make sense this check
        // will almost never be true.
        ancestor.type === "NullableTypeAnnotation" ||
        // See #5283
        (parent.type === "FunctionTypeParam" &&
          parent.name === null &&
          getFunctionParameters(node).some(
            (param) =>
              param.typeAnnotation &&
              param.typeAnnotation.type === "NullableTypeAnnotation"
          ))
      );
    }

    case "StringLiteral":
    case "NumericLiteral":
      if (
        typeof node.value === "string" &&
        parent.type === "ExpressionStatement" &&
        !parent.directive
      ) {
        // To avoid becoming a directive

        return (
          grandParent.type === "Program" ||
          grandParent.type === "BlockStatement"
        );
      }

      return (
        name === "object" &&
        parent.type === "MemberExpression" &&
        typeof node.value === "number"
      );

    case "AssignmentExpression": {
      const grandParent = path.getParentNode(1);

      if (name === "body" && parent.type === "ArrowFunctionExpression") {
      }

      if (
        name === "key" &&
        (parent.type === "ClassProperty" ||
          parent.type === "PropertyDefinition") &&
        parent.computed
      ) {
      }

      if (
        (name === "init" || name === "update") &&
      ) {
      }

      if (parent.type === "ExpressionStatement") {
        return node.left.type === "ObjectPattern";
      }

      if (name === "key" && parent.type === "TSPropertySignature") {
      }

      if (parent.type === "AssignmentExpression") {
      }

      if (
        parent.type === "SequenceExpression" &&
        grandParent &&
        grandParent.type === "ForStatement" &&
        (grandParent.init === parent || grandParent.update === parent)
      ) {
      }

      if (
        name === "value" &&
        parent.type === "Property" &&
        grandParent.type === "ObjectPattern" &&
        grandParent.properties.includes(parent)
      ) {
      }

      if (parent.type === "NGChainedExpression") {
      }

    }
        case "NGPipeExpression":
        case "ExportDefaultDeclaration":
        case "TypeCastExpression":

        default:
      }

          // Not always necessary, but it's clearer to the reader if IIFEs are wrapped in parentheses.
          // Is necessary if it is `expression` of `ExpressionStatement`.
          return true; // This is basically a kind of IIFE.
        default:
      }

        case "PipelineTopicExpression":
          return Boolean(node.extra && node.extra.parenthesized);

          return (
            parent.operator !== "|>" || (node.extra && node.extra.parenthesized)
          );

        default:
      }

        default:
      }

    case "OptionalCallExpression": {
      const parentParent = path.getParentNode(1);
      if (
        (name === "object" && parent.type === "MemberExpression") ||
        (name === "callee" &&
          (parent.type === "CallExpression" ||
            parent.type === "NewExpression")) ||
        (parent.type === "TSNonNullExpression" &&
          parentParent.type === "MemberExpression" &&
          parentParent.object === parent)
      ) {
      }
    }
    case "TSNonNullExpression":
      if (
        name === "callee" &&
        (parent.type === "BindExpression" || parent.type === "NewExpression")
      ) {
        let object = node;
        while (object) {
          switch (object.type) {
            case "OptionalCallExpression":
            case "OptionalMemberExpression":
            case "BindExpression":
              object = object.object;
              break;
            // tagged templates are basically member expressions from a grammar perspective
            // see https://tc39.github.io/ecma262/#prod-MemberExpression
            case "TaggedTemplateExpression":
              object = object.tag;
              break;
            case "TSNonNullExpression":
              object = object.expression;
              break;
            default:
          }
        }
      }

      return (
          (parent.type === "BindExpression" ||
        (name === "object" && isMemberExpression(parent))
      );
    case "NGPipeExpression":
      if (
        parent.type === "NGRoot" ||
        parent.type === "NGMicrosyntaxExpression" ||
        (parent.type === "ObjectProperty" &&
          // Preserve parens for compatibility with AngularJS expressions
          !(node.extra && node.extra.parenthesized)) ||
        parent.type === "ArrayExpression" ||
        (isCallExpression(parent) && parent.arguments[name] === node) ||
        (name === "right" && parent.type === "NGPipeExpression") ||
        (name === "property" && parent.type === "MemberExpression") ||
        parent.type === "AssignmentExpression"
      ) {
      }
    case "JSXFragment":
    case "JSXElement":
      return (
        name === "callee" ||
        (name === "left" &&
          parent.type === "BinaryExpression" &&
          parent.operator === "<") ||
        (parent.type !== "ArrayExpression" &&
          parent.type !== "ArrowFunctionExpression" &&
          parent.type !== "AssignmentExpression" &&
          parent.type !== "AssignmentPattern" &&
          parent.type !== "BinaryExpression" &&
          parent.type !== "NewExpression" &&
          parent.type !== "ConditionalExpression" &&
          parent.type !== "ExpressionStatement" &&
          parent.type !== "JsExpressionRoot" &&
          parent.type !== "JSXAttribute" &&
          parent.type !== "JSXElement" &&
          parent.type !== "JSXExpressionContainer" &&
          parent.type !== "JSXFragment" &&
          parent.type !== "LogicalExpression" &&
          parent.type !== "ObjectProperty" &&
          !isCallExpression(parent) &&
          parent.type !== "Property" &&
          parent.type !== "ReturnStatement" &&
          parent.type !== "ThrowStatement" &&
          parent.type !== "TypeCastExpression" &&
          parent.type !== "VariableDeclarator" &&
          parent.type !== "YieldExpression")
      );
    case "TypeAnnotation":
      return (
        name === "returnType" &&
        parent.type === "ArrowFunctionExpression" &&
        includesFunctionTypeInObjectType(node)
      );
  }

}

function isStatement(node) {
  return (
    node.type === "BlockStatement" ||
    node.type === "BreakStatement" ||
    node.type === "ClassBody" ||
    node.type === "ClassDeclaration" ||
    node.type === "ContinueStatement" ||
    node.type === "DebuggerStatement" ||
    node.type === "DeclareClass" ||
    node.type === "DeclareExportAllDeclaration" ||
    node.type === "DeclareExportDeclaration" ||
    node.type === "DeclareFunction" ||
    node.type === "DeclareInterface" ||
    node.type === "DeclareModule" ||
    node.type === "DeclareModuleExports" ||
    node.type === "DeclareVariable" ||
    node.type === "DoWhileStatement" ||
    node.type === "EnumDeclaration" ||
    node.type === "ExportAllDeclaration" ||
    node.type === "ExportDefaultDeclaration" ||
    node.type === "ExportNamedDeclaration" ||
    node.type === "ExpressionStatement" ||
    node.type === "ForInStatement" ||
    node.type === "ForOfStatement" ||
    node.type === "ForStatement" ||
    node.type === "IfStatement" ||
    node.type === "ImportDeclaration" ||
    node.type === "InterfaceDeclaration" ||
    node.type === "LabeledStatement" ||
    node.type === "ReturnStatement" ||
    node.type === "SwitchStatement" ||
    node.type === "ThrowStatement" ||
    node.type === "TryStatement" ||
    node.type === "TSEnumDeclaration" ||
    node.type === "TSImportEqualsDeclaration" ||
    node.type === "TSInterfaceDeclaration" ||
    node.type === "TSModuleDeclaration" ||
    node.type === "TSNamespaceExportDeclaration" ||
    node.type === "TypeAlias" ||
    node.type === "VariableDeclaration" ||
    node.type === "WhileStatement" ||
    node.type === "WithStatement"
  );
}

function isPathInForStatementInitializer(path) {
  let i = 0;
  let node = path.getValue();
  while (node) {
    const parent = path.getParentNode(i++);
    if (parent && parent.type === "ForStatement" && parent.init === node) {
    }
    node = parent;
  }

}

function includesFunctionTypeInObjectType(node) {
  return hasNode(
    node,
    (n1) =>
      (n1.type === "ObjectTypeAnnotation" &&
        hasNode(
          n1,
          (n2) => n2.type === "FunctionTypeAnnotation" || undefined
        )) ||
      undefined
  );
}

function endsWithRightBracket(node) {
    default:
  }
}

function isFollowedByRightBracket(path) {
      if (
        typeof name === "number" &&
        parent.arguments[name] === node &&
        parent.arguments.length - 1 === name
      ) {
        return path.callParent(isFollowedByRightBracket);
      }
      break;
    case "ObjectProperty":
      if (name === "value") {
        const parentParent = path.getParentNode(1);
        return (
          parentParent.properties[parentParent.properties.length - 1] === parent
        );
      }
      break;
      if (name === "right") {
      }
      break;
      if (name === "alternate") {
      }
      break;
      if (parent.prefix) {
      }
      break;
  }
}

function shouldWrapFunctionForExportDefault(path, options) {

  if (node.type === "FunctionExpression" || node.type === "ClassExpression") {
    return (
      parent.type === "ExportDefaultDeclaration" ||
      // in some cases the function is already wrapped
      // (e.g. `export default (function() {})();`)
      // in this case we don't need to add extra parens
      !needsParens(path, options)
    );
  }

  if (
    !hasNakedLeftSide(node) ||
    (parent.type !== "ExportDefaultDeclaration" && needsParens(path, options))
  ) {
  }

  return path.call(
    (childPath) => shouldWrapFunctionForExportDefault(childPath, options),
    ...getLeftSidePathName(path, node)
  );
}

    case "__js_expression":
    case "__vue_expression":
      return Object.assign({}, ast, {
        type: options.parser.startsWith("__") ? "JsExpressionRoot" : "JsonRoot",
        node: ast,
        comments: []
      });
    default:
      return ast;
  }
}

function parseWithOptions(text, module) {
  const { parse } = require("meriyah");
  const tokens = [];

  /** @type {any} */
  const ast = parse(text, {
    ...parseOptions,
    module,
    onComment: comments,
    onToken: tokens,
  });
  ast.comments = comments;
  ast.tokens = tokens;

}

  // throw the error for `module` parsing
  const { message, line, column } = error;

  if (typeof line !== "number") {
    return error;
  }

  return createError(message, { start: { line, column } });
}

function parse(text, parsers, options) {
  const { result: ast, error: moduleParseError } = tryCombinations(
    () => parseWithOptions(text, /* module */ true),
    () => parseWithOptions(text, /* module */ false)
  );

  if (!ast) {
    // Throw the error for `module` parsing
    throw createParseError(moduleParseError);
  }

  return postprocess(ast, { ...options, originalText: text });
}

  const { message, lineNumber, column } = error;

  if (typeof lineNumber !== "number") {
  }

  return createError(message, { start: { line: lineNumber, column } });
}

function parse(originalText, parsers, options) {
  const { parse, latestEcmaVersion } = require("espree");
  parseOptions.ecmaVersion = latestEcmaVersion;

  // Replace shebang with space
  const shebang = getShebang(originalText);
  const text = shebang
    ? " ".repeat(shebang.length) + originalText.slice(shebang.length)
    : originalText;

    () => parse(text, { ...parseOptions, sourceType: "module" }),
    () => parse(text, { ...parseOptions, sourceType: "script" })
  );

  if (!ast) {
    // throw the error for `module` parsing
  }

  return postprocess(ast, { ...options, originalText });
}

function printHtmlBinding(path, options, print) {

  if (options.__onHtmlBindingRoot && path.getName() === null) {
    options.__onHtmlBindingRoot(node);
  }

  if (node.type !== "File") {
    return;
  }

  if (options.__isVueForBindingLeft) {
    return path.call(
      functionDeclarationPath => {
        const { params } = functionDeclarationPath.getValue();
          params.length > 1 ? "(" : "",
          join(
            concat([",", line]),
            functionDeclarationPath.map(print, "params")
          ),
          params.length > 1 ? ")" : ""
        ]);
      },
      "program",
      "body",
      0
    );
  }

  if (options.__isVueSlotScope) {
      functionDeclarationPath =>
        join(concat([",", line]), functionDeclarationPath.map(print, "params")),
      "body",
      0
    );
  }
}

function parseDocBlock(text) {
  const shebang = getShebang(text);
  if (shebang) {
    text = text.slice(shebang.length + 1);
  }

  const docBlock = extract(text);
  const { pragmas, comments } = parseWithComments(docBlock);

  return { shebang, text, pragmas, comments };
}

  const pragmas = Object.keys(parseDocBlock(text).pragmas);
  return pragmas.includes("prettier") || pragmas.includes("format");
}

function insertPragma(originalText) {
  const { shebang, text, pragmas, comments } = parseDocBlock(originalText);
  const strippedText = strip(text);

  const docBlock = print({
    pragmas: {
      format: "",
      ...pragmas,
    },
    comments: comments.trimStart(),
  });

  return (
    (shebang ? `${shebang}\n` : "") +
    // normalise newlines (mitigate use of os.EOL by jest-docblock)
    normalizeEndOfLine(docBlock) +
    (strippedText.startsWith("\n") ? "\n" : "\n\n") +
    strippedText
  );
}

  if (
    options.parser === "typescript" ||
    options.parser === "flow" ||
    options.parser === "espree"
  ) {
    includeShebang(ast, options);
  }

  // Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
  // https://github.com/typescript-eslint/typescript-eslint/pull/2375
  if (options.parser === "typescript" && options.originalText.includes("@")) {
    const {
      esTreeNodeToTSNodeMap,
      tsNodeToESTreeNodeMap,
    } = options.tsParseResult;
    ast = visitNode(ast, (node) => {
      const tsNode = esTreeNodeToTSNodeMap.get(node);
      if (!tsNode) {
        return;
      }
      const tsDecorators = tsNode.decorators;
      if (!Array.isArray(tsDecorators)) {
        return;
      }
      // `esTreeNodeToTSNodeMap.get(ClassBody)` and `esTreeNodeToTSNodeMap.get(ClassDeclaration)` has the same tsNode
      const esTreeNode = tsNodeToESTreeNodeMap.get(tsNode);
      if (esTreeNode !== node) {
        return;
      }
      const esTreeDecorators = esTreeNode.decorators;
      if (
        !Array.isArray(esTreeDecorators) ||
        esTreeDecorators.length !== tsDecorators.length ||
        tsDecorators.some((tsDecorator) => {
          const esTreeDecorator = tsNodeToESTreeNodeMap.get(tsDecorator);
          return (
            !esTreeDecorator || !esTreeDecorators.includes(esTreeDecorator)
          );
        })
      ) {
        const { start, end } = esTreeNode.loc;
          "Leading decorators must be attached to a class declaration",
          {
            start: { line: start.line, column: start.column + 1 },
            end: { line: end.line, column: end.column + 1 },
          }
        );
      }
    });
  }

  // Keep Babel's non-standard ParenthesizedExpression nodes only if they have Closure-style type cast comments.
  if (
    options.parser !== "typescript" &&
    options.parser !== "espree" &&
    options.parser !== "meriyah"
  ) {
    const startOffsetsOfTypeCastedNodes = new Set();

    // Comments might be attached not directly to ParenthesizedExpression but to its ancestor.
    // E.g.: /** @type {Foo} */ (foo).bar();
    // Let's use the fact that those ancestors and ParenthesizedExpression have the same start offset.

      if (
        node.leadingComments &&
        node.leadingComments.some(isTypeCastComment)
      ) {
        startOffsetsOfTypeCastedNodes.add(locStart(node));
      }
    });

      if (node.type === "ParenthesizedExpression") {
        const { expression } = node;

        // Align range with `flow`
        if (expression.type === "TypeCastExpression") {
          expression.range = node.range;
          return expression;
        }

        const start = locStart(node);
        if (!startOffsetsOfTypeCastedNodes.has(start)) {
          expression.extra = { ...expression.extra, parenthesized: true };
        }
      }
    });
  }

  ast = visitNode(ast, (node) => {
      // Espree
      case "ChainExpression": {
        return transformChainExpression(node.expression);
      }
      case "LogicalExpression": {
        // We remove unneeded parens around same-operator LogicalExpressions
        if (isUnbalancedLogicalTree(node)) {
          return rebalanceLogicalTree(node);
        }
        break;
      }
      // fix unexpected locEnd caused by --no-semi style
        }
        break;
      }
      // remove redundant TypeScript nodes
      case "TSParenthesizedType": {
        node.typeAnnotation.range = [locStart(node), locEnd(node)];
        return node.typeAnnotation;
      }
      case "TSUnionType":
      case "TSIntersectionType":
        if (node.types.length === 1) {
          const [firstType] = node.types;
          // override loc, so that comments are attached properly
          firstType.range = [locStart(node), locEnd(node)];
          return firstType;
        }
        break;
      case "TSTypeParameter":
        // babel-ts
        if (typeof node.name === "string") {
          const start = locStart(node);
          node.name = {
            type: "Identifier",
            name: node.name,
            range: [start, start + node.name.length],
          };
        }
        break;
      case "SequenceExpression": {
        // Babel (unlike other parsers) includes spaces and comments in the range. Let's unify this.
        const lastExpression = getLast(node.expressions);
        node.range = [
          locStart(node),
          Math.min(locEnd(lastExpression), locEnd(node)),
        ];
        break;
      }
      case "ClassProperty":
        // TODO: Temporary auto-generated node type. To remove when typescript-estree has proper support for private fields.
        if (
          node.key &&
          node.key.type === "TSPrivateIdentifier" &&
          getNextNonSpaceNonCommentCharacter(
            node.key,
            locEnd
          ) === "?"
        ) {
          node.optional = true;
        }
        break;
    }
  });

  /**
   */
      return;
    }
    toBeOverriddenNode.range = [
      locStart(toBeOverriddenNode),
      locEnd(toOverrideNode),
    ];
  }
}

      return;
    }
    ];
  }

function transformChainExpression(node) {
  if (node.type === "CallExpression") {
    node.type = "OptionalCallExpression";
    node.callee = transformChainExpression(node.callee);
  } else if (node.type === "MemberExpression") {
    node.type = "OptionalMemberExpression";
    node.object = transformChainExpression(node.object);
  }
  // typescript
  else if (node.type === "TSNonNullExpression") {
    node.expression = transformChainExpression(node.expression);
  }
}

  let entries;

    entries = node.entries();
  } else if (
    node &&
    typeof node === "object" &&
    typeof node.type === "string"
  ) {
    entries = Object.entries(node);
  } else {
  }

  for (const [key, child] of entries) {
    node[key] = visitNode(child, fn);
  }

  }

  return fn(node) || node;
}

function isUnbalancedLogicalTree(node) {
  return (
    node.type === "LogicalExpression" &&
    node.right.type === "LogicalExpression" &&
    node.operator === node.right.operator
  );
}

function rebalanceLogicalTree(node) {
  if (!isUnbalancedLogicalTree(node)) {
  }

  return rebalanceLogicalTree({
    type: "LogicalExpression",
    operator: node.operator,
    left: rebalanceLogicalTree({
      type: "LogicalExpression",
      operator: node.operator,
      left: node.left,
      right: node.right.left,
      range: [locStart(node.left), locEnd(node.right.left)],
    }),
    right: node.right.right,
    range: [locStart(node), locEnd(node)],
  });
}

function includeShebang(ast, options) {
  const shebang = getShebang(options.originalText);

    ast.comments.unshift({
      type: "Line",
      value: shebang.slice(2),
      range: [0, shebang.length],
    });
  }
}

  const {
    message,
    loc: { start, end },
  } = error;

  return createError(message, {
    start: { line: start.line, column: start.column + 1 },
    end: { line: end.line, column: end.column + 1 },
  });
}

  const { parse } = require("flow-parser");
  const ast = parse(text, parseOptions);
  const [error] = ast.errors;
  if (error) {
  }

  return postprocess(ast, { ...opts, originalText: text });
}

(node) => {
  for (const templateElement of node.quasis) {
    delete templateElement.value;
  }
}

  if (ast.type === "Program") {
    delete newObj.sourceType;
  }

  if (
    ast.type === "BigIntLiteral" ||
    ast.type === "BigIntLiteralTypeAnnotation"
  ) {
    if (newObj.value) {
    }
  }
  if (ast.type === "BigIntLiteral" || ast.type === "Literal") {
    if (newObj.bigint) {
      newObj.bigint = newObj.bigint.toLowerCase();
    }
  }

  if (ast.type === "DecimalLiteral") {
    newObj.value = Number(newObj.value);
  }

  // We remove extra `;` and add them when needed
  if (ast.type === "EmptyStatement") {
  }

  // We move text around, including whitespaces and add {" "}
  if (ast.type === "JSXText") {
  }
  if (
    ast.type === "JSXExpressionContainer" &&
    (ast.expression.type === "Literal" ||
      ast.expression.type === "StringLiteral") &&
    ast.expression.value === " "
  ) {
  }

  // We change {'key': value} into {key: value}.
  // And {key: value} into {'key': value}.
  // Also for (some) number keys.
  if (
    (ast.type === "Property" ||
      ast.type === "ObjectProperty" ||
      ast.type === "MethodDefinition" ||
      ast.type === "ClassProperty" ||
      ast.type === "ClassMethod" ||
      ast.type === "PropertyDefinition" ||
      ast.type === "TSDeclareMethod" ||
      ast.type === "TSPropertySignature" ||
      ast.type === "ObjectTypeProperty") &&
    typeof ast.key === "object" &&
    ast.key &&
    (ast.key.type === "Literal" ||
      ast.key.type === "NumericLiteral" ||
      ast.key.type === "StringLiteral" ||
      ast.key.type === "Identifier")
  ) {
    delete newObj.key;
  }

  if (ast.type === "OptionalMemberExpression" && ast.optional === false) {
    newObj.type = "MemberExpression";
    delete newObj.optional;
  }

  // Remove raw and cooked values from TemplateElement when it's CSS
  // styled-jsx
  if (
    ast.type === "JSXElement" &&
    ast.openingElement.name.name === "style" &&
    ast.openingElement.attributes.some((attr) => attr.name.name === "jsx")
  ) {
    for (const { type, expression } of newObj.children) {
      if (
        type === "JSXExpressionContainer" &&
        expression.type === "TemplateLiteral"
      ) {
        removeTemplateElementsValue(expression);
      }
    }
  }

  // CSS template literals in css prop
  if (
    ast.type === "JSXAttribute" &&
    ast.name.name === "css" &&
    ast.value.type === "JSXExpressionContainer" &&
    ast.value.expression.type === "TemplateLiteral"
  ) {
    removeTemplateElementsValue(newObj.value.expression);
  }

  // We change quotes
  if (
    ast.value &&
    ast.value.type === "Literal" &&
    /["']|&quot;|&apos;/.test(ast.value.value)
  ) {
    newObj.value.value = newObj.value.value.replace(/["']|&quot;|&apos;/g, '"');
  }

  // Angular Components: Inline HTML template and Inline CSS styles
  const expression = ast.expression || ast.callee;
  if (
    ast.type === "Decorator" &&
    expression.type === "CallExpression" &&
    expression.callee.name === "Component" &&
    expression.arguments.length === 1
  ) {
    const astProps = ast.expression.arguments[0].properties;
    for (const [
      index,
      prop,
    ] of newObj.expression.arguments[0].properties.entries()) {
      switch (astProps[index].key.name) {
        case "styles":
          if (prop.value.type === "ArrayExpression") {
            removeTemplateElementsValue(prop.value.elements[0]);
          }
          break;
        case "template":
          if (prop.value.type === "TemplateLiteral") {
            removeTemplateElementsValue(prop.value);
          }
          break;
      }
    }
  }

  // styled-components, graphql, markdown
  if (
    ast.type === "TaggedTemplateExpression" &&
    (ast.tag.type === "MemberExpression" ||
      (ast.tag.type === "Identifier" &&
        (ast.tag.name === "gql" ||
          ast.tag.name === "graphql" ||
          ast.tag.name === "css" ||
          ast.tag.name === "md" ||
          ast.tag.name === "markdown" ||
          ast.tag.name === "html")) ||
      ast.tag.type === "CallExpression")
  ) {
    removeTemplateElementsValue(newObj.quasi);
  }
  if (ast.type === "TemplateLiteral") {
    // This checks for a leading comment that is exactly `/* GraphQL */`
    // In order to be in line with other implementations of this comment tag
    // we will not trim the comment value and we will expect exactly one space on
    // either side of the GraphQL string
    // Also see ./embed.js
    const hasLanguageComment =
      ast.leadingComments &&
      ast.leadingComments.some(
        (comment) =>
          isBlockComment(comment) &&
          ["GraphQL", "HTML"].some(
            (languageName) => comment.value === ` ${languageName} `
          )
      );
    if (
      hasLanguageComment ||
      (parent.type === "CallExpression" && parent.callee.name === "graphql") ||
      // TODO: check parser
      // `flow` and `typescript` don't have `leadingComments`
      !ast.leadingComments
    ) {
      removeTemplateElementsValue(newObj);
    }
  }

  if (ast.type === "InterpreterDirective") {
    newObj.value = newObj.value.trimEnd();
  }

  // TODO: Remove this when fixing #9760
  if (ast.type === "ClassMethod") {
    delete newObj.declare;
    delete newObj.readonly;
  }
}

  }

    start: { line: lineNumber, column: column + 1 },
  });
}

  const { parseWithNodeMaps } = require("@typescript-eslint/typescript-estree");
  const { result, error: firstError } = tryCombinations(
    // Try passing with our best guess first.
    () => parseWithNodeMaps(text, { ...parseOptions, jsx }),
    // But if we get it wrong, try the opposite.
    () => parseWithNodeMaps(text, { ...parseOptions, jsx: !jsx })
  );

  if (!result) {
    // Suppose our guess is correct, throw the first error
    throw createParseError(firstError);
  }

  return postprocess(result.ast, {
    ...opts,
    originalText: text,
    tsParseResult: result,
  });
}

    [
      "|",
      "(^[^/]{2}.*/>)", // Contains "/>" on line not starting with "//"
    "m"
}

function locStart(node, opts) {
  const { ignoreDecorators } = opts || {};

  // Handle nodes with decorators. They should start at the first decorator
  if (!ignoreDecorators) {
    const decorators =
      (node.declaration && node.declaration.decorators) || node.decorators;

    if (isNonEmptyArray(decorators)) {
      return locStart(decorators[0]);
    }
  }

  return node.range ? node.range[0] : node.start;
}

  const end = node.range ? node.range[1] : node.end;
  return node.typeAnnotation ? Math.max(end, locEnd(node.typeAnnotation)) : end;
}

function hasSameLocStart(nodeA, nodeB) {
  return locStart(nodeA) === locStart(nodeB);
}

function hasSameLocEnd(nodeA, nodeB) {
  return locEnd(nodeA) === locEnd(nodeB);
}

function hasSameLoc(nodeA, nodeB) {
  return hasSameLocStart(nodeA, nodeB) && hasSameLocEnd(nodeA, nodeB);
}

      return node.elements.length === 0
        ? "[]"
        : [
            "[",
            indent([
              hardline,
              join([",", hardline], path.map(print, "elements")),
            ]),
            hardline,
            "]",
          ];
      return node.properties.length === 0
        ? "{}"
        : [
            "{",
            indent([
              hardline,
              join([",", hardline], path.map(print, "properties")),
            ]),
            hardline,
            "}",
          ];
      return [
        node.operator === "+" ? "" : node.operator,
      ];
    case "NullLiteral":
    case "BooleanLiteral":
      return node.value ? "true" : "false";
      return JSON.stringify(node.value);
      return JSON.stringify(node.name);
    default:
      throw new Error("unknown type: " + JSON.stringify(node.type));
  }
}

function clean(node, newNode /*, parent*/) {
  const { type } = node;
  if (type === "Identifier") {
    return { type: "StringLiteral", value: node.name };
  }
  if (type === "UnaryExpression" && node.operator === "+") {
    return newNode.argument;
  }
}

function isFlowFile(text, options) {
  if (options.filepath && options.filepath.endsWith(".js.flow")) {
  }

    text = text.slice(shebang.length);
  }

  const firstNonSpaceNonCommentCharacterIndex = getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
    text,
    0
  );

  if (firstNonSpaceNonCommentCharacterIndex !== false) {
    text = text.slice(0, firstNonSpaceNonCommentCharacterIndex);
  }

  return FLOW_PRAGMA_REGEX.test(text);
}

function parseWithOptions(parseMethod, text, options) {
  /** @type {import("@babel/parser").parse | import("@babel/parser").parseExpression} */
  const parse = require("@babel/parser")[parseMethod];
  const ast = parse(text, options);
  const error = ast.errors.find((error) => shouldRethrowRecoveredError(error));
  }
}

  // babel error prints (l:c) with cols that are zero indexed
  // so we need our custom error
  const { message, loc } = error;

  return createError(message.replace(/ \(.*\)/, ""), {
    start: {
      line: loc ? loc.line : 0,
      column: loc ? loc.column + 1 : 0,
    },
  });
}

function createParse(parseMethod, ...pluginCombinations) {
  const commonPlugins = parseOptions.plugins;
  pluginCombinations =
    pluginCombinations.length > 0
      ? pluginCombinations.map((plugins) => [...commonPlugins, ...plugins])
      : [commonPlugins];

  return (text, parsers, opts = {}) => {
    if (opts.parser === "babel" && isFlowFile(text, opts)) {
      opts.parser = "babel-flow";
      return parseFlow(text, parsers, opts);
    }

    let combinations = pluginCombinations;
    if (text.includes("|>")) {
      combinations = flatten(
        pipelineOperatorPlugins.map((pipelineOperatorPlugin) =>
          combinations.map((plugins) => [...plugins, pipelineOperatorPlugin])
        )
      );
    }

    const sourceType =
      opts.__babelSourceType === "script" ? "script" : "module";
    const { result: ast, error } = tryCombinations(
      ...combinations.map((plugins) => () =>
        parseWithOptions(parseMethod, text, {
          ...parseOptions,
          sourceType,
          plugins,
        })
      )
    );

    if (!ast) {
      throw createParseError(error);
    }

    return postprocess(ast, { ...opts, originalText: text });
  };
}

function shouldRethrowRecoveredError(error) {
  const [, message] = error.message.match(/(.*?)\s*\(\d+:\d+\)/);
  // Only works for literal message
  return messagesShouldThrow.has(message);
}

function parseJson(text, parsers, opts) {
  const ast = parseExpression(text, parsers, opts);

  for (const comment of ast.comments) {
    assertJsonNode(comment);
  }
  assertJsonNode(ast);

}

function assertJsonNode(node, parent) {
      for (const element of node.elements) {
        assertJsonChildNode(element);
      }
      return;
      for (const property of node.properties) {
        assertJsonChildNode(property);
      }
      return;
      if (node.computed) {
        throw createJsonError("computed");
      }

      if (node.shorthand) {
        throw createJsonError("shorthand");
      }

      assertJsonChildNode(node.key);
      assertJsonChildNode(node.value);
      return;
      switch (node.operator) {
        case "+":
        case "-":
          return assertJsonChildNode(node.argument);
        default:
          throw createJsonError("operator");
      }
      if (parent && parent.type === "ObjectProperty" && parent.key === node) {
        return;
      }
      throw createJsonError();
      return;
    default:
  }

  function assertJsonChildNode(child) {
    return assertJsonNode(child, node);
  }

  function createJsonError(attribute) {
    const name = !attribute
      ? node.type
      : `${node.type} with ${attribute}=${JSON.stringify(node[attribute])}`;
    return createError(`${name} is not allowed in JSON.`, {
      start: {
        line: node.loc.start.line,
        column: node.loc.start.column + 1,
      },
    });
  }
}

function assertJsonChildNode(child) {
  }

function createJsonError(attribute) {
      start: {
      },
    });
  }

function createParser(_parse) {
  const parse = (text, parsers, options) => {
    const ngEstreeParser = require("angular-estree-parser");
    const node = _parse(text, ngEstreeParser);
    return {
      type: "NGRoot",
      node:
        options.parser === "__ng_action" && node.type !== "NGChainedExpression"
          ? { ...node, type: "NGChainedExpression", expressions: [node] }
          : node,
    };
  };
  return { astFormat: "estree", parse, locStart, locEnd };
}

(text, parsers, options) => {
    return {
      node:
          : node,
    };
  }

      return {
        ...ast,
        node: ast,
        comments: [],
        rootMarker: options.rootMarker,
      };
    default:
  }
}

  if (isLineComment(comment)) {
    // Supports `//`, `#!`, `<!--`, and `-->`
    return options.originalText
      .slice(locStart(comment), locEnd(comment))
      .trimEnd();
  }

  if (isBlockComment(comment)) {
    if (isIndentableBlockComment(comment)) {
      const printed = printIndentableBlockComment(comment);
      // We need to prevent an edge case of a previous trailing comment
      // printed as a `lineSuffix` which causes the comments to be
      // interleaved. See https://github.com/prettier/prettier/issues/4412
      if (
        comment.trailing &&
        !hasNewline(options.originalText, locStart(comment), {
        })
      ) {
        return [hardline, printed];
      }
    }

    const commentEnd = locEnd(comment);
    const isInsideFlowComment =
      options.originalText.slice(commentEnd - 3, commentEnd) === "*-/";
    return "/*" + comment.value + (isInsideFlowComment ? "*-/" : "*/");
  }

}

function isIndentableBlockComment(comment) {
  // If the comment has multiple lines and every line starts with a star
  // we can fix the indentation of each line. The stars in the `/*` and
  // `*/` delimiters are not included in the comment value, so add them
  // back first.
  const lines = `*${comment.value}*`.split("\n");
  return lines.length > 1 && lines.every((line) => line.trim()[0] === "*");
}

function printIndentableBlockComment(comment) {
  const lines = comment.value.split("\n");

  return [
    "/*",
    join(
      hardline,
      lines.map((line, index) =>
        index === 0
          ? line.trimEnd()
          : " " + (index < lines.length - 1 ? line.trim() : line.trimStart())
      )
    ),
    "*/",
  ];
}

function printFunctionDeclaration(path, print, options, expandArg) {

  // For TypeScript the TSDeclareFunction node shares the AST
  // structure with FunctionDeclaration
  if (n.type === "TSDeclareFunction" && n.declare) {
  }

  if (n.async) {
  }

  if (n.generator) {
    parts.push("function* ");
  } else {
    parts.push("function ");
  }

  if (n.id) {
    parts.push(path.call(print, "id"));
  }

    printFunctionTypeParameters(path, options, print),
    group([
      printFunctionParameters(path, print, options, expandArg),
      printReturnType(path, print, options),
    ]),
    n.body ? " " : "",
  );

  if (options.semi && (n.declare || !n.body)) {
  }

}

  const { kind } = node;
  const value = node.value || node;

    if (value.async) {
    }
  } else {

  }

  // A `getter`/`setter` can't be a generator, but it's recoverable
  if (value.generator) {
  }

    printPropertyKey(path, options, print),
    node.optional || node.key.optional ? "?" : ""
  );

  if (node === value) {
    parts.push(printMethodInternal(path, options, print));
  } else if (value.type === "FunctionExpression") {
      path.call((path) => printMethodInternal(path, options, print), "value")
    );
  } else {
  }

}

function printMethodInternal(path, options, print) {
    group([
      printFunctionParameters(path, print, options),
    ]),
  ];

  if (path.getNode().body) {
  } else {
    parts.push(options.semi ? ";" : "");
  }

}

function printArrowFunctionExpression(path, options, print, args) {

  }

  if (shouldPrintParamsWithoutParens(path, options)) {
    parts.push(path.call(print, "params", 0));
  } else {
      group([
        printFunctionParameters(
          path,
          print,
          options,
          /* expandLast */ args && (args.expandLastArg || args.expandFirstArg),
          /* printTypeParams */ true
        ),
        printReturnType(path, print, options),
      ])
    );
  }

  const dangling = printDanglingComments(
    path,
    options,
    /* sameIndent */ true,
    (comment) => {
      const nextCharacter = getNextNonSpaceNonCommentCharacterIndex(
        comment,
        locEnd
      );
      return (
        nextCharacter !== false &&
        options.originalText.slice(nextCharacter, nextCharacter + 2) === "=>"
      );
    }
  );
  if (dangling) {
    parts.push(" ", dangling);
  }

  parts.push(" =>");

  const body = path.call((bodyPath) => print(bodyPath, args), "body");

  // We want to always keep these types of nodes on the same line
  // as the arrow.
  if (
    !hasLeadingOwnLineComment(options.originalText, n.body) &&
    (n.body.type === "ArrayExpression" ||
      n.body.type === "ObjectExpression" ||
      n.body.type === "BlockStatement" ||
      isJsxNode(n.body) ||
      isTemplateOnItsOwnLine(n.body, options.originalText) ||
      n.body.type === "ArrowFunctionExpression" ||
      n.body.type === "DoExpression")
  ) {
    return group([...parts, " ", body]);
  }

  // We handle sequence expressions as the body of arrows specially,
  // so that the required parentheses end up on their own lines.
  if (n.body.type === "SequenceExpression") {
    return group([
      ...parts,
      group([" (", indent([softline, body]), softline, ")"]),
    ]);
  }

  // if the arrow function is expanded as last argument, we are adding a
  // level of indentation and need to add a softline to align the closing )
  // with the opening (, or if it's inside a JSXExpression (e.g. an attribute)
  // we should align the expression's closing } with the line with the opening {.
  const shouldAddSoftLine =
    ((args && args.expandLastArg) ||
      path.getParentNode().type === "JSXExpressionContainer") &&
    !hasComment(n);

  const printTrailingComma =
    args && args.expandLastArg && shouldPrintComma(options, "all");

  // In order to avoid confusion between
  // a => a ? a : a
  // a <= a ? a : a
  const shouldAddParens =
    n.body.type === "ConditionalExpression" &&
    !startsWithNoLookaheadToken(n.body, /* forbidFunctionAndClass */ false);

    ...parts,
    group([
      indent([
        line,
        shouldAddParens ? ifBreak("", "(") : "",
        body,
        shouldAddParens ? ifBreak("", ")") : "",
      ]),
      shouldAddSoftLine
        ? [ifBreak(printTrailingComma ? "," : ""), softline]
        : "",
    ]),
  ]);
}

function canPrintParamsWithoutParens(node) {
  return (
    parameters.length === 1 &&
    !node.typeParameters &&
    !hasComment(node, CommentCheckFlags.Dangling) &&
    parameters[0].type === "Identifier" &&
    !parameters[0].typeAnnotation &&
    !hasComment(parameters[0]) &&
    !parameters[0].optional &&
    !node.predicate &&
    !node.returnType
  );
}

function shouldPrintParamsWithoutParens(path, options) {
  if (options.arrowParens === "always") {
  }

  if (options.arrowParens === "avoid") {
    return canPrintParamsWithoutParens(node);
  }

  // Fallback default; should be unreachable
}

function printReturnType(path, print, options) {
  const returnType = path.call(print, "returnType");

  if (
    n.returnType &&
    isFlowAnnotationComment(options.originalText, n.returnType)
  ) {
    return [" /*: ", returnType, " */"];
  }

  const parts = [returnType];

  // prepend colon to TypeScript type annotation
  if (n.returnType && n.returnType.typeAnnotation) {
    parts.unshift(": ");
  }

  }

}

function printReturnAndThrowArgument(path, options, print) {

    if (returnArgumentHasLeadingComment(options, node.argument)) {
      parts.push([
        " (",
        indent([hardline, path.call(print, "argument")]),
        hardline,
        ")",
      ]);
    } else if (
      isBinaryish(node.argument) ||
      node.argument.type === "SequenceExpression"
    ) {
        group([
          ifBreak(" (", " "),
          indent([softline, path.call(print, "argument")]),
          softline,
          ifBreak(")"),
        ])
      );
    } else {
    }
  }

  const comments = getComments(node);
  const lastComment = comments[comments.length - 1];
  const isLastCommentLine = lastComment && isLineComment(lastComment);

  if (isLastCommentLine) {
    parts.push(semi);
  }

  if (hasComment(node, CommentCheckFlags.Dangling)) {
      " ",
      printDanglingComments(path, options, /* sameIndent */ true)
    );
  }

  if (!isLastCommentLine) {
  }

}

function printReturnStatement(path, options, print) {
  return ["return", printReturnAndThrowArgument(path, options, print)];
}

function printThrowStatement(path, options, print) {
  return ["throw", printReturnAndThrowArgument(path, options, print)];
}

function printFlow(path, options, print) {
    case "DeclareClass":
      return printFlowDeclaration(path, printClass(path, options, print));
    case "DeclareFunction":
      return printFlowDeclaration(path, [
        "function ",
        n.predicate ? " " : "",
        path.call(print, "predicate"),
        semi,
      ]);
    case "DeclareModule":
        "module ",
        " ",
        path.call(print, "body"),
      ]);
    case "DeclareModuleExports":
        "module.exports",
        ": ",
        semi,
      ]);
    case "DeclareVariable":
      return printFlowDeclaration(path, ["var ", path.call(print, "id"), semi]);
    case "DeclareOpaqueType":
      return printFlowDeclaration(path, printOpaqueType(path, options, print));
    case "DeclareInterface":
      return printFlowDeclaration(path, printInterface(path, options, print));
    case "DeclareTypeAlias":
      return printFlowDeclaration(path, printTypeAlias(path, options, print));
    case "DeclareExportDeclaration":
      return printFlowDeclaration(
        path,
        printExportDeclaration(path, options, print)
      );
    case "DeclareExportAllDeclaration":
        path,
        printExportAllDeclaration(path, options, print)
      );
    case "OpaqueType":
      return printOpaqueType(path, options, print);
    case "TypeAlias":
      return printTypeAlias(path, options, print);
      return printIntersectionType(path, options, print);
      return printUnionType(path, options, print);
    case "FunctionTypeAnnotation":
      return printFunctionType(path, options, print);
    case "TupleTypeAnnotation":
      return printTupleType(path, options, print);
    case "GenericTypeAnnotation":
      return [
        printTypeParameters(path, options, print, "typeParameters"),
      ];
    // Type Annotations for Facebook Flow, typically stripped out or
    // transformed away before printing.
      return path.call(print, "typeAnnotation");
  }
}

function printFlowDeclaration(path, printed) {

  }

  // If the parent node has type DeclareExportDeclaration, then it
  // will be responsible for printing the "declare" token. Otherwise
  // it needs to be printed with this non-exported declaration node.
  return ["declare ", printed];
}

function printMemberExpression(path, options, print) {

  let firstNonMemberParent;
  let i = 0;
  do {
    firstNonMemberParent = path.getParentNode(i);
    i++;
  } while (
    firstNonMemberParent &&
    (isMemberExpression(firstNonMemberParent) ||
      firstNonMemberParent.type === "TSNonNullExpression")
  );

  const shouldInline =
    (firstNonMemberParent &&
      (firstNonMemberParent.type === "NewExpression" ||
        firstNonMemberParent.type === "BindExpression" ||
        (firstNonMemberParent.type === "VariableDeclarator" &&
          firstNonMemberParent.id.type !== "Identifier") ||
        (firstNonMemberParent.type === "AssignmentExpression" &&
          firstNonMemberParent.left.type !== "Identifier"))) ||
    n.computed ||
    (n.object.type === "Identifier" &&
      n.property.type === "Identifier" &&
      !isMemberExpression(parent));

  return [
    path.call(print, "object"),
    shouldInline
      ? printMemberLookup(path, options, print)
      : group(indent([softline, printMemberLookup(path, options, print)])),
  ];
}

function printMemberLookup(path, options, print) {
  const optional = printOptionalToken(path);

  if (!n.computed) {
    return [optional, ".", property];
  }

  if (!n.property || isNumericLiteral(n.property)) {
    return [optional, "[", property, "]"];
  }

  return group([optional, "[", indent([softline, property]), softline, "]"]);
}

function printAngular(path, options, print) {
    case "NGRoot":
      return [
        path.call(print, "node"),
        !hasComment(n.node)
          ? ""
          : " //" + getComments(n.node)[0].value.trimEnd(),
      ];
    case "NGChainedExpression":
        join(
          [";", line],
          path.map(
            (childPath) =>
              hasNgSideEffect(childPath)
                ? print(childPath)
                : ["(", print(childPath), ")"],
            "expressions"
          )
        )
      );
    case "NGEmptyExpression":
      return "";
    case "NGQuotedExpression":
      return [n.prefix, ": ", n.value.trim()];
    case "NGMicrosyntax":
      return path.map(
        (childPath, index) => [
          index === 0
            ? ""
            : isNgForOf(childPath.getValue(), index, n)
            ? " "
            : [";", line],
          print(childPath),
        ],
        "body"
      );
    case "NGMicrosyntaxKey":
      return /^[$_a-z][\w$]*(-[$_a-z][\w$])*$/i.test(n.name)
        ? n.name
        : JSON.stringify(n.name);
    case "NGMicrosyntaxExpression":
      return [
        n.alias === null ? "" : [" as ", path.call(print, "alias")],
      ];
    case "NGMicrosyntaxKeyedExpression": {
      const index = path.getName();
      const shouldNotPrintColon =
        isNgForOf(n, index, parentNode) ||
        (((index === 1 && (n.key.name === "then" || n.key.name === "else")) ||
          (index === 2 &&
            n.key.name === "else" &&
            parentNode.body[index - 1].type ===
              "NGMicrosyntaxKeyedExpression" &&
            parentNode.body[index - 1].key.name === "then")) &&
          parentNode.body[0].type === "NGMicrosyntaxExpression");
      return [
        shouldNotPrintColon ? " " : ": ",
      ];
    }
    case "NGMicrosyntaxLet":
      return [
        "let ",
        n.value === null ? "" : [" = ", path.call(print, "value")],
      ];
    case "NGMicrosyntaxAs":
      return [path.call(print, "key"), " as ", path.call(print, "alias")];
  }
}

function isNgForOf(node, index, parentNode) {
  return (
    node.type === "NGMicrosyntaxKeyedExpression" &&
    node.key.name === "of" &&
    index === 1 &&
    parentNode.body[0].type === "NGMicrosyntaxLet" &&
    parentNode.body[0].value === null
  );
}

function hasNgSideEffect(path) {
  return hasNode(path.getValue(), (node) => {
      case undefined:
      case "CallExpression":
      case "OptionalCallExpression":
      case "AssignmentExpression":
    }
  });
}

function printMemberChain(path, options, print) {
  const isExpressionStatement =
    !parent || parent.type === "ExpressionStatement";

  // The first phase is to linearize the AST by traversing it down.
  //
  //   a().b()
  // has the following AST structure:
  //   CallExpression(MemberExpression(CallExpression(Identifier)))
  // and we transform it into
  //   [Identifier, CallExpression, MemberExpression, CallExpression]
  const printedNodes = [];

  // Here we try to retain one typed empty line after each call expression or
  // the first group whether it is in parentheses or not
  function shouldInsertEmptyLineAfter(node) {
    const { originalText } = options;
    const nextCharIndex = getNextNonSpaceNonCommentCharacterIndex(
      node,
      locEnd
    );
    const nextChar = originalText.charAt(nextCharIndex);

    // if it is cut off by a parenthesis, we only account for one typed empty
    // line after that parenthesis
    if (nextChar === ")") {
      return (
        nextCharIndex !== false &&
        isNextLineEmptyAfterIndex(originalText, nextCharIndex + 1)
      );
    }

    return isNextLineEmpty(node, options);
  }

  function rec(path) {
    if (
      isCallExpression(node) &&
      (isMemberish(node.callee) || isCallExpression(node.callee))
    ) {
      printedNodes.unshift({
        node,
        printed: [
          printComments(
            path,
            () => [
              printOptionalToken(path),
              printFunctionTypeParameters(path, options, print),
              printCallArguments(path, options, print),
            ],
            options
          ),
          shouldInsertEmptyLineAfter(node) ? hardline : "",
        ],
      });
      path.call((callee) => rec(callee), "callee");
    } else if (isMemberish(node)) {
        node,
        needsParens: pathNeedsParens(path, options),
        printed: printComments(
          path,
          () =>
            isMemberExpression(node)
              ? printMemberLookup(path, options, print)
              : printBindExpressionCallee(path, options, print),
          options
        ),
      });
      path.call((object) => rec(object), "object");
    } else if (node.type === "TSNonNullExpression") {
        node,
        printed: printComments(path, () => "!", options),
      });
      path.call((expression) => rec(expression), "expression");
    } else {
        node,
        printed: path.call(print),
      });
    }
  }
  // Note: the comments of the root node have already been printed, so we
  // need to extract this first call without printing them as they would
  // if handled inside of the recursive call.
  printedNodes.unshift({
    node,
    printed: [
      printOptionalToken(path),
      printFunctionTypeParameters(path, options, print),
      printCallArguments(path, options, print),
    ],
  });

    path.call((callee) => rec(callee), "callee");
  }

  // Once we have a linear list of printed nodes, we want to create groups out
  // of it.
  //
  //   a().b.c().d().e
  // will be grouped as
  //   [
  //     [Identifier, CallExpression],
  //     [MemberExpression, MemberExpression, CallExpression],
  //     [MemberExpression, CallExpression],
  //     [MemberExpression],
  //   ]
  // so that we can print it as
  //   a()
  //     .b.c()
  //     .d()
  //     .e

  // The first group is the first node followed by
  //   - as many CallExpression as possible
  //       < fn()()() >.something()
  //   - as many array accessors as possible
  //       < fn()[0][1][2] >.something()
  //   - then, as many MemberExpression as possible but the last one
  //       < this.items >.something()
  const groups = [];
  let currentGroup = [printedNodes[0]];
  let i = 1;
  for (; i < printedNodes.length; ++i) {
    if (
      printedNodes[i].node.type === "TSNonNullExpression" ||
      isCallExpression(printedNodes[i].node) ||
      (isMemberExpression(printedNodes[i].node) &&
        printedNodes[i].node.computed &&
        isNumericLiteral(printedNodes[i].node.property))
    ) {
      currentGroup.push(printedNodes[i]);
    } else {
      break;
    }
  }
  if (!isCallExpression(printedNodes[0].node)) {
    for (; i + 1 < printedNodes.length; ++i) {
      if (
        isMemberish(printedNodes[i].node) &&
        isMemberish(printedNodes[i + 1].node)
      ) {
        currentGroup.push(printedNodes[i]);
      } else {
        break;
      }
    }
  }
  groups.push(currentGroup);
  currentGroup = [];

  // Then, each following group is a sequence of MemberExpression followed by
  // a sequence of CallExpression. To compute it, we keep adding things to the
  // group until we has seen a CallExpression in the past and reach a
  // MemberExpression
  let hasSeenCallExpression = false;
    if (hasSeenCallExpression && isMemberish(printedNodes[i].node)) {
      // [0] should be appended at the end of the group instead of the
      // beginning of the next one
      if (
        isNumericLiteral(printedNodes[i].node.property)
      ) {
        continue;
      }

      groups.push(currentGroup);
      currentGroup = [];
      hasSeenCallExpression = false;
    }

    if (
      printedNodes[i].node.type === "ImportExpression"
    ) {
      hasSeenCallExpression = true;
    }
    currentGroup.push(printedNodes[i]);

    if (hasComment(printedNodes[i].node, CommentCheckFlags.Trailing)) {
    }
  }
  if (currentGroup.length > 0) {
    groups.push(currentGroup);
  }

  // There are cases like Object.keys(), Observable.of(), _.values() where
  // they are the subject of all the chained calls and therefore should
  // be kept on the same line:
  //
  //   Object.keys(items)
  //     .filter(x => x)
  //     .map(x => x)
  //
  // In order to detect those cases, we use an heuristic: if the first
  // node is an identifier with the name starting with a capital
  // letter or just a sequence of _$. The rationale is that they are
  // likely to be factories.
  function isFactory(name) {
    return /^[A-Z]|^[$_]+$/.test(name);
  }

  // In case the Identifier is shorter than tab width, we can keep the
  // first call in a single line, if it's an ExpressionStatement.
  //
  //   d3.scaleLinear()
  //     .domain([0, 100])
  //     .range([0, width]);
  //
  function isShort(name) {
    return name.length <= options.tabWidth;
  }

  function shouldNotWrap(groups) {
    const hasComputed = groups[1].length > 0 && groups[1][0].node.computed;

    if (groups[0].length === 1) {
      const firstNode = groups[0][0].node;
      return (
        firstNode.type === "ThisExpression" ||
        (firstNode.type === "Identifier" &&
          (isFactory(firstNode.name) ||
            (isExpressionStatement && isShort(firstNode.name)) ||
            hasComputed))
      );
    }

    const lastNode = getLast(groups[0]).node;
    return (
      isMemberExpression(lastNode) &&
      lastNode.property.type === "Identifier" &&
      (isFactory(lastNode.property.name) || hasComputed)
    );
  }

  const shouldMerge =
    groups.length >= 2 &&
    !hasComment(groups[1][0].node) &&
    shouldNotWrap(groups);

  function printGroup(printedGroup) {
    const printed = printedGroup.map((tuple) => tuple.printed);
    // Checks if the last node (i.e. the parent node) needs parens and print
    // accordingly
    if (
      printedGroup.length > 0 &&
      printedGroup[printedGroup.length - 1].needsParens
    ) {
      return ["(", ...printed, ")"];
    }
  }

  function printIndentedGroup(groups) {
    if (groups.length === 0) {
      return "";
    }
    return indent(group([hardline, join(hardline, groups.map(printGroup))]));
  }

  const printedGroups = groups.map(printGroup);
  const oneLine = printedGroups;

  const cutoff = shouldMerge ? 3 : 2;
  const flatGroups = flat(groups);

  const nodeHasComment =
    flatGroups
      .slice(1, -1)
      .some((node) => hasComment(node.node, CommentCheckFlags.Leading)) ||
      .slice(0, -1)
      .some((node) => hasComment(node.node, CommentCheckFlags.Trailing)) ||
    (groups[cutoff] &&
      hasComment(groups[cutoff][0].node, CommentCheckFlags.Leading));

  // If we only have a single `.`, we shouldn't do anything fancy and just
  // render everything concatenated together.
  if (groups.length <= cutoff && !nodeHasComment) {
    if (isLongCurriedCallExpression(path)) {
      return oneLine;
    }
    return group(oneLine);
  }

  // Find out the last node in the first group and check if it has an
  // empty line after
  const lastNodeBeforeIndent = getLast(groups[shouldMerge ? 1 : 0]).node;
  const shouldHaveEmptyLineBeforeIndent =
    !isCallExpression(lastNodeBeforeIndent) &&
    shouldInsertEmptyLineAfter(lastNodeBeforeIndent);

  const expanded = [
    printGroup(groups[0]),
    shouldMerge ? groups.slice(1, 2).map(printGroup) : "",
    shouldHaveEmptyLineBeforeIndent ? hardline : "",
    printIndentedGroup(groups.slice(shouldMerge ? 2 : 1)),
  ];

  const callExpressions = printedNodes
    .map(({ node }) => node)
    .filter(isCallExpression);

  function lastGroupWillBreakAndOtherCallsHaveFunctionArguments() {
    const lastGroupNode = getLast(getLast(groups)).node;
    const lastGroupDoc = getLast(printedGroups);
    return (
      isCallExpression(lastGroupNode) &&
      willBreak(lastGroupDoc) &&
      callExpressions
        .slice(0, -1)
        .some((n) => n.arguments.some(isFunctionOrArrowExpression))
    );
  }

  // We don't want to print in one line if at least one of these conditions occurs:
  //  * the chain has comments,
  //  * the chain is an expression statement and all the arguments are literal-like ("fluent configuration" pattern),
  //  * the chain is longer than 2 calls and has non-trivial arguments or more than 2 arguments in any call but the first one,
  //  * any group but the last one has a hard line,
  //  * the last call's arguments have a hard line and other calls have non-trivial arguments.
  if (
    nodeHasComment ||
    (callExpressions.length > 2 &&
      callExpressions.some(
        (expr) => !expr.arguments.every((arg) => isSimpleCallArgument(arg, 0))
      )) ||
    printedGroups.slice(0, -1).some(willBreak) ||
    lastGroupWillBreakAndOtherCallsHaveFunctionArguments()
  ) {
    result = group(expanded);
  } else {
    result = [
      // We only need to check `oneLine` because if `expanded` is chosen
      // that means that the parent group has already been broken
      // naturally
      willBreak(oneLine) || shouldHaveEmptyLineBeforeIndent ? breakParent : "",
      conditionalGroup([oneLine, expanded]),
    ];
  }

  return label("member-chain", result);
}

function shouldInsertEmptyLineAfter(node) {
      node,
      locEnd
    );

      return (
      );
    }

  }

function rec(path) {
    if (
    ) {
        node,
        printed: [
            path,
            () => [
            ],
            options
          ),
        ],
      });
        node,
          path,
          () =>
          options
        ),
      });
        node,
      });
    } else {
        node,
      });
    }
  }

function isFactory(name) {
  }

function isShort(name) {
  }

function shouldNotWrap(groups) {

      return (
      );
    }

    return (
    );
  }

function printGroup(printedGroup) {
    if (
    ) {
    }
  }

function printIndentedGroup(groups) {
      return "";
    }
  }

function lastGroupWillBreakAndOtherCallsHaveFunctionArguments() {
    return (
    );
  }

function printTemplateLiteral(path, print, options) {
  const isTemplateLiteral = node.type === "TemplateLiteral";

  if (
    isTemplateLiteral &&
    isJestEachTemplateLiteral(node, path.getParentNode())
  ) {
    const printed = printJestEachTemplateLiteral(path, options, print);
    if (printed) {
    }
  }
  }

  let expressions = path.map(print, expressionsKey);
  const isSimple = isSimpleTemplateLiteral(node);

  if (isSimple) {
    expressions = expressions.map(
      (doc) =>
        printDocToString(doc, {
          printWidth: Number.POSITIVE_INFINITY,
        }).formatted
    );
  }

  parts.push(lineSuffixBoundary, "`");

  path.each((childPath) => {
    const i = childPath.getName();

    parts.push(print(childPath));

    if (i < expressions.length) {
      // For a template literal of the following form:
      //   `someQuery {
      //     ${call({
      //       a,
      //       b,
      //     })}
      //   }`
      // the expression is on its own line (there is a \n in the previous
      // quasi literal), therefore we want to indent the JavaScript
      // expression inside at the beginning of ${ instead of the beginning
      // of the `.
      const { tabWidth } = options;
      const quasi = childPath.getValue();
      const indentSize = getIndentSize(quasi.value.raw, tabWidth);

      let printed = expressions[i];

      if (!isSimple) {
        const expression = node[expressionsKey][i];
        // Breaks at the template element boundaries (${ and }) are preferred to breaking
        // in the middle of a MemberExpression
        if (
          hasComment(expression) ||
          isMemberExpression(expression) ||
          expression.type === "ConditionalExpression" ||
          expression.type === "SequenceExpression" ||
          expression.type === "TSAsExpression" ||
          isBinaryish(expression)
        ) {
          printed = [indent([softline, printed]), softline];
        }
      }

      const aligned =
        indentSize === 0 && quasi.value.raw.endsWith("\n")
          ? align(Number.NEGATIVE_INFINITY, printed)
          : addAlignmentToDoc(printed, indentSize, tabWidth);

      parts.push(group(["${", aligned, lineSuffixBoundary, "}"]));
    }
  }, "quasis");

  parts.push("`");

}

function printJestEachTemplateLiteral(path, options, print) {
  /**
   * a    | b    | expected
   * ${1} | ${1} | ${2}
   * ${1} | ${2} | ${3}
   * ${2} | ${1} | ${3}
   */
  const headerNames = node.quasis[0].value.raw.trim().split(/\s*\|\s*/);
  if (
    headerNames.length > 1 ||
    headerNames.some((headerName) => headerName.length > 0)
  ) {
    options.__inJestEach = true;
    const expressions = path.map(print, "expressions");
    options.__inJestEach = false;
    const stringifiedExpressions = expressions.map(
      (doc) =>
        "${" +
          endOfLine: "lf",
        }).formatted +
        "}"
    );

    const tableBody = [{ hasLineBreak: false, cells: [] }];
    for (let i = 1; i < node.quasis.length; i++) {
      const row = tableBody[tableBody.length - 1];
      const correspondingExpression = stringifiedExpressions[i - 1];

      row.cells.push(correspondingExpression);
      if (correspondingExpression.includes("\n")) {
        row.hasLineBreak = true;
      }

      if (node.quasis[i].value.raw.includes("\n")) {
        tableBody.push({ hasLineBreak: false, cells: [] });
      }
    }

    const maxColumnCount = Math.max(
      headerNames.length,
      ...tableBody.map((row) => row.cells.length)
    );

    const maxColumnWidths = Array.from({ length: maxColumnCount }).fill(0);
    const table = [
      { cells: headerNames },
      ...tableBody.filter((row) => row.cells.length > 0),
    ];
    for (const { cells } of table.filter((row) => !row.hasLineBreak)) {
      for (const [index, cell] of cells.entries()) {
        maxColumnWidths[index] = Math.max(
          maxColumnWidths[index],
          getStringWidth(cell)
        );
      }
    }

      lineSuffixBoundary,
      "`",
      indent([
        hardline,
        join(
          hardline,
          table.map((row) =>
            join(
              " | ",
              row.cells.map((cell, index) =>
                row.hasLineBreak
                  ? cell
                  : cell +
                    " ".repeat(maxColumnWidths[index] - getStringWidth(cell))
              )
            )
          )
        ),
      ]),
      hardline,
      "`"
    );
    return parts;
  }
}

function printTemplateExpression(path, print) {
  let printed = print(path);
  if (hasComment(node)) {
    printed = group([indent([softline, printed]), softline]);
  }
  return ["${", printed, lineSuffixBoundary, "}"];
}

function printTemplateExpressions(path, print) {
  return path.map(
    (path) => printTemplateExpression(path, print),
    "expressions"
  );
}

function escapeTemplateCharacters(doc, raw) {
  return mapDoc(doc, (currentDoc) => {
    if (typeof currentDoc === "string") {
      return raw
        ? currentDoc.replace(/(\\*)`/g, "$1$1\\`")
        : uncookTemplateElementValue(currentDoc);
    }

    return currentDoc;
  });
}

function uncookTemplateElementValue(cookedValue) {
  return cookedValue.replace(/([\\`]|\${)/g, "\\$1");
}

function printTypescript(path, options, print) {
    case "TSTypeAssertion": {
      const shouldBreakAfterCast = !(
        n.expression.type === "ArrayExpression" ||
        n.expression.type === "ObjectExpression"
      );

      const castGroup = group([
        "<",
        indent([softline, path.call(print, "typeAnnotation")]),
        softline,
        ">",
      ]);

      const exprContents = [
        ifBreak("("),
        softline,
        ifBreak(")"),
      ];

      if (shouldBreakAfterCast) {
        return conditionalGroup([
          [castGroup, path.call(print, "expression")],
          [castGroup, group(exprContents, { shouldBreak: true })],
        ]);
      }
      return group([castGroup, path.call(print, "expression")]);
    }
    case "TSDeclareFunction":
      return printFunctionDeclaration(path, print, options);
    case "TSExportAssignment":
      return ["export = ", path.call(print, "expression"), semi];
    case "TSModuleBlock":
    case "TSInterfaceBody":
    case "TSTypeLiteral":
    case "TSTypeAliasDeclaration": {
      if (n.declare) {
      }

      const printed = printAssignmentRight(
        n.id,
        n.typeAnnotation,
        n.typeAnnotation && path.call(print, "typeAnnotation"),
        options
      );

        "type ",
        " =",
        printed,
        semi
      );

    }
    case "TSQualifiedName":
      return join(".", [path.call(print, "left"), path.call(print, "right")]);
    case "TSAbstractMethodDefinition":
    case "TSDeclareMethod":
    case "TSAbstractClassProperty":
    case "TSInterfaceHeritage":
    case "TSExpressionWithTypeArguments": // Babel AST
      parts.push(path.call(print, "expression"));

      if (n.typeParameters) {
        parts.push(path.call(print, "typeParameters"));
      }

    case "TSTemplateLiteralType":
    case "TSNamedTupleMember":
      return [
        path.call(print, "label"),
        n.optional ? "?" : "",
        ": ",
        path.call(print, "elementType"),
      ];
    case "TSRestType":
      return ["...", path.call(print, "typeAnnotation")];
    case "TSOptionalType":
      return [path.call(print, "typeAnnotation"), "?"];
    case "TSInterfaceDeclaration":
    case "TSClassImplements":
      return [
      ];
    case "TSTypeParameterDeclaration":
    case "TSTypeParameterInstantiation":
      return printTypeParameters(path, options, print, "params");

    case "TSTypeParameter":
    case "TypeParameter":
      return printTypeParameter(path, options, print);
    case "TypeofTypeAnnotation":
      return ["typeof ", path.call(print, "argument")];
    case "TSAbstractKeyword":
      return "abstract";
    case "TSAsyncKeyword":
      return "async";
    case "TSDeclareKeyword":
      return "declare";
    case "TSExportKeyword":
      return "export";
    case "TSNeverKeyword":
      return "never";
    case "TSObjectKeyword":
      return "object";
    case "TSProtectedKeyword":
      return "protected";
    case "TSPrivateKeyword":
      return "private";
    case "TSPublicKeyword":
      return "public";
    case "TSReadonlyKeyword":
      return "readonly";
    case "TSStaticKeyword":
      return "static";
    case "TSUndefinedKeyword":
    case "TSUnknownKeyword":
      return "unknown";
      return [
        " as ",
      ];
    case "TSArrayType":
    case "TSPropertySignature": {
      if (n.export) {
        parts.push("export ");
      }
      if (n.accessibility) {
        parts.push(n.accessibility + " ");
      }
      }
      if (n.readonly) {
        parts.push("readonly ");
      }

        printOptionalToken(path)
      );

      if (n.typeAnnotation) {
        parts.push(": ", path.call(print, "typeAnnotation"));
      }

      // This isn't valid semantically, but it's in the AST so we can print it.
      if (n.initializer) {
        parts.push(" = ", path.call(print, "initializer"));
      }

    }
    case "TSParameterProperty":
      }
      }
      }
      }

      parts.push(path.call(print, "parameter"));

    case "TSTypeQuery":
      return ["typeof ", path.call(print, "exprName")];
    case "TSIndexSignature": {

      // The typescript parser accepts multiple parameters here. If you're
      // using them, it makes sense to have a trailing comma. But if you
      // aren't, this is more like a computed property name than an array.
      // So we leave off the trailing comma when there's just one parameter.
      const trailingComma =
        n.parameters.length > 1
          ? ifBreak(shouldPrintComma(options) ? "," : "")
          : "";

      const parametersGroup = group([
        indent([
          softline,
          join([", ", softline], path.map(print, "parameters")),
        ]),
        trailingComma,
        softline,
      ]);

      return [
        n.export ? "export " : "",
        n.accessibility ? [n.accessibility, " "] : "",
        n.readonly ? "readonly " : "",
        "[",
        n.parameters ? parametersGroup : "",
        n.typeAnnotation ? "]: " : "]",
        n.typeAnnotation ? path.call(print, "typeAnnotation") : "",
        parent.type === "ClassBody" ? semi : "",
      ];
    }
    case "TSTypePredicate":
      return [
        n.asserts ? "asserts " : "",
        path.call(print, "parameterName"),
        n.typeAnnotation ? [" is ", path.call(print, "typeAnnotation")] : "",
      ];
      return [path.call(print, "expression"), "!"];
    case "TSImportType":
      return [
        !n.isTypeOf ? "" : "typeof ",
        "import(",
        path.call(print, n.parameter ? "parameter" : "argument"),
        ")",
        !n.qualifier ? "" : [".", path.call(print, "qualifier")],
      ];
    case "TSLiteralType":
      return path.call(print, "literal");
    case "TSIndexedAccessType":
      return [
        path.call(print, "objectType"),
        "[",
        path.call(print, "indexType"),
        "]",
      ];
    case "TSConstructSignatureDeclaration":
    case "TSCallSignatureDeclaration":
    case "TSConstructorType": {
      if (n.type !== "TSCallSignatureDeclaration") {
        parts.push("new ");
      }

        group(
          printFunctionParameters(
            path,
            print,
            options,
            /* expandArg */ false,
            /* printTypeParams */ true
          )
        )
      );

      if (n.returnType || n.typeAnnotation) {
        const isType = n.type === "TSConstructorType";
          isType ? " => " : ": ",
          path.call(print, "returnType"),
        );
      }
    }
      return [n.operator, " ", path.call(print, "typeAnnotation")];
    case "TSMappedType": {
      const shouldBreak = hasNewlineInRange(
        locStart(n),
        locEnd(n)
      );
        [
          "{",
          indent([
            n.readonly
              ? [getTypeScriptMappedTypeModifier(n.readonly, "readonly"), " "]
              : "",
            printTypeScriptModifiers(path, options, print),
            path.call(print, "typeParameter"),
            n.optional ? getTypeScriptMappedTypeModifier(n.optional, "?") : "",
            n.typeAnnotation ? ": " : "",
            path.call(print, "typeAnnotation"),
            ifBreak(semi),
          ]),
          printDanglingComments(path, options, /* sameIndent */ true),
          "}",
        ],
        { shouldBreak }
      );
    }
    case "TSMethodSignature":
        group([
          n.accessibility ? [n.accessibility, " "] : "",
          n.export ? "export " : "",
          n.static ? "static " : "",
          n.readonly ? "readonly " : "",
          n.computed ? "[" : "",
          path.call(print, "key"),
          n.computed ? "]" : "",
          printOptionalToken(path),
            path,
            print,
            options,
          ),
        ])
      );

          group([
            ": ",
            path.call(print, "returnType"),
          ])
        );
      }
    case "TSNamespaceExportDeclaration":
      parts.push("export as namespace ", path.call(print, "id"));

      if (options.semi) {
        parts.push(";");
      }

    case "TSEnumDeclaration":
      }

      if (n.modifiers) {
        parts.push(printTypeScriptModifiers(path, options, print));
      }
      if (n.const) {
        parts.push("const ");
      }

      parts.push("enum ", path.call(print, "id"), " ");

      if (n.members.length === 0) {
        );
      } else {
          group([
            "{",
            indent([
              hardline,
              printArrayItems(path, options, "members", print),
              shouldPrintComma(options, "es5") ? "," : "",
            ]),
            hardline,
            "}",
          ])
        );
      }

    case "TSEnumMember":
      }
    case "TSImportEqualsDeclaration":
      if (n.isExport) {
      }
        "import ",
        " = ",
        path.call(print, "moduleReference")
      );

      }

    case "TSExternalModuleReference":
      return ["require(", path.call(print, "expression"), ")"];
    case "TSModuleDeclaration": {
      const isExternalModule = isLiteral(n.id);
      const parentIsDeclaration = parent.type === "TSModuleDeclaration";
      const bodyIsDeclaration = n.body && n.body.type === "TSModuleDeclaration";

      if (parentIsDeclaration) {
        parts.push(".");
      } else {
        if (n.declare) {
          parts.push("declare ");
        }

        const textBetweenNodeAndItsId = options.originalText.slice(
          locStart(n),
          locStart(n.id)
        );

        // Global declaration looks like this:
        // (declare)? global { ... }
        const isGlobalDeclaration =
          n.id.type === "Identifier" &&
          n.id.name === "global" &&
          !/namespace|module/.test(textBetweenNodeAndItsId);

        if (!isGlobalDeclaration) {
            isExternalModule ||
              /(^|\s)module(\s|$)/.test(textBetweenNodeAndItsId)
              ? "module "
              : "namespace "
          );
        }
      }

      if (bodyIsDeclaration) {
        parts.push(path.call(print, "body"));
      } else if (n.body) {
        parts.push(" ", group(path.call(print, "body")));
      } else {
      }

    }
    // TODO: Temporary auto-generated node type. To remove when typescript-estree has proper support for private fields.
    case "TSPrivateIdentifier":
      return n.escapedText;

      return ["infer", " ", path.call(print, "typeParameter")];
    case "TSTupleType":
    case "TSTypeReference":
      return [
        path.call(print, "typeName"),
      ];
    case "TSTypeAnnotation":
    case "TSEmptyBodyFunctionExpression":
      return printMethodInternal(path, options, print);

    // These are not valid TypeScript. Printing them just for the sake of error recovery.
    case "TSJSDocAllType":
    case "TSJSDocUnknownType":
    case "TSJSDocNullableType":
    case "TSJSDocNonNullableType":
      return ["!", path.call(print, "typeAnnotation")];
      return [
        "function(",
        // The parameters could be here, but typescript-estree doesn't convert them anyway (throws an error).
        "): ",
      ];
  }
}

function printInterface(path, options, print) {
  if (n.declare) {
  }

  if (n.type === "TSInterfaceDeclaration") {
      n.abstract ? "abstract " : "",
      printTypeScriptModifiers(path, options, print)
    );
  }

  parts.push("interface");

  const partsGroup = [];
  const extendsParts = [];

  if (n.type !== "InterfaceTypeAnnotation") {
    partsGroup.push(
      " ",
    );
  }

  const shouldIndentOnlyHeritageClauses =
    n.typeParameters &&
    !hasComment(
      n.typeParameters,
      CommentCheckFlags.Trailing | CommentCheckFlags.Line
    );

  if (isNonEmptyArray(n.extends)) {
    extendsParts.push(
      shouldIndentOnlyHeritageClauses
        ? ifBreak(" ", line, {
            groupId: getTypeParametersGroupId(n.typeParameters),
          })
        : line,
      "extends ",
      (n.extends.length === 1 ? identity : indent)(
        join([",", line], path.map(print, "extends"))
      )
    );
  }

  if (
    (n.id && hasComment(n.id, CommentCheckFlags.Trailing)) ||
    isNonEmptyArray(n.extends)
  ) {
    if (shouldIndentOnlyHeritageClauses) {
      parts.push(group([...partsGroup, indent(extendsParts)]));
    } else {
      parts.push(group(indent([...partsGroup, ...extendsParts])));
    }
  } else {
    parts.push(...partsGroup, ...extendsParts);
  }

  return group(parts);
}

(doc) =>
  doc === "" || doc === line || doc === hardline || doc === softline

function printJsxElementInternal(path, options, print) {

  if (n.type === "JSXElement" && isEmptyJsxElement(n)) {
    return [
      path.call(print, "openingElement"),
      path.call(print, "closingElement"),
    ];
  }

  const openingLines =
    n.type === "JSXElement"
      ? path.call(print, "openingElement")
      : path.call(print, "openingFragment");
  const closingLines =
      ? path.call(print, "closingElement")
      : path.call(print, "closingFragment");

  if (
    n.children.length === 1 &&
    n.children[0].type === "JSXExpressionContainer" &&
    (n.children[0].expression.type === "TemplateLiteral" ||
      n.children[0].expression.type === "TaggedTemplateExpression")
  ) {
    return [openingLines, ...path.map(print, "children"), closingLines];
  }

  // Convert `{" "}` to text nodes containing a space.
  // This makes it easy to turn them into `jsxWhitespace` which
  // can then print as either a space or `{" "}` when breaking.
  n.children = n.children.map((child) => {
    if (isJsxWhitespaceExpression(child)) {
      return {
        type: "JSXText",
        value: " ",
        raw: " ",
      };
    }
    return child;
  });

  const containsTag = n.children.filter(isJsxNode).length > 0;
  const containsMultipleExpressions =
    n.children.filter((child) => child.type === "JSXExpressionContainer")
      .length > 1;
  const containsMultipleAttributes =
    n.type === "JSXElement" && n.openingElement.attributes.length > 1;

  // Record any breaks. Should never go from true to false, only false to true.
  let forcedBreak =
    willBreak(openingLines) ||
    containsTag ||
    containsMultipleAttributes ||
    containsMultipleExpressions;

  const isMdxBlock = path.getParentNode().rootMarker === "mdx";

  const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}';
  const jsxWhitespace = isMdxBlock
    ? " "
    : ifBreak([rawJsxWhitespace, softline], " ");

  const isFacebookTranslationTag =
    n.openingElement &&
    n.openingElement.name &&
    n.openingElement.name.name === "fbt";

  const children = printJsxChildren(
    path,
    options,
    print,
    jsxWhitespace,
    isFacebookTranslationTag
  );

  const containsText = n.children.some((child) => isMeaningfulJsxText(child));

  // We can end up we multiple whitespace elements with empty string
  // content between them.
  // We need to remove empty whitespace and softlines before JSX whitespace
  // to get the correct output.
  for (let i = children.length - 2; i >= 0; i--) {
    const isPairOfEmptyStrings = children[i] === "" && children[i + 1] === "";
    const isPairOfHardlines =
      children[i] === hardline &&
      children[i + 1] === "" &&
      children[i + 2] === hardline;
    const isLineFollowedByJsxWhitespace =
      (children[i] === softline || children[i] === hardline) &&
      children[i + 2] === jsxWhitespace;
    const isJsxWhitespaceFollowedByLine =
      children[i] === jsxWhitespace &&
      (children[i + 2] === softline || children[i + 2] === hardline);
    const isDoubleJsxWhitespace =
    const isPairOfHardOrSoftLines =
      (children[i] === softline &&
        children[i + 1] === "" &&
        children[i + 2] === hardline) ||
      (children[i] === hardline &&
        children[i + 2] === softline);

    if (
      (isPairOfHardlines && containsText) ||
      isPairOfEmptyStrings ||
      isLineFollowedByJsxWhitespace ||
      isDoubleJsxWhitespace ||
      isPairOfHardOrSoftLines
    ) {
      children.splice(i, 2);
    } else if (isJsxWhitespaceFollowedByLine) {
      children.splice(i + 1, 2);
    }
  }

  // Trim trailing lines (or empty strings)
  while (children.length > 0 && isEmptyStringOrAnyLine(getLast(children))) {
    children.pop();
  }

  // Trim leading lines (or empty strings)
  while (
    children.length > 1 &&
    isEmptyStringOrAnyLine(children[0]) &&
    isEmptyStringOrAnyLine(children[1])
  ) {
    children.shift();
  }

  // Tweak how we format children if outputting this element over multiple lines.
  // Also detect whether we will force this element to output over multiple lines.
  const multilineChildren = [];
  for (const [i, child] of children.entries()) {
    // There are a number of situations where we need to ensure we display
    // whitespace as `{" "}` when outputting this element over multiple lines.
    if (child === jsxWhitespace) {
      if (i === 1 && children[i - 1] === "") {
        if (children.length === 2) {
          // Solitary whitespace
          multilineChildren.push(rawJsxWhitespace);
          continue;
        }
        // Leading whitespace
        multilineChildren.push([rawJsxWhitespace, hardline]);
        continue;
      } else if (i === children.length - 1) {
        // Trailing whitespace
        multilineChildren.push(rawJsxWhitespace);
        continue;
      } else if (children[i - 1] === "" && children[i - 2] === hardline) {
        // Whitespace after line break
        continue;
      }
    }

    multilineChildren.push(child);

    if (willBreak(child)) {
      forcedBreak = true;
    }
  }

  // If there is text we use `fill` to fit as much onto each line as possible.
  // When there is no text (just tags and expressions) we use `group`
  // to output each on a separate line.
  const content = containsText
    ? fill(multilineChildren)
    : group(multilineChildren, { shouldBreak: true });

  if (isMdxBlock) {
    return content;
  }

  const multiLineElem = group([
    openingLines,
    indent([hardline, content]),
    hardline,
    closingLines,
  ]);

  if (forcedBreak) {
    return multiLineElem;
  }

  return conditionalGroup([
    group([openingLines, ...children, closingLines]),
    multiLineElem,
  ]);
}

function printJsxChildren(
  path,
  options,
  print,
  jsxWhitespace,
  isFacebookTranslationTag
) {
  path.each((childPath, i, children) => {
    if (isLiteral(child)) {
      const text = rawText(child);

      // Contains a non-whitespace character
      if (isMeaningfulJsxText(child)) {
        const words = text.split(matchJsxWhitespaceRegex);

        // Starts with whitespace
        if (words[0] === "") {
          parts.push("");
          words.shift();
          if (/\n/.test(words[0])) {
            const next = children[i + 1];
              separatorWithWhitespace(
                isFacebookTranslationTag,
                words[1],
                child,
                next
              )
            );
          } else {
            parts.push(jsxWhitespace);
          }
        }

        let endWhitespace;
        // Ends with whitespace
        if (getLast(words) === "") {
          words.pop();
          endWhitespace = words.pop();
        }

        // This was whitespace only without a new line.
        if (words.length === 0) {
          return;
        }

        for (const [i, word] of words.entries()) {
          if (i % 2 === 1) {
          } else {
            parts.push(word);
          }
        }

        if (endWhitespace !== undefined) {
          if (/\n/.test(endWhitespace)) {
                getLast(parts),
                child,
                next
              )
            );
          } else {
          }
        } else {
          const next = children[i + 1];
            separatorNoWhitespace(
              isFacebookTranslationTag,
              getLast(parts),
              child,
              next
            )
          );
        }
      } else if (/\n/.test(text)) {
        // Keep (up to one) blank line between tags/expressions/text.
        // Note: We don't keep blank lines between text elements.
        if (text.match(/\n/g).length > 1) {
          parts.push("", hardline);
        }
      } else {
        parts.push("", jsxWhitespace);
      }
    } else {
      const printedChild = print(childPath);
      parts.push(printedChild);

      const next = children[i + 1];
      const directlyFollowedByMeaningfulText =
        next && isMeaningfulJsxText(next);
      if (directlyFollowedByMeaningfulText) {
        const firstWord = trimJsxWhitespace(rawText(next)).split(
          matchJsxWhitespaceRegex
        )[0];
          separatorNoWhitespace(
            isFacebookTranslationTag,
            firstWord,
            child,
            next
          )
        );
      } else {
      }
    }

}

function separatorNoWhitespace(
  isFacebookTranslationTag,
  child,
  childNode,
  nextNode
) {
  if (isFacebookTranslationTag) {
    return "";
  }

  if (
    (childNode.type === "JSXElement" && !childNode.closingElement) ||
    (nextNode && nextNode.type === "JSXElement" && !nextNode.closingElement)
  ) {
    return child.length === 1 ? softline : hardline;
  }

  return softline;
}

function separatorWithWhitespace(
  child,
  nextNode
) {
  }

  if (child.length === 1) {
    return (childNode.type === "JSXElement" && !childNode.closingElement) ||
      (nextNode && nextNode.type === "JSXElement" && !nextNode.closingElement)
      ? hardline
  }

  return hardline;
}

function maybeWrapJsxElementInParens(path, elem, options) {
    return elem;
  }

  const NO_WRAP_PARENTS = {
    ArrayExpression: true,
    JSXAttribute: true,
    JSXElement: true,
    JSXExpressionContainer: true,
    JSXFragment: true,
    ExpressionStatement: true,
    CallExpression: true,
    OptionalCallExpression: true,
    ConditionalExpression: true,
    JsExpressionRoot: true,
  };
  if (NO_WRAP_PARENTS[parent.type]) {
  }

  const shouldBreak = path.match(
    undefined,
    (node) => node.type === "ArrowFunctionExpression",
    isCallExpression,
    (node) => node.type === "JSXExpressionContainer"
  );

  const needsParens = pathNeedsParens(path, options);

    [
      needsParens ? "" : ifBreak("("),
      indent([softline, elem]),
      softline,
      needsParens ? "" : ifBreak(")"),
    ],
    { shouldBreak }
  );
}

function printJsxAttribute(path, options, print) {
  parts.push(path.call(print, "name"));

  if (n.value) {
    let res;
    if (isStringLiteral(n.value)) {
      const raw = rawText(n.value);
      // Unescape all quotes so we get an accurate preferred quote
      let final = raw.replace(/&apos;/g, "'").replace(/&quot;/g, '"');
      const quote = getPreferredQuote(
        final,
        options.jsxSingleQuote ? "'" : '"'
      );
      const escape = quote === "'" ? "&apos;" : "&quot;";
      final = final.slice(1, -1).replace(new RegExp(quote, "g"), escape);
      res = [quote, final, quote];
    } else {
      res = path.call(print, "value");
    }
    parts.push("=", res);
  }

}

function printJsxExpressionContainer(path, options, print) {
  const parent = path.getParentNode(0);

    n.expression.type === "JSXEmptyExpression" ||
    (!hasComment(n.expression) &&
      (n.expression.type === "ArrayExpression" ||
        n.expression.type === "ObjectExpression" ||
        n.expression.type === "ArrowFunctionExpression" ||
        isCallExpression(n.expression) ||
        n.expression.type === "FunctionExpression" ||
        n.expression.type === "TemplateLiteral" ||
        n.expression.type === "TaggedTemplateExpression" ||
        n.expression.type === "DoExpression" ||
        (isJsxNode(parent) &&
          (n.expression.type === "ConditionalExpression" ||
            isBinaryish(n.expression)))));

  if (shouldInline) {
      "{",
      "}",
    ]);
  }

    "{",
    indent([softline, path.call(print, "expression")]),
    softline,
    lineSuffixBoundary,
    "}",
  ]);
}

function printJsxOpeningElement(path, options, print) {

  const nameHasComments =
    (n.name && hasComment(n.name)) ||
    (n.typeParameters && hasComment(n.typeParameters));

  // Don't break self-closing elements with no attributes and no comments
  if (n.selfClosing && n.attributes.length === 0 && !nameHasComments) {
    return [
      "<",
      " />",
    ];
  }

  // don't break up opening elements with a single long text attribute
  if (
    n.attributes &&
    n.attributes.length === 1 &&
    n.attributes[0].value &&
    isStringLiteral(n.attributes[0].value) &&
    !n.attributes[0].value.value.includes("\n") &&
    // We should break for the following cases:
    // <div
    //   // comment
    //   attr="value"
    // >
    // <div
    // >
    !nameHasComments &&
    !hasComment(n.attributes[0])
  ) {
      "<",
      " ",
      ...path.map(print, "attributes"),
      n.selfClosing ? " />" : ">",
    ]);
  }

  const lastAttrHasTrailingComments =
    n.attributes.length > 0 &&
    hasComment(getLast(n.attributes), CommentCheckFlags.Trailing);

  const bracketSameLine =
    // Simple tags (no attributes and no comment in tag name) should be
    // kept unbroken regardless of `jsxBracketSameLine`
    (n.attributes.length === 0 && !nameHasComments) ||
    (options.jsxBracketSameLine &&
      // We should print the bracket in a new line for the following cases:
      // <div
      //   // comment
      // >
      // <div
      //   attr // comment
      // >
      (!nameHasComments || n.attributes.length > 0) &&
      !lastAttrHasTrailingComments);

  // We should print the opening element expanded if any prop value is a
  // string literal with newlines
  const shouldBreak =
    n.attributes.some(
      (attr) =>
        attr.value &&
        isStringLiteral(attr.value) &&
        attr.value.value.includes("\n")
    );

    [
      "<",

      indent(path.map((attr) => [line, print(attr)], "attributes")),
      n.selfClosing ? line : bracketSameLine ? ">" : softline,
      n.selfClosing ? "/>" : bracketSameLine ? "" : ">",
    ],
  );
}

function printJsxClosingElement(path, options, print) {

  parts.push("</");

  const printed = path.call(print, "name");
  if (hasComment(n.name, CommentCheckFlags.Leading | CommentCheckFlags.Line)) {
    parts.push(indent([hardline, printed]), hardline);
  } else if (
    hasComment(n.name, CommentCheckFlags.Leading | CommentCheckFlags.Block)
  ) {
    parts.push(" ", printed);
  } else {
    parts.push(printed);
  }

  parts.push(">");

}

function printJsxOpeningClosingFragment(path, options /*, print*/) {
  const nodeHasComment = hasComment(n);
  const hasOwnLineComment = hasComment(n, CommentCheckFlags.Line);
  const isOpeningFragment = n.type === "JSXOpeningFragment";
  return [
    isOpeningFragment ? "<" : "</",
    indent([
      hasOwnLineComment
        ? hardline
        : nodeHasComment && !isOpeningFragment
        ? " "
        : "",
      printDanglingComments(path, options, true),
    ]),
    hasOwnLineComment ? hardline : "",
    ">",
  ];
}

function printJsxElement(path, options, print) {
  const elem = printComments(
    path,
    () => printJsxElementInternal(path, options, print),
    options
  );
  return maybeWrapJsxElementInParens(path, elem, options);
}

function printJsxEmptyExpression(path, options /*, print*/) {
  const requiresHardline = hasComment(n, CommentCheckFlags.Line);

  return [
    printDanglingComments(path, options, /* sameIndent */ !requiresHardline),
    requiresHardline ? hardline : "",
  ];
}

function printJsxSpreadAttribute(path, options, print) {
  return [
    "{",
    path.call(
      (p) => {
        const printed = ["...", print(p)];
        const n = p.getValue();
        if (!hasComment(n) || !willPrintOwnComments(p)) {
        }
        return [
          indent([softline, printComments(p, () => printed, options)]),
          softline,
        ];
      },
      n.type === "JSXSpreadAttribute" ? "argument" : "expression"
    ),
    "}",
  ];
}

function printJsx(path, options, print) {
    case "JSXAttribute":
      return printJsxAttribute(path, options, print);
    case "JSXIdentifier":
      return String(n.name);
    case "JSXNamespacedName":
      return join(":", [
        path.call(print, "namespace"),
      ]);
    case "JSXMemberExpression":
      return join(".", [
        path.call(print, "property"),
      ]);
    case "JSXSpreadAttribute":
      return printJsxSpreadAttribute(path, options, print);
    case "JSXSpreadChild": {
      // Same as `printJsxSpreadAttribute`
      const printJsxSpreadChild = printJsxSpreadAttribute;
      return printJsxSpreadChild(path, options, print);
    }
    case "JSXExpressionContainer":
      return printJsxExpressionContainer(path, options, print);
      return printJsxElement(path, options, print);
    case "JSXOpeningElement":
      return printJsxOpeningElement(path, options, print);
    case "JSXClosingElement":
      return printJsxClosingElement(path, options, print);
    case "JSXOpeningFragment":
    case "JSXClosingFragment":
      return printJsxOpeningClosingFragment(path, options /*, print*/);
    case "JSXEmptyExpression":
      return printJsxEmptyExpression(path, options /*, print*/);
    case "JSXText":
      throw new Error("JSXTest should be handled by JSXElement");
  }
}

(text) =>
  text.replace(
    new RegExp(
      "(?:^" +
        matchJsxWhitespaceRegex.source +
        "|" +
        "$)"
    ),
    ""
  )

function isEmptyJsxElement(node) {
  if (node.children.length === 0) {
  }
  if (node.children.length > 1) {
  }

  // if there is one text child and does not contain any meaningful text
  // we can treat the element as empty.
  return isLiteral(child) && !isMeaningfulJsxText(child);
}

function isMeaningfulJsxText(node) {
  return (
    isLiteral(node) &&
    (containsNonJsxWhitespaceRegex.test(rawText(node)) ||
      !/\n/.test(rawText(node)))
  );
}

function isJsxWhitespaceExpression(node) {
  return (
    node.type === "JSXExpressionContainer" &&
    isLiteral(node.expression) &&
    node.expression.value === " " &&
    !hasComment(node.expression)
  );
}

function hasJsxIgnoreComment(path) {
  if (!parent || !node || !isJsxNode(node) || !isJsxNode(parent)) {
  }

  // Lookup the previous sibling, ignoring any empty JSXText elements
  const index = parent.children.indexOf(node);
  let prevSibling = null;
  for (let i = index; i > 0; i--) {
    const candidate = parent.children[i - 1];
    if (candidate.type === "JSXText" && !isMeaningfulJsxText(candidate)) {
      continue;
    }
    prevSibling = candidate;
    break;
  }

  return (
    prevSibling &&
    prevSibling.type === "JSXExpressionContainer" &&
    prevSibling.expression.type === "JSXEmptyExpression" &&
    hasNodeIgnoreComment(prevSibling.expression)
  );
}

function printArray(path, options, print) {

  const openBracket = n.type === "TupleExpression" ? "#[" : "[";
  const closeBracket = "]";
  if (n.elements.length === 0) {
    if (!hasComment(n, CommentCheckFlags.Dangling)) {
      parts.push(openBracket, closeBracket);
    } else {
        group([
          openBracket,
          printDanglingComments(path, options),
          softline,
          closeBracket,
        ])
      );
    }
  } else {
    const lastElem = getLast(n.elements);
    const canHaveTrailingComma = !(lastElem && lastElem.type === "RestElement");

    // JavaScript allows you to have empty elements in an array which
    // changes its length based on the number of commas. The algorithm
    // is that if the last argument is null, we need to force insert
    // a comma to ensure JavaScript recognizes it.
    //   [,].length === 1
    //   [1,].length === 1
    //   [1,,].length === 2
    //
    // Note that getLast returns null if the array is empty, but
    // we already check for an empty array just above so we are safe
    const needsForcedTrailingComma = lastElem === null;

    const groupId = Symbol("array");

      !options.__inJestEach &&
      n.elements.length > 1 &&
      n.elements.every((element, i, elements) => {
        const elementType = element && element.type;
        if (
          elementType !== "ArrayExpression" &&
          elementType !== "ObjectExpression"
        ) {
        }

        const nextElement = elements[i + 1];
        if (nextElement && elementType !== nextElement.type) {
        }

        const itemsKey =
          elementType === "ArrayExpression" ? "elements" : "properties";

        return element[itemsKey] && element[itemsKey].length > 1;
      });

    const shouldUseConciseFormatting =
      n.elements.every(
        (element) =>
          element &&
          (isNumericLiteral(element) ||
            (isSignedNumericLiteral(element) &&
              !hasComment(element.argument))) &&
          !hasComment(
            element,
            CommentCheckFlags.Trailing | CommentCheckFlags.Line,
            (comment) =>
              !hasNewline(options.originalText, locStart(comment), {
              })
          )
      );

    const trailingComma = !canHaveTrailingComma
      ? ""
      : needsForcedTrailingComma
      ? ","
      : !shouldPrintComma(options)
      ? ""
      : shouldUseConciseFormatting
      ? ifBreak(",", "", { groupId })
      : ifBreak(",");

      group(
        [
          indent([
            softline,
            shouldUseConciseFormatting
              ? printArrayItemsConcisely(path, options, print, trailingComma)
              : [
                  printArrayItems(path, options, "elements", print),
                  trailingComma,
                ],
          ]),
          softline,
        ],
        { shouldBreak, id: groupId }
      )
    );
  }

    printOptionalToken(path),
    printTypeAnnotation(path, options, print)
  );

}

function printArrayItems(path, options, printPath, print) {
  const printedElements = [];
  let separatorParts = [];

    printedElements.push(separatorParts, group(print(childPath)));

    separatorParts = [",", line];
    if (
      childPath.getValue() &&
      isNextLineEmpty(childPath.getValue(), options)
    ) {
      separatorParts.push(softline);
    }
  }, printPath);

  return printedElements;
}

function printArrayItemsConcisely(path, options, print, trailingComma) {

  path.each((childPath, i, elements) => {
    const isLast = i === elements.length - 1;

    parts.push([print(childPath), isLast ? trailingComma : ","]);

    if (!isLast) {
        isNextLineEmpty(childPath.getValue(), options)
          ? [hardline, hardline]
          : hasComment(
              elements[i + 1],
              CommentCheckFlags.Leading | CommentCheckFlags.Line
            )
          ? hardline
          : line
      );
    }
  }, "elements");

  return fill(parts);
}

function printAssignment(
  leftNode,
  printedLeft,
  operator,
  rightNode,
  printedRight,
  options
) {
  if (!rightNode) {
    return printedLeft;
  }

  const printed = printAssignmentRight(
    leftNode,
    rightNode,
    printedRight,
    options
  );

  return group([printedLeft, operator, printed]);
}

function printAssignmentExpression(path, options, print) {
  return printAssignment(
    n.left,
    path.call(print, "left"),
    [" ", n.operator],
    n.right,
    path.call(print, "right"),
    options
  );
}

function printVariableDeclarator(path, options, print) {
    n.id,
    path.call(print, "id"),
    " =",
    n.init,
    n.init && path.call(print, "init"),
    options
  );
}

function printAssignmentRight(leftNode, rightNode, printedRight, options) {
  if (hasLeadingOwnLineComment(options.originalText, rightNode)) {
    return indent([line, printedRight]);
  }

  if (canBreakAssignmentRight(leftNode, rightNode, options)) {
    return group(indent([line, printedRight]));
  }

  return [" ", printedRight];
}

function canBreakAssignmentRight(leftNode, rightNode, options) {
  // do not put values on a separate line from the key in json
  if (options.parser === "json5" || options.parser === "json") {
  }

  if (isBinaryish(rightNode) && !shouldInlineLogicalExpression(rightNode)) {
  }

  switch (rightNode.type) {
    case "ConditionalExpression": {
      const { test } = rightNode;
      return isBinaryish(test) && !shouldInlineLogicalExpression(test);
    }
      return isNonEmptyArray(rightNode.decorators);
  }

  if (
    leftNode.type === "Identifier" ||
    isStringLiteral(leftNode) ||
    leftNode.type === "MemberExpression"
  ) {
    let node = rightNode;
    while (node.type === "UnaryExpression") {
      node = node.argument;
    }
    if (isStringLiteral(node) || isMemberExpressionChain(node)) {
    }
  }

}

function printCallArguments(path, options, print) {
  const isDynamicImport = node.type === "ImportExpression";

  const args = getCallArguments(node);
  if (args.length === 0) {
    return [
      "(",
      printDanglingComments(path, options, /* sameIndent */ true),
      ")",
    ];
  }

  // useEffect(() => { ... }, [foo, bar, baz])
  if (isReactHookCallWithDepsArray(args)) {
    return [
      "(",
      path.call(print, "arguments", 0),
      ", ",
      path.call(print, "arguments", 1),
      ")",
    ];
  }

  // func(
  //   ({
  //     a,
  //
  //     b
  //   }) => {}
  // );
  function shouldBreakForArrowFunctionInArguments(arg, argPath) {
    if (
      !arg ||
      arg.type !== "ArrowFunctionExpression" ||
      !arg.body ||
      arg.body.type !== "BlockStatement" ||
      getFunctionParameters(arg).length === 0
    ) {
    }

    let shouldBreak = false;
    iterateFunctionParametersPath(argPath, (parameterPath) => {
      shouldBreak = shouldBreak || willBreak(print(parameterPath));
    });

    return shouldBreak;
  }

  let anyArgEmptyLine = false;
  let shouldBreakForArrowFunction = false;
  let hasEmptyLineFollowingFirstArg = false;
  const lastArgIndex = args.length - 1;
  const printedArguments = [];
  iterateCallArgumentsPath(path, (argPath, index) => {
    const arg = argPath.getNode();
    const parts = [print(argPath)];

    if (index === lastArgIndex) {
      // do nothing
    } else if (isNextLineEmpty(arg, options)) {
        hasEmptyLineFollowingFirstArg = true;
      }

      anyArgEmptyLine = true;
      parts.push(",", hardline, hardline);
    } else {
      parts.push(",", line);
    }

    shouldBreakForArrowFunction = shouldBreakForArrowFunctionInArguments(
      arg,
      argPath
    );

    printedArguments.push(parts);
  });

  const maybeTrailingComma =
    // Dynamic imports cannot have trailing commas
    !(isDynamicImport || (node.callee && node.callee.type === "Import")) &&
    shouldPrintComma(options, "all")
      ? ","
      : "";

  function allArgsBrokenOut() {
      ["(", indent([line, ...printedArguments]), maybeTrailingComma, line, ")"],
      { shouldBreak: true }
    );
  }

  if (
    path.getParentNode().type !== "Decorator" &&
    isFunctionCompositionArgs(args)
  ) {
    return allArgsBrokenOut();
  }

  const shouldGroupFirst = shouldGroupFirstArg(args);
  const shouldGroupLast = shouldGroupLastArg(args);
  if (shouldGroupFirst || shouldGroupLast) {
      (shouldGroupFirst
        ? printedArguments.slice(1).some(willBreak)
        : printedArguments.slice(0, -1).some(willBreak)) ||
      anyArgEmptyLine ||
      shouldBreakForArrowFunction;

    // We want to print the last argument with a special flag
    let printedExpanded = [];
    iterateCallArgumentsPath(path, (argPath, i) => {
      if (shouldGroupFirst && i === 0) {
        printedExpanded = [
          [
            argPath.call((p) => print(p, { expandFirstArg: true })),
            printedArguments.length > 1 ? "," : "",
            hasEmptyLineFollowingFirstArg ? hardline : line,
            hasEmptyLineFollowingFirstArg ? hardline : "",
          ],
          ...printedArguments.slice(1),
        ];
      }
      if (shouldGroupLast && i === args.length - 1) {
          ...printedArguments.slice(0, -1),
          argPath.call((p) => print(p, { expandLastArg: true })),
        ];
      }
    });

    const somePrintedArgumentsWillBreak = printedArguments.some(willBreak);

    const simpleConcat = ["(", ...printedExpanded, ")"];

    return [
      somePrintedArgumentsWillBreak ? breakParent : "",
      conditionalGroup(
        [
          !somePrintedArgumentsWillBreak &&
          !node.typeArguments &&
          !node.typeParameters
            ? simpleConcat
            : ifBreak(allArgsBrokenOut(), simpleConcat),
          shouldGroupFirst
            ? [
                "(",
                group(printedExpanded[0], { shouldBreak: true }),
                ...printedExpanded.slice(1),
                ")",
              ]
            : [
                "(",
                ...printedArguments.slice(0, -1),
                group(getLast(printedExpanded), {
                  shouldBreak: true,
                }),
                ")",
              ],
          allArgsBrokenOut(),
        ],
      ),
    ];
  }

  const contents = [
    "(",
    indent([softline, ...printedArguments]),
    ifBreak(maybeTrailingComma),
    softline,
    ")",
  ];
  if (isLongCurriedCallExpression(path)) {
    // By not wrapping the arguments in a group, the printer prioritizes
    // breaking up these arguments rather than the args of the parent call.
    return contents;
  }

  return group(contents, {
    shouldBreak: printedArguments.some(willBreak) || anyArgEmptyLine,
  });
}

function shouldBreakForArrowFunctionInArguments(arg, argPath) {
    if (
      !arg ||
    ) {
    }

    });

  }

function allArgsBrokenOut() {
    );
  }

function couldGroupArg(arg) {
  return (
    (arg.type === "ObjectExpression" &&
      (arg.properties.length > 0 || hasComment(arg))) ||
    (arg.type === "ArrayExpression" &&
      (arg.elements.length > 0 || hasComment(arg))) ||
    (arg.type === "TSTypeAssertion" && couldGroupArg(arg.expression)) ||
    (arg.type === "TSAsExpression" && couldGroupArg(arg.expression)) ||
    arg.type === "FunctionExpression" ||
    (arg.type === "ArrowFunctionExpression" &&
      // we want to avoid breaking inside composite return types but not simple keywords
      // https://github.com/prettier/prettier/issues/4070
      // export class Thing implements OtherThing {
      //   do: (type: Type) => Provider<Prop> = memoize(
      //     (type: ObjectType): Provider<Opts> => {}
      //   );
      // }
      // https://github.com/prettier/prettier/issues/6099
      // app.get("/", (req, res): void => {
      //   res.send("Hello World!");
      // });
      (!arg.returnType ||
        !arg.returnType.typeAnnotation ||
        arg.returnType.typeAnnotation.type !== "TSTypeReference") &&
      (arg.body.type === "BlockStatement" ||
        arg.body.type === "ArrowFunctionExpression" ||
        arg.body.type === "ObjectExpression" ||
        arg.body.type === "ArrayExpression" ||
        isCallExpression(arg.body) ||
        arg.body.type === "ConditionalExpression" ||
        isJsxNode(arg.body)))
  );
}

function shouldGroupLastArg(args) {
  const lastArg = getLast(args);
  const penultimateArg = getPenultimate(args);
  return (
    !hasComment(lastArg, CommentCheckFlags.Leading) &&
    !hasComment(lastArg, CommentCheckFlags.Trailing) &&
    couldGroupArg(lastArg) &&
    // If the last two arguments are of the same type,
    // disable last element expansion.
    (!penultimateArg || penultimateArg.type !== lastArg.type) &&
    // useMemo(() => func(), [foo, bar, baz])
    (args.length !== 2 ||
      args[0].type !== "ArrowFunctionExpression" ||
      args[1].type !== "ArrayExpression")
  );
}

function shouldGroupFirstArg(args) {
  if (args.length !== 2) {
  }

  const [firstArg, secondArg] = args;
  return (
    !hasComment(firstArg) &&
    (firstArg.type === "FunctionExpression" ||
      (firstArg.type === "ArrowFunctionExpression" &&
        firstArg.body.type === "BlockStatement")) &&
    secondArg.type !== "FunctionExpression" &&
    secondArg.type !== "ArrowFunctionExpression" &&
    secondArg.type !== "ConditionalExpression" &&
    !couldGroupArg(secondArg)
  );
}

function isReactHookCallWithDepsArray(args) {
  return (
    args.length === 2 &&
    args[0].type === "ArrowFunctionExpression" &&
    getFunctionParameters(args[0]).length === 0 &&
    args[0].body.type === "BlockStatement" &&
    args[1].type === "ArrayExpression" &&
    !args.some((arg) => hasComment(arg))
  );
}

function printBlock(path, options, print) {

  if (node.type === "StaticBlock") {
    parts.push("static ");
  }

  if (node.type === "ClassBody" && isNonEmptyArray(node.body)) {
    const parent = path.getParentNode();
    parts.push(printHardlineAfterHeritage(parent));
  }

  parts.push("{");
  const printed = printBlockBody(path, options, print);
  if (printed) {
  } else {
    const parentParent = path.getParentNode(1);
    if (
      !(
        parent.type === "ArrowFunctionExpression" ||
        parent.type === "FunctionExpression" ||
        parent.type === "FunctionDeclaration" ||
        parent.type === "ObjectMethod" ||
        parent.type === "ClassMethod" ||
        parent.type === "ClassPrivateMethod" ||
        parent.type === "ForStatement" ||
        parent.type === "WhileStatement" ||
        parent.type === "DoWhileStatement" ||
        parent.type === "DoExpression" ||
        (parent.type === "CatchClause" && !parentParent.finalizer) ||
        parent.type === "TSModuleDeclaration" ||
        parent.type === "TSDeclareFunction" ||
        node.type === "StaticBlock" ||
        node.type === "ClassBody"
      )
    ) {
    }
  }

  parts.push("}");

}

function printBlockBody(path, options, print) {

  const nodeHasDirectives = isNonEmptyArray(node.directives);
  const nodeHasBody = node.body.some((node) => node.type !== "EmptyStatement");
  const nodeHasComment = hasComment(node, CommentCheckFlags.Dangling);

  if (!nodeHasDirectives && !nodeHasBody && !nodeHasComment) {
    return "";
  }

  // Babel 6
  if (nodeHasDirectives) {
    path.each((childPath, index, directives) => {
      parts.push(print(childPath));
      if (index < directives.length - 1 || nodeHasBody || nodeHasComment) {
        if (isNextLineEmpty(childPath.getValue(), options)) {
        }
      }
    }, "directives");
  }

  if (nodeHasBody) {
    parts.push(printBody(path, options, print));
  }

  if (nodeHasComment) {
    parts.push(printDanglingComments(path, options, /* sameIndent */ true));
  }

  if (node.type === "Program") {
    parts.push(hardline);
  }

}

    options.__onHtmlBindingRoot(node, options);
  }

    return;
  }

      (functionDeclarationPath) => {
        const printed = join(
          [",", line],
          functionDeclarationPath.map(print, "params")
        );

        if (params.length === 1) {
        }

        return ["(", indent([softline, group(printed)]), softline, ")"];
      },
      "body",
      0
    );
  }

  if (options.__isVueBindings) {
      (functionDeclarationPath) =>
        join([",", line], functionDeclarationPath.map(print, "params")),
      "body",
      0
    );
  }
}

function isVueEventBindingExpression(node) {
      switch (node.property.type) {
        case "Identifier":
        case "NumericLiteral":
        case "StringLiteral":
          return isVueEventBindingExpression(node.object);
      }
    default:
  }
}

function printObject(path, options, print) {

  let propertiesField;

  if (n.type === "TSTypeLiteral") {
    propertiesField = "members";
  } else if (n.type === "TSInterfaceBody") {
    propertiesField = "body";
  } else {
    propertiesField = "properties";
  }

  const isTypeAnnotation = n.type === "ObjectTypeAnnotation";
  const fields = [];
  if (isTypeAnnotation) {
    fields.push("indexers", "callProperties", "internalSlots");
  }
  fields.push(propertiesField);

  const firstProperty = fields
    .map((field) => n[field][0])
    .sort((a, b) => locStart(a) - locStart(b))[0];

  const isFlowInterfaceLikeBody =
    isTypeAnnotation &&
    parent &&
    (parent.type === "InterfaceDeclaration" ||
      parent.type === "DeclareInterface" ||
      parent.type === "DeclareClass") &&
    path.getName() === "body";
    n.type === "TSInterfaceBody" ||
    isFlowInterfaceLikeBody ||
    (n.type === "ObjectPattern" &&
      parent.type !== "FunctionDeclaration" &&
      parent.type !== "FunctionExpression" &&
      parent.type !== "ArrowFunctionExpression" &&
      parent.type !== "ObjectMethod" &&
      parent.type !== "ClassMethod" &&
      parent.type !== "ClassPrivateMethod" &&
      parent.type !== "AssignmentPattern" &&
      parent.type !== "CatchClause" &&
      n.properties.some(
        (property) =>
          property.value &&
          (property.value.type === "ObjectPattern" ||
            property.value.type === "ArrayPattern")
      )) ||
    (n.type !== "ObjectPattern" &&
      firstProperty &&
      hasNewlineInRange(
        locStart(firstProperty)
      ));

  const separator = isFlowInterfaceLikeBody
    ? ";"
    : n.type === "TSInterfaceBody" || n.type === "TSTypeLiteral"
    ? ifBreak(semi, ";")
    : ",";
  const leftBrace = n.type === "RecordExpression" ? "#{" : n.exact ? "{|" : "{";
  const rightBrace = n.exact ? "|}" : "}";

  // Unfortunately, things are grouped together in the ast can be
  // interleaved in the source code. So we need to reorder them before
  // printing them.
  const propsAndLoc = [];
  for (const field of fields) {
    path.each((childPath) => {
      const node = childPath.getValue();
      propsAndLoc.push({
        node,
        printed: print(childPath),
        loc: locStart(node),
      });
    }, field);
  }

  /** @type {Doc[]} */
  const props = propsAndLoc
    .sort((a, b) => a.loc - b.loc)
    .map((prop) => {
      const result = [...separatorParts, group(prop.printed)];
      separatorParts = [separator, line];
      if (
        (prop.node.type === "TSPropertySignature" ||
          prop.node.type === "TSMethodSignature" ||
          prop.node.type === "TSConstructSignatureDeclaration") &&
        hasComment(prop.node, CommentCheckFlags.PrettierIgnore)
      ) {
        separatorParts.shift();
      }
      if (isNextLineEmpty(prop.node, options)) {
        separatorParts.push(hardline);
      }
    });

  if (n.inexact) {
    let printed;
    if (hasComment(n, CommentCheckFlags.Dangling)) {
      const hasLineComments = hasComment(n, CommentCheckFlags.Line);
      const printedDanglingComments = printDanglingComments(
        path,
        options,
        /* sameIndent */ true
      );
      printed = [
        printedDanglingComments,
        hasLineComments ||
        hasNewline(options.originalText, locEnd(getLast(getComments(n))))
          ? hardline
          : line,
        "...",
      ];
    } else {
      printed = ["..."];
    }
    props.push([...separatorParts, ...printed]);
  }

  const lastElem = getLast(n[propertiesField]);

  const canHaveTrailingSeparator = !(
    n.inexact ||
    (lastElem && lastElem.type === "RestElement") ||
    (lastElem &&
      (lastElem.type === "TSPropertySignature" ||
        lastElem.type === "TSCallSignatureDeclaration" ||
        lastElem.type === "TSMethodSignature" ||
        lastElem.type === "TSConstructSignatureDeclaration") &&
      hasComment(lastElem, CommentCheckFlags.PrettierIgnore))
  );

  let content;
  if (props.length === 0) {
      return [leftBrace, rightBrace, printTypeAnnotation(path, options, print)];
    }

    content = group([
      leftBrace,
      printDanglingComments(path, options),
      softline,
      rightBrace,
      printTypeAnnotation(path, options, print),
    ]);
  } else {
    content = [
      isFlowInterfaceLikeBody && isNonEmptyArray(n.properties)
        ? printHardlineAfterHeritage(parent)
        : "",
      indent([options.bracketSpacing ? line : softline, ...props]),
      ifBreak(
        canHaveTrailingSeparator &&
          (separator !== "," || shouldPrintComma(options))
          ? separator
          : ""
      ),
      options.bracketSpacing ? line : softline,
    ];
  }

  // If we inline the object as first argument of the parent, we don't want
  // to create another group so that the object breaks before the return
  // type
  if (
      (node) => node.type === "ObjectPattern" && !node.decorators,
      (node, name, number) =>
        shouldHugFunctionParameters(node) &&
        (name === "params" ||
          name === "parameters" ||
          name === "this" ||
          name === "rest") &&
        number === 0
    ) ||
      shouldHugType,
      (node, name) => name === "typeAnnotation",
    )
  ) {
  }

  return group(content, { shouldBreak });
}

function shouldHugType(node) {
  if (isSimpleType(node) || isObjectType(node)) {
  }

  if (node.type === "UnionTypeAnnotation" || node.type === "TSUnionType") {
    const voidCount = node.types.filter(
      (n) =>
        n.type === "VoidTypeAnnotation" ||
        n.type === "TSVoidKeyword" ||
        n.type === "NullLiteralTypeAnnotation" ||
        n.type === "TSNullKeyword"
    ).length;

    const hasObject = node.types.some(
      (n) =>
        n.type === "ObjectTypeAnnotation" ||
        n.type === "TSTypeLiteral" ||
        // This is a bit aggressive but captures Array<{x}>
        n.type === "GenericTypeAnnotation" ||
        n.type === "TSTypeReference"
    );

    if (node.types.length - 1 === voidCount && hasObject) {
    }
  }

}

function printOpaqueType(path, options, print) {
    "opaque type ",
    path.call(print, "typeParameters")
  );

  if (n.supertype) {
    parts.push(": ", path.call(print, "supertype"));
  }

  if (n.impltype) {
    parts.push(" = ", path.call(print, "impltype"));
  }

  parts.push(semi);

}

function printTypeAlias(path, options, print) {
  }

    n.id,
    n.right,
    options
  );

    "type ",
    path.call(print, "typeParameters"),
    " =",
    printed,
    semi
  );

}

function printIntersectionType(path, options, print) {
  const types = path.map(print, "types");
  let wasIndented = false;
  for (let i = 0; i < types.length; ++i) {
    if (i === 0) {
      result.push(types[i]);
    } else if (isObjectType(n.types[i - 1]) && isObjectType(n.types[i])) {
      // If both are objects, don't indent
      result.push([" & ", wasIndented ? indent(types[i]) : types[i]]);
    } else if (!isObjectType(n.types[i - 1]) && !isObjectType(n.types[i])) {
      // If no object is involved, go to the next line if it breaks
      result.push(indent([" &", line, types[i]]));
    } else {
      // If you go from object to non-object or vis-versa, then inline it
      if (i > 1) {
        wasIndented = true;
      }
      result.push(" & ", i > 1 ? indent(types[i]) : types[i]);
    }
  }
  return group(result);
}

function printUnionType(path, options, print) {
  // single-line variation
  // A | B | C

  // multi-line variation
  // | A
  // | B
  // | C

  // If there's a leading comment, the parent is doing the indentation
  const shouldIndent =
    parent.type !== "TypeParameterInstantiation" &&
    parent.type !== "TSTypeParameterInstantiation" &&
    parent.type !== "GenericTypeAnnotation" &&
    parent.type !== "TSTypeReference" &&
    parent.type !== "TSTypeAssertion" &&
    parent.type !== "TupleTypeAnnotation" &&
    parent.type !== "TSTupleType" &&
    !(
      parent.type === "FunctionTypeParam" &&
      !parent.name &&
      path.getParentNode(1).this !== parent
    ) &&
    !(
      (parent.type === "TypeAlias" ||
        parent.type === "VariableDeclarator" ||
        parent.type === "TSTypeAliasDeclaration") &&
      hasLeadingOwnLineComment(options.originalText, n)
    );

  // {
  //   a: string
  // } | null | void
  // should be inlined and not be printed in the multi-line variant
  const shouldHug = shouldHugType(n);

  // We want to align the children but without its comment, so it looks like
  // | child1
  // // comment
  // | child2
  const printed = path.map((typePath) => {
    let printedType = typePath.call(print);
    if (!shouldHug) {
      printedType = align(2, printedType);
    }
    return printComments(typePath, () => printedType, options);
  }, "types");

  if (shouldHug) {
    return join(" | ", printed);
  }

  const shouldAddStartLine =
    shouldIndent && !hasLeadingOwnLineComment(options.originalText, n);

  const code = [
    ifBreak([shouldAddStartLine ? line : "", "| "]),
    join([line, "| "], printed),
  ];

  if (pathNeedsParens(path, options)) {
    return group([indent(code), softline]);
  }

  if (
    (parent.type === "TupleTypeAnnotation" && parent.types.length > 1) ||
    (parent.type === "TSTupleType" && parent.elementTypes.length > 1)
  ) {
      indent([ifBreak(["(", softline]), code]),
      softline,
      ifBreak(")"),
    ]);
  }

  return group(shouldIndent ? indent(code) : code);
}

function printFunctionType(path, options, print) {
  // FunctionTypeAnnotation is ambiguous:
  // declare function foo(a: B): void; OR
  // var A: (a: B) => void;
  const parentParentParent = path.getParentNode(2);
  let isArrowFunctionTypeAnnotation =
    n.type === "TSFunctionType" ||
    !(
      ((parent.type === "ObjectTypeProperty" ||
        parent.type === "ObjectTypeInternalSlot") &&
        !parent.variance &&
        !parent.optional &&
        locStart(parent) === locStart(n)) ||
      parent.type === "ObjectTypeCallProperty" ||
      (parentParentParent && parentParentParent.type === "DeclareFunction")
    );

  let needsColon =
    isArrowFunctionTypeAnnotation &&
    (parent.type === "TypeAnnotation" || parent.type === "TSTypeAnnotation");

  // Sadly we can't put it inside of AstPath::needsColon because we are
  // printing ":" as part of the expression and it would put parenthesis
  // around :(
  const needsParens =
    needsColon &&
    (parent.type === "TypeAnnotation" || parent.type === "TSTypeAnnotation") &&
    parentParent.type === "ArrowFunctionExpression";

  if (isObjectTypePropertyAFunction(parent)) {
    isArrowFunctionTypeAnnotation = true;
    needsColon = true;
  }

    parts.push("(");
  }

    printFunctionParameters(
      path,
      print,
      options,
      /* expandArg */ false,
      /* printTypeParams */ true
    )
  );

  // The returnType is not wrapped in a TypeAnnotation, so the colon
  // needs to be added separately.
  if (n.returnType || n.predicate || n.typeAnnotation) {
      isArrowFunctionTypeAnnotation ? " => " : ": ",
      path.call(print, "returnType"),
    );
  }
  }

}

function printTupleType(path, options, print) {
  const typesField = n.type === "TSTupleType" ? "elementTypes" : "types";
  const hasRest =
    n[typesField].length > 0 && getLast(n[typesField]).type === "TSRestType";
    "[",
    indent([softline, printArrayItems(path, options, typesField, print)]),
    ifBreak(shouldPrintComma(options, "all") && !hasRest ? "," : ""),
    printDanglingComments(path, options, /* sameIndent */ true),
    softline,
    "]",
  ]);
}

function printImportDeclaration(path, options, print) {

  const { importKind } = node;

  parts.push("import");

  if (importKind && importKind !== "value") {
    parts.push(" ", importKind);
  }

    printModuleSpecifiers(path, options, print),
    printModuleSource(path, options, print),
    printImportAssertions(path, options, print),
    semi
  );

}

  const { type, exportKind, declaration } = node;

  parts.push("export");

  const isDefaultExport = node.default || type === "ExportDefaultDeclaration";
  if (isDefaultExport) {
    parts.push(" default");
  }

      " ",
    );

    if (needsHardlineAfterDanglingComment(node)) {
    }
  }

  if (declaration) {
    parts.push(" ", path.call(print, "declaration"));
  } else {
      exportKind === "type" ? " type" : "",
      printModuleSpecifiers(path, options, print),
      printModuleSource(path, options, print),
      printImportAssertions(path, options, print)
    );
  }

  if (shouldExportDeclarationPrintSemi(node, options)) {
  }

}

function printExportAllDeclaration(path, options, print) {

  const { exportKind, exported } = node;

  if (exportKind === "type") {
    parts.push(" type");
  }

  parts.push(" *");

  if (exported) {
    parts.push(" as ", path.call(print, "exported"));
  }

    semi
  );

}

function shouldExportDeclarationPrintSemi(node, options) {
  if (!options.semi) {
  }

  const { type, declaration } = node;
  if (!declaration) {
  }

  const { type: declarationType } = declaration;
  if (
    isDefaultExport &&
    declarationType !== "ClassDeclaration" &&
    declarationType !== "FunctionDeclaration" &&
    declarationType !== "TSInterfaceDeclaration" &&
    declarationType !== "DeclareClass" &&
    declarationType !== "DeclareFunction" &&
    declarationType !== "TSDeclareFunction" &&
    declarationType !== "EnumDeclaration"
  ) {
  }
}

function printModuleSource(path, options, print) {

  if (!node.source) {
    return "";
  }

  if (!shouldNotPrintSpecifiers(node, options)) {
    parts.push(" from");
  }
  parts.push(" ", path.call(print, "source"));

}

function printModuleSpecifiers(path, options, print) {

  if (shouldNotPrintSpecifiers(node, options)) {
    return "";
  }

  const parts = [" "];

  if (isNonEmptyArray(node.specifiers)) {
    const standaloneSpecifiers = [];
    const groupedSpecifiers = [];

    path.each((specifierPath) => {
      const specifierType = path.getValue().type;
      if (
        specifierType === "ExportNamespaceSpecifier" ||
        specifierType === "ExportDefaultSpecifier" ||
        specifierType === "ImportNamespaceSpecifier" ||
        specifierType === "ImportDefaultSpecifier"
      ) {
        standaloneSpecifiers.push(print(specifierPath));
      } else if (
        specifierType === "ExportSpecifier" ||
        specifierType === "ImportSpecifier"
      ) {
        groupedSpecifiers.push(print(specifierPath));
      } else {
        throw new Error(
          `Unknown specifier type ${JSON.stringify(specifierType)}`
        );
      }
    }, "specifiers");

    parts.push(join(", ", standaloneSpecifiers));

    if (groupedSpecifiers.length > 0) {
      if (standaloneSpecifiers.length > 0) {
        parts.push(", ");
      }

      const canBreak =
        groupedSpecifiers.length > 1 ||
        standaloneSpecifiers.length > 0 ||
        node.specifiers.some((node) => hasComment(node));

      if (canBreak) {
          group([
            "{",
            indent([
              join([",", line], groupedSpecifiers),
            ]),
            ifBreak(shouldPrintComma(options) ? "," : ""),
            "}",
          ])
        );
      } else {
        parts.push([
          "{",
          options.bracketSpacing ? " " : "",
          ...groupedSpecifiers,
          "}",
        ]);
      }
    }
  } else {
    parts.push("{}");
  }
}

function shouldNotPrintSpecifiers(node, options) {
  const { type, importKind, source, specifiers } = node;

  if (
    type !== "ImportDeclaration" ||
    isNonEmptyArray(specifiers) ||
    importKind === "type"
  ) {
  }

  // TODO: check tokens
  return !/{\s*}/.test(
    options.originalText.slice(locStart(node), locStart(source))
  );
}

function printImportAssertions(path, options, print) {
  if (isNonEmptyArray(node.assertions)) {
    return [
      " assert {",
      options.bracketSpacing ? " " : "",
      join(", ", path.map(print, "assertions")),
      "}",
    ];
  }
  return "";
}

function printModuleSpecifier(path, options, print) {

  const { type, importKind } = node;
  if (type === "ImportSpecifier" && importKind) {
    parts.push(importKind, " ");
  }

  const isImport = type.startsWith("Import");
  const leftSideProperty = isImport ? "imported" : "local";
  const rightSideProperty = isImport ? "local" : "exported";
  let left = "";
  let right = "";
  if (
    type === "ExportNamespaceSpecifier" ||
    type === "ImportNamespaceSpecifier"
  ) {
    left = "*";
  } else if (node[leftSideProperty]) {
    left = path.call(print, leftSideProperty);
  }

  if (
    node[rightSideProperty] &&
    (!node[leftSideProperty] ||
      // import {a as a} from '.'
      !hasSameLoc(node[leftSideProperty], node[rightSideProperty]))
  ) {
    right = path.call(print, rightSideProperty);
  }

  parts.push(left, left && right ? " as " : "", right);
}

function printCallExpression(path, options, print) {
  const isNew = n.type === "NewExpression";
  const isDynamicImport = n.type === "ImportExpression";

  const args = getCallArguments(n);
  if (
    // Dangling comments not handled, all these special cases should has argument #9668
    args.length > 0 &&
    // We want to keep CommonJS- and AMD-style require calls, and AMD-style
    // define calls, as a unit.
    // e.g. `define(["some/lib", (lib) => {`
    ((!isDynamicImport &&
      !isNew &&
      n.callee.type === "Identifier" &&
      (n.callee.name === "require" || n.callee.name === "define")) ||
      // Template literals as single arguments
      (args.length === 1 &&
        isTemplateOnItsOwnLine(args[0], options.originalText)) ||
      // Keep test declarations on a single line
      // e.g. `it('long name', () => {`
      (!isNew && isTestCall(n, path.getParentNode())))
  ) {
    const printed = [];
    iterateCallArgumentsPath(path, (argPath) => {
      printed.push(print(argPath));
    });
    return [
      isNew ? "new " : "",
      path.call(print, "callee"),
      optional,
      "(",
      join(", ", printed),
      ")",
    ];
  }

  // Inline Flow annotation comments following Identifiers in Call nodes need to
  // stay with the Identifier. For example:
  //
  // foo /*:: <SomeGeneric> */(bar);
  //
  // Here, we ensure that such comments stay between the Identifier and the Callee.
  const isIdentifierWithFlowAnnotation =
    (options.parser === "babel" || options.parser === "babel-flow") &&
    n.callee &&
    n.callee.type === "Identifier" &&
    hasFlowAnnotationComment(n.callee.trailingComments);
  if (isIdentifierWithFlowAnnotation) {
    n.callee.trailingComments[0].printed = true;
  }

  // We detect calls on member lookups and possibly print them in a
  // special chain format. See `printMemberChain` for more info.
  if (
    !isDynamicImport &&
    !isNew &&
    isMemberish(n.callee) &&
    !path.call((path) => pathNeedsParens(path, options), "callee")
  ) {
    return printMemberChain(path, options, print);
  }

    isNew ? "new " : "",
    isDynamicImport ? "import" : path.call(print, "callee"),
    optional,
    isIdentifierWithFlowAnnotation
      ? `/*:: ${n.callee.trailingComments[0].value.slice(2).trim()} */`
      : "",
    printCallArguments(path, options, print),
  ];

  // We group here when the callee is itself a call expression.
  // See `isLongCurriedCallExpression` for more info.
  if (isDynamicImport || isCallExpression(n.callee)) {
    return group(contents);
  }

  return contents;
}

function printStatementSequence(path, options, print, property) {
  const isClassBody = node.type === "ClassBody";
  const lastStatement = getLastStatement(node[property]);

  path.each((path, index, statements) => {

    if (node.type === "EmptyStatement") {
      return;
    }

    // in no-semi mode, prepend statement with semicolon if it might break ASI
    // don't prepend the only JSX element in a program with semicolon
    if (
      !options.semi &&
      !isClassBody &&
      !isTheOnlyJsxElementInMarkdown(options, path) &&
      statementNeedsASIProtection(path, options)
    ) {
      if (hasComment(node, CommentCheckFlags.Leading)) {
        parts.push(print(path, { needsSemi: true }));
      } else {
        parts.push(";", printed);
      }
    } else {
      parts.push(printed);
    }

    if (!options.semi && isClassBody) {
      if (classPropMayCauseASIProblems(node)) {
      } else if (
        node.type === "ClassProperty" ||
        node.type === "PropertyDefinition"
      ) {
        // `ClassBody` don't allow `EmptyStatement`,
        // so we can use `statements` to get next node
        if (classChildNeedsASIProtection(statements[index + 1])) {
          parts.push(";");
        }
      }
    }

    if (node !== lastStatement) {

      if (isNextLineEmpty(node, options)) {
      }
    }
  }, property);

}

function getLastStatement(statements) {
  for (let i = statements.length - 1; i >= 0; i--) {
    const statement = statements[i];
    if (statement.type !== "EmptyStatement") {
      return statement;
    }
  }
}

function statementNeedsASIProtection(path, options) {

  if (node.type !== "ExpressionStatement") {
  }

    (childPath) => expressionNeedsASIProtection(childPath, options),
    "expression"
  );
}

function expressionNeedsASIProtection(path, options) {

  const maybeASIProblem =
    pathNeedsParens(path, options) ||
    node.type === "ParenthesizedExpression" ||
    node.type === "TypeCastExpression" ||
      !shouldPrintParamsWithoutParens(path, options)) ||
    node.type === "ArrayExpression" ||
    node.type === "ArrayPattern" ||
    (node.type === "UnaryExpression" &&
      node.prefix &&
      (node.operator === "+" || node.operator === "-")) ||
    node.type === "TemplateElement" ||
    isJsxNode(node) ||
    (node.type === "BindExpression" && !node.object) ||
    (node.type === "Literal" && node.pattern) ||
    (node.type === "Literal" && node.regex);

  if (maybeASIProblem) {
  }

  if (!hasNakedLeftSide(node)) {
  }

  );
}

function printBody(path, options, print) {
  return printStatementSequence(path, options, print, "body");
}

function printSwitchCaseConsequent(path, options, print) {
  return printStatementSequence(path, options, print, "consequent");
}

function classPropMayCauseASIProblems(node) {
  if (node.type !== "ClassProperty" && node.type !== "PropertyDefinition") {
  }

  const name = node.key && node.key.name;

  // this isn't actually possible yet with most parsers available today
  // so isn't properly tested yet.
  if (
    (name === "static" || name === "get" || name === "set") &&
    !node.value &&
    !node.typeAnnotation
  ) {
  }

}

function classChildNeedsASIProtection(node) {
    return;
  }

  if (
    node.static ||
    node.accessibility // TypeScript
  ) {
  }

  if (!node.computed) {
    const name = node.key && node.key.name;
    if (name === "in" || name === "instanceof") {
    }
  }
      return node.computed;
    case "MethodDefinition": // Flow
    case "TSAbstractMethodDefinition": // TypeScript
    case "ClassPrivateMethod": {
      // Babel
      const isAsync = node.value ? node.value.async : node.async;
      const isGenerator = node.value ? node.value.generator : node.generator;
      if (isAsync || node.kind === "get" || node.kind === "set") {
      }
      if (node.computed || isGenerator) {
      }
    }
    case "TSIndexSignature":
  }

}

function printClass(path, options, print) {

  }

  if (n.abstract) {
    parts.push("abstract ");
  }

  parts.push("class");

  // Keep old behaviour of extends in same line
  // If there is only on extends and there are not comments
  const groupMode =
    (n.superClass && hasComment(n.superClass)) ||
    isNonEmptyArray(n.extends) || // DeclareClass
    isNonEmptyArray(n.mixins) ||
    isNonEmptyArray(n.implements);

  if (n.id) {
    partsGroup.push(" ", path.call(print, "id"));
  }

  partsGroup.push(path.call(print, "typeParameters"));

    const printed = [
      printSuperClass(path, options, print),
      path.call(print, "superTypeParameters"),
    ];
    const printedWithComments = path.call(
      (superClass) => printComments(superClass, () => printed, options),
      "superClass"
    );
    if (groupMode) {
      extendsParts.push(line, group(printedWithComments));
    } else {
      extendsParts.push(" ", printedWithComments);
    }
  } else {
    extendsParts.push(printList(path, options, print, "extends"));
  }

  extendsParts.push(
    printList(path, options, print, "mixins"),
    printList(path, options, print, "implements")
  );

  if (groupMode) {
    let printedPartsGroup;
    if (shouldIndentOnlyHeritageClauses(n)) {
      printedPartsGroup = [...partsGroup, indent(extendsParts)];
    } else {
      printedPartsGroup = indent([...partsGroup, extendsParts]);
    }
    parts.push(group(printedPartsGroup, { id: getHeritageGroupId(n) }));
  } else {
  }

}

function printHardlineAfterHeritage(node) {
  return ifBreak(hardline, "", { groupId: getHeritageGroupId(node) });
}

function hasMultipleHeritage(node) {
  return (
    ["superClass", "extends", "mixins", "implements"].filter((key) =>
      Boolean(node[key])
    ).length > 1
  );
}

function shouldIndentOnlyHeritageClauses(node) {
  return (
    node.typeParameters &&
      node.typeParameters,
    ) &&
    !hasMultipleHeritage(node)
  );
}

function printList(path, options, print, listName) {
  if (!isNonEmptyArray(n[listName])) {
    return "";
  }

  const printedLeadingComments = printDanglingComments(
    path,
    options,
    ({ marker }) => marker === listName
  );
  return [
    shouldIndentOnlyHeritageClauses(n)
      ? ifBreak(" ", line, {
          groupId: getTypeParametersGroupId(n.typeParameters),
        })
      : line,
    printedLeadingComments,
    printedLeadingComments && hardline,
    listName,
    group(indent([line, join([",", line], path.map(print, listName))])),
  ];
}

function printSuperClass(path, options, print) {
  const printed = path.call(print, "superClass");
  if (parent.type === "AssignmentExpression") {
      ifBreak(["(", indent([softline, printed]), softline, ")"], printed)
    );
  }
}

function printClassMethod(path, options, print) {

  if (isNonEmptyArray(n.decorators)) {
    parts.push(printDecorators(path, options, print));
  }
  if (n.accessibility) {
    parts.push(n.accessibility + " ");
  }
  if (n.static) {
  }
  if (n.type === "TSAbstractMethodDefinition" || n.abstract) {
  }

  parts.push(printMethod(path, options, print));

}

function printClassProperty(path, options, print) {

  }
  }
  }
  }
  if (n.type === "TSAbstractClassProperty" || n.abstract) {
  }
  if (n.readonly) {
    parts.push("readonly ");
  }
  if (n.variance) {
    parts.push(path.call(print, "variance"));
  }
  );
      " =",
      printAssignmentRight(n.key, n.value, path.call(print, "value"), options)
    );
  }

}

function printDecorators(path, options, print) {
    join(line, path.map(print, "decorators")),
    hasNewlineBetweenOrAfterDecorators(node, options) ? hardline : line,
  ]);
}

function printPropertyKey(path, options, print) {

    return ["[", path.call(print, "key"), "]"];
  }

  const { key } = node;

  // flow has `Identifier` key, other parsers use `PrivateIdentifier` (ESTree) or `PrivateName`
  if (node.type === "ClassPrivateProperty" && key.type === "Identifier") {
    return ["#", path.call(print, "key")];
  }

  if (options.quoteProps === "consistent" && !needsQuoteProps.has(parent)) {
    const objectHasStringProp = (
      parent.properties ||
      parent.body ||
      parent.members
    ).some(
      (prop) =>
        !prop.computed &&
        prop.key &&
        isStringLiteral(prop.key) &&
        !isStringPropSafeToUnquote(prop, options)
    );
    needsQuoteProps.set(parent, objectHasStringProp);
  }

  if (
    (key.type === "Identifier" ||
      (isNumericLiteral(key) &&
        isSimpleNumber(printNumber(rawText(key))) &&
        // Avoid converting 999999999999999999999 to 1e+21, 0.99999999999999999 to 1 and 1.0 to 1.
        String(key.value) === printNumber(rawText(key)) &&
        // Quoting number keys is safe in JS and Flow, but not in TypeScript (as
        // mentioned in `isStringPropSafeToUnquote`).
        !(options.parser === "typescript" || options.parser === "babel-ts"))) &&
    (options.parser === "json" ||
      (options.quoteProps === "consistent" && needsQuoteProps.get(parent)))
  ) {
    // a -> "a"
    // 1 -> "1"
    // 1.5 -> "1.5"
    const prop = printString(
      JSON.stringify(
        key.type === "Identifier" ? key.name : key.value.toString()
      ),
      options
    );
      (keyPath) => printComments(keyPath, () => prop, options),
      "key"
    );
  }

  if (
    isStringPropSafeToUnquote(node, options) &&
    (options.quoteProps === "as-needed" ||
      (options.quoteProps === "consistent" && !needsQuoteProps.get(parent)))
  ) {
    // 'a' -> a
    // '1' -> 1
    // '1.5' -> 1.5
      (keyPath) =>
        printComments(
          keyPath,
          () => (/^\d/.test(key.value) ? printNumber(key.value) : key.value),
          options
        ),
      "key"
    );
  }

  return path.call(print, "key");
}

function printProperty(path, options, print) {
  if (n.shorthand) {
  }

    n.key,
    ":",
    n.value,
    path.call(print, "value"),
    options
  );
}

function printBinaryishExpression(path, options, print) {
  const isInsideParenthesis =
    n !== parent.body &&
    (parent.type === "IfStatement" ||
      parent.type === "WhileStatement" ||
      parent.type === "SwitchStatement" ||
      parent.type === "DoWhileStatement");

  const parts = printBinaryishExpressions(
    path,
    print,
    options,
    /* isNested */ false,
    isInsideParenthesis
  );

  //   if (
  //     this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft
  //   ) {
  //
  // looks super weird, we want to break the children if the parent breaks
  //
  //   if (
  //     this.hasPlugin("dynamicImports") &&
  //     this.lookahead().type === tt.parenLeft
  //   ) {
  if (isInsideParenthesis) {
  }

  // Break between the parens in
  // unaries or in a member or specific call expression, i.e.
  //
  //   (
  //     a &&
  //     b &&
  //     c
  //   ).call()
  if (
    (isCallExpression(parent) && parent.callee === n) ||
    parent.type === "UnaryExpression" ||
    (isMemberExpression(parent) && !parent.computed)
  ) {
    return group([indent([softline, ...parts]), softline]);
  }

  // Avoid indenting sub-expressions in some cases where the first sub-expression is already
  // indented accordingly. We should indent sub-expressions where the first case isn't indented.
  const shouldNotIndent =
    parent.type === "ReturnStatement" ||
    parent.type === "ThrowStatement" ||
    (parent.type === "JSXExpressionContainer" &&
      parentParent.type === "JSXAttribute") ||
    (n.operator !== "|" && parent.type === "JsExpressionRoot") ||
    (n.type !== "NGPipeExpression" &&
      ((parent.type === "NGRoot" && options.parser === "__ng_binding") ||
        (parent.type === "NGMicrosyntaxExpression" &&
          parentParent.type === "NGMicrosyntax" &&
          parentParent.body.length === 1))) ||
    (n === parent.body && parent.type === "ArrowFunctionExpression") ||
    (n !== parent.body && parent.type === "ForStatement") ||
    (parent.type === "ConditionalExpression" &&
      parentParent.type !== "ReturnStatement" &&
      parentParent.type !== "ThrowStatement" &&
      !isCallExpression(parentParent)) ||
    parent.type === "TemplateLiteral";

  const shouldIndentIfInlining =
    parent.type === "AssignmentExpression" ||
    parent.type === "VariableDeclarator" ||
    parent.type === "ClassProperty" ||
    parent.type === "PropertyDefinition" ||
    parent.type === "TSAbstractClassProperty" ||
    parent.type === "ClassPrivateProperty" ||
    parent.type === "ObjectProperty" ||
    parent.type === "Property";

  const samePrecedenceSubExpression =
    isBinaryish(n.left) && shouldFlatten(n.operator, n.left.operator);

  if (
    shouldNotIndent ||
    (shouldInlineLogicalExpression(n) && !samePrecedenceSubExpression) ||
    (!shouldInlineLogicalExpression(n) && shouldIndentIfInlining)
  ) {
    return group(parts);
  }

    return "";
  }

  // If the right part is a JSX node, we include it in a separate group to
  // prevent it breaking the whole chain, so we can print the expression like:
  //
  //   foo && bar && (
  //     <Foo>
  //       <Bar />
  //     </Foo>
  //   )

  const hasJsx = isJsxNode(n.right);

  const firstGroupIndex = parts.findIndex(
    (part) =>
      typeof part !== "string" && !Array.isArray(part) && part.type === "group"
  );

  // Separate the leftmost expression, possibly with its leading comments.
  const headParts = parts.slice(
    0,
    firstGroupIndex === -1 ? 1 : firstGroupIndex + 1
  );

  const rest = parts.slice(headParts.length, hasJsx ? -1 : undefined);

  const groupId = Symbol("logicalChain-" + ++uid);

  const chain = group(
    [
      // Don't include the initial expression in the indentation
      // level. The first item is guaranteed to be the first
      // left-most expression.
      ...headParts,
      indent(rest),
    ],
    { id: groupId }
  );

  if (!hasJsx) {
    return chain;
  }

  const jsxPart = getLast(parts);
  return group([chain, indentIfBreak(jsxPart, { groupId })]);
}

function printBinaryishExpressions(
  path,
  print,
  options,
  isNested,
  isInsideParenthesis
) {

  // We treat BinaryExpression and LogicalExpression nodes the same.
  if (isBinaryish(node)) {
    // Put all operators with the same precedence level in the same
    // group. The reason we only need to do this with the `left`
    // expression is because given an expression like `1 + 2 - 3`, it
    // is always parsed like `((1 + 2) - 3)`, meaning the `left` side
    // is where the rest of the expression will exist. Binary
    // expressions on the right side mean they have a difference
    // precedence level and should be treated as a separate group, so
    // print them normally. (This doesn't hold for the `**` operator,
    // which is unique in that it is right-associative.)
    if (shouldFlatten(node.operator, node.left.operator)) {
      // Flatten them out by recursively calling this function.
      parts = [
        ...parts,
        ...path.call(
          (left) =>
            printBinaryishExpressions(
              left,
              print,
              options,
              /* isNested */ true,
              isInsideParenthesis
            ),
          "left"
        ),
      ];
    } else {
      parts.push(group(path.call(print, "left")));
    }

    const shouldInline = shouldInlineLogicalExpression(node);
    const lineBeforeOperator =
      (node.operator === "|>" ||
        node.type === "NGPipeExpression" ||
        (node.operator === "|" && options.parser === "__vue_expression")) &&
      !hasLeadingOwnLineComment(options.originalText, node.right);

    const operator = node.type === "NGPipeExpression" ? "|" : node.operator;
    const rightSuffix =
      node.type === "NGPipeExpression" && node.arguments.length > 0
        ? group(
            indent([
              softline,
              ": ",
              join(
                [softline, ":", ifBreak(" ")],
                path.map(print, "arguments").map((arg) => align(2, group(arg)))
              ),
            ])
          )
        : "";

    const right = shouldInline
      ? [operator, " ", path.call(print, "right"), rightSuffix]
      : [
          lineBeforeOperator ? line : "",
          operator,
          lineBeforeOperator ? " " : line,
          path.call(print, "right"),
          rightSuffix,
        ];

    // If there's only a single binary expression, we want to create a group
    // in order to avoid having a small right part like -1 be on its own line.
    const shouldBreak = hasComment(
      node.left,
    );
    const shouldGroup =
      shouldBreak ||
      (!(isInsideParenthesis && node.type === "LogicalExpression") &&
        parent.type !== node.type &&
        node.left.type !== node.type &&
        node.right.type !== node.type);

      lineBeforeOperator ? "" : " ",
      shouldGroup ? group(right, { shouldBreak }) : right
    );

    // The root comments are already printed, but we need to manually print
    // the other ones since we don't call the normal print on BinaryExpression,
    // only for the left and right parts
    if (isNested && hasComment(node)) {
      const printed = cleanDoc(printComments(path, () => parts, options));
      /* istanbul ignore else */
        parts = getDocParts(printed);
      } else {
        parts = [printed];
      }
    }
  } else {
    // Our stopping case. Simply print the node normally.
    parts.push(group(path.call(print)));
  }

}

function shouldInlineLogicalExpression(node) {
  if (node.type !== "LogicalExpression") {
  }

  if (
    node.right.type === "ObjectExpression" &&
    node.right.properties.length > 0
  ) {
  }

  if (node.right.type === "ArrayExpression" && node.right.elements.length > 0) {
  }

  if (isJsxNode(node.right)) {
  }

}

function printFunctionParameters(
  path,
  print,
  options,
  expandArg,
  printTypeParams
) {
  const functionNode = path.getValue();
  const parameters = getFunctionParameters(functionNode);
  const typeParams = printTypeParams
    ? printFunctionTypeParameters(path, options, print)
    : "";

  if (parameters.length === 0) {
    return [
      typeParams,
      "(",
      printDanglingComments(
        path,
        options,
        /* sameIndent */ true,
            comment,
            locEnd
          ) === ")"
      ),
      ")",
    ];
  }

  const isParametersInTestCall = isTestCall(parent);
  const shouldHugParameters = shouldHugFunctionParameters(functionNode);
  const shouldExpandParameters =
    expandArg && !parameters.some((node) => hasComment(node));
  const printed = [];
  iterateFunctionParametersPath(path, (parameterPath, index) => {
    const isLastParameter = index === parameters.length - 1;
    if (isLastParameter && functionNode.rest) {
      printed.push("...");
    }
    printed.push(parameterPath.call(print));
    if (isLastParameter) {
      return;
    }
    printed.push(",");
    if (
      isParametersInTestCall ||
      shouldHugParameters ||
      shouldExpandParameters
    ) {
      printed.push(" ");
    } else if (isNextLineEmpty(parameters[index], options)) {
      printed.push(hardline, hardline);
    } else {
      printed.push(line);
    }
  });

  // If the parent is a call with the first/last argument expansion and this is the
  // params of the first/last argument, we don't want the arguments to break and instead
  // want the whole expression to be on a new line.
  //
  // Good:                 Bad:
  //   verylongcall(         verylongcall((
  //     (a, b) => {           a,
  //     }                     b,
  //   })                    ) => {
  //                         })
  if (shouldExpandParameters) {
      removeLines(typeParams),
      "(",
      ...printed.map(removeLines),
      ")",
    ]);
  }

  // Single object destructuring should hug
  //
  // function({
  //   a,
  //   b,
  //   c
  // }) {}
  const hasNotParameterDecorator = parameters.every((node) => !node.decorators);
  if (shouldHugParameters && hasNotParameterDecorator) {
    return [typeParams, "(", ...printed, ")"];
  }

  // don't break in specs, eg; `it("should maintain parens around done even when long", (done) => {})`
  if (isParametersInTestCall) {
  }

  const isFlowShorthandWithOneArg =
    (isObjectTypePropertyAFunction(parent) ||
      isTypeAnnotationAFunction(parent) ||
      parent.type === "TypeAlias" ||
      parent.type === "TSUnionType" ||
      parent.type === "IntersectionTypeAnnotation" ||
      (parent.type === "FunctionTypeAnnotation" &&
        parent.returnType === functionNode)) &&
    parameters[0].name === null &&
    // `type q = (this: string) => void;`
    functionNode.this !== parameters[0] &&
    parameters[0].typeAnnotation &&
    functionNode.typeParameters === null &&
    isSimpleType(parameters[0].typeAnnotation) &&
    !functionNode.rest;

  if (isFlowShorthandWithOneArg) {
    if (options.arrowParens === "always") {
    }
  }

  return [
    typeParams,
    "(",
    indent([softline, ...printed]),
    ifBreak(
      !hasRestParameter(functionNode) && shouldPrintComma(options, "all")
        ? ","
        : ""
    ),
    softline,
    ")",
  ];
}

function shouldHugFunctionParameters(node) {
  }
  if (parameters.length !== 1) {
  }
  const [parameter] = parameters;
  return (
    !hasComment(parameter) &&
    (parameter.type === "ObjectPattern" ||
      parameter.type === "ArrayPattern" ||
      (parameter.type === "Identifier" &&
        parameter.typeAnnotation &&
        (parameter.typeAnnotation.type === "TypeAnnotation" ||
          parameter.typeAnnotation.type === "TSTypeAnnotation") &&
        isObjectType(parameter.typeAnnotation.typeAnnotation)) ||
      (parameter.type === "FunctionTypeParam" &&
        isObjectType(parameter.typeAnnotation)) ||
      (parameter.type === "AssignmentPattern" &&
        (parameter.left.type === "ObjectPattern" ||
          parameter.left.type === "ArrayPattern") &&
        (parameter.right.type === "Identifier" ||
          (parameter.right.type === "ObjectExpression" &&
            parameter.right.properties.length === 0) ||
          (parameter.right.type === "ArrayExpression" &&
            parameter.right.elements.length === 0))))
  );
}

function conditionalExpressionChainContainsJsx(node) {
  // Given this code:
  //
  // // Using a ConditionalExpression as the consequent is uncommon, but should
  // // be handled.
  // A ? B : C ? D : E ? F ? G : H : I
  //
  // which has this AST:
  //
  // ConditionalExpression {
  //   test: Identifier(A),
  //   consequent: Identifier(B),
  //   alternate: ConditionalExpression {
  //     test: Identifier(C),
  //     consequent: Identifier(D),
  //     alternate: ConditionalExpression {
  //       test: Identifier(E),
  //       consequent: ConditionalExpression {
  //         test: Identifier(F),
  //         consequent: Identifier(G),
  //         alternate: Identifier(H),
  //       },
  //       alternate: Identifier(I),
  //     }
  //   }
  // }
  //
  // We don't care about whether each node was the test, consequent, or alternate
  // We are only checking if there's any JSXElements inside.
  const conditionalExpressions = [node];
  for (let index = 0; index < conditionalExpressions.length; index++) {
    const conditionalExpression = conditionalExpressions[index];
    for (const property of ["test", "consequent", "alternate"]) {
      const node = conditionalExpression[property];

      if (isJsxNode(node)) {
      }

      if (node.type === "ConditionalExpression") {
        conditionalExpressions.push(node);
      }
    }
  }

}

function printTernaryTest(path, options, print) {
  const isConditionalExpression = node.type === "ConditionalExpression";
  const alternateNodePropertyName = isConditionalExpression
    ? "alternate"
    : "falseType";

  const printed = isConditionalExpression
    ? path.call(print, "test")
    : [
        path.call(print, "checkType"),
        " ",
        "extends",
        " ",
        path.call(print, "extendsType"),
      ];
  /**
   *     a
   *       ? b
   *       : multiline
   *         test
   *         node
   *       ^^ align(2)
   *       ? d
   *       : e
   */
  if (parent.type === node.type && parent[alternateNodePropertyName] === node) {
    return align(2, printed);
  }
}

function shouldExtraIndentForConditionalExpression(path) {
  if (node.type !== "ConditionalExpression") {
  }

  let parent;
  let child = node;
  for (let ancestorCount = 0; !parent; ancestorCount++) {
    const node = path.getParentNode(ancestorCount);

    if (
      (isCallExpression(node) && node.callee === child) ||
      (isMemberExpression(node) && node.object === child) ||
      (node.type === "TSNonNullExpression" && node.expression === child)
    ) {
      child = node;
      continue;
    }

    // Reached chain root

    if (
      (node.type === "NewExpression" && node.callee === child) ||
      (node.type === "TSAsExpression" && node.expression === child)
    ) {
      parent = path.getParentNode(ancestorCount + 1);
    } else {
      parent = node;
    }
  }

  // Do not add indent to direct `ConditionalExpression`
  if (child === node) {
  }

  return parent[ancestorNameMap.get(parent.type)] === child;
}

function printTernary(path, options, print) {
  const consequentNodePropertyName = isConditionalExpression
    ? "consequent"
    : "trueType";
  const testNodePropertyNames = isConditionalExpression
    ? ["test"]
    : ["checkType", "extendsType"];
  const consequentNode = node[consequentNodePropertyName];
  const alternateNode = node[alternateNodePropertyName];

  // We print a ConditionalExpression in either "JSX mode" or "normal mode".
  // See tests/jsx/conditional-expression.js for more info.
  let jsxMode = false;
  const isParentTest =
    parent.type === node.type &&
    testNodePropertyNames.some((prop) => parent[prop] === node);
  let forceNoIndent = parent.type === node.type && !isParentTest;

  // Find the outermost non-ConditionalExpression parent, and the outermost
  // ConditionalExpression parent. We'll use these to determine if we should
  // print in JSX mode.
  let currentParent;
  let previousParent;
  let i = 0;
  do {
    previousParent = currentParent || node;
    currentParent = path.getParentNode(i);
    i++;
  } while (
    currentParent &&
    currentParent.type === node.type &&
    testNodePropertyNames.every(
      (prop) => currentParent[prop] !== previousParent
    )
  );
  const firstNonConditionalParent = currentParent || parent;
  const lastConditionalParent = previousParent;

  if (
    isConditionalExpression &&
    (isJsxNode(node[testNodePropertyNames[0]]) ||
      isJsxNode(consequentNode) ||
      isJsxNode(alternateNode) ||
      conditionalExpressionChainContainsJsx(lastConditionalParent))
  ) {
    jsxMode = true;
    forceNoIndent = true;

    // Even though they don't need parens, we wrap (almost) everything in
    // parens when using ?: within JSX, because the parens are analogous to
    // curly braces in an if statement.
    const wrap = (doc) => [
      ifBreak("("),
      indent([softline, doc]),
      softline,
    ];

    // The only things we don't wrap are:
    // * Nested conditional expressions in alternates
    // * null
    // * undefined
    const isNil = (node) =>
      node.type === "NullLiteral" ||
      (node.type === "Literal" && node.value === null) ||
      (node.type === "Identifier" && node.name === "undefined");

      " ? ",
      isNil(consequentNode)
        ? path.call(print, consequentNodePropertyName)
        : wrap(path.call(print, consequentNodePropertyName)),
      " : ",
      alternateNode.type === node.type || isNil(alternateNode)
        ? path.call(print, alternateNodePropertyName)
        : wrap(path.call(print, alternateNodePropertyName))
    );
  } else {
    // normal mode
    const part = [
      line,
      "? ",
      consequentNode.type === node.type ? ifBreak("", "(") : "",
      align(2, path.call(print, consequentNodePropertyName)),
      consequentNode.type === node.type ? ifBreak("", ")") : "",
      line,
      ": ",
      alternateNode.type === node.type
        : align(2, path.call(print, alternateNodePropertyName)),
    ];
      parent.type !== node.type ||
        parent[alternateNodePropertyName] === node ||
        isParentTest
        ? part
        : options.useTabs
        ? dedent(indent(part))
        : align(Math.max(0, options.tabWidth - 2), part)
    );
  }

  // We want a whole chain of ConditionalExpressions to all
  // break if any of them break. That means we should only group around the
  // outer-most ConditionalExpression.
  const comments = flat([
    ...testNodePropertyNames.map((propertyName) =>
      getComments(node[propertyName])
    ),
    getComments(consequentNode),
    getComments(alternateNode),
  ]);
  const shouldBreak = comments.some(
    (comment) =>
      isBlockComment(comment) &&
        locStart(comment),
        locEnd(comment)
      )
  );
  const maybeGroup = (doc) =>
    parent === firstNonConditionalParent
      ? group(doc, { shouldBreak })
      : shouldBreak
      ? [doc, breakParent]
      : doc;

  // Break the closing paren to keep the chain right after it:
  // (a
  //   ? b
  //   : c
  // ).call()
  const breakClosingParen =
    !jsxMode &&
    (isMemberExpression(parent) ||
      (parent.type === "NGPipeExpression" && parent.left === node)) &&
    !parent.computed;

  const shouldExtraIndent = shouldExtraIndentForConditionalExpression(path);

  const result = maybeGroup([
    printTernaryTest(path, options, print),
    forceNoIndent ? parts : indent(parts),
    isConditionalExpression && breakClosingParen && !shouldExtraIndent
      ? softline
      : "",
  ]);

  return isParentTest || shouldExtraIndent
    ? group([indent([softline, result]), softline])
    : result;
}

(doc) => [
      softline,
    ]

(node) =>
      (node.type === "Identifier" && node.name === "undefined")

(doc) =>
      : doc

function printTypeParameters(path, options, print, paramsKey) {

  if (!n[paramsKey]) {
    return "";
  }

  // for TypeParameterDeclaration typeParameters is a single node
  if (!Array.isArray(n[paramsKey])) {
    return path.call(print, paramsKey);
  }

  const grandparent = path.getNode(2);
  const isParameterInTestCall = grandparent != null && isTestCall(grandparent);

    isParameterInTestCall ||
    n[paramsKey].length === 0 ||
    (n[paramsKey].length === 1 &&
      (shouldHugType(n[paramsKey][0]) ||
        (n[paramsKey][0].type === "GenericTypeAnnotation" &&
          shouldHugType(n[paramsKey][0].id)) ||
        (n[paramsKey][0].type === "TSTypeReference" &&
          shouldHugType(n[paramsKey][0].typeName)) ||
        n[paramsKey][0].type === "NullableTypeAnnotation"));

    return [
      "<",
      join(", ", path.map(print, paramsKey)),
      printDanglingCommentsForInline(path, options),
      ">",
    ];
  }

  // Keep comma if the file extension is .tsx and
  // has one type parameter that isn't extend with any types.
  // Because, otherwise formatted result will be invalid as tsx.
  const trailingComma =
    getFunctionParameters(n).length === 1 &&
    isTSXFile(options) &&
    !n[paramsKey][0].constraint &&
    path.getParentNode().type === "ArrowFunctionExpression"
      ? ","
      : shouldPrintComma(options, "all")
      ? ifBreak(",")
      : "";

    [
      "<",
      indent([softline, join([",", line], path.map(print, paramsKey))]),
      trailingComma,
      softline,
      ">",
    ],
    { id: getTypeParametersGroupId(n) }
  );
}

function printDanglingCommentsForInline(path, options) {
  if (!hasComment(n, CommentCheckFlags.Dangling)) {
    return "";
  }
  const hasOnlyBlockComments = !hasComment(n, CommentCheckFlags.Line);
  const printed = printDanglingComments(
    path,
    options,
    /* sameIndent */ hasOnlyBlockComments
  );
  if (hasOnlyBlockComments) {
  }
  return [printed, hardline];
}

function printTypeParameter(path, options, print) {
  if (parent.type === "TSMappedType") {
    parts.push("[", path.call(print, "name"));
    if (n.constraint) {
      parts.push(" in ", path.call(print, "constraint"));
    }
    if (parent.nameType) {
        " as ",
        path.callParent((path) => path.call(print, "nameType"))
      );
    }
    parts.push("]");
  }

  }

  if (n.bound) {
    parts.push(": ", path.call(print, "bound"));
  }

  if (n.constraint) {
    parts.push(" extends ", path.call(print, "constraint"));
  }

  if (n.default) {
    parts.push(" = ", path.call(print, "default"));
  }

}

function printOptionalToken(path) {
  if (
    !node.optional ||
    // It's an optional computed method parsed by typescript-estree.
    // "?" is printed in `printMethod`.
    (node.type === "Identifier" && node === path.getParentNode().key)
  ) {
    return "";
  }
  if (
    node.type === "OptionalCallExpression" ||
    (node.type === "OptionalMemberExpression" && node.computed)
  ) {
    return "?.";
  }
  return "?";
}

function printFunctionTypeParameters(path, options, print) {
  const fun = path.getValue();
  if (fun.typeArguments) {
    return path.call(print, "typeArguments");
  }
  if (fun.typeParameters) {
    return path.call(print, "typeParameters");
  }
  return "";
}

function printTypeAnnotation(path, options, print) {
  if (!node.typeAnnotation) {
    return "";
  }

  const isDefinite =
    node.definite ||
    (parentNode &&
      parentNode.type === "VariableDeclarator" &&
      parentNode.definite);

  const isFunctionDeclarationIdentifier =
    parentNode.type === "DeclareFunction" && parentNode.id === node;

  if (isFlowAnnotationComment(options.originalText, node.typeAnnotation)) {
    return [" /*: ", path.call(print, "typeAnnotation"), " */"];
  }

  return [
    isFunctionDeclarationIdentifier ? "" : isDefinite ? "!: " : ": ",
    path.call(print, "typeAnnotation"),
  ];
}

function printBindExpressionCallee(path, options, print) {
  return ["::", path.call(print, "callee")];
}

function printTypeScriptModifiers(path, options, print) {
  if (!isNonEmptyArray(n.modifiers)) {
    return "";
  }
  return [join(" ", path.map(print, "modifiers")), " "];
}

function adjustClause(node, clause, forceSpace) {
  if (node.type === "EmptyStatement") {
    return ";";
  }

  if (node.type === "BlockStatement" || forceSpace) {
    return [" ", clause];
  }

  return indent([line, clause]);
}

function format(path, print, textToDoc) {

  const numQuasis = node.quasis.length;
  if (numQuasis === 1 && node.quasis[0].value.raw.trim() === "") {
  }

  const expressionDocs = printTemplateExpressions(path, print);

  for (let i = 0; i < numQuasis; i++) {
    const templateElement = node.quasis[i];
    const isFirst = i === 0;
    const isLast = i === numQuasis - 1;
    const text = templateElement.value.cooked;

    const lines = text.split("\n");
    const numLines = lines.length;
    const expressionDoc = expressionDocs[i];

    const startsWithBlankLine =
      numLines > 2 && lines[0].trim() === "" && lines[1].trim() === "";
    const endsWithBlankLine =
      numLines > 2 &&
      lines[numLines - 1].trim() === "" &&
      lines[numLines - 2].trim() === "";

    const commentsAndWhitespaceOnly = lines.every((line) =>
      /^\s*(?:#[^\n\r]*)?$/.test(line)
    );

    // Bail out if an interpolation occurs within a comment.
    if (!isLast && /#[^\n\r]*$/.test(lines[numLines - 1])) {
    }

    let doc = null;

    if (commentsAndWhitespaceOnly) {
      doc = printGraphqlComments(lines);
    } else {
      doc = textToDoc(
        text,
        { parser: "graphql" },
      );
    }

    if (doc) {
      doc = escapeTemplateCharacters(doc, false);
      if (!isFirst && startsWithBlankLine) {
        parts.push("");
      }
      parts.push(doc);
      if (!isLast && endsWithBlankLine) {
      }
    } else if (!isFirst && !isLast && startsWithBlankLine) {
      parts.push("");
    }

    if (expressionDoc) {
      parts.push(expressionDoc);
    }
  }

  return ["`", indent([hardline, join(hardline, parts)]), hardline, "`"];
}

  const array = lines.map((textLine) => textLine.trim());
  for (const [i, textLine] of array.entries()) {
    // Lines are either whitespace only, or a comment (with potential whitespace
      continue;
    }

      parts.push([hardline, textLine]);
    } else {
    }

  }

}

function format(path, print, textToDoc, options, { parser }) {
  const counter = htmlTemplateLiteralCounter;
  htmlTemplateLiteralCounter = (htmlTemplateLiteralCounter + 1) >>> 0;

  const composePlaceholder = (index) =>
    `PRETTIER_HTML_PLACEHOLDER_${index}_${counter}_IN_JS`;

  const text = node.quasis
    .map((quasi, index, quasis) =>
      index === quasis.length - 1
        ? quasi.value.cooked
        : quasi.value.cooked + composePlaceholder(index)
    )
    .join("");

  if (expressionDocs.length === 0 && text.trim().length === 0) {
  }

  const placeholderRegex = new RegExp(composePlaceholder("(\\d+)"), "g");
  let topLevelCount = 0;
  const doc = textToDoc(
    text,
    {
      parser,
      __onHtmlRoot(root) {
        topLevelCount = root.children.length;
      },
    },
    { stripTrailingHardline: true }
  );

  const contentDoc = mapDoc(doc, (doc) => {
    if (typeof doc !== "string") {
    }

    const components = doc.split(placeholderRegex);
    for (let i = 0; i < components.length; i++) {
      let component = components[i];

      if (i % 2 === 0) {
        if (component) {
          component = uncookTemplateElementValue(component);
          if (options.__embeddedInHtml) {
            component = component.replace(/<\/(script)\b/gi, "<\\/$1");
          }
          parts.push(component);
        }
        continue;
      }

      const placeholderIndex = Number(component);
      parts.push(expressionDocs[placeholderIndex]);
    }

  });

  const leadingWhitespace = /^\s/.test(text) ? " " : "";
  const trailingWhitespace = /\s$/.test(text) ? " " : "";

  const linebreak =
      ? hardline
      : leadingWhitespace && trailingWhitespace
      ? line
      : null;

  if (linebreak) {
    return group(["`", indent([linebreak, group(contentDoc)]), linebreak, "`"]);
  }

    "`",
    topLevelCount > 1 ? indent(group(contentDoc)) : group(contentDoc),
    "`",
  ]);
}

(index) =>
    `PRETTIER_HTML_PLACEHOLDER_${index}_${counter}_IN_JS`

__onHtmlRoot(root) {
      }

  let text = node.quasis[0].value.raw.replace(
    /((?:\\\\)*)\\`/g,
    (_, backslashes) => "\\".repeat(backslashes.length / 2) + "`"
  );
  const indentation = getIndentation(text);
  const hasIndent = indentation !== "";
  if (hasIndent) {
    text = text.replace(new RegExp(`^${indentation}`, "gm"), "");
  }
  const doc = escapeTemplateCharacters(
      text,
      { parser: "markdown", __inJsTemplate: true },
    ),
    true
  );
  return [
    "`",
    hasIndent ? indent([softline, doc]) : [literalline, dedentToRoot(doc)],
    softline,
    "`",
  ];
}

function getIndentation(str) {
  const firstMatchedIndent = str.match(/^([^\S\n]*)\S/m);
  return firstMatchedIndent === null ? "" : firstMatchedIndent[1];
}

  // Get full template literal with expressions replaced by placeholders
  const rawQuasis = node.quasis.map((q) => q.value.raw);
  let placeholderID = 0;
  const text = rawQuasis.reduce(
    (prevVal, currVal, idx) =>
      idx === 0
        ? currVal
        : prevVal +
          "@prettier-placeholder-" +
          placeholderID++ +
          "-id" +
          currVal,
    ""
  );
    text,
    { parser: "scss" },
  );
  return transformCssDoc(doc, node, expressionDocs);
}

function transformCssDoc(quasisDoc, parentNode, expressionDocs) {
  }

  }
  return ["`", indent([hardline, newDoc]), softline, "`"];
}

  if (!isNonEmptyArray(expressionDocs)) {
  }
  let replaceCounter = 0;
  const newDoc = mapDoc(cleanDoc(quasisDoc), (doc) => {
    if (typeof doc !== "string" || !doc.includes("@prettier-placeholder")) {
    }
    // When we have multiple placeholders in one line, like:
    // ${Child}${Child2}:not(:first-child)
    return doc.split(/@prettier-placeholder-(\d+)-id/).map((component, idx) => {
      // The placeholder is always at odd indices
      if (idx % 2 === 0) {
        return replaceNewlinesWithLiterallines(component);
      }

      // The component will always be a number at odd index
      replaceCounter++;
      return expressionDocs[component];
    });
  });
  return expressionDocs.length === replaceCounter ? newDoc : null;
}

function createParser(options) {
  options = typeof options === "function" ? { parse: options } : options;

  return {
    astFormat: "estree",
    locStart,
    locEnd,
    ...options,
  };
}

  return {
    length: 0,
    value: ""
  };
}

function makeIndent(ind, options) {
  return {
    length: ind.length + options.tabWidth,
    value: ind.value + (options.useTabs ? "\t" : " ".repeat(options.tabWidth))
  };
}

function makeAlign(ind, n, options) {
  return n === -Infinity
    ? rootIndent()
    : typeof n === "string"
      ? {
          length: ind.length + n.length,
          value: ind.value + n
        }
      : options.useTabs && n > 0
        ? makeIndent(ind, options)
        : {
            length: ind.length + n,
            value: ind.value + " ".repeat(n)
          };
}

function fits(next, restCommands, width, options, mustBeFlat) {
      }

      continue;
    }

    } else {
          }

          break;
          cmds.push([makeIndent(ind, options), mode, doc.contents]);

          break;
          cmds.push([makeAlign(ind, doc.n, options), mode, doc.contents]);

          break;
          }

          break;
          }

          break;
            }
          }
            }
          }

          break;
                  width -= 1;
                }

                break;
              }

          }
          break;
      }
    }
  }
}

  let pos = 0;

    } else {

          break;
          }

          break;

          break;

          break;
                  ind,
                ]);

                break;
              }

              if (!doc.break && fits(next, cmds, rem, options)) {
              } else {

                    break;
                  } else {

                        break;
                      } else {

                        if (fits(cmd, cmds, rem, options)) {

                          break;
                        }
                      }
                    }
                  }
                } else {
                }
              }

              break;
            }
          }
          break;
        //
        //
        // or
        //

            break;
          }

          const contentFits = fits(contentFlatCmd, [], rem, options, true);

            } else {
            }
            break;
          }

            } else {
            }
            break;
          }

            ind,
          ];
            [],
            rem,
            options,
            true
          );

          } else {
          }
          break;
        }
            }
          }
            }
          }

          break;
          break;
          }
          break;

                  pos += 1;
                }

                break;
              } else {
              }

                break;
              }

                pos = 0;
              } else {
                  while (
                  ) {
                  }

                  if (
                    out.length &&
                    (options.parser !== "markdown" ||
                      // preserve markdown's `break` node (two trailing spaces)
                      !/\S {2}$/.test(out[out.length - 1]))
                  ) {
                      ""
                    );
                  }
                }

                out.push(newLine + ind.value);
                pos = ind.length;
              }
              break;
          }
          break;
        default:
      }
    }
  }

    return {
    };
  }

}

  if (
    doc.parts.length === 2 &&
    doc.parts[1].type === "concat" &&
    doc.parts[1].parts.length === 2 &&
    doc.parts[1].parts[0].hard &&
    doc.parts[1].parts[1].type === "break-parent"
  ) {
    return doc.parts[0];
  }
}

function tryCombinations(...combinations) {
  let firstError;
  for (const [index, fn] of combinations.entries()) {
    try {
      return { result: fn() };
        firstError = error;
      }
    }
  }
  return { error: firstError };
}

function getFileContentOrNull(filename) {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, "utf8", (error, data) => {
      if (error && error.code !== "ENOENT") {
        reject(createError(filename, error));
      } else {
        resolve(error ? null : data);
      }
    });
  });
}

function createError(filename, error) {
  return new Error(`Unable to read ${filename}: ${error.message}`);
}

(object, keyName) =>
  Object.entries(object).map(([key, value]) => ({
    [keyName]: key,
    ...value,
  }))

  let delimiter;

  if (text.indexOf("---") === 0) {
    delimiter = "---";
  } else if (text.indexOf("+++") === 0) {
    delimiter = "+++";
  }

  let end = -1;

  if (!delimiter || (end = text.indexOf(`\n${delimiter}`, 3)) === -1) {
    return { frontMatter: null, content: text };
  }

  end = end + 4;

  return {
    frontMatter: text.slice(0, end),
    content: text.slice(end)
  };
}

  const match = text.match(frontMatterRegex);
    return { content: text };
  }

  const { startDelimiter, language, value = "", endDelimiter } = match.groups;

  let lang = language.trim() || "yaml";
  if (startDelimiter === "+++") {
    lang = "toml";
  }

  // Only allow yaml to parse with a different end delimiter
  if (lang !== "yaml" && startDelimiter !== endDelimiter) {
  }

  const [raw] = match;
  const frontMatter = {
    type: "front-matter",
    lang,
    value,
    startDelimiter,
    endDelimiter,
    raw: raw.replace(/\n$/, ""),
  };

  return {
    frontMatter,
    content: raw.replace(/[^\n]/g, " ") + text.slice(raw.length),
  };
}

function print(node, textToDoc) {
  if (node.lang === "yaml") {
    const value = node.value.trim();
    const doc = value
      ? textToDoc(value, { parser: "yaml" }, { stripTrailingHardline: true })
      : "";
    return markAsRoot([
      node.startDelimiter,
      hardline,
      doc,
      doc ? hardline : "",
      node.endDelimiter,
    ]);
  }
}

  return { value: "", length: 0, queue: [] };
}

  return generateInd(ind, { type: "indent" }, options);
}

function makeAlign(indent, n, options) {
  if (n === Number.NEGATIVE_INFINITY) {
    return indent.root || rootIndent();
  }

  if (n < 0) {
    return generateInd(indent, { type: "dedent" }, options);
  }

  if (!n) {
    return indent;
  }

  if (n.type === "root") {
    return { ...indent, root: indent };
  }

  const alignType = typeof n === "string" ? "stringAlign" : "numberAlign";

  return generateInd(indent, { type: alignType, n }, options);
}

function generateInd(ind, newPart, options) {
  const queue =
    newPart.type === "dedent"
      ? ind.queue.slice(0, -1)
      : [...ind.queue, newPart];

  let value = "";
  let length = 0;
  let lastTabs = 0;
  let lastSpaces = 0;

  for (const part of queue) {
    switch (part.type) {
        flush();
        if (options.useTabs) {
          addTabs(1);
        } else {
          addSpaces(options.tabWidth);
        }
        break;
      case "stringAlign":
        flush();
        value += part.n;
        length += part.n.length;
        break;
      case "numberAlign":
        lastTabs += 1;
        lastSpaces += part.n;
        break;
      default:
        throw new Error(`Unexpected type '${part.type}'`);
    }
  }

  flushSpaces();

  return { ...ind, value, length, queue };

  function addTabs(count) {
    value += "\t".repeat(count);
    length += options.tabWidth * count;
  }

  function addSpaces(count) {
    value += " ".repeat(count);
    length += count;
  }

  function flush() {
    if (options.useTabs) {
      flushTabs();
    } else {
      flushSpaces();
    }
  }

  function flushTabs() {
    if (lastTabs > 0) {
      addTabs(lastTabs);
    }
    resetLast();
  }

  function flushSpaces() {
    if (lastSpaces > 0) {
      addSpaces(lastSpaces);
    }
  }

  function resetLast() {
    lastTabs = 0;
    lastSpaces = 0;
  }
}

function addTabs(count) {
  }

function addSpaces(count) {
  }

function flush() {
    } else {
    }
  }

function flushTabs() {
    }
  }

function flushSpaces() {
    }
  }

function resetLast() {
  }

function trim(out) {
  if (out.length === 0) {
    return 0;
  }

  let trimCount = 0;

  // Trim whitespace at the end of line
  while (
    out.length > 0 &&
    typeof out[out.length - 1] === "string" &&
    /^[\t ]*$/.test(out[out.length - 1])
  ) {
    trimCount += out.pop().length;
  }

  if (out.length > 0 && typeof out[out.length - 1] === "string") {
    const trimmed = out[out.length - 1].replace(/[\t ]*$/, "");
    trimCount += out[out.length - 1].length - trimmed.length;
    out[out.length - 1] = trimmed;
  }

  return trimCount;
}

function fits(next, restCommands, width, options, hasLineSuffix, mustBeFlat) {
  // `out` is only used for width counting because `trim` requires to look
  // backwards for space characters.
      }

      continue;
    }

    const [ind, mode, doc] = cmds.pop();

      width -= getStringWidth(doc);
    } else if (isConcat(doc)) {
      const parts = getDocParts(doc);
      for (let i = parts.length - 1; i >= 0; i--) {
        cmds.push([ind, mode, parts[i]]);
      }
    } else {

          break;

          break;
        case "trim":
          width += trim(out);

          break;
          }

          if (doc.id) {
            groupModeMap[doc.id] = cmds[cmds.length - 1][1];
          }
          break;
          }

          break;
        case "indent-if-break": {
          const groupMode = doc.groupId ? groupModeMap[doc.groupId] : mode;
          if (groupMode === MODE_BREAK) {
            const breakContents =
              doc.type === "if-break"
                ? doc.breakContents
                : doc.negate
                ? doc.contents
                : indent(doc.contents);
            if (breakContents) {
              cmds.push([ind, mode, breakContents]);
            }
          }
          if (groupMode === MODE_FLAT) {
            const flatContents =
                ? doc.flatContents
                ? indent(doc.contents)
                : doc.contents;
            if (flatContents) {
              cmds.push([ind, mode, flatContents]);
            }
          }

          break;
        }

                  width -= 1;
                }

                break;
              }

          }
          break;
          hasLineSuffix = true;
          break;
          if (hasLineSuffix) {
          }
          break;
        case "label":
          cmds.push([ind, mode, doc.contents]);
          break;
      }
    }
  }
}

  groupModeMap = {};

  const newLine = convertEndOfLineToChars(options.endOfLine);
  let pos = 0;

  while (cmds.length > 0) {

      const formatted = newLine !== "\n" ? doc.replace(/\n/g, newLine) : doc;
      out.push(formatted);
      pos += getStringWidth(formatted);
      }
    } else {

          break;

          break;

          break;
          pos -= trim(out);

          break;
                  ind,
                  doc.contents,
                ]);

                break;
              }

              const hasLineSuffix = lineSuffix.length > 0;

              if (!doc.break && fits(next, cmds, rem, options, hasLineSuffix)) {
              } else {

                    break;
                  } else {

                        break;
                      } else {

                        if (fits(cmd, cmds, rem, options, hasLineSuffix)) {

                          break;
                        }
                      }
                    }
                  }
                } else {
                }
              }

              break;
            }
          }

          }
          break;
        //
        //
        // or
        //

          const { parts } = doc;
            break;
          }

          const [content, whitespace] = parts;
          const contentFits = fits(
            contentFlatCmd,
            [],
            rem,
            options,
            lineSuffix.length > 0,
            true
          );

            } else {
            }
            break;
          }

              cmds.push(whitespaceFlatCmd, contentFlatCmd);
            } else {
              cmds.push(whitespaceBreakCmd, contentBreakCmd);
            }
            break;
          }

          // Ideally we wouldn't mutate the array here but copying all the

            ind,
            [content, whitespace, secondContent],
          ];
            [],
            rem,
            options,
            true
          );

            cmds.push(remainingCmd, whitespaceFlatCmd, contentFlatCmd);
            cmds.push(remainingCmd, whitespaceBreakCmd, contentFlatCmd);
          } else {
            cmds.push(remainingCmd, whitespaceBreakCmd, contentBreakCmd);
          }
          break;
        }
            }
          }
            }
          }

          break;
        }
          break;
          }
          break;

                  pos += 1;
                }

                break;
              } else {
              }

              if (lineSuffix.length > 0) {
                cmds.push([ind, mode, doc], ...lineSuffix.reverse());
                break;
              }

                if (ind.root) {
                  out.push(newLine, ind.root.value);
                  pos = ind.root.length;
                } else {
                  out.push(newLine);
                  pos = 0;
                }
              } else {
                pos -= trim(out);
              }
              break;
          }
          break;
          break;
        default:
      }
    }

    // Flush remaining line-suffix contents at the end of the document, in case
    // there is no new line after the line-suffix.
    if (cmds.length === 0 && lineSuffix.length > 0) {
      cmds.push(...lineSuffix.reverse());
      lineSuffix = [];
    }
  }

    const otherCursorPlaceholderIndex = out.indexOf(
      cursor.placeholder,
      cursorPlaceholderIndex + 1
    );
    const aroundCursor = out
      .slice(cursorPlaceholderIndex + 1, otherCursorPlaceholderIndex)
      .join("");
    const afterCursor = out.slice(otherCursorPlaceholderIndex + 1).join("");

    return {
      formatted: beforeCursor + aroundCursor + afterCursor,
      cursorNodeStart: beforeCursor.length,
      cursorNodeText: aroundCursor,
    };
  }

}

  if (isConcat(doc)) {
    for (const part of getDocParts(doc)) {
      if (isConcat(part)) {
        res.push(...flattenDoc(part).parts);
      } else {
        const flattened = flattenDoc(part);
        }
      }
    }

    return { type: "concat", parts: res };
  }

    return {
      ...doc,
        doc.flatContents != null ? flattenDoc(doc.flatContents) : null,
    };
  }

    return {
      ...doc,
        : doc.expandedStates,
    };
  }

    return { type: "fill", parts: doc.parts.map(flattenDoc) };
  }

  if (doc.contents) {
    return { ...doc, contents: flattenDoc(doc.contents) };
  }

}

function printDocToDebug(doc) {
  /** @type Record<symbol, string> */
  const printedSymbols = Object.create(null);
  /** @type Set<string> */
  const usedKeysForSymbols = new Set();
  return printDoc(flattenDoc(doc));

  function printDoc(doc, index, parentParts) {
      return JSON.stringify(doc);
    }

    if (isConcat(doc)) {
      const printed = getDocParts(doc).map(printDoc).filter(Boolean);
      return printed.length === 1 ? printed[0] : `[${printed.join(", ")}]`;
    }

    if (doc.type === "line") {
      const withBreakParent =
        Array.isArray(parentParts) &&
        parentParts[index + 1] &&
        parentParts[index + 1].type === "break-parent";
      if (doc.literal) {
        return withBreakParent
          ? "literalline"
          : "literallineWithoutBreakParent";
      }
        return withBreakParent ? "hardline" : "hardlineWithoutBreakParent";
      }
      if (doc.soft) {
        return "softline";
      }
      return "line";
    }

    if (doc.type === "break-parent") {
      const afterHardline =
        parentParts[index - 1] &&
        parentParts[index - 1].type === "line" &&
        parentParts[index - 1].hard;
      return afterHardline ? undefined : "breakParent";
    }

    if (doc.type === "trim") {
      return "trim";
    }

    if (doc.type === "indent") {
      return "indent(" + printDoc(doc.contents) + ")";
    }

    if (doc.type === "align") {
      return doc.n === Number.NEGATIVE_INFINITY
        ? "dedentToRoot(" + printDoc(doc.contents) + ")"
        : doc.n < 0
        ? "dedent(" + printDoc(doc.contents) + ")"
        : doc.n.type === "root"
        ? "markAsRoot(" + printDoc(doc.contents) + ")"
        : "align(" +
          JSON.stringify(doc.n) +
          ", " +
          printDoc(doc.contents) +
          ")";
    }

    if (doc.type === "if-break") {
      return (
        "ifBreak(" +
        printDoc(doc.breakContents) +
        (doc.flatContents ? ", " + printDoc(doc.flatContents) : "") +
        (doc.groupId
          ? (!doc.flatContents ? ', ""' : "") +
            `, { groupId: ${printGroupId(doc.groupId)} }`
          : "") +
        ")"
      );
    }

    if (doc.type === "indent-if-break") {
      const optionsParts = [];

      if (doc.negate) {
        optionsParts.push("negate: true");
      }

      if (doc.groupId) {
        optionsParts.push(`groupId: ${printGroupId(doc.groupId)}`);
      }

      const options =
        optionsParts.length > 0 ? `, { ${optionsParts.join(", ")} }` : "";

      return `indentIfBreak(${printDoc(doc.contents)}${options})`;
    }

    if (doc.type === "group") {

      if (doc.break && doc.break !== "propagated") {
        optionsParts.push("shouldBreak: true");
      }

      if (doc.id) {
        optionsParts.push(`id: ${printGroupId(doc.id)}`);
      }

      if (doc.expandedStates) {
        return `conditionalGroup([${doc.expandedStates
          .map((part) => printDoc(part))
          .join(",")}]${options})`;
      }

      return `group(${printDoc(doc.contents)}${options})`;
    }

    if (doc.type === "fill") {
      return `fill([${doc.parts.map((part) => printDoc(part)).join(", ")}])`;
    }

    if (doc.type === "line-suffix") {
      return "lineSuffix(" + printDoc(doc.contents) + ")";
    }

    if (doc.type === "line-suffix-boundary") {
      return "lineSuffixBoundary";
    }

    if (doc.type === "label") {
      return `label(${JSON.stringify(doc.label)}, ${printDoc(doc.contents)})`;
    }

    throw new Error("Unknown doc type " + doc.type);
  }

  function printGroupId(id) {
    if (typeof id !== "symbol") {
      return JSON.stringify(String(id));
    }

    if (id in printedSymbols) {
      return printedSymbols[id];
    }

    // TODO: use Symbol.prototype.description instead of slice once Node 10 is dropped
    const prefix = String(id).slice(7, -1) || "symbol";
    for (let counter = 0; ; counter++) {
      const key = prefix + (counter > 0 ? ` #${counter}` : "");
      if (!usedKeysForSymbols.has(key)) {
        usedKeysForSymbols.add(key);
        return (printedSymbols[id] = `Symbol.for(${JSON.stringify(key)})`);
      }
    }
  }
}

function printDoc(doc, index, parentParts) {
    }

    }

      }
      }
      }
    }

    }

    }

    }

        : doc.n < 0
          ", " +
          ")";
    }

      return (
          : "") +
        ")"
      );
    }

      }

      }

    }

      }

      }

      }

    }

    }

    }

    }

    }

  }

function printGroupId(id) {
    }

    }

      }
    }
  }

(doc) => {
  if (Array.isArray(doc)) {
    return doc;
  }

  if (doc.type !== "concat" && doc.type !== "fill") {
    throw new Error("Expect doc type to be `concat` or `fill`.");
  }

  return doc.parts;
}

  const docsStack = [doc];

  while (docsStack.length > 0) {
    const doc = docsStack.pop();

    if (doc === traverseDocOnExitStackMarker) {
      onExit(docsStack.pop());
      continue;
    }

      docsStack.push(doc, traverseDocOnExitStackMarker);
    }

    if (
      // Should Recurse
      !onEnter ||
      onEnter(doc) !== false
    ) {
      // When there are multiple parts to process,
      // the parts need to be pushed onto the stack in reverse order,
      // so that they are processed in the original order
      // when the stack is popped.
      if (isConcat(doc) || doc.type === "fill") {
        const parts = getDocParts(doc);
        for (let ic = parts.length, i = ic - 1; i >= 0; --i) {
          docsStack.push(parts[i]);
        }
          docsStack.push(doc.flatContents);
        }
          docsStack.push(doc.breakContents);
        }
          for (let ic = doc.expandedStates.length, i = ic - 1; i >= 0; --i) {
            docsStack.push(doc.expandedStates[i]);
          }
        } else {
          docsStack.push(doc.contents);
        }
        docsStack.push(doc.contents);
      }
    }
  }
}

function mapDoc(doc, cb) {
    return cb(doc.map((part) => mapDoc(part, cb)));
  }

    const parts = doc.parts.map((part) => mapDoc(part, cb));
    return cb({ ...doc, parts });
  }

    const breakContents = doc.breakContents && mapDoc(doc.breakContents, cb);
    const flatContents = doc.flatContents && mapDoc(doc.flatContents, cb);
    return cb({ ...doc, breakContents, flatContents });
  }

    const contents = mapDoc(doc.contents, cb);
    return cb({ ...doc, contents });
  }
  return cb(doc);
}

  function findInDocOnEnterFn(doc) {
    }
    }
  }
  traverseDoc(doc, findInDocOnEnterFn);
}

function findInDocOnEnterFn(doc) {
    }
    }
  }

function willBreakFn(doc) {
  if (doc.type === "group" && doc.break) {
  }
  if (doc.type === "line" && doc.hard) {
  }
  }
}

  return findInDoc(doc, willBreakFn, false);
}

    if (!parentGroup.expandedStates && !parentGroup.break) {
      // An alternative truthy value allows to distinguish propagated group breaks
      // and not to print them as `group(..., { break: true })` in `--debug-print-doc`.
      parentGroup.break = "propagated";
    }
  }
}

  const alreadyVisitedSet = new Set();
  function propagateBreaksOnEnterFn(doc) {
      breakParentGroup(groupStack);
    }
      groupStack.push(doc);
      if (alreadyVisitedSet.has(doc)) {
      }
      alreadyVisitedSet.add(doc);
    }
  }
  function propagateBreaksOnExitFn(doc) {
      const group = groupStack.pop();
      if (group.break) {
      }
    }
  }
    doc,
    propagateBreaksOnEnterFn,
    propagateBreaksOnExitFn,
  );
}

function propagateBreaksOnEnterFn(doc) {
    }
      }
    }
  }

function propagateBreaksOnExitFn(doc) {
      }
    }
  }

function removeLinesFn(doc) {
  if (doc.type === "line" && !doc.hard) {
    return doc.soft ? "" : " ";
  }

    return doc.flatContents || "";
  }

}

  return mapDoc(doc, removeLinesFn);
}

(doc, nextDoc) =>
  doc &&
  doc.type === "line" &&
  doc.hard &&
  nextDoc &&
  nextDoc.type === "break-parent"

function stripDocTrailingHardlineFromDoc(doc) {
  if (!doc) {
  }

  if (isConcat(doc) || doc.type === "fill") {
    const parts = getDocParts(doc);

    while (parts.length > 1 && isHardline(...parts.slice(-2))) {
      parts.length -= 2;
    }

    if (parts.length > 0) {
      const lastPart = stripDocTrailingHardlineFromDoc(parts[parts.length - 1]);
      parts[parts.length - 1] = lastPart;
    }
    return Array.isArray(doc) ? parts : { ...doc, parts };
  }

  switch (doc.type) {
    case "align":
    case "indent":
    case "indent-if-break":
    case "group":
    case "line-suffix":
    case "label": {
      const contents = stripDocTrailingHardlineFromDoc(doc.contents);
      return { ...doc, contents };
    }
    case "if-break": {
      const breakContents = stripDocTrailingHardlineFromDoc(doc.breakContents);
      const flatContents = stripDocTrailingHardlineFromDoc(doc.flatContents);
      return { ...doc, breakContents, flatContents };
    }
  }

}

  return stripDocTrailingHardlineFromDoc(cleanDoc(doc));
}

function cleanDocFn(doc) {
    case "fill":
      if (doc.parts.length === 0 || doc.parts.every((part) => part === "")) {
        return "";
      }
      break;
      if (!doc.contents && !doc.id && !doc.break && !doc.expandedStates) {
        return "";
      }
      // Remove nested only group
      if (
        doc.contents.type === "group" &&
        doc.contents.id === doc.id &&
        doc.contents.break === doc.break &&
        doc.contents.expandedStates === doc.expandedStates
      ) {
        return doc.contents;
      }
      break;
      if (!doc.contents) {
        return "";
      }
      break;
    case "if-break":
      if (!doc.flatContents && !doc.breakContents) {
        return "";
      }
      break;
  }

  if (!isConcat(doc)) {
  }

  for (const part of getDocParts(doc)) {
    if (!part) {
      continue;
    }
    const [currentPart, ...restParts] = isConcat(part)
      ? getDocParts(part)
      : [part];
    if (
      typeof currentPart === "string" &&
      typeof parts[parts.length - 1] === "string"
    ) {
      parts[parts.length - 1] += currentPart;
    } else {
      parts.push(currentPart);
    }
    parts.push(...restParts);
  }

    return "";
  }

  if (parts.length === 1) {
    return parts[0];
  }
  return Array.isArray(doc) ? parts : { ...doc, parts };
}

function cleanDoc(doc) {
  return mapDoc(doc, (currentDoc) => cleanDocFn(currentDoc));
}

  const newParts = [];

  const restParts = parts.filter(Boolean);
  while (restParts.length > 0) {
    const part = restParts.shift();

      continue;
    }

    if (isConcat(part)) {
      restParts.unshift(...getDocParts(part));
      continue;
    }

    if (
      newParts.length > 0 &&
      typeof newParts[newParts.length - 1] === "string" &&
      typeof part === "string"
    ) {
      newParts[newParts.length - 1] += part;
      continue;
    }

    newParts.push(part);
  }

  return newParts;
}

    if (Array.isArray(currentDoc)) {
      return normalizeParts(currentDoc);
    }
    }
    return {
      ...currentDoc,
      parts: normalizeParts(currentDoc.parts),
    };
  });
}

function replaceNewlinesWithLiterallines(doc) {
  return mapDoc(doc, (currentDoc) =>
    typeof currentDoc === "string" && currentDoc.includes("\n")
      ? currentDoc.split(/(\n)/g).map((v, i) => (i % 2 === 0 ? v : literalline))
      : currentDoc
  );
}

  if (typeof val === "string") {
    return;
  }

  if (Array.isArray(val)) {
    for (const doc of val) {
      assertDoc(doc);
    }
    return;
  }

  if (val && typeof val.type === "string") {
    return;
  }

  throw new Error("Value " + JSON.stringify(val) + " is not a valid document");
}

    for (const part of parts) {
      assertDoc(part);
    }
  }

  // }
}

function group(contents, opts = {}) {
  }

  return {
    id: opts.id,
    contents,
    break: Boolean(opts.shouldBreak),
    expandedStates: opts.expandedStates,
  };
}

function dedentToRoot(contents) {
  return align(Number.NEGATIVE_INFINITY, contents);
}

function markAsRoot(contents) {
  // @ts-ignore - TBD ???:
  return align({ type: "root" }, contents);
}

  return group(states[0], { ...opts, expandedStates: states });
}

    }
  }

}

function ifBreak(breakContents, flatContents, opts = {}) {
    }
    }
  }

  return {
    type: "if-break",
    breakContents,
    flatContents,
    groupId: opts.groupId,
  };
}

function indentIfBreak(contents, opts) {
  return {
    type: "indent-if-break",
    contents,
    negate: opts.negate,
  };
}

    }

  }

  // eslint-disable-next-line prettier-internal-rules/no-doc-builder-concat
}

    }
    aligned = align(Number.NEGATIVE_INFINITY, aligned);
  }
}

function label(label, contents) {
  return { type: "label", label, contents };
}

function embed(path, print, textToDoc /*, options */) {

  if (node.type === "front-matter") {
    const doc = printFrontMatter(node, textToDoc);
    return doc ? [doc, hardline] : "";
  }
}

function getPropOfDeclNode(path) {
  const declAncestorNode = getAncestorNode(path, "css-decl");

  return (
    declAncestorNode &&
    declAncestorNode.prop &&
    declAncestorNode.prop.toLowerCase()
  );
}

function hasSCSSInterpolation(groupList) {
  if (isNonEmptyArray(groupList)) {
    for (let i = groupList.length - 1; i > 0; i--) {
      // If we find `#{`, return true.
      if (
        groupList[i].type === "word" &&
        groupList[i].value === "{" &&
        groupList[i - 1].type === "word" &&
        groupList[i - 1].value.endsWith("#")
      ) {
      }
    }
  }
}

function hasStringOrFunction(groupList) {
    for (let i = 0; i < groupList.length; i++) {
      if (groupList[i].type === "string" || groupList[i].type === "func") {
      }
    }
  }
}

function isSCSS(parser, text) {
  const hasExplicitParserChoice = parser === "less" || parser === "scss";
  const IS_POSSIBLY_SCSS = /(\w\s*:\s*[^:}]+|#){|@import[^\n]+(?:url|,)/;
  return hasExplicitParserChoice
    ? parser === "scss"
}

function isSCSSVariable(node) {
  return Boolean(node && node.type === "word" && node.value.startsWith("$"));
}

function isWideKeywords(value) {
  return ["initial", "inherit", "unset", "revert"].includes(
    value.toLowerCase()
  );
}

function isKeyframeAtRuleKeywords(path, value) {
  const atRuleAncestorNode = getAncestorNode(path, "css-atrule");
  return (
    atRuleAncestorNode &&
    atRuleAncestorNode.name &&
    atRuleAncestorNode.name.toLowerCase().endsWith("keyframes") &&
    ["from", "to"].includes(value.toLowerCase())
  );
}

    value.startsWith("--") ||
    value.startsWith(":--") ||
    (value.includes("(") && value.includes(")"))
    ? value
}

function insideValueFunctionNode(path, functionName) {
  const funcAncestorNode = getAncestorNode(path, "value-func");
  return (
    funcAncestorNode &&
    funcAncestorNode.value &&
    funcAncestorNode.value.toLowerCase() === functionName
  );
}

function insideICSSRuleNode(path) {
  const ruleAncestorNode = getAncestorNode(path, "css-rule");

  return (
    ruleAncestorNode &&
    ruleAncestorNode.raws &&
    ruleAncestorNode.raws.selector &&
    (ruleAncestorNode.raws.selector.startsWith(":import") ||
      ruleAncestorNode.raws.selector.startsWith(":export"))
  );
}

function insideAtRuleNode(path, atRuleNameOrAtRuleNames) {
  const atRuleNames = Array.isArray(atRuleNameOrAtRuleNames)
    ? atRuleNameOrAtRuleNames
    : [atRuleNameOrAtRuleNames];

  return (
    atRuleNames.includes(atRuleAncestorNode.name.toLowerCase())
  );
}

function insideURLFunctionInImportAtRuleNode(path) {

  return (
    atRuleAncestorNode.name === "import" &&
    node.groups[0].value === "url" &&
    node.groups.length === 2
  );
}

function isURLFunctionNode(node) {
  return node.type === "value-func" && node.value.toLowerCase() === "url";
}

function isLastNode(path, node) {

  if (!parentNode) {
  }
  const { nodes } = parentNode;
  return nodes && nodes.indexOf(node) === nodes.length - 1;
}

function isDetachedRulesetDeclarationNode(node) {
  // If a Less file ends up being parsed with the SCSS parser, Less
  // variable declarations will be parsed as atrules with names ending
  // with a colon, so keep the original case then.
  if (!node.selector) {
  }

  return (
    (typeof node.selector === "string" && /^@.+:.*$/.test(node.selector)) ||
    (node.selector.value && /^@.+:.*$/.test(node.selector.value))
  );
}

function isForKeywordNode(node) {
  return (
    node.type === "value-word" &&
    ["from", "through", "end"].includes(node.value)
  );
}

function isIfElseKeywordNode(node) {
  return (
    node.type === "value-word" && ["and", "or", "not"].includes(node.value)
  );
}

function isEachKeywordNode(node) {
  return node.type === "value-word" && node.value === "in";
}

function isMultiplicationNode(node) {
  return node.type === "value-operator" && node.value === "*";
}

function isDivisionNode(node) {
  return node.type === "value-operator" && node.value === "/";
}

function isAdditionNode(node) {
  return node.type === "value-operator" && node.value === "+";
}

function isSubtractionNode(node) {
  return node.type === "value-operator" && node.value === "-";
}

function isModuloNode(node) {
  return node.type === "value-operator" && node.value === "%";
}

function isMathOperatorNode(node) {
  return (
    isMultiplicationNode(node) ||
    isDivisionNode(node) ||
    isAdditionNode(node) ||
    isSubtractionNode(node) ||
    isModuloNode(node)
  );
}

function isEqualityOperatorNode(node) {
  return node.type === "value-word" && ["==", "!="].includes(node.value);
}

function isRelationalOperatorNode(node) {
  return (
    node.type === "value-word" && ["<", ">", "<=", ">="].includes(node.value)
  );
}

function isSCSSControlDirectiveNode(node) {
  return (
    node.type === "css-atrule" &&
    ["if", "else", "for", "each", "while"].includes(node.name)
  );
}

function isSCSSNestedPropertyNode(node) {
  }

  return node.selector
    .replace(/\/\*.*?\*\//, "")
    .replace(/\/\/.*?\n/, "")
    .trim()
    .endsWith(":");
}

function isDetachedRulesetCallNode(node) {
  return node.raws && node.raws.params && /^\(\s*\)$/.test(node.raws.params);
}

function isTemplatePlaceholderNode(node) {
  return node.name.startsWith("prettier-placeholder");
}

function isTemplatePropNode(node) {
  return node.prop.startsWith("@prettier-placeholder");
}

function isPostcssSimpleVarNode(currentNode, nextNode) {
  return (
    currentNode.value === "$$" &&
    currentNode.type === "value-func" &&
    nextNode &&
    nextNode.type === "value-word" &&
    !nextNode.raws.before
  );
}

function hasComposesNode(node) {
  return (
    node.value.type === "value-root" &&
    node.value.group &&
    node.value.group.type === "value-value" &&
    node.prop.toLowerCase() === "composes"
  );
}

function hasParensAroundNode(node) {
  return (
    node.value.group.group &&
    node.value.group.group.type === "value-paren_group" &&
    node.value.group.group.open !== null &&
    node.value.group.group.close !== null
  );
}

function hasEmptyRawBefore(node) {
  return node.raws && node.raws.before === "";
}

function isKeyValuePairNode(node) {
  return (
    node.type === "value-comma_group" &&
    node.groups &&
    node.groups[1] &&
    node.groups[1].type === "value-colon"
  );
}

function isKeyValuePairInParenGroupNode(node) {
  return (
    node.type === "value-paren_group" &&
    node.groups[0] &&
    isKeyValuePairNode(node.groups[0])
  );
}

function isSCSSMapItemNode(path) {

  // Ignore empty item (i.e. `$key: ()`)
  if (node.groups.length === 0) {
  }

  const parentParentNode = path.getParentNode(1);

  // Check open parens contain key/value pair (i.e. `(key: value)` and `(key: (value, other-value)`)
  if (
    !isKeyValuePairInParenGroupNode(node) &&
    !(parentParentNode && isKeyValuePairInParenGroupNode(parentParentNode))
  ) {
  }

  const declNode = getAncestorNode(path, "css-decl");

  // SCSS map declaration (i.e. `$map: (key: value, other-key: other-value)`)
  if (declNode && declNode.prop && declNode.prop.startsWith("$")) {
  }

  // List as value of key inside SCSS map (i.e. `$map: (key: (value other-value other-other-value))`)
  if (isKeyValuePairInParenGroupNode(parentParentNode)) {
  }

  // SCSS Map is argument of function (i.e. `func((key: value, other-key: other-value))`)
  if (parentParentNode.type === "value-func") {
  }

}

function isInlineValueCommentNode(node) {
  return node.type === "value-comment" && node.inline;
}

function isHashNode(node) {
  return node.type === "value-word" && node.value === "#";
}

function isLeftCurlyBraceNode(node) {
  return node.type === "value-word" && node.value === "{";
}

function isRightCurlyBraceNode(node) {
  return node.type === "value-word" && node.value === "}";
}

function isWordNode(node) {
  return ["value-word", "value-atword"].includes(node.type);
}

function isColonNode(node) {
  return node && node.type === "value-colon";
}

function isKeyInValuePairNode(node, parentNode) {
  if (!isKeyValuePairNode(parentNode)) {
  }

  const { groups } = parentNode;
  const index = groups.indexOf(node);

  if (index === -1) {
  }

  return isColonNode(groups[index + 1]);
}

function isMediaAndSupportsKeywords(node) {
  return node.value && ["not", "and", "or"].includes(node.value.toLowerCase());
}

function isColorAdjusterFuncNode(node) {
  if (node.type !== "value-func") {
  }

  return colorAdjusterFunctions.has(node.value.toLowerCase());
}

function isLessParser(options) {
  return options.parser === "css" || options.parser === "less";
}

function lastLineHasInlineComment(text) {
  return /\/\//.test(text.split(/[\n\r]/).pop());
}

function stringifyNode(node) {
  if (node.groups) {
    const open = node.open && node.open.value ? node.open.value : "";
    const groups = node.groups.reduce(
      (previousValue, currentValue, index) =>
        previousValue +
        stringifyNode(currentValue) +
        (node.groups[0].type === "comma_group" &&
        index !== node.groups.length - 1
          ? ","
          : ""),
      ""
    );
    const close = node.close && node.close.value ? node.close.value : "";

    return open + groups + close;
  }

  const before = node.raws && node.raws.before ? node.raws.before : "";
  const quote = node.raws && node.raws.quote ? node.raws.quote : "";
  const atword = node.type === "atword" ? "@" : "";
  const value = node.value ? node.value : "";
  const unit = node.unit ? node.unit : "";
  const group = node.group ? stringifyNode(node.group) : "";
  const after = node.raws && node.raws.after ? node.raws.after : "";

  return before + quote + atword + value + quote + unit + group + after;
}

function isAtWordPlaceholderNode(node) {
  return (
    node &&
    node.type === "value-atword" &&
    node.value.startsWith("prettier-placeholder-")
  );
}

get css() {
    return require("./parser-postcss").parsers.css;
  }

    return require("./parser-postcss").parsers.less;
  }

    return require("./parser-postcss").parsers.scss;
  }

(node) => {
  while (node.parent) {
    node = node.parent;
  }
}

function parseValueNode(valueNode, options) {
  const { nodes } = valueNode;
    type: "paren_group",
  };
    type: "comma_group",
  };

    if (
      isSCSS(options.parser, node.value) &&
      node.type === "number" &&
      node.unit === ".." &&
      node.value[node.value.length - 1] === "."
    ) {
      // Work around postcss bug parsing `50...` as `50.` with unit `..`
      // Set the unit to `...` to "accidentally" have arbitrary arguments work in the same way that cases where the node already had a unit work.
      // For example, 50px... is parsed as `50` with unit `px...` already by postcss-values-parser.
      node.value = node.value.slice(0, -1);
      node.unit = "...";
    }

    if (node.type === "func" && node.value === "selector") {
      node.group.groups = [
        parseSelector(
          getHighestAncestor(valueNode).text.slice(
            node.group.open.sourceIndex + 1,
            node.group.close.sourceIndex
          )
        ),
      ];
    }

    if (node.type === "func" && node.value === "url") {
      const groups = (node.group && node.group.groups) || [];

      // Create a view with any top-level comma groups flattened.
      let groupList = [];
      for (let i = 0; i < groups.length; i++) {
        const group = groups[i];
        if (group.type === "comma_group") {
          groupList = [...groupList, ...group.groups];
        } else {
          groupList.push(group);
        }
      }

      // Stringify if the value parser can't handle the content.
      if (
        hasSCSSInterpolation(groupList) ||
        (!hasStringOrFunction(groupList) && !isSCSSVariable(groupList[0]))
      ) {
        const stringifiedContent = stringifyNode({
          groups: node.group.groups,
        });
        node.group.groups = [stringifiedContent.trim()];
      }
    }
        type: "paren_group",
      };

        type: "comma_group",
      };
      if (commaGroup.groups.length > 0) {
      }

      }

      };
    } else {
    }
  }
  }
}

  if (
  ) {
  }

  }

    return { ...node, groups: node.groups.map(flattenGroups) };
  }

}

function addTypePrefix(node, prefix, skipPrefix) {
      addTypePrefix(node[key], prefix, skipPrefix);
        if (
          !node[key].startsWith(prefix) &&
          (!skipPrefix || !skipPrefix.test(node[key]))
        ) {
        }
      }
    }
  }
}

function parseNestedValue(node, options) {
      if (key !== "parent") {
        parseNestedValue(node[key], options);
        if (key === "nodes") {
          node.group = flattenGroups(parseValueNode(node, options));
          delete node[key];
        }
      }
    }
  }
}

function parseValue(value, options) {

  let result = null;

  try {
    result = valueParser(value, { loose: true }).parse();
    return {
      type: "value-unknown",
      value,
    };
  }

  result.text = value;

  const parsedResult = parseNestedValue(result, options);

  return addTypePrefix(parsedResult, "value-", /^selector-/);
}

  // If there's a comment inside of a selector, the parser tries to parse
  // the content of the comment as selectors which turns it into complete
  // garbage. Better to print the whole selector as-is and not try to parse
  // and reformat it.
  if (/\/\/|\/\*/.test(selector)) {
    return {
      type: "selector-unknown",
      value: selector.trim(),
    };
  }

  try {
    selectorParser((result_) => {
      result = result_;
    }).process(selector);
    // Fail silently. It's better to print it as is than to try and parse it
    // Note: A common failure is for SCSS nested properties. `background:
    // none { color: red; }` is parsed as a NestedDeclaration by
    // postcss-scss, while `background: { color: red; }` is parsed as a Rule
    // with a selector ending with a colon. See:
    // https://github.com/postcss/postcss-scss/issues/39
    return {
      value: selector,
    };
  }

}

function parseMediaQuery(params) {

  try {
    result = mediaParser(params);
    // Ignore bad media queries
    return {
      value: params,
    };
  }

  return addTypePrefix(addMissingType(result), "media-");
}

function parseNestedCSS(node, options) {

      parseNestedCSS(node[key], options);
    }

    if (!node.type) {
    }

    if (!node.raws) {
      node.raws = {};
    }

    let selector = "";

      selector = node.raws.selector
        ? node.raws.selector.scss
          ? node.raws.selector.scss
          : node.raws.selector.raw

      if (node.raws.between && node.raws.between.trim().length > 0) {
        selector += node.raws.between;
      }

      node.raws.selector = selector;
    }

    let value = "";

    if (typeof node.value === "string") {
      value = node.raws.value
        ? node.raws.value.scss
          ? node.raws.value.scss
          : node.raws.value.raw

      value = value.trim();

      node.raws.value = value;
    }

    let params = "";

    if (typeof node.params === "string") {
      params = node.raws.params
        ? node.raws.params.scss
          ? node.raws.params.scss
          : node.raws.params.raw
        : node.params;

      if (node.raws.afterName && node.raws.afterName.trim().length > 0) {
        params = node.raws.afterName + params;
      }

        params = params + node.raws.between;
      }

      params = params.trim();

      node.raws.params = params;
    }

    // Ignore LESS mixin declaration
    if (selector.trim().length > 0) {
      // TODO: confirm this code is dead
      if (selector.startsWith("@") && selector.endsWith(":")) {
      }

      // Ignore LESS mixins
      if (node.mixin) {
        node.selector = parseValue(selector, options);

      }

      // Check on SCSS nested property
      if (isSCSSNestedPropertyNode(node)) {
        node.isSCSSNesterProperty = true;
      }

      node.selector = parseSelector(selector);

    }

    if (value.length > 0) {
      const defaultSCSSDirectiveIndex = value.match(DEFAULT_SCSS_DIRECTIVE);

      if (defaultSCSSDirectiveIndex) {
        value = value.slice(0, defaultSCSSDirectiveIndex.index);
        node.scssDefault = true;

        if (defaultSCSSDirectiveIndex[0].trim() !== "!default") {
          node.raws.scssDefault = defaultSCSSDirectiveIndex[0];
        }
      }

      const globalSCSSDirectiveIndex = value.match(GLOBAL_SCSS_DIRECTIVE);

      if (globalSCSSDirectiveIndex) {
        value = value.slice(0, globalSCSSDirectiveIndex.index);
        node.scssGlobal = true;

        if (globalSCSSDirectiveIndex[0].trim() !== "!global") {
          node.raws.scssGlobal = globalSCSSDirectiveIndex[0];
        }
      }

      if (value.startsWith("progid:")) {
        return {
          type: "value-unknown",
          value,
        };
      }

      node.value = parseValue(value, options);
    }

    if (
      isLessParser(options) &&
      node.type === "css-decl" &&
      value.startsWith("extend(")
    ) {
      // extend is missing
      if (!node.extend) {
        node.extend = node.raws.between === ":";
      }

      // `:extend()` is parsed as value
      if (node.extend && !node.selector) {
        delete node.value;
        node.selector = parseSelector(value.slice("extend(".length, -1));
      }
    }

    if (node.type === "css-atrule") {
      if (isLessParser(options)) {
        // mixin
        if (node.mixin) {
          const source =
            node.raws.identifier +
            node.name +
            node.raws.afterName +
            node.raws.params;
          node.selector = parseSelector(source);
          delete node.params;
        }

        // function
        if (node.function) {
        }
      }

      // only css support custom-selector
      if (options.parser === "css" && node.name === "custom-selector") {
        const customSelector = node.params.match(/:--\S+?\s+/)[0].trim();
        node.customSelector = customSelector;
        node.selector = parseSelector(
          node.params.slice(customSelector.length).trim()
        );
        delete node.params;
      }

        // postcss-less doesn't recognize variables in some cases.
        // `@color: blue;` is recognized fine, but the cases below aren't:

        // `@color:blue;`
        if (node.name.includes(":") && !node.params) {
          node.variable = true;
          const parts = node.name.split(":");
          node.name = parts[0];
          node.value = parseValue(parts.slice(1).join(":"), options);
        }

        // `@color :blue;`
        if (
          !["page", "nest"].includes(node.name) &&
          node.params &&
          node.params[0] === ":"
        ) {
          node.value = parseValue(node.params.slice(1), options);
          node.raws.afterName += ":";
        }

        // Less variable
        if (node.variable) {
        }
      }
    }

    if (node.type === "css-atrule" && params.length > 0) {
      const { name } = node;
      const lowercasedName = node.name.toLowerCase();

      if (name === "warn" || name === "error") {
        node.params = {
          type: "media-unknown",
          value: params,
        };

      }

      if (name === "extend" || name === "nest") {
        node.selector = parseSelector(params);

      }

      if (name === "at-root") {
        if (/^\(\s*(without|with)\s*:[\S\s]+\)$/.test(params)) {
          node.params = parseValue(params, options);
        } else {
          node.selector = parseSelector(params);
        }

      }

      if (lowercasedName === "import") {
        node.import = true;
        delete node.filename;
        node.params = parseValue(params, options);
      }

      if (
        [
          "namespace",
          "supports",
          "if",
          "else",
          "for",
          "each",
          "while",
          "debug",
          "mixin",
          "include",
          "function",
          "return",
          "define-mixin",
          "add-mixin",
        ].includes(name)
      ) {
        // Remove unnecessary spaces in SCSS variable arguments
        params = params.replace(/(\$\S+?)\s+?\.{3}/, "$1...");
        // Remove unnecessary spaces before SCSS control, mixin and function directives
        params = params.replace(/^(?!if)(\S+)\s+\(/, "$1(");

        node.value = parseValue(params, options);

      }

      if (["media", "custom-media"].includes(lowercasedName)) {
        if (params.includes("#{")) {
          // Workaround for media at rule with scss interpolation
          return {
            type: "media-unknown",
            value: params,
          };
        }

        node.params = parseMediaQuery(params);

      }

      node.params = params;

    }
  }

}

function parseWithParser(parse, text, options) {
  const parsed = parseFrontMatter(text);
  const { frontMatter } = parsed;
  text = parsed.content;

  try {
    result = parse(text);
    const { name, reason, line, column } = error;
    if (typeof line !== "number") {
    }
    throw createError(`${name}: ${reason}`, { start: { line, column } });
  }

  result = parseNestedCSS(addTypePrefix(result, "css-"), options);

  calculateLoc(result, text);

    frontMatter.source = {
      startOffset: 0,
      endOffset: frontMatter.raw.length,
    };
    result.nodes.unshift(frontMatter);
  }

}

function parseCss(text, parsers, options) {
  const isSCSSParser = isSCSS(options.parser, text);
  const parseFunctions = isSCSSParser
    ? [parseScss, parseLess]
    : [parseLess, parseScss];

  let error;
  for (const parse of parseFunctions) {
    try {
      return parse(text, parsers, options);
    } catch (parseError) {
      error = error || parseError;
    }
  }

  }
}

function parseLess(text, parsers, options) {
  const lessParser = require("postcss-less");
  return parseWithParser(
    // Workaround for https://github.com/shellscape/postcss-less/issues/145
    // See comments for `replaceQuotesInInlineComments` in `loc.js`.
    (text) => lessParser.parse(replaceQuotesInInlineComments(text)),
    text,
    options
  );
}

function parseScss(text, parsers, options) {
  const { parse } = require("postcss-scss");
  return parseWithParser(parse, text, options);
}

  return jsPragma.hasPragma(parseFrontMatter(text).content);
}

  const { frontMatter, content } = parseFrontMatter(text);
  return (
    (frontMatter ? frontMatter.raw + "\n\n" : "") +
    jsPragma.insertPragma(content)
  );
}

  if (isFrontMatterNode(ast) && ast.lang === "yaml") {
  }

  if (
    ast.type === "css-comment" &&
    parent.type === "css-root" &&
    parent.nodes.length > 0
  ) {
    // --insert-pragma
    // first non-front-matter comment
    if (
      parent.nodes[0] === ast ||
      (isFrontMatterNode(parent.nodes[0]) && parent.nodes[1] === ast)
    ) {
      /**
       * something
       *
       * @format
       */
      delete newObj.text;

      // standalone pragma
      if (/^\*\s*@(format|prettier)\s*$/.test(ast.text)) {
      }
    }

    // Last comment is not parsed, when omitting semicolon, #8675
    if (parent.type === "css-root" && getLast(parent.nodes) === ast) {
    }
  }

  if (ast.type === "value-root") {
    delete newObj.text;
  }

  if (
    ast.type === "media-query" ||
    ast.type === "media-query-list" ||
    ast.type === "media-feature-expression"
  ) {
  }

  if (ast.type === "css-rule") {
    delete newObj.params;
  }

  if (ast.type === "selector-combinator") {
    newObj.value = newObj.value.replace(/\s+/g, " ");
  }

  if (ast.type === "media-feature") {
    newObj.value = newObj.value.replace(/ /g, "");
  }

  if (
    (ast.type === "value-word" &&
      ((ast.isColor && ast.isHex) ||
        ["initial", "inherit", "unset", "revert"].includes(
          newObj.value.replace().toLowerCase()
        ))) ||
    ast.type === "media-feature" ||
    ast.type === "selector-root-invalid" ||
    ast.type === "selector-pseudo"
  ) {
    newObj.value = newObj.value.toLowerCase();
  }
  if (ast.type === "css-decl") {
    newObj.prop = newObj.prop.toLowerCase();
  }
  if (ast.type === "css-atrule" || ast.type === "css-import") {
    newObj.name = newObj.name.toLowerCase();
  }
  if (ast.type === "value-number") {
    newObj.unit = newObj.unit.toLowerCase();
  }

  if (
    (ast.type === "media-feature" ||
      ast.type === "media-keyword" ||
      ast.type === "media-type" ||
      ast.type === "media-unknown" ||
      ast.type === "media-url" ||
      ast.type === "media-value" ||
      ast.type === "selector-attribute" ||
      ast.type === "selector-string" ||
      ast.type === "selector-class" ||
      ast.type === "selector-combinator" ||
      ast.type === "value-string") &&
    newObj.value
  ) {
    newObj.value = cleanCSSStrings(newObj.value);
  }

  if (ast.type === "selector-attribute") {
    newObj.attribute = newObj.attribute.trim();

    if (newObj.namespace) {
      if (typeof newObj.namespace === "string") {
        newObj.namespace = newObj.namespace.trim();

        if (newObj.namespace.length === 0) {
          newObj.namespace = true;
        }
      }
    }

      newObj.value = newObj.value.trim().replace(/^["']|["']$/g, "");
    }
  }

  if (
    (ast.type === "media-value" ||
      ast.type === "value-number" ||
      ast.type === "selector-tag") &&
  ) {
    newObj.value = newObj.value.replace(
      /([\d+.Ee-]+)([A-Za-z]*)/g,
      (match, numStr, unit) => {
        const num = Number(numStr);
        return Number.isNaN(num) ? match : num + unit.toLowerCase();
      }
    );
  }

  if (ast.type === "selector-tag") {
    const lowercasedValue = ast.value.toLowerCase();

    if (["from", "to"].includes(lowercasedValue)) {
      newObj.value = lowercasedValue;
    }
  }

  // Workaround when `postcss-values-parser` parse `not`, `and` or `or` keywords as `value-func`
  if (ast.type === "css-atrule" && ast.name.toLowerCase() === "supports") {
  }

  // Workaround for SCSS nested properties
  if (ast.type === "selector-unknown") {
  }
}

  return value.replace(/'/g, '"').replace(/\\([^\dA-Fa-f])/g, "$1");
}

function calculateLocStart(node, text) {
  // value-* nodes have this
  if (typeof node.sourceIndex === "number") {
    return node.sourceIndex;
  }

  return node.source ? lineColumnToIndex(node.source.start, text) - 1 : null;
}

function calculateLocEnd(node, text) {
  if (node.type === "css-comment" && node.inline) {
    return skipEverythingButNewLine(text, node.source.startOffset);
  }
  const endNode = node.nodes && getLast(node.nodes);
  if (endNode && node.source && !node.source.end) {
    node = endNode;
  }
  if (node.source && node.source.end) {
    return lineColumnToIndex(node.source.end, text);
  }
}

function calculateLoc(node, text) {
  if (node.source) {
    node.source.startOffset = calculateLocStart(node, text);
    node.source.endOffset = calculateLocEnd(node, text);
  }

  for (const key in node) {
    const child = node[key];

    if (key === "source" || !child || typeof child !== "object") {
      continue;
    }

    if (child.type === "value-root" || child.type === "value-unknown") {
      calculateValueNodeLoc(
        child,
        getValueRootOffset(node),
        child.text || child.value
      );
    } else {
      calculateLoc(child, text);
    }
  }
}

function calculateValueNodeLoc(node, rootOffset, text) {
    node.source.startOffset = calculateLocStart(node, text) + rootOffset;
    node.source.endOffset = calculateLocEnd(node, text) + rootOffset;
  }

      continue;
    }

    calculateValueNodeLoc(child, rootOffset, text);
  }
}

function getValueRootOffset(node) {
  let result = node.source.startOffset;
  if (typeof node.prop === "string") {
    result += node.prop.length;
  }

  if (node.type === "css-atrule" && typeof node.name === "string") {
    result +=
      1 + node.name.length + node.raws.afterName.match(/^\s*:?\s*/)[0].length;
  }

  if (
    node.type !== "css-atrule" &&
    node.raws &&
    typeof node.raws.between === "string"
  ) {
    result += node.raws.between.length;
  }

}

function replaceQuotesInInlineComments(text) {
  /** @typedef { 'initial' | 'single-quotes' | 'double-quotes' | 'url' | 'comment-block' | 'comment-inline' } State */
  /** @type {State} */
  let state = "initial";
  let stateToReturnFromQuotes = "initial";
  let inlineCommentStartIndex;
  let inlineCommentContainsQuotes = false;
  const inlineCommentsToReplace = [];

    const c = text[i];

    switch (state) {
      case "initial":
        if (c === "'") {
          state = "single-quotes";
          continue;
        }

        if (c === '"') {
          state = "double-quotes";
          continue;
        }

        if (
          (c === "u" || c === "U") &&
          text.slice(i, i + 4).toLowerCase() === "url("
        ) {
          state = "url";
          i += 3;
          continue;
        }

        if (c === "*" && text[i - 1] === "/") {
          state = "comment-block";
          continue;
        }

        if (c === "/" && text[i - 1] === "/") {
          state = "comment-inline";
          inlineCommentStartIndex = i - 1;
          continue;
        }

        continue;

      case "single-quotes":
        if (c === "'" && text[i - 1] !== "\\") {
          state = stateToReturnFromQuotes;
          stateToReturnFromQuotes = "initial";
        }
        if (c === "\n" || c === "\r") {
          return text; // invalid input
        }
        continue;

      case "double-quotes":
        if (c === '"' && text[i - 1] !== "\\") {
        }
        }
        continue;

      case "url":
        if (c === ")") {
          state = "initial";
        }
        }
          stateToReturnFromQuotes = "url";
          continue;
        }
          continue;
        }
        continue;

      case "comment-block":
        if (c === "/" && text[i - 1] === "*") {
        }
        continue;

      case "comment-inline":
        if (c === '"' || c === "'" || c === "*") {
          inlineCommentContainsQuotes = true;
        }
          if (inlineCommentContainsQuotes) {
            inlineCommentsToReplace.push([inlineCommentStartIndex, i]);
          }
          inlineCommentContainsQuotes = false;
        }
        continue;
    }
  }

  for (const [start, end] of inlineCommentsToReplace) {
    text =
      text.slice(0, start) +
      text.slice(start, end).replace(/["'*]/g, " ") +
      text.slice(end);
  }

  return text;
}

function shouldPrintComma(options) {
  return options.trailingComma === "es5" || options.trailingComma === "all";
}

    return "";
  }

  if (typeof node === "string") {
  }

      return [node.raw, hardline];
      const nodes = printNodeSequence(path, options, print);
      const after = node.raws.after.trim();

      return [
        nodes,
        after ? ` ${after}` : "",
        getDocParts(nodes).length > 0 ? hardline : "",
      ];
    }
      const isInlineComment = node.inline || node.raws.inline;

      const text = options.originalText.slice(locStart(node), locEnd(node));

      return isInlineComment ? text.trimEnd() : text;
    }
      return [
        node.important ? " !important" : "",
        node.nodes
          ? [
              node.selector &&
              node.selector.type === "selector-unknown" &&
              lastLineHasInlineComment(node.selector.value)
                ? line
                : " ",
              "{",
              node.nodes.length > 0
                ? indent([hardline, printNodeSequence(path, options, print)])
                : "",
              hardline,
              "}",
              isDetachedRulesetDeclarationNode(node) ? ";" : "",
            ]
          : ";",
      ];
    }

      const { between: rawBetween } = node.raws;
      const trimmedBetween = rawBetween.trim();
      const isColon = trimmedBetween === ":";

      let value = hasComposesNode(node)
        ? removeLines(path.call(print, "value"))
        : path.call(print, "value");

      if (!isColon && lastLineHasInlineComment(trimmedBetween)) {
        value = indent([hardline, dedent(value)]);
      }

      return [
        node.raws.before.replace(/[\s;]/g, ""),
        insideICSSRuleNode(path) ? node.prop : maybeToLowerCase(node.prop),
        trimmedBetween.startsWith("//") ? " " : "",
        trimmedBetween,
        node.extend ? "" : " ",
        isLessParser(options) && node.extend && node.selector
          ? ["extend(", path.call(print, "selector"), ")"]
          : "",
        value,
        node.raws.important
          ? node.raws.important.replace(/\s*!\s*important/i, " !important")
          : node.important
          ? " !important"
          : "",
        node.raws.scssDefault
          ? node.raws.scssDefault.replace(/\s*!default/i, " !default")
          : node.scssDefault
          ? " !default"
          : "",
        node.raws.scssGlobal
          ? node.raws.scssGlobal.replace(/\s*!global/i, " !global")
          : node.scssGlobal
          ? " !global"
          : "",
          ? [
              " {",
              indent([softline, printNodeSequence(path, options, print)]),
              softline,
              "}",
            ]
          : isTemplatePropNode(node) &&
            !parentNode.raws.semicolon &&
            options.originalText[locEnd(node) - 1] !== ";"
          ? ""
          : options.__isHTMLStyleAttribute && isLastNode(path, node)
          ? ifBreak(";")
          : ";",
      ];
    }
      const isTemplatePlaceholderNodeWithoutSemiColon =
        isTemplatePlaceholderNode(node) &&
        !parentNode.raws.semicolon &&
        options.originalText[locEnd(node) - 1] !== ";";

          return [
            path.call(print, "selector"),
            node.important ? " !important" : "",
            isTemplatePlaceholderNodeWithoutSemiColon ? "" : ";",
          ];
        }

          return [
            node.name,
            path.call(print, "params"),
          ];
        }

          return [
            "@",
            ": ",
            node.value ? path.call(print, "value") : "",
            node.raws.between.trim() ? node.raws.between.trim() + " " : "",
            node.nodes
              ? [
                  "{",
                  indent([
                    node.nodes.length > 0 ? softline : "",
                    printNodeSequence(path, options, print),
                  ]),
                  softline,
                  "}",
                ]
              : "",
          ];
        }
      }

      return [
        "@",
        // variable declarations will be parsed as at-rules with names ending
        isDetachedRulesetCallNode(node) || node.name.endsWith(":")
          ? node.name
          : maybeToLowerCase(node.name),
        node.params
          ? [
              isDetachedRulesetCallNode(node)
                ? ""
                : isTemplatePlaceholderNode(node)
                ? node.raws.afterName === ""
                  ? ""
                  : node.name.endsWith(":")
                  ? " "
                  : /^\s*\n\s*\n/.test(node.raws.afterName)
                  ? [hardline, hardline]
                  : /^\s*\n/.test(node.raws.afterName)
                  ? hardline
                  : " "
                : " ",
              path.call(print, "params"),
            ]
          : "",
        node.selector ? indent([" ", path.call(print, "selector")]) : "",
          ? group([
              " ",
              path.call(print, "value"),
              isSCSSControlDirectiveNode(node)
                ? hasParensAroundNode(node)
                  ? " "
                  : line
                : "",
            ])
          : node.name === "else"
          ? " "
          : "",
          ? [
                ? ""
                : (node.selector &&
                    !node.selector.nodes &&
                    typeof node.selector.value === "string" &&
                    lastLineHasInlineComment(node.selector.value)) ||
                  (!node.selector &&
                    typeof node.params === "string" &&
                    lastLineHasInlineComment(node.params))
                ? line
                : " ",
              "{",
              indent([
                node.nodes.length > 0 ? softline : "",
                printNodeSequence(path, options, print),
              ]),
              softline,
              "}",
            ]
          : isTemplatePlaceholderNodeWithoutSemiColon
          ? ""
          : ";",
      ];
    }
      path.each((childPath) => {
          return;
        }

      return group(indent(join(line, parts)));
    }
      return [
        join(" ", path.map(print, "nodes")),
        isLastNode(path, node) ? "" : ",",
      ];
    }
      return adjustNumbers(adjustStrings(node.value, options));
    }
      if (!node.nodes) {
        return node.value;
      }
      return ["(", ...path.map(print, "nodes"), ")"];
    }
        adjustStrings(node.value.replace(/ +/g, " "), options)
      );
    }
      return [node.value, " "];
    }
    }
      return adjustStrings(node.value, options);
    }
      return adjustStrings(
        node.value.replace(/^url\(\s+/gi, "url(").replace(/\s+\)$/gi, ")"),
        options
      );
    }
    }
        insideAtRuleNode(path, "custom-selector")
          ? [getAncestorNode(path, "css-atrule").customSelector, line]
          : "",
        join(
          [
            ",",
            insideAtRuleNode(path, ["extend", "custom-selector", "nest"])
              ? line
              : hardline,
          ],
          path.map(print, "nodes")
        ),
      ]);
    }
      return group(indent(path.map(print, "nodes")));
    }
    }
    }
      const index = parentNode && parentNode.nodes.indexOf(node);
      const prevNode = index && parentNode.nodes[index - 1];

      return [
        node.namespace
          ? [node.namespace === true ? "" : node.namespace.trim(), "|"]
          : "",
        prevNode.type === "selector-nesting"
          ? node.value
          : adjustNumbers(
              isKeyframeAtRuleKeywords(path, node.value)
                ? node.value.toLowerCase()
            ),
      ];
    }
      return ["#", node.value];
    }
      return [".", adjustNumbers(adjustStrings(node.value, options))];
    }
      return [
        "[",
          : "",
        node.attribute.trim(),
        node.operator ? node.operator : "",
          ? quoteAttributeValue(
              adjustStrings(node.value.trim(), options),
              options
            )
          : "",
        node.insensitive ? " i" : "",
        "]",
      ];
    }
      if (
        node.value === "+" ||
        node.value === ">" ||
        node.value === "~" ||
        node.value === ">>>"
      ) {
          parentNode.type === "selector-selector" &&
          parentNode.nodes[0] === node
            ? ""
            : line;

        return [leading, node.value, isLastNode(path, node) ? "" : " "];
      }

      const leading = node.value.trim().startsWith("(") ? line : "";
        adjustNumbers(adjustStrings(node.value.trim(), options)) || line;

      return [leading, value];
    }
      return [
          : "",
        node.value,
      ];
    }
      return [
        maybeToLowerCase(node.value),
        isNonEmptyArray(node.nodes)
          ? ["(", join(", ", path.map(print, "nodes")), ")"]
          : "",
      ];
    }
    }
    case "selector-unknown": {
      const ruleAncestorNode = getAncestorNode(path, "css-rule");

      // Nested SCSS property
      if (ruleAncestorNode && ruleAncestorNode.isSCSSNesterProperty) {
        return adjustNumbers(
          adjustStrings(maybeToLowerCase(node.value), options)
        );
      }

      // originalText has to be used for Less, see replaceQuotesInInlineComments in loc.js
      if (parentNode.raws && parentNode.raws.selector) {
        const start = locStart(parentNode);
        const end = start + parentNode.raws.selector.length;
        return options.originalText.slice(start, end).trim();
      }

      // Same reason above
      if (
        parentNode.type === "value-paren_group" &&
        grandParent.type === "value-func" &&
        grandParent.value === "selector"
      ) {
        const start = locStart(parentNode.open) + 1;
        const end = locEnd(parentNode.close) - 1;
        const selector = options.originalText.slice(start, end).trim();

        return lastLineHasInlineComment(selector)
          ? [breakParent, selector]
          : selector;
      }

    }
    case "value-value":
    }
    case "value-comment": {
    }
      const parentParentNode = path.getParentNode(1);
      const declAncestorProp = getPropOfDeclNode(path);
        declAncestorProp &&
        parentNode.type === "value-value" &&
        (declAncestorProp === "grid" ||
          declAncestorProp.startsWith("grid-template"));
      const atRuleAncestorNode = getAncestorNode(path, "css-atrule");
      const isControlDirective =
        atRuleAncestorNode && isSCSSControlDirectiveNode(atRuleAncestorNode);
      const hasInlineComment = node.groups.some((node) =>
        isInlineValueCommentNode(node)
      );

      const insideURLFunction = insideValueFunctionNode(path, "url");

      let insideSCSSInterpolationInString = false;
      for (let i = 0; i < node.groups.length; ++i) {

        const iPrevNode = node.groups[i - 1];
        const iNode = node.groups[i];
        const iNextNode = node.groups[i + 1];
        const iNextNextNode = node.groups[i + 2];

        if (insideURLFunction) {
          if (
            (iNextNode && isAdditionNode(iNextNode)) ||
            isAdditionNode(iNode)
          ) {
          }
          continue;
        }

        // Ignore after latest node (i.e. before semicolon)
        if (!iNextNode) {
          continue;
        }

        // styled.div` background: var(--${one}); `
        if (
          iNode.type === "value-word" &&
          iNode.value.endsWith("-") &&
          isAtWordPlaceholderNode(iNextNode)
        ) {
          continue;
        }

        // Ignore spaces before/after string interpolation (i.e. `"#{my-fn("_")}"`)
        const isStartSCSSInterpolationInString =
          iNode.type === "value-string" && iNode.value.startsWith("#{");
        const isEndingSCSSInterpolationInString =
          insideSCSSInterpolationInString &&
          iNextNode.type === "value-string" &&
          iNextNode.value.endsWith("}");

        if (
          isStartSCSSInterpolationInString ||
          isEndingSCSSInterpolationInString
        ) {
          insideSCSSInterpolationInString = !insideSCSSInterpolationInString;

          continue;
        }

        if (insideSCSSInterpolationInString) {
          continue;
        }

        // Ignore colon (i.e. `:`)
        if (isColonNode(iNode) || isColonNode(iNextNode)) {
          continue;
        }

        // Ignore `@` in Less (i.e. `@@var;`)
        if (iNode.type === "value-atword" && iNode.value === "") {
          continue;
        }

        // Ignore `~` in Less (i.e. `content: ~"^//* some horrible but needed css hack";`)
        if (iNode.value === "~") {
          continue;
        }

        // Ignore escape `\`
        if (
          iNode.value &&
          iNode.value.includes("\\") &&
          iNextNode &&
          iNextNode.type !== "value-comment"
        ) {
          continue;
        }

        // Ignore escaped `/`
        if (
          iPrevNode &&
          iPrevNode.value &&
          iPrevNode.value.indexOf("\\") === iPrevNode.value.length - 1 &&
          iNode.type === "value-operator" &&
          iNode.value === "/"
        ) {
          continue;
        }

        // Ignore `\` (i.e. `$variable: \@small;`)
        if (iNode.value === "\\") {
          continue;
        }

        // Ignore `$$` (i.e. `background-color: $$(style)Color;`)
        if (isPostcssSimpleVarNode(iNode, iNextNode)) {
          continue;
        }

        // Ignore spaces after `#` and after `{` and before `}` in SCSS interpolation (i.e. `#{variable}`)
        if (
          isHashNode(iNode) ||
          isLeftCurlyBraceNode(iNode) ||
          isRightCurlyBraceNode(iNextNode) ||
          (isLeftCurlyBraceNode(iNextNode) && hasEmptyRawBefore(iNextNode)) ||
          (isRightCurlyBraceNode(iNode) && hasEmptyRawBefore(iNextNode))
        ) {
          continue;
        }

        // Ignore css variables and interpolation in SCSS (i.e. `--#{$var}`)
        if (iNode.value === "--" && isHashNode(iNextNode)) {
          continue;
        }

        // Formatting math operations
        const isMathOperator = isMathOperatorNode(iNode);
        const isNextMathOperator = isMathOperatorNode(iNextNode);

        // Print spaces before and after math operators beside SCSS interpolation as is
        // (i.e. `#{$var}+5`, `#{$var} +5`, `#{$var}+ 5`, `#{$var} + 5`)
        // (i.e. `5+#{$var}`, `5 +#{$var}`, `5+ #{$var}`, `5 + #{$var}`)
        if (
          ((isMathOperator && isHashNode(iNextNode)) ||
            (isNextMathOperator && isRightCurlyBraceNode(iNode))) &&
          hasEmptyRawBefore(iNextNode)
        ) {
          continue;
        }

        // absolute paths are only parsed as one token if they are part of url(/abs/path) call
        // but if you have custom -fb-url(/abs/path/) then it is parsed as "division /" and rest
        // of the path. We don't want to put a space after that first division in this case.
        if (!iPrevNode && isDivisionNode(iNode)) {
          continue;
        }

        // Print spaces before and after addition and subtraction math operators as is in `calc` function
        // due to the fact that it is not valid syntax
        // (i.e. `calc(1px+1px)`, `calc(1px+ 1px)`, `calc(1px +1px)`, `calc(1px + 1px)`)
        if (
          insideValueFunctionNode(path, "calc") &&
          (isAdditionNode(iNode) ||
            isAdditionNode(iNextNode) ||
            isSubtractionNode(iNode) ||
            isSubtractionNode(iNextNode)) &&
        ) {
          continue;
        }

        // Print spaces after `+` and `-` in color adjuster functions as is (e.g. `color(red l(+ 20%))`)
        // Adjusters with signed numbers (e.g. `color(red l(+20%))`) output as-is.
        const isColorAdjusterNode =
          (isAdditionNode(iNode) || isSubtractionNode(iNode)) &&
          i === 0 &&
          (iNextNode.type === "value-number" || iNextNode.isHex) &&
          parentParentNode &&
          isColorAdjusterFuncNode(parentParentNode) &&
          !hasEmptyRawBefore(iNextNode);

        const requireSpaceBeforeOperator =
          (iNextNextNode && iNextNextNode.type === "value-func") ||
          (iNextNextNode && isWordNode(iNextNextNode)) ||
          iNode.type === "value-func" ||
          isWordNode(iNode);
        const requireSpaceAfterOperator =
          iNextNode.type === "value-func" ||
          isWordNode(iNextNode) ||
          (iPrevNode && iPrevNode.type === "value-func") ||
          (iPrevNode && isWordNode(iPrevNode));

        // Formatting `/`, `+`, `-` sign
        if (
          !(isMultiplicationNode(iNextNode) || isMultiplicationNode(iNode)) &&
          !insideValueFunctionNode(path, "calc") &&
          !isColorAdjusterNode &&
          ((isDivisionNode(iNextNode) && !requireSpaceBeforeOperator) ||
            (isDivisionNode(iNode) && !requireSpaceAfterOperator) ||
            (isAdditionNode(iNextNode) && !requireSpaceBeforeOperator) ||
            (isAdditionNode(iNode) && !requireSpaceAfterOperator) ||
            isSubtractionNode(iNextNode) ||
            isSubtractionNode(iNode)) &&
          (hasEmptyRawBefore(iNextNode) ||
            (isMathOperator &&
              (!iPrevNode || (iPrevNode && isMathOperatorNode(iPrevNode)))))
        ) {
          continue;
        }

        // Add `hardline` after inline comment (i.e. `// comment\n foo: bar;`)
        if (isInlineValueCommentNode(iNode)) {
          if (parentNode.type === "value-paren_group") {
            parts.push(dedent(hardline));
            continue;
          }
          continue;
        }

        // Handle keywords in SCSS control directive
        if (
          isControlDirective &&
          (isEqualityOperatorNode(iNextNode) ||
            isRelationalOperatorNode(iNextNode) ||
            isIfElseKeywordNode(iNextNode) ||
            isEachKeywordNode(iNode) ||
            isForKeywordNode(iNode))
        ) {
          parts.push(" ");

          continue;
        }

        // At-rule `namespace` should be in one line
        if (
          atRuleAncestorNode &&
          atRuleAncestorNode.name.toLowerCase() === "namespace"
        ) {

          continue;
        }

        // Formatting `grid` property
        if (isGridValue) {
          if (
            iNode.source &&
            iNextNode.source &&
            iNode.source.start.line !== iNextNode.source.start.line
          ) {

            didBreak = true;
          } else {
          }

          continue;
        }

        // Add `space` before next math operation
        // Note: `grip` property have `/` delimiter and it is not math operation, so
        // `grid` property handles above
        if (isNextMathOperator) {

          continue;
        }
        // allow function(returns-list($list)...)
        if (iNextNode && iNextNode.value === "...") {
          continue;
        }

        if (
          isAtWordPlaceholderNode(iNode) &&
          isAtWordPlaceholderNode(iNextNode) &&
          locEnd(iNode) === locStart(iNextNode)
        ) {
          continue;
        }

        // Be default all values go through `line`
        parts.push(line);
      }

      if (hasInlineComment) {
        parts.push(breakParent);
      }

      }

      if (isControlDirective) {
        return group(indent(parts));
      }

      // Indent is not needed for import url when url is very long
      // and node has two groups
      // when type is value-comma_group
      // example @import url("verylongurl") projection,tv
      if (insideURLFunctionInImportAtRuleNode(path)) {
        return group(fill(parts));
      }

    }

      if (
        parentNode &&
        isURLFunctionNode(parentNode) &&
        (node.groups.length === 1 ||
          (node.groups.length > 0 &&
            node.groups[0].type === "value-comma_group" &&
            node.groups[0].groups.length > 0 &&
            node.groups[0].groups[0].type === "value-word" &&
            node.groups[0].groups[0].value.startsWith("data:")))
      ) {
        return [
          node.open ? path.call(print, "open") : "",
          node.close ? path.call(print, "close") : "",
        ];
      }

      if (!node.open) {

            res.push([",", line]);
          }
        }

      }

      const isSCSSMapItem = isSCSSMapItemNode(path);

      const lastItem = node.groups[node.groups.length - 1];
      const isLastItemComment = lastItem && lastItem.type === "value-comment";
      const isKey = isKeyInValuePairNode(node, parentNode);

      const printed = group(
        [
          indent([
            softline,
            join(
              [",", line],
              path.map((childPath) => {
                const node = childPath.getValue();
                const printed = print(childPath);

                // Key/Value pair in open paren already indented
                if (
                  isKeyValuePairNode(node) &&
                  node.type === "value-comma_group" &&
                  node.groups &&
                  node.groups[0].type !== "value-paren_group" &&
                  node.groups[2] &&
                  node.groups[2].type === "value-paren_group"
                ) {
                  const parts = getDocParts(printed.contents.contents);
                  parts[1] = group(parts[1]);

                  return group(dedent(printed));
                }

                return printed;
              }, "groups")
            ),
          ]),
          ifBreak(
            !isLastItemComment &&
              isSCSS(options.parser, options.originalText) &&
              isSCSSMapItem &&
              shouldPrintComma(options)
              ? ","
              : ""
          ),
          softline,
        ],
        {
          shouldBreak: isSCSSMapItem && !isKey,
        }
      );

      return isKey ? dedent(printed) : printed;
    }
      return [
        insideAtRuleNode(path, "supports") && isMediaAndSupportsKeywords(node)
          ? " "
          : "",
        path.call(print, "group"),
      ];
    }
    }
      return [printCssNumber(node.value), maybeToLowerCase(node.unit)];
    }
    }
      if ((node.isColor && node.isHex) || isWideKeywords(node.value)) {
        return node.value.toLowerCase();
      }

    }
      const index = parentNode && parentNode.groups.indexOf(node);
      const prevNode = index && parentNode.groups[index - 1];
      return [
        // Don't add spaces on escaped colon `:`, e.g: grid-template-rows: [row-1-00\:00] auto;
          typeof prevNode.value === "string" &&
          prevNode.value[prevNode.value.length - 1] === "\\") ||
        // Don't add spaces on `:` in `url` function (i.e. `url(fbglyph: cross-outline, fig-white)`)
        insideValueFunctionNode(path, "url")
          ? ""
          : line,
      ];
    }
    // TODO: confirm this code is dead
    }
      return printString(
        node.raws.quote + node.value + node.raws.quote,
        options
      );
    }
      return ["@", node.value];
    }
    case "value-unicode-range": {
    }
    case "value-unknown": {
    }
    default:
      throw new Error(`Unknown postcss type ${JSON.stringify(node.type)}`);
  }
}

  path.each((pathChild, i, nodes) => {
    const prevNode = nodes[i - 1];
    if (
    ) {
        options.originalText.slice(locStart(childNode), locEnd(childNode))
      );
    } else {
    }

    if (i !== nodes.length - 1) {
      if (
        (nodes[i + 1].type === "css-comment" &&
          !hasNewline(options.originalText, locStart(nodes[i + 1]), {
            backwards: true,
          }) &&
          !isFrontMatterNode(nodes[i])) ||
        (nodes[i + 1].type === "css-atrule" &&
          nodes[i + 1].name === "else" &&
          nodes[i].type !== "css-comment")
      ) {
      } else {
        parts.push(options.__isHTMLStyleAttribute ? line : hardline);
        if (
          isNextLineEmpty(options.originalText, pathChild.getValue(), locEnd) &&
          !isFrontMatterNode(nodes[i])
        ) {
        }
      }
    }

}

  return value.replace(STRING_REGEX, (match) => printString(match, options));
}

        ? printCssNumber(number) + maybeToLowerCase(unit || "")
        : match
  );
}

function printCssNumber(rawNumber) {
  return (
    printNumber(rawNumber)
  );
}

  if (!parent || parent.tag !== "root") {
  }

  let parser;

  if (node.tag === "style") {
    const langAttr = node.attrs.find(attr => attr.name === "lang");
    if (!langAttr) {
      parser = "css";
    } else if (langAttr.value === "scss") {
      parser = "scss";
    } else if (langAttr.value === "less") {
      parser = "less";
    }
  }

  if (node.tag === "script") {
      parser = "babylon";
    } else if (langAttr.value === "ts") {
      parser = "typescript";
    }
  }

  if (!parser) {
  }

    options.originalText.slice(node.start, node.contentStart),
    hardline,
    textToDoc(options.originalText.slice(node.contentStart, node.contentEnd), {
      parser
    }),
    options.originalText.slice(node.contentEnd, node.end)
  ]);
}

function makeMap(str, expectsLowerCase) {
  const list = str.split(",");
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true;
  }
  return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val];
}

(tag, html) =>
  tag && isIgnoreNewlineTag(tag) && html[0] === "\n"

function decodeAttr(value, shouldDecodeNewlines) {
  const re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr;
  return value.replace(re, match => decodingMap[match]);
}

function parseHTML(html, options) {
  const stack = [];
  const expectHTML = options.expectHTML;
  const isUnaryTag = options.isUnaryTag || no;
  const canBeLeftOpenTag = options.canBeLeftOpenTag || no;
  let last;
  let lastTag;
  while (html) {
    last = html;
    // Make sure we're not in a plaintext content element like script/style
    if (!lastTag || !isPlainTextElement(lastTag)) {
      let textEnd = html.indexOf("<");
      if (textEnd === 0) {
        // Comment:
        if (comment.test(html)) {
          const commentEnd = html.indexOf("-->");

          if (commentEnd >= 0) {
            if (options.shouldKeepComment) {
              options.comment(html.substring(4, commentEnd));
            }
            advance(commentEnd + 3);
            continue;
          }
        }

        // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
        if (conditionalComment.test(html)) {
          const conditionalEnd = html.indexOf("]>");

          if (conditionalEnd >= 0) {
            advance(conditionalEnd + 2);
            continue;
          }
        }

        // Doctype:
        const doctypeMatch = html.match(doctype);
        if (doctypeMatch) {
          advance(doctypeMatch[0].length);
          continue;
        }

        // End tag:
        const endTagMatch = html.match(endTag);
        if (endTagMatch) {
          const curIndex = index;
          advance(endTagMatch[0].length);
          parseEndTag(endTagMatch[1], curIndex, index);
          continue;
        }

        // Start tag:
        const startTagMatch = parseStartTag();
        if (startTagMatch) {
          handleStartTag(startTagMatch);
          if (shouldIgnoreFirstNewline(lastTag, html)) {
            advance(1);
          }
          continue;
        }
      }

      let text;
      let rest;
      let next;
      if (textEnd >= 0) {
        rest = html.slice(textEnd);
        while (
          !endTag.test(rest) &&
          !startTagOpen.test(rest) &&
          !comment.test(rest) &&
          !conditionalComment.test(rest)
        ) {
          // < in plain text, be forgiving and treat it as text
          next = rest.indexOf("<", 1);
          if (next < 0) {
            break;
          }
          textEnd += next;
          rest = html.slice(textEnd);
        }
        text = html.substring(0, textEnd);
        advance(textEnd);
      }

      if (textEnd < 0) {
        text = html;
        html = "";
      }

      if (options.chars && text) {
        options.chars(text);
      }
    } else {
      let endTagLength = 0;
      const stackedTag = lastTag.toLowerCase();
      const reStackedTag =
        reCache[stackedTag] ||
        (reCache[stackedTag] = new RegExp(
          "([\\s\\S]*?)(</" + stackedTag + "[^>]*>)",
          "i"
        ));
      const rest = html.replace(reStackedTag, (all, text, endTag) => {
        endTagLength = endTag.length;
        if (!isPlainTextElement(stackedTag) && stackedTag !== "noscript") {
          text = text
            .replace(/<!--([\s\S]*?)-->/g, "$1")
            .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, "$1");
        }
        if (shouldIgnoreFirstNewline(stackedTag, text)) {
          text = text.slice(1);
        }
        if (options.chars) {
          options.chars(text);
        }
        return "";
      });
      index += html.length - rest.length;
      html = rest;
      parseEndTag(stackedTag, index - endTagLength, index);
    }

    if (html === last) {
      options.chars && options.chars(html);
      if (
        process.env.NODE_ENV !== "production" &&
        !stack.length &&
        options.warn
      ) {
        options.warn(`Mal-formatted tag at end of template: "${html}"`);
      }
      break;
    }
  }

  // Clean up any remaining tags
  parseEndTag();

  function advance(n) {
    index += n;
    html = html.substring(n);
  }

  function parseStartTag() {
    const start = html.match(startTagOpen);
    if (start) {
      const match = {
        tagName: start[1],
        attrs: [],
        start: index
      };
      advance(start[0].length);
      let end;
      let attr;
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(attribute))
      ) {
        advance(attr[0].length);
        match.attrs.push(attr);
      }
      if (end) {
        match.unarySlash = end[1];
        advance(end[0].length);
        match.end = index;
        return match;
      }
    }
  }

  function handleStartTag(match) {
    const tagName = match.tagName;
    const unarySlash = match.unarySlash;

    if (expectHTML) {
      if (lastTag === "p" && isNonPhrasingTag(tagName)) {
        parseEndTag(lastTag);
      }
      if (canBeLeftOpenTag(tagName) && lastTag === tagName) {
        parseEndTag(tagName);
      }
    }

    const unary = isUnaryTag(tagName) || !!unarySlash;

    const l = match.attrs.length;
    const attrs = new Array(l);
    for (let i = 0; i < l; i++) {
      const args = match.attrs[i];
      // hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
      if (IS_REGEX_CAPTURING_BROKEN && args[0].indexOf('""') === -1) {
        if (args[3] === "") {
          delete args[3];
        }
        if (args[4] === "") {
          delete args[4];
        }
        if (args[5] === "") {
          delete args[5];
        }
      }
      const value = args[3] || args[4] || args[5] || "";
      const shouldDecodeNewlines =
        tagName === "a" && args[1] === "href"
          ? options.shouldDecodeNewlinesForHref
          : options.shouldDecodeNewlines;
      attrs[i] = {
        name: args[1],
        value: decodeAttr(value, shouldDecodeNewlines)
      };
    }

    if (!unary) {
      stack.push({
        tag: tagName,
        lowerCasedTag: tagName.toLowerCase(),
        attrs: attrs
      });
      lastTag = tagName;
    }

    if (options.start) {
      options.start(tagName, attrs, unary, match.start, match.end);
    }
  }

  function parseEndTag(tagName, start, end) {
    let pos;
    let lowerCasedTagName;
    if (start == null) {
      start = index;
    }
    if (end == null) {
      end = index;
    }

    if (tagName) {
      lowerCasedTagName = tagName.toLowerCase();
    }

    // Find the closest opened tag of the same type
      for (pos = stack.length - 1; pos >= 0; pos--) {
        if (stack[pos].lowerCasedTag === lowerCasedTagName) {
          break;
        }
      }
    } else {
      // If no tag name is provided, clean shop
      pos = 0;
    }

    if (pos >= 0) {
      // Close all the open elements, up the stack
      for (let i = stack.length - 1; i >= pos; i--) {
        if (
          process.env.NODE_ENV !== "production" &&
          (i > pos || !tagName) &&
          options.warn
        ) {
          options.warn(`tag <${stack[i].tag}> has no matching end tag.`);
        }
        if (options.end) {
          options.end(stack[i].tag, start, end);
        }
      }

      // Remove the open elements from the stack
      stack.length = pos;
      lastTag = pos && stack[pos - 1].tag;
    } else if (lowerCasedTagName === "br") {
      if (options.start) {
        options.start(tagName, [], true, start, end);
      }
    } else if (lowerCasedTagName === "p") {
        options.start(tagName, [], false, start, end);
      }
      if (options.end) {
        options.end(tagName, start, end);
      }
    }
  }
}

function advance(n) {
    index += n;
  }

function parseStartTag() {
        attrs: [],
      };
      let end;
      let attr;
      while (
      ) {
      }
      if (end) {
      }
    }
  }

function handleStartTag(match) {

      }
      }
    }

        }
        }
        }
      }
      };
    }

      });
    }

    }
  }

function parseEndTag(tagName, start, end) {
    let pos;
    }
    }

    }

          break;
        }
      }
    } else {
      pos = 0;
    }

        if (
        ) {
        }
        }
      }

      }
      }
      }
    }
  }

  const rootObj = {
    tag: "root",
    attrs: [],
    unary: false,
    start: 0,
    contentStart: 0,
    contentEnd: text.length,
    end: text.length,
    children: [],
    comments: []
  };
  const objStack = [rootObj];
  let obj = rootObj;
  parseHTML(text, {
    start: function(tag, attrs, unary, start, end) {
      const newObj = {
        tag,
        attrs,
        unary,
        start,
        contentStart: end,
        children: []
      };
      obj.children.push(newObj);
      objStack.push(newObj);
      obj = newObj;
    },
    end: function(tag, start, end) {
      objStack.pop();
      obj.contentEnd = start;
      obj.end = end;
      obj = objStack[objStack.length - 1];
    }
  });
  return rootObj;
}

get parse() {
      return eval("require")("./parser-vue");
    }

  let index = n.start;

    res.push(options.originalText.slice(index, child.start));
    res.push(childPath.call(print));
    index = child.end;
  res.push(options.originalText.slice(index, n.end));

}

function getOptions(argv, detailedOptions) {
  return fromPairs(
    detailedOptions
      .filter(({ forwardToApi }) => forwardToApi)
      .map(({ forwardToApi, name }) => [forwardToApi, argv[name]])
  );
}

function cliifyOptions(object, apiDetailedOptionMap) {
    Object.entries(object || {}).map(([key, value]) => {
      const apiOption = apiDetailedOptionMap[key];
      const cliKey = apiOption ? apiOption.name : key;

      return [dashify(cliKey), value];
    })
  );
}

function createApiDetailedOptionMap(detailedOptions) {
      .filter(
        (option) => option.forwardToApi && option.forwardToApi !== option.name
      )
      .map((option) => [option.forwardToApi, option])
  );
}

function parseArgsToOptions(context, overrideDefaults) {
  const minimistOptions = createMinimistOptions(context.detailedOptions);
  const apiDetailedOptionMap = createApiDetailedOptionMap(
    context.detailedOptions
  );
    optionsNormalizer.normalizeCliOptions(
      minimist(context.rawArguments, {
        string: minimistOptions.string,
        boolean: minimistOptions.boolean,
        default: cliifyOptions(overrideDefaults, apiDetailedOptionMap),
      }),
      context.detailedOptions,
      { logger: false }
    ),
  );
}

function getOptionsOrDie(context, filePath) {
  try {
    if (context.argv.config === false) {
      context.logger.debug(
        "'--no-config' option found, skip loading config file."
      );
    }

    context.logger.debug(
      context.argv.config
        ? `load config file from '${context.argv.config}'`
    );

    const options = prettier.resolveConfig.sync(filePath, {
      editorconfig: context.argv.editorconfig,
      config: context.argv.config,
    });

    context.logger.debug("loaded options `" + JSON.stringify(options) + "`");
    context.logger.error(
      `Invalid configuration file \`${filePath}\`: ` + error.message
    );
  }
}

function applyConfigPrecedence(context, options) {
  try {
    switch (context.argv["config-precedence"]) {
        return parseArgsToOptions(context, options);
        return { ...parseArgsToOptions(context), ...options };
        return options || parseArgsToOptions(context);
    }
    context.logger.error(error.toString());

  }
}

function getOptionsForFile(context, filepath) {
  const options = getOptionsOrDie(context, filepath);

  const hasPlugins = options && options.plugins;
  if (hasPlugins) {
    context.pushContextPlugins(options.plugins);
  }

  const appliedOptions = {
    filepath,
    ...applyConfigPrecedence(
      context,
      options &&
        optionsNormalizer.normalizeApiOptions(options, context.supportOptions, {
          logger: context.logger,
        })
    ),
  };

  context.logger.debug(
    `applied config-precedence (${context.argv["config-precedence"]}): ` +
  );

    context.popContextPlugins();
  }

}

(stream, text) => {
  const columns = stream.columns || 80;
  let lineCount = 0;
  for (const line of stripAnsi(text).split("\n")) {
    lineCount += Math.max(1, Math.ceil(wcwidth(line) / columns));
  }
  return lineCount;
}

function createLogger(logLevel = "log") {
  return {
    logLevel,
    warn: createLogFunc("warn", "yellow"),
    error: createLogFunc("error", "red"),
    debug: createLogFunc("debug", "blue"),
    log: createLogFunc("log"),
  };

  function createLogFunc(loggerName, color) {
    if (!shouldLog(loggerName)) {
      return () => emptyLogResult;
    }

    const prefix = color ? `[${chalk[color](loggerName)}] ` : "";
    const stream = process[loggerName === "log" ? "stdout" : "stderr"];

    return (message, options) => {
      options = {
        newline: true,
        clearable: false,
        ...options,
      };
      message = message.replace(/^/gm, prefix) + (options.newline ? "\n" : "");
      stream.write(message);

      if (options.clearable) {
        return {
          clear: clear(stream, message),
        };
      }
    };
  }

  function shouldLog(loggerName) {
    switch (logLevel) {
      case "silent":
      case "debug":
        if (loggerName === "debug") {
        }
      // fall through
      case "log":
        if (loggerName === "log") {
        }
      case "warn":
        if (loggerName === "warn") {
        }
      case "error":
        return loggerName === "error";
    }
  }
}

function createLogFunc(loggerName, color) {
    }

      options = {
      };

        return {
        };
      }
    };
  }

        }
        }
        }
    }
  }

function run(rawArguments) {
  // Create a default level logger, so we can log errors during `logLevel` parsing
  let logger = core.createLogger();

  try {
    const logLevel = core.parseArgvWithoutPlugins(
      rawArguments,
      logger,
      "loglevel"
    ).loglevel;
    if (logLevel !== logger.logLevel) {
      logger = core.createLogger(logLevel);
    }

    main(rawArguments, logger);
    logger.error(error.message);
  }
}

function main(rawArguments, logger) {
  const context = new core.Context({ rawArguments, logger });

  logger.debug(`normalized argv: ${JSON.stringify(context.argv)}`);

  if (context.argv.check && context.argv["list-different"]) {
    throw new Error("Cannot use --check and --list-different together.");
  }

  if (context.argv.write && context.argv["debug-check"]) {
    throw new Error("Cannot use --write and --debug-check together.");
  }

  if (context.argv["find-config-path"] && context.filePatterns.length > 0) {
    throw new Error("Cannot use --find-config-path with multiple files");
  }

  if (context.argv["file-info"] && context.filePatterns.length > 0) {
    throw new Error("Cannot use --file-info with multiple files");
  }

  if (context.argv.version) {
    logger.log(prettier.version);
    return;
  }

  if (context.argv.help !== undefined) {
    logger.log(
      typeof context.argv.help === "string" && context.argv.help !== ""
        ? core.createDetailedUsage(context, context.argv.help)
        : core.createUsage(context)
    );
    return;
  }

  if (context.argv["support-info"]) {
      prettier.format(stringify(prettier.getSupportInfo()), {
        parser: "json",
      })
    );
    return;
  }

  const hasFilePatterns = context.filePatterns.length > 0;
  const useStdin =
    !hasFilePatterns &&
    (!process.stdin.isTTY || context.argv["stdin-filepath"]);

  if (context.argv["find-config-path"]) {
    core.logResolvedConfigPathOrDie(context);
  } else if (context.argv["file-info"]) {
    core.logFileInfoOrDie(context);
    core.formatStdin(context);
    core.formatFiles(context);
  } else {
    logger.log(core.createUsage(context));
  }
}

function normalizeDetailedOption(name, option) {
  return {
    category: coreOptions.CATEGORY_OTHER,
    ...option,
    choices:
      option.choices &&
      option.choices.map((choice) => {
        const newChoice = {
          description: "",
          deprecated: false,
          ...(typeof choice === "object" ? choice : { value: choice }),
        };
        if (newChoice.value === true) {
          newChoice.value = ""; // backward compatibility for original boolean option
        }
        return newChoice;
      }),
  };
}

function normalizeDetailedOptionMap(detailedOptionMap) {
    Object.entries(detailedOptionMap)
      .sort(([leftName], [rightName]) => leftName.localeCompare(rightName))
      .map(([name, option]) => [name, normalizeDetailedOption(name, option)])
  );
}

function createDetailedOptionMap(supportOptions) {
    supportOptions.map((option) => {
      const newOption = {
        ...option,
        name: option.cliName || dashify(option.name),
        description: option.cliDescription || option.description,
        category: option.cliCategory || coreOptions.CATEGORY_FORMAT,
        forwardToApi: option.name,
      };

      if (option.deprecated) {
        delete newOption.forwardToApi;
        delete newOption.description;
        delete newOption.oppositeDescription;
        newOption.deprecated = true;
      }

      return [newOption.name, newOption];
    })
  );
}

  return constant.detailedOptions.filter(option => option.forwardToApi).reduce(
    (current, option) =>
      Object.assign(current, {
        [option.forwardToApi]: option.array
          ? [].concat(argv[option.name] || [])
          : argv[option.name]
      }),
    {}
  );
}

function cliifyOptions(object) {
    const apiOption = constant.apiDetailedOptionMap[key];
    const cliKey = apiOption ? apiOption.name : key;

    output[dashify(cliKey)] = object[key];
  }, {});
}

    logger.log(path.relative(process.cwd(), configFile));
  } else {
  }
}

    return;
  }

      logger.log(filename);
    }
  }

}

  try {
    }

    );
      editorconfig: argv.editorconfig,
    });

  }
}

      "cli",
      minimist(
            {},
            cliifyOptions(apiDefaultOptions),
            cliifyOptions(overrideDefaults)
          )
        })
      ),
    )
  );
}

  }

  try {
      .sync(patterns, { dot: true, nodir: true })

      return;
    }
    ignorer
      );
    );
  }
}

      logger.log(filename, { newline: false });
    }

    let input;
    try {
      logger.log("");

      return;
    }

    try {
        argv,
        input,
      );

      return;
    }

      }

          logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
        }
      } else {
          logger.log(filename);
        } else {
          logger.log(`${filename} ${Date.now() - start}ms`);
        }

        try {
        }
      }
        logger.log(output);
      } else {
      }
    }
  });
}

    ])

  );

  }

  );

      `Unknown option name "${optionName}", did you mean "${suggestedOptionName}"?`
    );

  }

}

  }

      return;
    }

      return;
    }

    let option = constant.detailedOptionMap[key];
    if (type === "api" && option === undefined) {
      option = constant.apiDetailedOptionMap[key];
    }

      } else {
      }
      return;
    }

          return;
        }
      } else {
          return;
        }
      }
    }

    try {
          break;
          break;
        default:
          break;
      }
    }
  });

  }

  }

      }
    }

          `\`${optionName}\` ${warningDescription} is deprecated. Prettier now treats it as: \`${redirectName}\`.`
        );
      }
    }

  }
}

      }
    }

        );
      }
    }

  }

class Context {
  constructor({ rawArguments, logger }) {
    this.rawArguments = rawArguments;
    this.logger = logger;
    this.stack = [];

    const {
      plugin: plugins,
      "plugin-search-dir": pluginSearchDirs,
    } = parseArgvWithoutPlugins(rawArguments, logger, [
      "plugin",
      "plugin-search-dir",
    ]);

    this.pushContextPlugins(plugins, pluginSearchDirs);

    const argv = parseArgv(rawArguments, this.detailedOptions, logger);
    this.argv = argv;
    this.filePatterns = argv._.map((file) => String(file));
  }

  /**
   * @param {string[]} plugins
   * @param {string[]=} pluginSearchDirs
   */
  pushContextPlugins(plugins, pluginSearchDirs) {
    this.stack.push(
      pick(this, [
        "supportOptions",
        "detailedOptions",
        "detailedOptionMap",
        "apiDefaultOptions",
        "languages",
      ])
    );

    Object.assign(this, getContextOptions(plugins, pluginSearchDirs));
  }

  popContextPlugins() {
    Object.assign(this, this.stack.pop());
  }
}

constructor({ rawArguments, logger }) {

    const {
      "plugin",
    ]);

  }

pushContextPlugins(plugins, pluginSearchDirs) {
      ])
    );

  }

popContextPlugins() {
  }

function getContextOptions(plugins, pluginSearchDirs) {
  const { options: supportOptions, languages } = prettier.getSupportInfo({
    showInternal: true,
    plugins,
    pluginSearchDirs,
  });
  const detailedOptionMap = normalizeDetailedOptionMap({
    ...createDetailedOptionMap(supportOptions),
    ...constant.options,
  });

  const detailedOptions = arrayify(detailedOptionMap, "name");

  const apiDefaultOptions = {
    ...optionsModule.hiddenDefaults,
        .filter(({ deprecated }) => !deprecated)
    ),
  };

  return {
    supportOptions,
    detailedOptions,
    detailedOptionMap,
    apiDefaultOptions,
    languages,
  };
}

function parseArgv(rawArguments, detailedOptions, logger, keys) {
  const minimistOptions = createMinimistOptions(detailedOptions);
  let argv = minimist(rawArguments, minimistOptions);

  if (keys) {
    detailedOptions = detailedOptions.filter((option) =>
      keys.includes(option.name)
    );
    argv = pick(argv, keys);
  }

  return normalizeCliOptions(argv, detailedOptions, { logger });
}

function parseArgvWithoutPlugins(rawArguments, logger, keys) {
  return parseArgv(
    rawArguments,
    detailedOptionsWithoutPlugins,
    logger,
    typeof keys === "string" ? [keys] : keys
  );
}

function logResolvedConfigPathOrDie(context) {
  const file = context.argv["find-config-path"];
  const configFile = prettier.resolveConfigFile.sync(file);
    context.logger.log(path.relative(process.cwd(), configFile));
  } else {
    throw new Error(`Can not find configure file for "${file}"`);
  }
}

function logFileInfoOrDie(context) {
  const options = {
    ignorePath: context.argv["ignore-path"],
    withNodeModules: context.argv["with-node-modules"],
    plugins: context.argv.plugin,
    pluginSearchDirs: context.argv["plugin-search-dir"],
    resolveConfig: context.argv.config !== false,
  };

  context.logger.log(
    prettier.format(
      stringify(prettier.getFileInfo.sync(context.argv["file-info"], options)),
      { parser: "json" }
    )
  );
}

function createDefaultValueDisplay(value) {
  return Array.isArray(value)
    ? `[${value.map(createDefaultValueDisplay).join(", ")}]`
    : value;
}

function getOptionDefaultValue(context, optionName) {
  if (!(optionName in context.detailedOptionMap)) {
    return;
  }

  const option = context.detailedOptionMap[optionName];

  }

  if (optionCamelName in context.apiDefaultOptions) {
    return context.apiDefaultOptions[optionCamelName];
  }
}

        .filter((choice) => !choice.deprecated && choice.since !== null)
        .map((choice) => choice.value)
    default:
  }
}

  const activeChoices = choices.filter(
    (choice) => !choice.deprecated && choice.since !== null
  );
      .map((choice) => choice.value.length)
  return activeChoices.map((choice) =>
    indent(
    )
  );
}

function createOptionUsage(context, option, threshold) {
  const optionDefaultValue = getOptionDefaultValue(context, option.name);
    header,
        ? ""
        : `\nDefaults to ${createDefaultValueDisplay(optionDefaultValue)}.`
    }`,
    threshold
  );
}

  const optionsWithOpposites = options.map((option) => [
      ? {
          ...option,
          description: option.oppositeDescription,
        }
      : null,
  ]);
  return flat(optionsWithOpposites).filter(Boolean);
}

function createUsage(context) {
  const options = getOptionsWithOpposites(context.detailedOptions).filter(
    (option) =>
      !(
      )
  );

  const groupedOptions = groupBy(options, (option) => option.category);

    (category) => !constant.categoryOrder.includes(category)
  );
  const allCategories = [
    ...firstCategories,
    ...restCategories,
    ...lastCategories,
  ];

  const optionsUsage = allCategories.map((category) => {
      .map((option) =>
        createOptionUsage(context, option, OPTION_USAGE_THRESHOLD)
      )
  });

  return [constant.usageSummary, ...optionsUsage, ""].join("\n\n");
}

function createDetailedUsage(context, flag) {
  const option = getOptionsWithOpposites(context.detailedOptions).find(
    (option) => option.name === flag || option.alias === flag
  );

      ? ""

      ? `\n\nDefault: ${createDefaultValueDisplay(optionDefaultValue)}`
      : "";

  const pluginDefaults =
    option.pluginDefaults && Object.keys(option.pluginDefaults).length > 0
      ? `\nPlugin defaults:${Object.entries(option.pluginDefaults).map(
          ([key, value]) => `\n* ${key}: ${createDefaultValueDisplay(value)}`
        )}`
      : "";
  return `${header}${description}${choices}${defaults}${pluginDefaults}`;
}

    context: 2,
  });
}

function handleError(context, filename, error, printedFilename) {
  if (error instanceof errors.UndefinedParserError) {
    // Can't test on CI, `isTTY()` is always false, see ./is-tty.js
    if (
      (context.argv.write || context.argv["ignore-unknown"]) &&
      printedFilename
    ) {
      printedFilename.clear();
    }
    if (context.argv["ignore-unknown"]) {
      return;
    }
    if (!context.argv.check && !context.argv["list-different"]) {
    }
    context.logger.error(error.message);
    return;
  }

  if (context.argv.write) {
    // Add newline to split errors from filename line.
    process.stdout.write("\n");
  }

  const isValidationError = /^Invalid \S+ value\./.test(error && error.message);

    // `invalid.js: SyntaxError: Unexpected token (1:1)`.
    context.logger.error(`${filename}: ${String(error)}`);
    // `Invalid printWidth value. Expected an integer, but received 0.5.`
    // `invalid.js: Some debug error message`
    context.logger.error(`${filename}: ${error.message}`);
  } else {
    // `invalid.js: Error: Some unexpected error\n[stack trace]`
    context.logger.error(filename + ": " + (error.stack || error));
  }

}

function writeOutput(context, result, options) {
  process.stdout.write(
    context.argv["debug-check"] ? result.filepath : result.formatted
  );

  if (options && options.cursorOffset >= 0) {
  }
}

function listDifferent(context, input, options, filename) {
  if (!context.argv.check && !context.argv["list-different"]) {
    return;
  }

  try {
    if (!options.filepath && !options.parser) {
      throw new errors.UndefinedParserError(
        "No parser and no file path given, couldn't infer a parser."
      );
    }
    if (!prettier.check(input, options)) {
      if (!context.argv.write) {
        context.logger.log(filename);
        process.exitCode = 1;
      }
    }
  }

}

function format(context, input, opt) {
  if (!opt.parser && !opt.filepath) {
    throw new errors.UndefinedParserError(
      "No parser and no file path given, couldn't infer a parser."
    );
  }

  if (context.argv["debug-print-doc"]) {
    return { formatted: prettier.__debug.formatDoc(doc) + "\n" };
  }

  if (context.argv["debug-print-comments"]) {
    return {
      formatted: prettier.format(
        JSON.stringify(prettier.formatWithCursor(input, opt).comments || []),
        { parser: "json" }
      ),
    };
  }

  if (context.argv["debug-check"]) {
      );
    } else {
      const stringify = (obj) => JSON.stringify(obj, null, 2);
      const ast = stringify(
        prettier.__debug.parse(input, opt, /* massage */ true).ast
      );
      const past = stringify(
        prettier.__debug.parse(pp, opt, /* massage */ true).ast
      );

            astDiff +
            "\n" +
        );
      }
    }
    return { formatted: pp, filepath: opt.filepath || "(stdin)\n" };
  }

  if (context.argv["debug-benchmark"]) {
    let benchmark;
    try {
      benchmark = eval("require")("benchmark");
        "'--debug-benchmark' requires the 'benchmark' package to be installed."
      );
    }
      "'--debug-benchmark' option found, measuring formatWithCursor with 'benchmark' module."
    );
    const suite = new benchmark.Suite();
    suite
      .add("format", () => {
        prettier.formatWithCursor(input, opt);
      })
      .on("cycle", (event) => {
        const results = {
          benchmark: String(event.target),
          hz: event.target.hz,
          ms: event.target.times.cycle * 1000,
        };
        context.logger.debug(
          "'--debug-benchmark' measurements for formatWithCursor: " +
            JSON.stringify(results, null, 2)
        );
      })
      .run({ async: false });
  } else if (context.argv["debug-repeat"] > 0) {
    const repeat = context.argv["debug-repeat"];
      "'--debug-repeat' option found, running formatWithCursor " +
        repeat +
        " times."
    );
    let totalMs = 0;
    for (let i = 0; i < repeat; ++i) {
      // should be using `performance.now()`, but only `Date` is cross-platform enough
      const startMs = Date.now();
      prettier.formatWithCursor(input, opt);
      totalMs += Date.now() - startMs;
    }
    const averageMs = totalMs / repeat;
    const results = {
      repeat,
      hz: 1000 / averageMs,
      ms: averageMs,
    };
      "'--debug-repeat' measurements for formatWithCursor: " +
        JSON.stringify(results, null, 2)
    );
  }

}

function createIgnorerFromContextOrDie(context) {
  try {
    return createIgnorer.sync(
      context.argv["ignore-path"],
      context.argv["with-node-modules"]
    );
    context.logger.error(e.message);
  }
}

function formatStdin(context) {
  const filepath = context.argv["stdin-filepath"]
    ? path.resolve(process.cwd(), context.argv["stdin-filepath"])

  const ignorer = createIgnorerFromContextOrDie(context);
  // If there's an ignore-path set, the filename must be relative to the
  // ignore path, not the current working directory.
  const relativeFilepath = context.argv["ignore-path"]
    ? path.relative(path.dirname(context.argv["ignore-path"]), filepath)
    : path.relative(process.cwd(), filepath);

  getStdin()
    .then((input) => {
      if (
        relativeFilepath &&
        ignorer.ignores(fixWindowsSlashes(relativeFilepath))
      ) {
        writeOutput(context, { formatted: input });
        return;
      }

      const options = getOptionsForFile(context, filepath);

      if (listDifferent(context, input, options, "(stdin)")) {
        return;
      }

      writeOutput(context, format(context, input, options), options);
    })
    .catch((error) => {
      handleError(context, relativeFilepath || "stdin", error);
    });
}

function formatFiles(context) {
  // before any files are actually written

  let numberOfUnformattedFilesFound = 0;

  if (context.argv.check) {
    context.logger.log("Checking formatting...");
  }

  for (const pathOrError of expandPatterns(context)) {
    if (typeof pathOrError === "object") {
      context.logger.error(pathOrError.error);
      // Don't exit, but set the exit code to 2
      continue;
    }

    const filename = pathOrError;
    // If there's an ignore-path set, the filename must be relative to the
    // ignore path, not the current working directory.
    const ignoreFilename = context.argv["ignore-path"]
      ? path.relative(path.dirname(context.argv["ignore-path"]), filename)
      : filename;

    const fileIgnored = ignorer.ignores(fixWindowsSlashes(ignoreFilename));
    if (
      fileIgnored &&
      (context.argv["debug-check"] ||
        context.argv.write ||
        context.argv.check ||
        context.argv["list-different"])
    ) {
      continue;
    }

    const options = {
      ...getOptionsForFile(context, filename),
      filepath: filename,
    };

    let printedFilename;
    if (isTTY()) {
      printedFilename = context.logger.log(filename, {
        newline: false,
        clearable: true,
      });
    }

    let input;
    try {
      context.logger.log("");

      context.logger.error(
        `Unable to read file: ${filename}\n${error.message}`
      );

      continue;
    }

    if (fileIgnored) {
      writeOutput(context, { formatted: input }, options);
      continue;
    }

    try {
      result = format(context, input, options);
      handleError(context, filename, error, printedFilename);
      continue;
    }

    const isDifferent = output !== input;

    if (printedFilename) {
      // Remove previously printed filename to log it with duration.
    }

    if (context.argv.write) {
      if (isDifferent) {
        if (!context.argv.check && !context.argv["list-different"]) {
          context.logger.log(`${filename} ${Date.now() - start}ms`);
        }

        try {
          /* istanbul ignore next */
          context.logger.error(
            `Unable to write file: ${filename}\n${error.message}`
          );

        }
      } else if (!context.argv.check && !context.argv["list-different"]) {
        context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
      }
    } else if (context.argv["debug-check"]) {
      if (result.filepath) {
        context.logger.log(result.filepath);
      } else {
      }
    } else if (!context.argv.check && !context.argv["list-different"]) {
      writeOutput(context, result, options);
    }

    if (isDifferent) {
      if (context.argv.check) {
        context.logger.warn(filename);
      } else if (context.argv["list-different"]) {
      }
      numberOfUnformattedFilesFound += 1;
    }
  }

  // Print check summary based on expected exit code
    if (numberOfUnformattedFilesFound === 0) {
      context.logger.log("All matched files use Prettier code style!");
    } else {
      context.logger.warn(
        context.argv.write
          ? "Code style issues fixed in the above file(s)."
          : "Code style issues found in the above file(s). Forgot to run Prettier?"
      );
    }
  }

  // Ensure non-zero exitCode when using --check/list-different is not combined with --write
  if (
    (context.argv.check || context.argv["list-different"]) &&
    numberOfUnformattedFilesFound > 0 &&
    !process.exitCode &&
    !context.argv.write
  ) {
  }
}

function getSupportedFilesGlob() {
    if (!supportedFilesGlob) {
      const extensions = flat(
        context.languages.map((lang) => lang.extensions || [])
      );
      const filenames = flat(
        context.languages.map((lang) => lang.filenames || [])
      );
      supportedFilesGlob = `**/{${[
        ...extensions.map((ext) => "*" + (ext[0] === "." ? ext : "." + ext)),
        ...filenames,
      ]}}`;
    }
    return supportedFilesGlob;
  }

function containsIgnoredPathSegment(absolutePath, cwd, ignoredDirectories) {
  return path
    .relative(cwd, absolutePath)
    .split(path.sep)
    .some((dir) => ignoredDirectories.includes(dir));
}

function sortPaths(paths) {
  return paths.sort((a, b) => a.localeCompare(b));
}

function statSafeSync(filePath) {
  try {
    return fs.statSync(filePath);
    if (error.code !== "ENOENT") {
    }
  }
}

function escapePathForGlob(path) {
  return fastGlob
    .escapePath(
      path.replace(/\\/g, "\0") // Workaround for fast-glob#262 (part 1)
    )
    .replace(/\\!/g, "@(!)") // Workaround for fast-glob#261
    .replace(/\0/g, "@(\\\\)"); // Workaround for fast-glob#262 (part 2)
}

function fixWindowsSlashes(pattern) {
  return isWindows ? pattern.replace(/\\/g, "/") : pattern;
}

  // Try to format `.prettierrc` as `json` first
  if (
    node.type === "root" &&
    options.filepath &&
    /(?:[/\\]|^)\.prettierrc$/.test(options.filepath)
  ) {
    return textToDoc(options.originalText, { ...options, parser: "json" });
  }
}

function getAncestorCount(path, filter) {
  const pathStackLength = path.stack.length - 1;
  for (let i = 0; i < pathStackLength; i++) {
    if (isNode(value) && filter(value)) {
    }
  }
}

function isNode(value, types) {
  return (
    value &&
    typeof value.type === "string" &&
    (!types || types.includes(value.type))
  );
}

function mapNode(node, callback, parent) {
  return callback(
    "children" in node
      ? {
          ...node,
          children: node.children.map((childNode) =>
            mapNode(childNode, callback, node)
          ),
        }
      : node,
    parent
  );
}

function defineShortcut(x, key, getter) {
  Object.defineProperty(x, key, {
    get: getter,
    enumerable: false,
  });
}

function isNextLineEmpty(node, text) {
  let newlineCount = 0;
  const textLength = text.length;
  for (let i = node.position.end.offset - 1; i < textLength; i++) {
    const char = text[i];

    if (char === "\n") {
      newlineCount++;
    }

    if (newlineCount === 1 && /\S/.test(char)) {
    }

    if (newlineCount === 2) {
    }
  }

}

function isLastDescendantNode(path) {

    case "tag":
    case "anchor":
  }

  const pathStackLength = path.stack.length;

  for (let i = 1; i < pathStackLength; i++) {
    const item = path.stack[i];
    const parentItem = path.stack[i - 1];

    if (
      Array.isArray(parentItem) &&
      typeof item === "number" &&
      item !== parentItem.length - 1
    ) {
    }
  }

}

  return isNonEmptyArray(node.children)
    ? getLastDescendantNode(getLast(node.children))
    : node;
}

function isPrettierIgnore(comment) {
  return comment.value.trim() === "prettier-ignore";
}

  if (node.type === "documentBody") {
    const document = path.getParentNode();
    return (
      hasEndComments(document.head) &&
      isPrettierIgnore(getLast(document.head.endComments))
    );
  }

  return (
    hasLeadingComments(node) && isPrettierIgnore(getLast(node.leadingComments))
  );
}

function isEmptyNode(node) {
  return !isNonEmptyArray(node.children) && !hasComments(node);
}

function hasComments(node) {
  return (
    hasLeadingComments(node) ||
    hasMiddleComments(node) ||
    hasIndicatorComment(node) ||
    hasTrailingComment(node) ||
    hasEndComments(node)
  );
}

function hasLeadingComments(node) {
  return node && isNonEmptyArray(node.leadingComments);
}

function hasMiddleComments(node) {
  return node && isNonEmptyArray(node.middleComments);
}

function hasIndicatorComment(node) {
  return node && node.indicatorComment;
}

function hasTrailingComment(node) {
  return node && node.trailingComment;
}

function hasEndComments(node) {
  return node && isNonEmptyArray(node.endComments);
}

function splitWithSingleSpace(text) {

  let lastPart;
  for (const part of text.split(/( +)/g)) {
    /* istanbul ignore else */
    if (part !== " ") {
      if (lastPart === " ") {
      } else {
        parts.push((parts.pop() || "") + part);
      }
    } else if (lastPart === undefined) {
      parts.unshift("");
    }

    lastPart = part;
  }

  if (lastPart === " ") {
    parts.push((parts.pop() || "") + " ");
  }

  if (parts[0] === "") {
    parts.shift();
    parts.unshift(" " + (parts.shift() || ""));
  }

}

function getFlowScalarLineContents(nodeType, content, options) {
  const rawLineContents = content
    .split("\n")
    .map((lineContent, index, lineContents) =>
      index === 0 && index === lineContents.length - 1
        ? lineContent
        : index !== 0 && index !== lineContents.length - 1
        ? lineContent.trim()
        : index === 0
        ? lineContent.trimEnd()
        : lineContent.trimStart()
    );

  if (options.proseWrap === "preserve") {
    return rawLineContents.map((lineContent) =>
      lineContent.length === 0 ? [] : [lineContent]
    );
  }

  return rawLineContents
    .map((lineContent) =>
      lineContent.length === 0 ? [] : splitWithSingleSpace(lineContent)
    )
    .reduce(
      (reduced, lineContentWords, index) =>
        index !== 0 &&
        rawLineContents[index - 1].length > 0 &&
        lineContentWords.length > 0 &&
        !(
          // trailing backslash in quoteDouble should be preserved
          (
            nodeType === "quoteDouble" &&
            getLast(getLast(reduced)).endsWith("\\")
          )
        )
          ? [
              ...reduced.slice(0, -1),
              [...getLast(reduced), ...lineContentWords],
            ]
          : [...reduced, lineContentWords],
      []
    )
    .map((lineContentWords) =>
      options.proseWrap === "never"
        ? [lineContentWords.join(" ")]
        : lineContentWords
    );
}

function getBlockValueLineContents(
  node,
  { parentIndent, isLastDescendant, options }
) {
  const content =
    node.position.start.line === node.position.end.line
      ? ""
      : options.originalText
          .slice(node.position.start.offset, node.position.end.offset)
          // exclude open line `>` or `|`
          .match(/^[^\n]*?\n([\S\s]*)$/)[1];

  const leadingSpaceCount =
    node.indent === null
      ? ((match) => (match ? match[1].length : Number.POSITIVE_INFINITY))(
          content.match(/^( *)\S/m)
        )
      : node.indent - 1 + parentIndent;

    .map((lineContent) => lineContent.slice(leadingSpaceCount));

  if (options.proseWrap === "preserve" || node.type === "blockLiteral") {
    return removeUnnecessaryTrailingNewlines(
      rawLineContents.map((lineContent) =>
        lineContent.length === 0 ? [] : [lineContent]
      )
    );
  }

  return removeUnnecessaryTrailingNewlines(
    rawLineContents
      .map((lineContent) =>
        lineContent.length === 0 ? [] : splitWithSingleSpace(lineContent)
      )
      .reduce(
        (reduced, lineContentWords, index) =>
          index !== 0 &&
          rawLineContents[index - 1].length > 0 &&
          lineContentWords.length > 0 &&
          !/^\s/.test(lineContentWords[0]) &&
          !/^\s|\s$/.test(getLast(reduced))
            ? [
                ...reduced.slice(0, -1),
                [...getLast(reduced), ...lineContentWords],
              ]
            : [...reduced, lineContentWords],
        []
      )
      .map((lineContentWords) =>
        lineContentWords.reduce(
          (reduced, word) =>
            // disallow trailing spaces
            reduced.length > 0 && /\s$/.test(getLast(reduced))
              ? [...reduced.slice(0, -1), getLast(reduced) + " " + word]
              : [...reduced, word],
          []
        )
      )
        options.proseWrap === "never"
          ? [lineContentWords.join(" ")]
          : lineContentWords
      )
  );

  function removeUnnecessaryTrailingNewlines(lineContents) {
    if (node.chomping === "keep") {
      return getLast(lineContents).length === 0
        ? lineContents.slice(0, -1)
        : lineContents;
    }

    let trailingNewlineCount = 0;
    for (let i = lineContents.length - 1; i >= 0; i--) {
      if (lineContents[i].length === 0) {
        trailingNewlineCount++;
      } else {
        break;
      }
    }

    return trailingNewlineCount === 0
      ? lineContents
      : trailingNewlineCount >= 2 && !isLastDescendant
      ? // next empty line
        lineContents.slice(0, -(trailingNewlineCount - 1))
      : lineContents.slice(0, -trailingNewlineCount);
  }
}

function removeUnnecessaryTrailingNewlines(lineContents) {
    }

      } else {
        break;
      }
    }

  }

function isInlineNode(node) {
  }

    case "plain":
    case "quoteDouble":
    case "quoteSingle":
    case "alias":
    case "flowMapping":
    case "flowSequence":
    default:
  }
}

get yaml() {
    return require("./parser-yaml").parsers.yaml;
  }

  try {
    const root = require("yaml-unist-parser").parse(text);

    /**
     * suppress `comment not printed` error
     *
     * comments are handled in printer-yaml.js without using `printComment`
     * so that it'll always throw errors even if we printed it correctly
     */
    delete root.comments;

    return root;
    if (error && error.position) {
      throw createError(error.message, error.position);
    }

  }
}

function isPragma(text) {
  return /^\s*@(prettier|format)\s*$/.test(text);
}

  return /^\s*#[^\S\n]*@(prettier|format)\s*?(\n|$)/.test(text);
}

  return `# @format\n\n${text}`;
}

  if (node.type !== "mappingValue" && hasLeadingComments(node)) {
    parts.push([join(hardline, path.map(print, "leadingComments")), hardline]);
  }

  const { tag, anchor } = node;
  if (tag) {
    parts.push(path.call(print, "tag"));
  }
  if (tag && anchor) {
    parts.push(" ");
  }
  if (anchor) {
    parts.push(path.call(print, "anchor"));
  }

  /** @type {Doc} */
  let nextEmptyLine = "";

  if (
    isNode(node, [
      "mapping",
      "sequence",
      "comment",
      "directive",
      "mappingItem",
      "sequenceItem",
    ]) &&
    !isLastDescendantNode(path)
  ) {
    nextEmptyLine = printNextEmptyLine(path, options.originalText);
  }

  if (tag || anchor) {
    if (isNode(node, ["sequence", "mapping"]) && !hasMiddleComments(node)) {
    } else {
    }
  }

  if (hasMiddleComments(node)) {
    parts.push([
      node.middleComments.length === 1 ? "" : hardline,
      join(hardline, path.map(print, "middleComments")),
      hardline,
    ]);
  }

      replaceEndOfLineWith(
        options.originalText
          .trimEnd(),
        literalline
      )
    );
  } else {
    parts.push(group(printNode(node, parentNode, path, options, print)));
  }

  if (hasTrailingComment(node) && !isNode(node, ["document", "documentHead"])) {
      lineSuffix([
        node.type === "mappingValue" && !node.content ? "" : " ",
        parentNode.type === "mappingKey" &&
        path.getParentNode(2).type === "mapping" &&
        isInlineNode(node)
          ? ""
          : breakParent,
        path.call(print, "trailingComment"),
      ])
    );
  }

  if (shouldPrintEndComments(node)) {
      alignWithSpaces(node.type === "sequenceItem" ? 2 : 0, [
        hardline,
        join(
          hardline,
          path.map(
            (path) => [
              isPreviousLineEmpty(
                options.originalText,
                path.getValue(),
                locStart
              )
                ? hardline
                : "",
              print(path),
            ],
            "endComments"
          )
        ),
      ])
    );
  }
  parts.push(nextEmptyLine);
}

function printNode(node, parentNode, path, options, print) {
      const { children } = node;
      path.each((childPath, index) => {
        const document = children[index];
        const nextDocument = children[index + 1];
        if (index !== 0) {
        }
        if (shouldPrintDocumentEndMarker(document, nextDocument)) {
          parts.push(hardline, "...");
          if (hasTrailingComment(document)) {
            parts.push(" ", path.call(print, "trailingComment"));
          }
        } else if (nextDocument && !hasTrailingComment(nextDocument.head)) {
          parts.push(hardline, "---");
        }
      }, "children");

      const lastDescendantNode = getLastDescendantNode(node);
      if (
        !isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) ||
        lastDescendantNode.chomping !== "keep"
      ) {
      }
    }
    case "document": {
      const nextDocument = parentNode.children[path.getName() + 1];
      if (
        shouldPrintDocumentHeadEndMarker(
          node,
          nextDocument,
          parentNode,
          options
        ) === "head"
      ) {
        if (node.head.children.length > 0 || node.head.endComments.length > 0) {
          parts.push(path.call(print, "head"));
        }

        if (hasTrailingComment(node.head)) {
          parts.push(["---", " ", path.call(print, "head", "trailingComment")]);
        } else {
          parts.push("---");
        }
      }

      if (shouldPrintDocumentBody(node)) {
      }

      return join(hardline, parts);
    }
    case "documentHead":
      return join(hardline, [
        ...path.map(print, "endComments"),
      ]);
    case "documentBody": {
      const { children, endComments } = node;
      /** @type {Doc} */
      let separator = "";
      if (children.length > 0 && endComments.length > 0) {
        const lastDescendantNode = getLastDescendantNode(node);
        // there's already a newline printed at the end of blockValue (chomping=keep, lastDescendant=true)
        if (isNode(lastDescendantNode, ["blockFolded", "blockLiteral"])) {
          // an extra newline for better readability
          if (lastDescendantNode.chomping !== "keep") {
            separator = [hardline, hardline];
          }
        } else {
          separator = hardline;
        }
      }

      return [
        join(hardline, path.map(print, "children")),
        separator,
        join(hardline, path.map(print, "endComments")),
      ];
    }
      return ["%", join(" ", [node.name, ...node.parameters])];
      return ["*", node.value];
      );
      return ["&", node.value];
      return printFlowScalarContent(
        node.type,
        ),
        options
      );
    case "quoteSingle": {
      const singleQuote = "'";
      const doubleQuote = '"';

      const raw = options.originalText.slice(
        node.position.start.offset + 1,
        node.position.end.offset - 1
      );

      if (
        (node.type === "quoteSingle" && raw.includes("\\")) ||
        (node.type === "quoteDouble" && /\\[^"]/.test(raw))
      ) {
        // only quoteDouble can use escape chars
        // and quoteSingle do not need to escape backslashes
        const originalQuote =
          node.type === "quoteDouble" ? doubleQuote : singleQuote;
        return [
          originalQuote,
          printFlowScalarContent(node.type, raw, options),
        ];
      }

      if (raw.includes(doubleQuote)) {
        return [
          singleQuote,
          printFlowScalarContent(
            node.type,
            node.type === "quoteDouble"
              ? raw
                  // double quote needs to be escaped by backslash in quoteDouble
                  .replace(/\\"/g, doubleQuote)
                  .replace(/'/g, singleQuote.repeat(2))
              : raw,
            options
          ),
        ];
      }

      if (raw.includes(singleQuote)) {
        return [
          doubleQuote,
            node.type === "quoteSingle"
              ? // single quote needs to be escaped by 2 single quotes in quoteSingle
                raw.replace(/''/g, singleQuote)
              : raw,
            options
          ),
        ];
      }

      const quote = options.singleQuote ? singleQuote : doubleQuote;
      return [quote, printFlowScalarContent(node.type, raw, options), quote];
    }
    case "blockFolded":
    case "blockLiteral": {
      return printBlock(path, print, options);
    }
    case "sequence":
      return join(hardline, path.map(print, "children"));
    case "sequenceItem":
      return [
        "- ",
        alignWithSpaces(2, !node.content ? "" : path.call(print, "content")),
      ];
    case "mappingKey":
      return !node.content ? "" : path.call(print, "content");
    case "mappingValue":
    case "mapping":
    case "mappingItem":
    case "flowMappingItem": {
      return printMappingItem(node, parentNode, path, print, options);
    }
      return printFlowMapping(path, print, options);
      return printFlowSequence(path, print, options);
    case "flowSequenceItem":
      return path.call(print, "content");
    default:
  }
}

function shouldPrintDocumentBody(document) {
  return document.body.children.length > 0 || hasEndComments(document.body);
}

function shouldPrintDocumentEndMarker(document, nextDocument) {
  return (
    /**
     *... # trailingComment
     */
    hasTrailingComment(document) ||
    (nextDocument &&
      /**
       * ...
       * %DIRECTIVE
       * ---
       */
      (nextDocument.head.children.length > 0 ||
        /**
         * ...
         * # endComment
         * ---
         */
        hasEndComments(nextDocument.head)))
  );
}

function shouldPrintDocumentHeadEndMarker(
  document,
  nextDocument,
  root,
  options
) {
  if (
    /**
     * ---
     * preserve the first document head end marker
     */
    (root.children[0] === document &&
      /---(\s|$)/.test(
        options.originalText.slice(locStart(document), locStart(document) + 4)
      )) ||
    /**
     * %DIRECTIVE
     * ---
     */
    document.head.children.length > 0 ||
    /**
     * # end comment
     * ---
     */
    hasEndComments(document.head) ||
    /**
     * --- # trailing comment
     */
    hasTrailingComment(document.head)
  ) {
    return "head";
  }

  if (shouldPrintDocumentEndMarker(document, nextDocument)) {
  }

  return nextDocument ? "root" : false;
}

function printFlowScalarContent(nodeType, content, options) {
  const lineContents = getFlowScalarLineContents(nodeType, content, options);
    hardline,
    lineContents.map((lineContentWords) =>
      fill(getDocParts(join(line, lineContentWords)))
    )
  );
}

function clean(node, newNode /*, parent */) {
  if (isNode(newNode)) {
    delete newNode.position;
    switch (newNode.type) {
      case "comment":
        // insert pragma
        if (isPragma(newNode.value)) {
          return null;
        }
        break;
      case "quoteDouble":
      case "quoteSingle":
        newNode.type = "quote";
        break;
    }
  }
}

function preprocess(ast) {
  return mapNode(ast, defineShortcuts);
}

function defineShortcuts(node) {
    case "document":
      defineShortcut(node, "head", () => node.children[0]);
      defineShortcut(node, "body", () => node.children[1]);
      break;
    case "documentBody":
      defineShortcut(node, "content", () => node.children[0]);
      break;
    case "flowMappingItem":
      defineShortcut(node, "key", () => node.children[0]);
      defineShortcut(node, "value", () => node.children[1]);
      break;
  }
}

function printMappingItem(node, parentNode, path, print, options) {
  const { key, value } = node;

  const isEmptyMappingKey = isEmptyNode(key);
  const isEmptyMappingValue = isEmptyNode(value);

  if (isEmptyMappingKey && isEmptyMappingValue) {
    return ": ";
  }

  const printedKey = path.call(print, "key");
  const spaceBeforeColon = needsSpaceInFrontOfMappingValue(node) ? " " : "";

  if (isEmptyMappingValue) {
    if (node.type === "flowMappingItem" && parentNode.type === "flowMapping") {
      return printedKey;
    }

    if (
      node.type === "mappingItem" &&
      isAbsolutelyPrintedAsSingleLineNode(key.content, options) &&
      !hasTrailingComment(key.content) &&
      (!parentNode.tag || parentNode.tag.value !== "tag:yaml.org,2002:set")
    ) {
      return [printedKey, spaceBeforeColon, ":"];
    }

    return ["? ", alignWithSpaces(2, printedKey)];
  }

  const printedValue = path.call(print, "value");
  if (isEmptyMappingKey) {
    return [": ", alignWithSpaces(2, printedValue)];
  }

  // force explicit Key
  if (hasLeadingComments(value) || !isInlineNode(key.content)) {
    return [
      "? ",
      alignWithSpaces(2, printedKey),
      hardline,
      join(
        "",
        path
          .map(print, "value", "leadingComments")
          .map((comment) => [comment, hardline])
      ),
      ": ",
      alignWithSpaces(2, printedValue),
    ];
  }

  // force singleline
  if (
    isSingleLineNode(key.content) &&
    !hasLeadingComments(key.content) &&
    !hasMiddleComments(key.content) &&
    !hasTrailingComment(key.content) &&
    !hasEndComments(key) &&
    !hasLeadingComments(value.content) &&
    !hasMiddleComments(value.content) &&
    !hasEndComments(value) &&
    isAbsolutelyPrintedAsSingleLineNode(value.content, options)
  ) {
    return [printedKey, spaceBeforeColon, ": ", printedValue];
  }

  const groupId = Symbol("mappingKey");
  const groupedKey = group([
    ifBreak("? "),
    group(alignWithSpaces(2, printedKey), { id: groupId }),
  ]);
  const breakValue = [hardline, ": ", alignWithSpaces(2, printedValue)];
  const flatValueParts = [spaceBeforeColon, ":"];
  if (
    hasLeadingComments(value.content) ||
    (hasEndComments(value) &&
      value.content &&
      !isNode(value.content, ["mapping", "sequence"])) ||
    (parentNode.type === "mapping" &&
      hasTrailingComment(key.content) &&
      isInlineNode(value.content)) ||
    (isNode(value.content, ["mapping", "sequence"]) &&
      value.content.tag === null &&
      value.content.anchor === null)
  ) {
    flatValueParts.push(hardline);
  } else if (value.content) {
    flatValueParts.push(line);
  }
  flatValueParts.push(printedValue);
  const flatValue = alignWithSpaces(options.tabWidth, flatValueParts);

    [groupedKey, ifBreak(breakValue, flatValue, { groupId })],
  ]);
}

function isAbsolutelyPrintedAsSingleLineNode(node, options) {
  }

      break;
    default:
  }

    return node.position.start.line === node.position.end.line;
  }

  if (
    // backslash-newline
    /\\$/m.test(
      )
    )
  ) {
  }

  switch (options.proseWrap) {
    case "never":
      return !node.value.includes("\n");
    case "always":
      return !/[\n ]/.test(node.value);
    default:
  }
}

function needsSpaceInFrontOfMappingValue(node) {
  return node.key.content && node.key.content.type === "alias";
}

function isSingleLineNode(node) {
  }

      return node.position.start.line === node.position.end.line;
    default:
  }
}

function printBlock(path, print, options) {
  const parentIndent = getAncestorCount(path, (ancestorNode) =>
    isNode(ancestorNode, ["sequence", "mapping"])
  );
  const isLastDescendant = isLastDescendantNode(path);
  const parts = [node.type === "blockFolded" ? ">" : "|"];
  if (node.indent !== null) {
    parts.push(node.indent.toString());
  }

  if (node.chomping !== "clip") {
    parts.push(node.chomping === "keep" ? "+" : "-");
  }

  if (hasIndicatorComment(node)) {
    parts.push(" ", path.call(print, "indicatorComment"));
  }

  const lineContents = getBlockValueLineContents(node, {
    parentIndent,
    isLastDescendant,
    options,
  });
  const contentsParts = [];
  for (const [index, lineWords] of lineContents.entries()) {
    if (index === 0) {
      contentsParts.push(hardline);
    }
    contentsParts.push(fill(getDocParts(join(line, lineWords))));
    if (index !== lineContents.length - 1) {
      contentsParts.push(
        lineWords.length === 0 ? hardline : markAsRoot(literalline)
      );
    } else if (node.chomping === "keep" && isLastDescendant) {
        dedentToRoot(lineWords.length === 0 ? hardline : literalline)
      );
    }
  }
  if (node.indent === null) {
    parts.push(dedent(alignWithSpaces(options.tabWidth, contentsParts)));
  } else {
      dedentToRoot(
        alignWithSpaces(node.indent - 1 + parentIndent, contentsParts)
      )
    );
  }

}

function printFlowMapping(path, print, options) {
  const isMapping = node.type === "flowMapping";
  const openMarker = isMapping ? "{" : "[";
  const closeMarker = isMapping ? "}" : "]";

  /** @type {softline | line} */
  let bracketSpacing = softline;
  if (isMapping && node.children.length > 0 && options.bracketSpacing) {
    bracketSpacing = line;
  }
  const lastItem = getLast(node.children);
  const isLastItemEmptyMappingItem =
    lastItem &&
    lastItem.type === "flowMappingItem" &&
    isEmptyNode(lastItem.key) &&
    isEmptyNode(lastItem.value);

  return [
    openMarker,
    alignWithSpaces(options.tabWidth, [
      bracketSpacing,
      printChildren(path, print, options),
      options.trailingComma === "none" ? "" : ifBreak(","),
      hasEndComments(node)
        ? [hardline, join(hardline, path.map(print, "endComments"))]
        : "",
    ]),
    isLastItemEmptyMappingItem ? "" : bracketSpacing,
    closeMarker,
  ];
}

function printChildren(path, print, options) {
  const parts = path.map(
    (childPath, index) => [
      print(childPath),
      index === node.children.length - 1
        ? ""
        : [
            ",",
            line,
            node.children[index].position.start.line !==
            node.children[index + 1].position.start.line
              ? printNextEmptyLine(childPath, options.originalText)
              : "",
          ],
    ],
  );
}

function printNextEmptyLine(path, originalText) {
  const root = path.stack[0];

  let isNextEmptyLinePrintedSet;
  if (printedEmptyLineCache.has(root)) {
    isNextEmptyLinePrintedSet = printedEmptyLineCache.get(root);
  } else {
    isNextEmptyLinePrintedSet = new Set();
    printedEmptyLineCache.set(root, isNextEmptyLinePrintedSet);
  }

  if (!isNextEmptyLinePrintedSet.has(node.position.end.line)) {
    isNextEmptyLinePrintedSet.add(node.position.end.line);
    if (
      isNextLineEmpty(node, originalText) &&
      !shouldPrintEndComments(path.getParentNode())
    ) {
      return softline;
    }
  }

  return "";
}

function shouldPrintEndComments(node) {
  return (
    hasEndComments(node) &&
    !isNode(node, [
      "documentHead",
      "documentBody",
      "flowMapping",
      "flowSequence",
    ])
  );
}

function alignWithSpaces(n, doc) {
  return align(" ".repeat(n), doc);
}

  }

  }

  }

  }
  if (
    ast.expression.type === "Literal" &&
  ) {
  }

  for (const key in ast) {
    if (typeof ast[key] !== "function") {
      newObj[key] = massageAST(ast[key], ast);
    }
  }

  [
    "loc",
    "range",
    "raw",
    "comments",
    "contentStart",
    "contentEnd",
    "leadingComments",
    "trailingComments",
    "extra",
    "start",
    "end",
    "tokens",
    "flags",
    "raws",
    "sourceIndex",
    "id",
    "source",
    "before",
    "after",
    "trailingComma",
    "parent",
    "prev",
    "position"
  ].forEach(name => {
    delete newObj[name];
  });

  // for markdown codeblock
  if (ast.type === "code") {
  }
  // for markdown whitespace: "\n" and " " are considered the same
  if (ast.type === "whitespace" && ast.value === "\n") {
    newObj.value = " ";
  }

  if (
  ) {
  }

  }

  }

  }

  // (Glimmer/HTML) ignore TextNode whitespace
    if (ast.chars.replace(/\s+/, "") === "") {
    }
    newObj.chars = ast.chars.replace(/^\s+/, "").replace(/\s+$/, "");
  }

  if (
    (ast.type === "value-word" && ast.isColor && ast.isHex) ||
  ) {
  }
  }
  }
  }

  if (
  ) {
  }

  if (ast.type === "css-import" && newObj.importPath) {
    newObj.importPath = cleanCSSStrings(newObj.importPath);
  }

  if (ast.type === "selector-attribute" && newObj.value) {
    newObj.value = newObj.value.replace(/^['"]|['"]$/g, "");
    delete newObj.quoted;
  }

  if (
  ) {
      /([\d.eE+-]+)([a-zA-Z]*)/g,
        return isNaN(num) ? match : num + unit.toLowerCase();
      }
    );
  }

  // (TypeScript) Ignore `static` in `constructor(static p) {}`
  // and `export` in `constructor(export p) {}`
  if (
    ast.type === "TSParameterProperty" &&
    ast.accessibility === null &&
    !ast.readonly
  ) {
    return {
      type: "Identifier",
      name: ast.parameter.name,
      typeAnnotation: newObj.parameter.typeAnnotation,
      decorators: newObj.decorators
    };
  }

  // (TypeScript) ignore empty `specifiers` array
  if (
    ast.type === "TSNamespaceExportDeclaration" &&
    ast.specifiers &&
    ast.specifiers.length === 0
  ) {
    delete newObj.specifiers;
  }

  // (TypeScript) bypass TSParenthesizedType
  if (
    ast.type === "TSParenthesizedType" &&
    ast.typeAnnotation.type === "TSTypeAnnotation"
  ) {
    return newObj.typeAnnotation.typeAnnotation;
  }

  // We convert <div></div> to <div />
  if (ast.type === "JSXOpeningElement") {
    delete newObj.selfClosing;
  }
  if (ast.type === "JSXElement") {
    delete newObj.closingElement;
  }

  // We change {'key': value} into {key: value}
  if (
    ast.key &&
    (ast.key.type === "Literal" || ast.key.type === "Identifier")
  ) {
  }

  if (
    ast.openingElement.attributes.some(attr => attr.name.name === "jsx")
  ) {
    const templateLiterals = newObj.children
      .filter(
        child =>
          child.type === "JSXExpressionContainer" &&
          child.expression.type === "TemplateLiteral"
      )
      .map(container => container.expression);

    const quasis = templateLiterals.reduce(
      (quasis, templateLiteral) => quasis.concat(templateLiteral.quasis),
      []
    );

    quasis.forEach(q => delete q.value);
  }

  if (
  ) {
    newObj.value.expression.quasis.forEach(q => delete q.value);
  }

  if (
          ast.tag.name === "markdown")) ||
  ) {
    newObj.quasi.quasis.forEach(quasi => delete quasi.value);
  }
  if (
    ast.type === "TemplateLiteral" &&
    parent.type === "CallExpression" &&
    parent.callee.name === "graphql"
  ) {
    newObj.quasis.forEach(quasi => delete quasi.value);
  }

}

function getName() {
  const s = this.stack;
  const len = s.length;
  if (len > 1) {
    return s[len - 2];
  }
  // Since the name is always a string, null is a safe sentinel value to
  // return if we do not know the name of the (root) value.
}

function getValue() {
  return s[s.length - 1];
}

  const s = path.stack;

  for (let i = s.length - 1; i >= 0; i -= 2) {
    const value = s[i];

    if (value && !Array.isArray(value) && --count < 0) {
    }
  }

}

function getNode(count) {
  return getNodeHelper(this, ~~count);
}

function getParentNode(count) {
  return getNodeHelper(this, ~~count + 1);
}

function call(callback /*, name1, name2, ... */) {
  const origLen = s.length;
  let value = s[origLen - 1];
  const argc = arguments.length;
  for (let i = 1; i < argc; ++i) {
    const name = arguments[i];
    value = value[name];
    s.push(name, value);
  }
  const result = callback(this);
  s.length = origLen;
}

function each(callback /*, name1, name2, ... */) {

  }

  for (let i = 0; i < value.length; ++i) {
    if (i in value) {
      s.push(i, value[i]);
      // If the callback needs to know the value of i, call
      // path.getName(), assuming path is the parameter name.
      callback(this);
      s.length -= 2;
    }
  }

}

function map(callback /*, name1, name2, ... */) {

  }

  const result = new Array(value.length);

      result[i] = callback(this, i);
    }
  }

}

function(options) {
  const parent = this.getParentNode();
  }

  const name = this.getName();
  const node = this.getNode();

  // If the value of this path is some child of a Node and not a Node
  // itself, then it doesn't need parentheses. Only Node objects (in
  // fact, only Expression nodes) need parentheses.
  if (this.getValue() !== node) {
  }

  }

  // Closure compiler requires that type casted expressions to be surrounded by
  if (util.hasClosureCompilerTypeCastComment(options.originalText, node)) {
  }

  }

  if (parent.type === "ParenthesizedExpression") {
  }

  // Add parens around the extends clause of a class. It is needed for almost
  // all expressions.
  if (
    (parent.type === "ClassDeclaration" || parent.type === "ClassExpression") &&
    parent.superClass === node &&
    (node.type === "ArrowFunctionExpression" ||
      node.type === "AssignmentExpression" ||
      node.type === "AwaitExpression" ||
      node.type === "BinaryExpression" ||
      node.type === "ConditionalExpression" ||
      node.type === "LogicalExpression" ||
      node.type === "NewExpression" ||
      node.type === "ObjectExpression" ||
      node.type === "ParenthesizedExpression" ||
      node.type === "SequenceExpression" ||
      node.type === "TaggedTemplateExpression" ||
      node.type === "UnaryExpression" ||
      node.type === "UpdateExpression" ||
      node.type === "YieldExpression")
  ) {
  }

  if (
    (parent.type === "ArrowFunctionExpression" &&
    parent.body === node &&
    node.type !== "SequenceExpression" && // these have parens added anyway
      startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ false)) ||
    (parent.type === "ExpressionStatement" &&
      startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ true))
  ) {
  }

    case "CallExpression": {
      let firstParentNotMemberExpression = parent;
      let i = 0;
      while (
        firstParentNotMemberExpression &&
        firstParentNotMemberExpression.type === "MemberExpression"
      ) {
        firstParentNotMemberExpression = this.getParentNode(++i);
      }

      if (
        firstParentNotMemberExpression.type === "NewExpression" &&
        firstParentNotMemberExpression.callee === this.getParentNode(i - 1)
      ) {
      }
    }

      return (
        parent.object === node
      );

        return (
        );
      }
          return (
          );

          return name === "object" && parent.object === node;

          return name === "callee" && parent.callee === node;

          return parent.operator === "**" && name === "left";

        default:
      }

      if (parent.type === "UpdateExpression") {
      }

      const isLeftOfAForStatement = node => {
        let i = 0;
        while (node) {
          const parent = this.getParentNode(i++);
          if (!parent) {
          }
          if (parent.type === "ForStatement" && parent.init === node) {
          }
          node = parent;
        }
      };
      if (node.operator === "in" && isLeftOfAForStatement(node)) {
      }
    }
    case "TSTypeAssertionExpression":

        case "TSAbstractClassDeclaration":
          return name === "superClass" && parent.superClass === node;
        case "TSTypeAssertionExpression":
        case "ExperimentalSpreadProperty":

          return (
            parent.left === node &&
            (node.type === "TSTypeAssertionExpression" ||
              node.type === "TSAsExpression")
          );
        case "Decorator":
          return (
            parent.expression === node &&
          );

        case "LogicalExpression": {
          if (!node.operator && node.type !== "TSTypeAssertionExpression") {
          }

          const po = parent.operator;
          const pp = util.getPrecedence(po);
          const no = node.operator;
          const np = util.getPrecedence(no);

          if (pp > np) {
          }

          if ((po === "||" || po === "??") && no === "&&") {
          }

          if (pp === np && name === "right") {
            assert.strictEqual(parent.right, node);
          }

          if (pp === np && !util.shouldFlatten(po, no)) {
          }

          // Add parenthesis when working with binary operators
          // It's not stricly needed but helps with code understanding
          if (util.isBitwiseOperator(po)) {
          }

        }

        default:
      }

    case "TSParenthesizedType": {
      const grandParent = this.getParentNode(1);
      if (
        (parent.type === "TSTypeParameter" ||
          parent.type === "TypeParameter" ||
          parent.type === "VariableDeclarator" ||
          parent.type === "TSTypeAnnotation" ||
          parent.type === "GenericTypeAnnotation" ||
          parent.type === "TSTypeReference") &&
        (node.typeAnnotation.type === "TSTypeAnnotation" &&
          node.typeAnnotation.typeAnnotation.type !== "TSFunctionType" &&
          grandParent.type !== "TSTypeOperator")
      ) {
      }
      // Delegate to inner TSParenthesizedType
      if (node.typeAnnotation.type === "TSParenthesizedType") {
      }
    }

        default:
      }

      if (
      ) {
      }

          return parent.object === node;

          return parent.callee === node;

          return parent.test === node;

        default:
      }

      return (
      );

      return (
        parent.type === "UnionTypeAnnotation" ||
        parent.type === "ArrayTypeAnnotation"
      );

      if (
        // TypeScript workaround for eslint/typescript-eslint-parser#267
        // See corresponding workaround in printer.js case: "Literal"
        ((options.parser !== "typescript" && !parent.directive) ||
          (options.parser === "typescript" &&
            options.originalText.substr(util.locStart(node) - 1, 1) === "("))
      ) {
        const grandParent = this.getParentNode(1);

        return (
        );
      }

      return (
        typeof node.value === "number" &&
      );

      if (parent.type === "ArrowFunctionExpression" && parent.body === node) {
      } else if (
        parent.type === "ClassProperty" &&
        parent.key === node &&
      ) {
      } else if (
        parent.type === "TSPropertySignature" &&
        parent.name === node
      ) {
      } else if (
        parent.type === "ForStatement" &&
        (parent.init === node || parent.update === node)
      ) {
      } else if (parent.type === "ExpressionStatement") {
      } else if (parent.type === "TSPropertySignature" && parent.key === node) {
      } else if (parent.type === "AssignmentExpression") {
      } else if (
      ) {
      }
    }

          return name === "test" && parent.test === node;

        default:
      }

          return name === "callee"; // Not strictly necessary, but it's clearer to the reader if IIFEs are wrapped in parentheses.
        default:
      }

        default:
      }

      return parent.type === "ExportDefaultDeclaration";
  }

}

  return (
    node.type === "ForAwaitStatement" ||
    node.type === "TSAbstractClassDeclaration" ||
  );
}

  const stackIndex = getNodeStackIndexHelper(path.stack, count);
  return stackIndex === -1 ? null : path.stack[stackIndex];
}

function getNodeStackIndexHelper(stack, count) {
  for (let i = stack.length - 1; i >= 0; i -= 2) {
    const value = stack[i];
      return i;
    }
  }
  return -1;
}

class AstPath {
  constructor(value) {
    this.stack = [value];
  }

  // The name of the current property is always the penultimate element of
  // this.stack, and always a String.
  getName() {
    const { stack } = this;
    const { length } = stack;
    if (length > 1) {
      return stack[length - 2];
    }
    // Since the name is always a string, null is a safe sentinel value to
    // return if we do not know the name of the (root) value.
  }

  // The value of the current property is always the final element of
  // this.stack.
  getValue() {
    return getLast(this.stack);
  }

  getNode(count = 0) {
    return getNodeHelper(this, count);
  }

  getParentNode(count = 0) {
    return getNodeHelper(this, count + 1);
  }

  // Temporarily push properties named by string arguments given after the
  // callback function onto this.stack, then call the callback with a
  // reference to this (modified) AstPath object. Note that the stack will
  // be restored to its original state after the callback is finished, so it
  // is probably a mistake to retain a reference to the path.
  call(callback, ...names) {
    let value = getLast(stack);

    for (const name of names) {
      value = value[name];
      stack.push(name, value);
    }
    const result = callback(this);
    stack.length = length;
    return result;
  }

  callParent(callback, count = 0) {
    const stackIndex = getNodeStackIndexHelper(this.stack, count + 1);
    const parentValues = this.stack.splice(stackIndex + 1);
    this.stack.push(...parentValues);
  }

  // Similar to AstPath.prototype.call, except that the value obtained by
  // accessing this.getValue()[name1][name2]... should be array. The
  // callback will be called with a reference to this path object for each
  // element of the array.
  each(callback, ...names) {

    }

    for (let i = 0; i < value.length; ++i) {
      stack.push(i, value[i]);
      callback(this, i, value);
      stack.length -= 2;
    }

  }

  // Similar to AstPath.prototype.each, except that the results of the
  // callback function invocations are stored in an array and returned at
  // the end of the iteration.
  map(callback, ...names) {
    const result = [];
    this.each((path, index, value) => {
      result[index] = callback(path, index, value);
    }, ...names);
  }

  /**
   * @param {...(
   *   | ((node: any, name: string | null, number: number | null) => boolean)
   *   | undefined
   * )} predicates
   */
  match(...predicates) {
    let stackPointer = this.stack.length - 1;

    let name = null;
    let node = this.stack[stackPointer--];

    for (const predicate of predicates) {
      if (node === undefined) {
      }

      // skip index/array
      let number = null;
      if (typeof name === "number") {
        number = name;
        name = this.stack[stackPointer--];
        node = this.stack[stackPointer--];
      }

      if (predicate && !predicate(node, name, number)) {
      }

      name = this.stack[stackPointer--];
      node = this.stack[stackPointer--];
    }

  }
}

getName() {
    }
  }

getParentNode(count = 0) {
  }

call(callback, ...names) {

    }
  }

callParent(callback, count = 0) {
  }

each(callback, ...names) {

    }

    }

  }

map(callback, ...names) {
  }

match(...predicates) {

      }

      }

      }

    }

  }

async function getFileInfo(filePath, opts) {
  if (typeof filePath !== "string") {
    throw new TypeError(
      `expect \`filePath\` to be a string, got \`${typeof filePath}\``
    );
  }

  const ignorer = await createIgnorer(opts.ignorePath, opts.withNodeModules);
  return _getFileInfo({
    ignorer,
    filePath,
    plugins: opts.plugins,
    resolveConfig: opts.resolveConfig,
    ignorePath: opts.ignorePath,
    sync: false,
  });
}

function getFileParser(resolvedConfig, filePath, plugins) {
  if (resolvedConfig && resolvedConfig.parser) {
    return resolvedConfig.parser;
  }

  const inferredParser = options.inferParser(filePath, plugins);

  if (inferredParser) {
    return inferredParser;
  }

}

function _getFileInfo({
  ignorer,
  filePath,
  plugins,
  resolveConfig = false,
  ignorePath,
  sync = false,
}) {
  const normalizedFilePath = normalizeFilePath(filePath, ignorePath);

  const fileInfo = {
    ignored: ignorer.ignores(normalizedFilePath),
    inferredParser: null,
  };

  if (fileInfo.ignored) {
    return fileInfo;
  }

  let resolvedConfig;

  if (resolveConfig) {
    if (sync) {
      resolvedConfig = config.resolveConfig.sync(filePath);
    } else {
      return config.resolveConfig(filePath).then((resolvedConfig) => {
        fileInfo.inferredParser = getFileParser(
          resolvedConfig,
          filePath,
          plugins
        );
        return fileInfo;
      });
    }
  }

  fileInfo.inferredParser = getFileParser(resolvedConfig, filePath, plugins);
  return fileInfo;
}

function normalizeFilePath(filePath, ignorePath) {
  return ignorePath
    ? path.relative(path.dirname(ignorePath), filePath)
    : filePath;
}

async function createIgnorer(ignorePath, withNodeModules) {
  const ignoreContent = ignorePath
    ? await getFileContentOrNull(path.resolve(ignorePath))
    : null;

  return _createIgnorer(ignoreContent, withNodeModules);
}

function _createIgnorer(ignoreContent, withNodeModules) {
  const ignorer = ignore().add(ignoreContent || "");
  if (!withNodeModules) {
    ignorer.add("node_modules");
  }
  return ignorer;
}

function skip(chars) {
  return (text, index, opts) => {
    const backwards = opts && opts.backwards;

    // Allow `skip` functions to be threaded together without having
    // to check for failures (did someone say monads?).
    if (index === false) {
    }

    const { length } = text;
    let cursor = index;
    while (cursor >= 0 && cursor < length) {
      const c = text.charAt(cursor);
      if (chars instanceof RegExp) {
        if (!chars.test(c)) {
          return cursor;
        }
      } else if (!chars.includes(c)) {
        return cursor;
      }

      backwards ? cursor-- : cursor++;
    }

    if (cursor === -1 || cursor === length) {
      // If we reached the beginning or end of the file, return the
      // out-of-bounds cursor. It's up to the caller to handle this
      // correctly. We don't want to indicate `false` though if it
      // actually skipped valid characters.
    }
  };
}

function skipInlineComment(text, index) {
  if (index === false) {
  }

  if (text.charAt(index) === "/" && text.charAt(index + 1) === "*") {
    for (let i = index + 2; i < text.length; ++i) {
      if (text.charAt(i) === "*" && text.charAt(i + 1) === "/") {
        return i + 2;
      }
    }
  }
}

function skipTrailingComment(text, index) {
  }

  if (text.charAt(index) === "/" && text.charAt(index + 1) === "/") {
    return skipEverythingButNewLine(text, index);
  }
}

function skipNewline(text, index, opts) {
  const backwards = opts && opts.backwards;
  }

  const atIndex = text.charAt(index);
  if (backwards) {
    // We already replace `\r\n` with `\n` before parsing
    if (text.charAt(index - 1) === "\r" && atIndex === "\n") {
      return index - 2;
    }
    if (
      atIndex === "\n" ||
      atIndex === "\r" ||
      atIndex === "\u2028" ||
      atIndex === "\u2029"
    ) {
      return index - 1;
    }
  } else {
    if (atIndex === "\r" && text.charAt(index + 1) === "\n") {
      return index + 2;
    }
    if (
    ) {
      return index + 1;
    }
  }

}

function hasNewline(text, index, opts = {}) {
  const idx = skipSpaces(text, opts.backwards ? index - 1 : index, opts);
  const idx2 = skipNewline(text, idx, opts);
  return idx !== idx2;
}

function hasNewlineInRange(text, start, end) {
  for (let i = start; i < end; ++i) {
    if (text.charAt(i) === "\n") {
    }
  }
}

function isPreviousLineEmpty(text, node, locStart) {
  /** @type {number | false} */
  let idx = locStart(node) - 1;
  idx = skipSpaces(text, idx, { backwards: true });
  idx = skipNewline(text, idx, { backwards: true });
  const idx2 = skipNewline(text, idx, { backwards: true });
}

function isNextLineEmptyAfterIndex(text, index) {
  let oldIdx = null;
  let idx = index;
  while (idx !== oldIdx) {
    // We need to skip all the potential trailing inline comments
    oldIdx = idx;
    idx = skipToLineEnd(text, idx);
    idx = skipInlineComment(text, idx);
    idx = skipSpaces(text, idx);
  }
  idx = skipTrailingComment(text, idx);
  idx = skipNewline(text, idx);
  return idx !== false && hasNewline(text, idx);
}

function isNextLineEmpty(text, node, locEnd) {
  return isNextLineEmptyAfterIndex(text, locEnd(node));
}

function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(text, idx) {
  let nextIdx = idx;
  while (nextIdx !== oldIdx) {
    oldIdx = nextIdx;
    nextIdx = skipSpaces(text, nextIdx);
    nextIdx = skipInlineComment(text, nextIdx);
    nextIdx = skipTrailingComment(text, nextIdx);
    nextIdx = skipNewline(text, nextIdx);
  }
  return nextIdx;
}

function getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd) {
  return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
    text,
    locEnd(node)
  );
}

function getNextNonSpaceNonCommentCharacter(text, node, locEnd) {
  return text.charAt(
    // @ts-ignore => TBD: can return false, should we define a fallback?
    getNextNonSpaceNonCommentCharacterIndex(text, node, locEnd)
  );
}

function hasSpaces(text, index, opts = {}) {
  return idx !== index;
}

function getAlignmentSize(value, tabWidth, startIndex = 0) {
  let size = 0;
  for (let i = startIndex; i < value.length; ++i) {
    if (value[i] === "\t") {
      // Tabs behave in a way that they are aligned to the nearest
      // multiple of tabWidth:
      // 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
      // 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
      size = size + tabWidth - (size % tabWidth);
    } else {
      size++;
    }
  }

  return size;
}

function getIndentSize(value, tabWidth) {
  const lastNewlineIndex = value.lastIndexOf("\n");
  if (lastNewlineIndex === -1) {
    return 0;
  }

  return getAlignmentSize(
    // All the leading whitespaces
    value.slice(lastNewlineIndex + 1).match(/^[\t ]*/)[0],
    tabWidth
  );
}

function getPreferredQuote(raw, preferredQuote) {
  // `rawContent` is the string exactly like it appeared in the input source
  // code, without its enclosing quotes.
  const rawContent = raw.slice(1, -1);

  /** @type {{ quote: '"', regex: RegExp }} */
  /** @type {{ quote: "'", regex: RegExp }} */

  const preferred = preferredQuote === "'" ? single : double;

  let result = preferred.quote;

  // If `rawContent` contains at least one of the quote preferred for enclosing
  // the string, we might want to enclose with the alternate quote instead, to
  // minimize the number of escaped quotes.
  if (
    rawContent.includes(preferred.quote) ||
    rawContent.includes(alternate.quote)
  ) {
    const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
    const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;

    result =
      numPreferredQuotes > numAlternateQuotes
        ? alternate.quote
        : preferred.quote;
  }

}

function printString(raw, options, isDirectiveLiteral) {

  // Check for the alternate quote, to determine if we're allowed to swap
  // the quotes on a DirectiveLiteral.
  const canChangeDirectiveQuotes =
    !rawContent.includes('"') && !rawContent.includes("'");

  /** @type {Quote} */
  const enclosingQuote =
    options.parser === "json"
      ? '"'
      : options.__isInHtmlAttribute
      ? "'"
      : getPreferredQuote(raw, options.singleQuote ? "'" : '"');

  // Directives are exact code unit sequences, which means that you can't
  // change the escape sequences they use.
  // See https://github.com/prettier/prettier/issues/1555
  // and https://tc39.github.io/ecma262/#directive-prologue
  if (isDirectiveLiteral) {
    if (canChangeDirectiveQuotes) {
      return enclosingQuote + rawContent + enclosingQuote;
    }
    return raw;
  }

  // It might sound unnecessary to use `makeString` even if the string already
  // is enclosed with `enclosingQuote`, but it isn't. The string could contain
  // unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
  // sure that we consistently output the minimum amount of escaped quotes.
  return makeString(
    rawContent,
    enclosingQuote,
    !(
      options.parser === "css" ||
      options.parser === "less" ||
      options.parser === "scss" ||
      options.__embeddedInHtml
    )
  );
}

function makeString(rawContent, enclosingQuote, unescapeUnnecessaryEscapes) {
  const otherQuote = enclosingQuote === '"' ? "'" : '"';

  // Matches _any_ escape and unescaped quotes (both single and double).
  const regex = /\\([\S\s])|(["'])/g;

  // Escape and unescape single and double quotes as needed to be able to
  // enclose `rawContent` with `enclosingQuote`.
  const newContent = rawContent.replace(regex, (match, escaped, quote) => {
    // If we matched an escape, and the escaped character is a quote of the
    // other type than we intend to enclose the string with, there's no need for
    // it to be escaped, so return it _without_ the backslash.
    if (escaped === otherQuote) {
      return escaped;
    }

    // If we matched an unescaped quote and it is of the _same_ type as we
    // intend to enclose the string with, it must be escaped, so return it with
    // a backslash.
    if (quote === enclosingQuote) {
      return "\\" + quote;
    }

    if (quote) {
      return quote;
    }

    // Unescape any unnecessarily escaped character.
    // Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27
    return unescapeUnnecessaryEscapes &&
      /^[^\n\r"'0-7\\bfnrt-vx\u2028\u2029]$/.test(escaped)
      ? escaped
      : "\\" + escaped;
  });

  return enclosingQuote + newContent + enclosingQuote;
}

  return (
    rawNumber
      .toLowerCase()
      // Remove unnecessary plus and zeroes from scientific notation.
      .replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(\d)/, "$1$2$3")
      // Remove unnecessary scientific notation (1e0).
      .replace(/^([+-]?[\d.]+)e[+-]?0+$/, "$1")
      // Make sure numbers always start with a digit.
      .replace(/^([+-])?\./, "$10.")
      // Remove extraneous trailing decimal zeroes.
      .replace(/(\.\d+?)0+(?=e|$)/, "$1")
      // Remove trailing dot.
      .replace(/\.(?=e|$)/, "")
  );
}

function getMaxContinuousCount(str, target) {
  const results = str.match(
    new RegExp(`(${escapeStringRegexp(target)})+`, "g")
  );

  if (results === null) {
    return 0;
  }

  return results.reduce(
    (maxCount, result) => Math.max(maxCount, result.length / target.length),
    0
  );
}

function getMinNotPresentContinuousCount(str, target) {
  const matches = str.match(
  );

  if (matches === null) {
    return 0;
  }

  const countPresent = new Map();
  let max = 0;

  for (const match of matches) {
    const count = match.length / target.length;
    countPresent.set(count, true);
    if (count > max) {
      max = count;
    }
  }

  for (let i = 1; i < max; i++) {
    if (!countPresent.get(i)) {
      return i;
    }
  }

  return max + 1;
}

function getStringWidth(text) {
  if (!text) {
    return 0;
  }

  // shortcut to avoid needless string `RegExp`s, replacements, and allocations within `string-width`
  if (!notAsciiRegex.test(text)) {
    return text.length;
  }

  return stringWidth(text);
}

  const comments = node.comments || (node.comments = []);
  comment.printed = false;
  comment.nodeDescription = describeNodeForDebugging(node);
}

function addDanglingComment(node, comment, marker) {
  if (marker) {
    comment.marker = marker;
  }
}

function replaceEndOfLineWith(text, replacement) {
  for (const part of text.split("\n")) {
      parts.push(replacement);
    }
    parts.push(part);
  }
}

function inferParserByLanguage(language, options) {
  const { languages } = getSupportInfo({ plugins: options.plugins });
  const matched =
    languages.find(({ name }) => name.toLowerCase() === language) ||
    languages.find(
      ({ aliases }) => Array.isArray(aliases) && aliases.includes(language)
    ) ||
      ({ extensions }) =>
        Array.isArray(extensions) && extensions.includes(`.${language}`)
    );
  return matched && matched.parsers[0];
}

function isFrontMatterNode(node) {
  return node && node.type === "front-matter";
}

function getShebang(text) {
    return "";
  }
    return text;
  }
  return text.slice(0, index);
}

function isNonEmptyArray(object) {
  return Array.isArray(object) && object.length > 0;
}

function createGroupIdMapper(description) {
  const groupIds = new WeakMap();
  return function (node) {
    if (!groupIds.has(node)) {
      groupIds.set(node, Symbol(description));
    }
    return groupIds.get(node);
  };
}

function describeNodeForDebugging(node) {
  const nodeType = node.type || node.kind || "(unknown type)";
  let nodeName = String(
    node.name ||
      (node.id && (typeof node.id === "object" ? node.id.name : node.id)) ||
      (node.key && (typeof node.key === "object" ? node.key.name : node.key)) ||
      (node.value &&
        (typeof node.value === "object" ? "" : String(node.value))) ||
      node.operator ||
      ""
  );
  if (nodeName.length > 20) {
    nodeName = nodeName.slice(0, 19) + "…";
  }
  return nodeType + (nodeName ? " " + nodeName : "");
}

function getSupportInfo(version, options) {
  }

  const languages = loadPlugins(options)
    .reduce((all, plugin) => all.concat(plugin.languages), [])
      // Prevent breaking changes
      if (language.name === "Markdown") {
          parsers: ["markdown"]
        });
      }
      if (language.name === "TypeScript") {
          parsers: ["typescript"]
        });
      }

        });
      }
    });

}

function guessEndOfLine(text) {
  const index = text.indexOf("\r");
  if (index >= 0) {
    return text.charAt(index + 1) === "\n" ? "crlf" : "cr";
  }
  return "lf";
}

function convertEndOfLineToChars(value) {
  switch (value) {
    case "cr":
      return "\r";
    case "crlf":
      return "\r\n";
    default:
      return "\n";
  }
}

function countEndOfLineChars(text, eol) {
  let regex;

  /* istanbul ignore else */
  if (eol === "\n") {
    regex = /\n/g;
  } else if (eol === "\r") {
    regex = /\r/g;
  } else if (eol === "\r\n") {
    regex = /\r\n/g;
  } else {
    throw new Error(`Unexpected "eol" ${JSON.stringify(eol)}.`);
  }

  const endOfLines = text.match(regex);
  return endOfLines ? endOfLines.length : 0;
}

function normalizeEndOfLine(text) {
  return text.replace(/\r\n?/g, "\n");
}

() => {
  mem.clear(memoizedLoad);
  mem.clear(memoizedSearch);
}

function load(plugins, pluginSearchDirs) {
  if (!plugins) {
    plugins = [];
  }

  if (!pluginSearchDirs) {
    pluginSearchDirs = [];
  }
  // unless pluginSearchDirs are provided, auto-load plugins from node_modules that are parent to Prettier
  if (pluginSearchDirs.length === 0) {
    const autoLoadDir = thirdParty.findParentDir(__dirname, "node_modules");
    if (autoLoadDir) {
      pluginSearchDirs = [autoLoadDir];
    }
  }

  const [externalPluginNames, externalPluginInstances] = partition(
    plugins,
    (plugin) => typeof plugin === "string"
  );

  const externalManualLoadPluginInfos = externalPluginNames.map(
    (pluginName) => {
      let requirePath;
      try {
        // try local files
        requirePath = resolve(path.resolve(process.cwd(), pluginName));
      } catch (_) {
        // try node modules
        requirePath = resolve(pluginName, { paths: [process.cwd()] });
      }

      return {
        name: pluginName,
        requirePath,
      };
    }
  );

  const externalAutoLoadPluginInfos = flatten(
    pluginSearchDirs.map((pluginSearchDir) => {
      const resolvedPluginSearchDir = path.resolve(
        process.cwd(),
        pluginSearchDir
      );

      const nodeModulesDir = path.resolve(
        resolvedPluginSearchDir,
        "node_modules"
      );

      // In some fringe cases (ex: files "mounted" as virtual directories), the
      // isDirectory(resolvedPluginSearchDir) check might be false even though
      // the node_modules actually exists.
      if (
        !isDirectory(nodeModulesDir) &&
        !isDirectory(resolvedPluginSearchDir)
      ) {
          `${pluginSearchDir} does not exist or is not a directory`
        );
      }

      return memoizedSearch(nodeModulesDir).map((pluginName) => ({
        requirePath: resolve(pluginName, { paths: [resolvedPluginSearchDir] }),
      }));
    })
  );

  const externalPlugins = [
    ...uniqBy(
      [...externalManualLoadPluginInfos, ...externalAutoLoadPluginInfos],
      "requirePath"
    ).map((externalPluginInfo) => ({
      name: externalPluginInfo.name,
      ...eval("require")(externalPluginInfo.requirePath),
    })),
    ...externalPluginInstances,
  ];

  return [...internalPlugins, ...externalPlugins];
}

function findPluginsInNodeModules(nodeModulesDir) {
  const pluginPackageJsonPaths = globby.sync(
    [
      "prettier-plugin-*/package.json",
      "@*/prettier-plugin-*/package.json",
      "@prettier/plugin-*/package.json",
    ],
    {
      cwd: nodeModulesDir,
      expandDirectories: false,
    }
  );
  return pluginPackageJsonPaths.map(path.dirname);
}

function isDirectory(dir) {
  try {
    return fs.statSync(dir).isDirectory();
  }
}

  // Construct an error similar to the ones thrown by Babel.
  );
  // @ts-ignore - TBD (...)
}

        return $$$r("../language-js/parser-babylon").parsers.babylon;
      }

        return $$$r("../language-js/parser-babylon").parsers.json;
      }

        return $$$r("../language-js/parser-babylon").parsers.json5;
      }

        return $$$r("../language-js/parser-flow").parsers.flow;
      }

        return $$$r("../language-js/parser-typescript").parsers.typescript;
      }

get css() {
        return $$$r("../language-css/parser-postcss").parsers.css;
      }

      }

      }

        return $$$r("../language-handlebars/parser-glimmer").parsers.glimmer;
      }

        return $$$r("../language-graphql/parser-graphql").parsers.graphql;
      }

        return $$$r("../language-markdown/parser-markdown").parsers.remark;
      }

      }

        return $$$r("../language-html/parser-parse5").parsers.parse5;
      }

get vue() {
        return $$$r("../language-vue/parser-vue").parsers.vue;
      }

(filename, options) => {
  const testFunction = unstableTests.get(filename);

  if (!testFunction) {
  }

  return testFunction(options);
}

  const { errors = {} } = options;
  if (errors === true) {
  }

  const files = errors[options.parser];

  if (files === true || (Array.isArray(files) && files.includes(filename))) {
  }

}

(dirname, name) =>
  (dirname + path.sep).startsWith(
    path.join(__dirname, "../tests", name) + path.sep
  )

function runSpec(fixtures, parsers, options) {
  let { dirname, snippets = [] } =
    typeof fixtures === "string" ? { dirname: fixtures } : fixtures;

  // `IS_PARSER_INFERENCE_TESTS` mean to test `inferParser` on `standalone`
  const IS_PARSER_INFERENCE_TESTS = isTestDirectory(
    dirname,
    "misc/parser-inference"
  );

  // `IS_ERROR_TESTS` mean to watch errors like:
  // - syntax parser hasn't supported yet
  // - syntax errors that should throws
  const IS_ERROR_TESTS = isTestDirectory(dirname, "misc/errors");
  if (IS_ERROR_TESTS) {
    options = { errors: true, ...options };
  }

  if (IS_PARSER_INFERENCE_TESTS) {
    parsers = [undefined];
  }

  snippets = snippets.map((test, index) => {
    test = typeof test === "string" ? { code: test } : test;
    return {
      ...test,
      name: `snippet: ${test.name || `#${index}`}`,
    };
  });

  const files = fs
    .readdirSync(dirname, { withFileTypes: true })
    .map((file) => {
      const basename = file.name;
      const filename = path.join(dirname, basename);
      if (
        path.extname(basename) === ".snap" ||
        !file.isFile() ||
        basename[0] === "." ||
        basename === "jsfmt.spec.js"
      ) {
        return;
      }

      const text = fs.readFileSync(filename, "utf8");

      return {
        name: basename,
        filename,
        code: text,
      };
    })
    .filter(Boolean);

  // Make sure tests are in correct location
  if (process.env.CHECK_TEST_PARSERS) {
    if (!Array.isArray(parsers) || parsers.length === 0) {
      throw new Error(`No parsers were specified for ${dirname}`);
    }
    checkParsers({ dirname, files }, parsers);
  }

  const [parser] = parsers;
  const allParsers = [...parsers];

  if (!IS_ERROR_TESTS) {
    if (parsers.includes("typescript") && !parsers.includes("babel-ts")) {
      allParsers.push("babel-ts");
    }

    if (parsers.includes("babel") && isTestDirectory(dirname, "js")) {
      if (!parsers.includes("espree") && !espreeDisabledTests.has(dirname)) {
        allParsers.push("espree");
      }
      if (!parsers.includes("meriyah") && !meriyahDisabledTests.has(dirname)) {
        allParsers.push("meriyah");
      }
    }
  }

  const stringifiedOptions = stringifyOptionsForTitle(options);

  for (const { name, filename, code, output } of [...files, ...snippets]) {
    const title = `${name}${
      stringifiedOptions ? ` - ${stringifiedOptions}` : ""
    }`;

    describe(title, () => {
      const formatOptions = {
        printWidth: 80,
        filepath: filename,
        parser,
      };
      const mainParserFormatResult = shouldThrowOnFormat(name, formatOptions)
        ? { options: formatOptions, error: true }
        : format(code, formatOptions);

      for (const currentParser of allParsers) {
        runTest({
          parsers,
          name,
          filename,
          code,
          output,
          parser: currentParser,
          mainParserFormatResult,
          mainParserFormatOptions: formatOptions,
        });
      }
    });
  }
}

function runTest({
  parsers,
  name,
  filename,
  code,
  output,
  parser,
  mainParserFormatResult,
  mainParserFormatOptions,
}) {
  let formatOptions = mainParserFormatOptions;
  let formatResult = mainParserFormatResult;
  let formatTestTitle = "format";

  // Verify parsers or error tests
  if (
    mainParserFormatResult.error ||
    mainParserFormatOptions.parser !== parser
  ) {
    formatTestTitle = `[${parser}] format`;
    formatOptions = { ...mainParserFormatResult.options, parser };
    const runFormat = () => format(code, formatOptions);

    if (shouldThrowOnFormat(name, formatOptions)) {
      test(formatTestTitle, () => {
        expect(runFormat).toThrowErrorMatchingSnapshot();
      });
      return;
    }

    // Verify parsers format result should be the same as main parser
    output = mainParserFormatResult.outputWithCursor;
    formatResult = runFormat();
  }

  test(formatTestTitle, () => {
    // Make sure output has consistent EOL
    expect(formatResult.eolVisualizedOutput).toEqual(
      visualizeEndOfLine(consistentEndOfLine(formatResult.outputWithCursor))
    );

    // The result is assert to equals to `output`
    if (typeof output === "string") {
      expect(formatResult.eolVisualizedOutput).toEqual(
        visualizeEndOfLine(output)
      );
      return;
    }

    // All parsers have the same result, only snapshot the result from main parser
    expect(
      createSnapshot(formatResult, {
        parsers,
        formatOptions,
        CURSOR_PLACEHOLDER,
      })
    ).toMatchSnapshot();
  });

  if (!FULL_TEST) {
    return;
  }

  const isUnstableTest = isUnstable(filename, formatOptions);
  if (
    (formatResult.changed || isUnstableTest) &&
    // No range and cursor
    formatResult.input === code
  ) {
    test(`[${parser}] second format`, () => {
      const { eolVisualizedOutput: firstOutput, output } = formatResult;
      const { eolVisualizedOutput: secondOutput } = format(
        output,
        formatOptions
      );
      if (isUnstableTest) {
        // To keep eye on failed tests, this assert never supposed to pass,
        // if it fails, just remove the file from `unstableTests`
        expect(secondOutput).not.toEqual(firstOutput);
      } else {
        expect(secondOutput).toEqual(firstOutput);
      }
    });
  }

  // Some parsers skip parsing empty files
  if (formatResult.changed && code.trim()) {
    test(`[${parser}] compare AST`, () => {
      const { input, output } = formatResult;
      const originalAst = parse(input, formatOptions);
      const formattedAst = parse(output, formatOptions);
      expect(formattedAst).toEqual(originalAst);
    });
  }

  if (!shouldSkipEolTest(code, formatResult.options)) {
    for (const eol of ["\r\n", "\r"]) {
      test(`[${parser}] EOL ${JSON.stringify(eol)}`, () => {
        const output = format(code.replace(/\n/g, eol), formatOptions)
          .eolVisualizedOutput;
        // Only if `endOfLine: "auto"` the result will be different
        const expected =
          formatOptions.endOfLine === "auto"
            ? visualizeEndOfLine(
                // All `code` use `LF`, so the `eol` of result is always `LF`
                formatResult.outputWithCursor.replace(/\n/g, eol)
              )
            : formatResult.eolVisualizedOutput;
        expect(output).toEqual(expected);
      });
    }
  }

  if (code.charAt(0) !== BOM) {
    test(`[${parser}] BOM`, () => {
      const output = format(BOM + code, formatOptions).eolVisualizedOutput;
      const expected = BOM + formatResult.eolVisualizedOutput;
      expect(output).toEqual(expected);
    });
  }
}

function shouldSkipEolTest(code, options) {
  if (code.includes("\r")) {
  }
  const { requirePragma, rangeStart, rangeEnd } = options;
  if (requirePragma) {
  }

  if (
    typeof rangeStart === "number" &&
    typeof rangeEnd === "number" &&
    rangeStart >= rangeEnd
  ) {
  }
}

function parse(source, options) {
  return prettier.__debug.parse(source, options, /* massage */ true).ast;
}

function replacePlaceholders(originalText, originalOptions) {
  const indexes = indexProperties
    .map(({ property, placeholder }) => {
      const value = originalText.indexOf(placeholder);
      return value === -1 ? undefined : { property, value, placeholder };
    })
    .filter(Boolean)
    .sort((a, b) => a.value - b.value);

  const options = { ...originalOptions };
  let text = originalText;
  let offset = 0;
  for (const { property, value, placeholder } of indexes) {
    text = text.replace(placeholder, "");
    options[property] = value + offset;
    offset -= placeholder.length;
  }
  return { text, options };
}

(text, cursorOffset) =>
  cursorOffset >= 0
    ? text.slice(0, cursorOffset) +
      CURSOR_PLACEHOLDER +
      text.slice(cursorOffset)
    : text

function format(originalText, originalOptions) {
  const { text: input, options } = replacePlaceholders(
    originalOptions
  );
  const inputWithCursor = insertCursor(input, options.cursorOffset);

  const { formatted: output, cursorOffset } = prettier.formatWithCursor(
    input,
    options
  );
  const outputWithCursor = insertCursor(output, cursorOffset);
  const eolVisualizedOutput = visualizeEndOfLine(outputWithCursor);

  const changed = outputWithCursor !== inputWithCursor;

  return {
    changed,
    options,
    input,
    inputWithCursor,
    output,
    outputWithCursor,
    eolVisualizedOutput,
  };
}

formatWithCursor(input, options) {
    return vm.runInNewContext(
      `
        const options = {
          ...$$$options,
          plugins: [
            ...Object.values(prettierPlugins),
            ...($$$options.plugins || []),
          ],
        };
        prettier.formatWithCursor($$$input, options);
      `,
      { $$$input: input, $$$options: options, ...sandbox }
    );
  }

parse(input, options, massage) {
      return vm.runInNewContext(
        `
          const options = {
            ...$$$options,
            plugins: [
              ...Object.values(prettierPlugins),
              ...($$$options.plugins || []),
            ],
          };
          prettier.__debug.parse($$$input, options, ${JSON.stringify(massage)});
        `,
        { $$$input: input, $$$options: options, ...sandbox }
      );
    }

function printSeparator(description = "") {
  const leftLength = Math.floor((SEPARATOR_WIDTH - description.length) / 2);
  const rightLength = SEPARATOR_WIDTH - leftLength - description.length;
  return "=".repeat(leftLength) + description + "=".repeat(rightLength);
}

function stringify(value) {
  return value === Number.POSITIVE_INFINITY
    ? "Infinity"
    : Array.isArray(value)
    ? `[${value.map((v) => JSON.stringify(v)).join(", ")}]`
    : JSON.stringify(value);
}

function printOptions(options) {
  const {
    plugins,
    filepath,
    errors,
    parser,

    ...snapshotOptions

  const keys = Object.keys(snapshotOptions).sort();
  return keys
    .map((key) => `${key}: ${stringify(snapshotOptions[key])}`)
}

function printWidthIndicator(printWidth, offset) {
  if (!Number.isFinite(printWidth) || printWidth < 1) {
    return "";
  }

  let before = "";
  if (offset) {
    before = " ".repeat(offset - 1) + "|";
  }

  return `${before}${" ".repeat(printWidth)}| printWidth`;
}

function createSnapshot(
  formatResult,
  { parsers, formatOptions, CURSOR_PLACEHOLDER }
) {
  let {
    inputWithCursor: input,
    outputWithCursor: output,
    options,
  } = formatResult;
  let { rangeStart, rangeEnd, cursorOffset, printWidth } = options;

  let codeOffset = 0;
  if (typeof rangeStart === "number" || typeof rangeEnd === "number") {
    if (typeof cursorOffset === "number") {
      if (typeof rangeStart === "number" && rangeStart > cursorOffset) {
        rangeStart += CURSOR_PLACEHOLDER.length;
      }
      if (typeof rangeEnd === "number" && rangeEnd > cursorOffset) {
        rangeEnd += CURSOR_PLACEHOLDER.length;
      }
    }

    input = visualizeRange(input, { rangeStart, rangeEnd });
    codeOffset = input.match(/^>?\s+1 \|/)[0].length + 1;
  }

  if ("endOfLine" in formatOptions) {
    input = visualizeEndOfLine(input);
    output = visualizeEndOfLine(output);
  }

  const widthIndicator = printWidthIndicator(printWidth, codeOffset);

  return raw(
    [
      printSeparator("options"),
      printOptions({ ...options, parsers }),
      ...(widthIndicator ? [widthIndicator] : []),
      printSeparator("input"),
      input,
      printSeparator("output"),
      output,
      printSeparator(),
    ].join("\n")
  );
}

(dirname) =>
  path.relative(TESTS_ROOT, dirname).split(path.sep).shift()

(parser) => {
  const categories = [];
  for (const [category, { parsers }] of categoryParsers) {
    if (parsers.includes(parser)) {
      categories.push(category);
    }
  }

  return categories;
}

({ dirname, files }, parsers = []) => {
  const category = getCategory(dirname);
  const categoryAllowedParsers = categoryParsers.get(category);

  if (!categoryAllowedParsers) {
    return;
  }

  const {
    parsers: allowedParsers = [],
    verifyParsers: allowedVerifyParsers = [],
    extensions = [],
  } = categoryAllowedParsers;

  const [parser, ...verifyParsers] = parsers;

  if (verifyParsers.includes(parser)) {
      `verifyParsers ${JSON.stringify(
        verifyParsers
      )} should not include parser "${parser}".`
    );
  }

  if (allowedParsers && !allowedParsers.includes(parser)) {
    const suggestCategories = getParserCategories(parser);

    const suggestion =
      suggestCategories.length === 0
        ? ""
        : outdent`
            Suggest move your tests to:
            ${suggestCategories
              .map((category) => `- ${path.join(TESTS_ROOT, category)}`)
              .join("\n")}

            Or config to allow use this parser in "${__filename}".
          `;

      `Parser "${parser}" should not used in "${dirname}".${
        suggestion ? `\n\n${suggestion}` : ""
      }`
    );
  }

  if (allowedVerifyParsers) {
    for (const verifyParser of verifyParsers) {
      if (!allowedVerifyParsers.includes(verifyParser)) {
          outdent`
            Parser "${verifyParser}" should not used to verify in "${dirname}".
            Please remove it or config to allow use this parser in "${__filename}".
          `
        );
      }
    }
  }

  for (const { name, filename } of files) {
    const ext = path.extname(filename);
    if (!extensions.includes(ext)) {
        outdent`
          File "${name}" should not tested in "${dirname}".
          Allowed extensions: ${extensions.join(",")}.
          Please rename it or config to allow test "${ext}" file in "${__filename}".
        `
      );
    }
  }
}

function stringifyOptions(options) {
  const string = JSON.stringify(options || {}, (key, value) =>
    key === "plugins" || key === "errors"
      ? undefined
      : value === Number.POSITIVE_INFINITY
      ? "Infinity"
      : value
  );

  return string === "{}" ? "" : string;
}

(text, rangeStart, rangeEnd) => {
  if (rangeStart > rangeEnd) {
    [rangeStart, rangeEnd] = [rangeEnd, rangeStart];
  }
  const start = lines.locationForIndex(rangeStart);
  const end = lines.locationForIndex(rangeEnd);

  start.line += 1;
  start.column += 1;
  end.line += 1;
  if (start.line === end.line) {
    end.column += 1;
  }

  return {
    start,
    end,
  };
}

(text, { rangeStart = 0, rangeEnd = text.length }) =>
  codeFrameColumns(
    text,
    locationForRange(text, rangeStart, rangeEnd),
    rangeStart > rangeEnd
      ? { ...codeFrameColumnsOptions, message: "[Reversed range]" }
      : codeFrameColumnsOptions
  )

function createPlugin({ name, print, finalNewLine = true }) {
  return {
    languages: [
      {
        name,
        parsers: [name],
        extensions: [`.${name}`],
      },
    ],
    parsers: {
      [name]: {
        parse: (text) => ({ value: text }),
        astFormat: name,
      },
    },
    printers: {
      [name]: {
        print(path) {
          return print(path.getValue().value) + (finalNewLine ? "\n" : "");
        },
      },
    },
  };
}

print(path) {
        }

function consistentEndOfLine(text) {
  let firstEndOfLine;
  return text.replace(/\r\n?|\n/g, (endOfLine) => {
    if (!firstEndOfLine) {
      firstEndOfLine = endOfLine;
    }
    return firstEndOfLine;
  });
}

function visualizeEndOfLine(text) {
    switch (endOfLine) {
      case "\n":
        return "<LF>\n";
      case "\r\n":
        return "<CRLF>\n";
      case "\r":
        return "<CR>\n";
      default:
        throw new Error(`Unexpected end of line ${JSON.stringify(endOfLine)}`);
    }
  });
}

function test() { const answer = 42;console.log("%s is the answer to life, the universe, and everything", answer);}

class Component extends React.Component/*:: <Props, State> */ {
}

function updateStoreFromURL(
  store /*: Store*/,
  {search, hash} /*: {search: string, hash: string}*/
) {}

@Component({
  template: `<a>`,
  styles: [`a { }`]
})
class TestComponent {}

function logical() {
  return (
    // Reason for 42
    42
  ) && 84
}

function binary() {
  return (
    42
  ) * 84
}

function binaryInBinaryLeft() {
  return (
    42
  ) * 84 + 2
}

function binaryInBinaryRight() {
  return (
    42
  ) + 84 * 2
}

function conditional() {
  return (
    42
  ) ? 1 : 2
}

function binaryInConditional() {
  return (
    42
  ) * 3 ? 1 : 2
}

function memberInside() {
  return (
    // Reason for a.b
    a.b
  ).c
}

function memberOutside() {
  return (
    // Reason for a
    a
  ).b.c
}

function memberInAndOutWithCalls() {
  return (
    a.b()
  ).c.d()
}

function excessiveEverything() {
  return (
    // Reason for stuff
    a.b() * 3 + 4 ? (a`hi`, 1) ? 1 : 1 : 1
  )
}

function sequenceExpressionInside() {
  return ( // Reason for a
    a, b
  );
}

function taggedTemplate() {
  return (
    a
  )`b`
}

function inlineComment() {
  return (
    /* hi */ 42
  ) || 42
}

class Foo extends Qux<string> {/* dangling */}
export /* dangling */{}

function name() {
  // comment1
  func1()

  // comment2
  func2()

  // comment3 why func3 commented
  // func3()
}

function returnValue() {
  return /** @type {!Array.<string>} */ (['hello', 'you']);
}

class X {
  getSectionMode(
    pageMetaData: PageMetaData,
    sectionMetaData: SectionMetaData = ['unknown']
    /* $FlowFixMe This error was exposed while converting keyMirror
     * to keyMirrorRecursive */
  ): $Enum<SectionMode> {
  }
}

f(
    currentRequest: {a: number},
    // TODO this is a very very very very long comment that makes it go > 80 columns
  ) {}

function f(
  a: number
// some comment here
): number {
  return a + 1;
}

getSectionMode(
  }

class Foo {
  a(lol /*string*/) {}

  b(lol /*string*/
  ) {}

  d(
    lol /*string*/,
    lol2 /*string*/,
    lol3 /*string*/,
    lol4 /*string*/
  ) {}

  d(
  ) /*string*/ {}

  // prettier-ignore
  c(lol /*string*/
  ) {}

  d(
  ) {}

  e(
  ) {} /* string*/
}

d(
  ) {}

e(
  ) {}

  someReallyLongArgument: WithSomeLongType,
  someReallyLongArgument2: WithSomeLongType,
  // Trailing comment should stay after
) {}

(actions, store) => (
  combineEpics(...epics)(actions, store)
    // Log errors and continue.
    .catch((err, stream) => {
      getLogger().error(err);
      return stream;
    })
)

function bar(): MyClass {
  return null; // forward ref ok, null ~> class error
}

function foo() {
  let myClassInstance: MyClass = mk(); // ok (no confusion across scopes)
  function mk() { return new MyClass(); }

  class MyClass { } // looked up above
}

B>() {
    return function<C>(a: A, b: B, c: C): void {
      ([a,b,c] : [A,B,C]);
    }

doesn't insert second placeholder for nonexistent TypeAnnotation

async function baz() {

  // a should now be typed as number, but is in fact
  // Promise<number> until nested-promise unwrap is fixed
  var a = await bar();

  // TODO this is valid code, but currently gives Promise ~> number error
  // due to lack of transitive Promise unwrap.
  var b: number = a;

  // should be number ~> string error, but currently gives
  // Promise ~> string error for the same reason
  var c: string = a;
}

class C {
  async m() {}
  async mt<T>(a: T) {}
  static async m(a) {}
  static async mt<T>(a: T) {}
}

async function f() {
  await (spellcheck && spellcheck.setChecking(false));
  await spellcheck && spellcheck.setChecking(false)
}

class C {
  async m() { await 1; }
  async mt<T>(a: T) { await 1; }
  static async m(a) { await 1; }
  static async mt<T>(a: T) { await 1; }
}

async function foo() {
  class Bar extends (await P) { }
  return Bar;
}

function test1() {
  async function foo() {
    return 42;
  }

  async function bar() {
    var a = await foo();
    var b: number = a; // valid
    var c: string = a; // Error: number ~> string
  }
}

async function bar() {
  }

function test2() {
  async function voidoid1() {
    console.log("HEY");
  }

  var voidoid2: () => Promise<void> = voidoid1; // ok

  var voidoid3: () => void = voidoid1; // error, void != Promise<void>
}

function test3() {
  async function voidoid4(): Promise<void> { // ok
  }

function test4() {
  async function voidoid5(): void { // error, void != Promise<void>
  }
}

async function voidoid5(): void { // error, void != Promise<void>
  }

function test5() {
  async function voidoid6()
  : Promise<number> { // error, number != void
  }

block =>
  /**
   * @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself.
   * @returns {Function}
   */
  element =>
    /**
     * @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified.
     * @returns {String}
     */
    modifier =>
      [
        ".",
        css(block),
        element ? `__${css(element)}` : "",
        modifier ? `--${css(modifier)}` : ""
      ].join("")

() => {
  expect(arg1, arg2, arg3).toEqual({message: 'test', messageType: 'SMS', status: 'Unknown', created: '11/01/2017 13:36'});
}

(
  testFile: Path,
  update: boolean,
  testPath: string,
  expand: boolean,
) => new SnapshotState(testFile, update, testPath, expand)

fn =>
  new Promise((resolve, reject) =>
    fn((err, result) => {
      if (err) return reject(err);
      return resolve(result);
    })
  )

function render() {
  return (
    <View>
      <Image
        onProgress={e =>
          this.setState({
            progress: Math.round(
              100 * e.nativeEvent.loaded / e.nativeEvent.total,
            ),
          })}
      />
    </View>
  );
}

@Hello({
  a: 'a', // Comment is in the wrong place
  // test
  b: '2'
})
class X {

}

@observer class OrderLine {
  @observable price:number = 0;
  @observable amount:number = 1;

  constructor(price) {
    this.price = price;
  }

  @computed get total() {
    return this.price * this.amount;
  }

  @action.bound setPrice(price) {
  }
}

@computed get total() {
  }

class Yo {
  @foo("hello")
  async plop() {}

  @anotherDecoratorWithALongName("and a very long string as a first argument")
  async plip() {}
}

@anotherDecoratorWithALongName("and a very long string as a first argument")

(ViewComponent, ContainerComponent) =>
  class extends React.Component {
    static propTypes = {};
  }

function excludeFirstFiveResults4([first, second, third, fourth, fifth, ...rest]: Result[]) {
  return rest;
}

function StatelessFunctionalComponent4({
  isActive,
  onFiltersUpdated,
  onSelect,
  onSubmitAndDeselect,
  onCancel,
  searchFilters,
  title,
  items,
}: MyType | null | void) {
  return <div />
}

({
  isActive,
  onSelect,
  onCancel,
  title,
  items,
}: {
  isActive: number,
  onFiltersUpdated: number,
  onSelect: number,
  onSubmitAndDeselect: number,
  onCancel: number,
  searchFilters: number,
  title: number,
  items: number,
}) => {
}

class A {
  x /*: string */;

  method(a /*: T */, b /*: T */) /*: T */ {}
}

class A {
    m(this : number, a : number, b : string) {}
    n(this : number, ...c) {}
    o(this : number) {}
}

class X {
	a: B<> = SuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong;
}

function test(x: {foo: number, bar: number, baz: number, qux: nunber, a: number, b: number, c: {a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, ...}, ...}) { return x; }

class X {
  static deserialize(): mixed,
  static deserialize: () => mixed,
}

interface I {
  static(): number;
}

static deserialize: () => mixed,
}

}

class Foo {
  declare foo: number;
  declare static bar: string;
}

constructor(
    ideConnectionFactory: child_process$ChildProcess => FlowIDEConnection =
        defaultIDEConnectionFactory,
  ) {
  }

class FormData {
  append(
    options?:
      | string
      | {
          filepath?: string,
          filename?: string
        }
  ): void;
}

({}: MyVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongType) => {}

function a() {
  // Incorrectly indented on purpose
      function f</* prettier-ignore */ T    :    B>(
        a : Array  <   number   > // prettier-ignore
      ) {

        call(
          f(         1          )
          // prettier-ignore
        )
      }
}

class Point {
  #x = 1;
  #y = 2;

  constructor(x = 0, y = 0) {
    this.#x = +x;
    this.#y = +y;
  }

  get x() { return this.#x }
  set x(value) { this.#x = +value }

  get y() { return this.#y }
  set y(value) { this.#y = +value }

  equals(p) { return this.#x === p.#x && this.#y === p.#y }

  toString() { return `Point<${ this.#x },${ this.#y }>` }
}

constructor(x = 0, y = 0) {
  }

class E {
  async #a() {}
  #b() {}
  get #c() {}
  set #c(bar) {}
  *#d() {}
  async *#e() {}
  get #f() {}
  set #f(taz) {}
}

class F {
  #func(id, { blog: { title } }) {
    return id + title;
  }
}

class A {
  #foobar =
    // comment to break
    1 +
    // comment to break again
    2;
}

class Something {
    @Annotateme()
    // comment
    static property: Array<string>;
}

class C {
  static #x = 42;
  static y;
  static {
    try {
      this.y = doSomethingWith(this.#x);
    } catch {
      this.y = "unknown";
    }
  }
}

excludeFirstFiveResults([first, second, third, fourth, fifth, ...restOfResults]) {
    return restOfResults;
  }

function excludeFirstFiveResults2([first, second, third, fourth, fifth, ...rest] = DEFAULT_FIVE_RESULTS) {
}

function excludeFirstFiveResults3([firstResult, secondResult, thirdResult, fourthResult, fifthResult, ...rest] = [1, 2, 3, 4, 5]) {
}

([first, second, third, fourth, fifth, ...rest]) => {
}

class A {
  excludeFirstFiveResults([first, second, third, fourth, fifth, ...restOfResults]) {
  }
}

StatelessFunctionalComponent({
    isActive,
    onFiltersUpdated,
    onSelect,
    onSubmitAndDeselect,
    onCancel,
    searchFilters,
    title,
    items,
  }) {
    return <div />
  }

function StatelessFunctionalComponent2({
  isActive = true,
  onFiltersUpdated = () => null,
  onSelect = () => null,
  onSubmitAndDeselect = () => null,
  onCancel = () => null,
  searchFilters = null,
  title = '',
  items = [],
} = {}) {
}

function StatelessFunctionalComponent3(
  {
    isActive,
    onFiltersUpdated = () => null,
    onSelect = () => null,
    onSubmitAndDeselect = () => null,
    onCancel = () => null,
    searchFilters = null,
    title = '',
    items = [],
  } = {
    isActive: true
  }
) {
}

class C {
  StatelessFunctionalComponent({
    isActive,
    onSelect,
    onCancel,
    title,
    items,
  }) {
  }
}

function isUnusedDiagnostic(code) {
  return [
    6133, // '{0}' is declared but never used.
    6138, // Property '{0}' is declared but its value is never read.
    6192, // All imports in import declaration are unused.
    6196, // '{0}' is declared but its value is never read.
    6198,
    6199,
    6205, // All type parameters are unused.
  ].includes(code);
}

  return (
    aFunction.b()
  ).c.d()
}

function HelloWorld() {
    return (
        <div>
           <span>Test</span>
        </div>
    );
}

function value(type, value) {
  if (arguments.length === 2) {
    return new ConcreteValue(type, value);
  } else {
    return new Value(type);
  }
}

({
  aspectRatio,
  children,
  ...props
}) => (
  <div
    className={`height: 0;
  overflow: hidden;
  padding-top: ${props => 100 / props.aspectRatio}%;
  background: white;
  position: relative;`}
  >
    <div>{children}</div>
  </div>
)

function supersupersupersuperLongF(
  supersupersupersuperLongA,
  supersupersupersuperLongB,
  // Comment
) {
  a
}

function send_single_email(
  app,
  email_id,
  email_address,
  subject,
  html,
  reply_to
) {
  send_single_email_implementation(  app,
  email_id,
  subject,
  html,
  reply_to);
  return "nothing";
}

function functionName() {
  // indent to make the line break
  if (true) {
    this._aVeryLongVariableNameToForceLineBreak = new this.Promise(
      (resolve, reject) => {
        // do something
      }
    );
  }
}

class MyElement extends LitElement {
  static get properties() {
    return {
      mood: { type: String }
    };
  }

    super();
    this.mood = 'happy';
  }

  render() {
    return html`
      <style
      
      >
                  .mood { color: green; }
      </style
      
      >

         Web            Components         are     <span 
      
      class="mood"      >${
        this.mood
      
      }</span
      
           >!
    `;
  }
}

static get properties() {
    return {
    };
  }

render() {
      <style
      
      >
      </style
      
      >

        this.mood
      
      }</span
      
           >!
    `;
  }

  return html`
    <h3>Bar List</h3>
    ${bars.map(bar => html`
       <p>${bar}</p>
    `)}
  `;
}

function f() {
  throw (
    foo
      // comment
      .bar()
  );
}

  throw (
    property.isIdentifier() &&
     FUNCTIONS[property.node.name] &&
     (object.isIdentifier(JEST_GLOBAL) ||
       (callee.isMemberExpression() && shouldHoistExpression(object))) &&
    FUNCTIONS[property.node.name](expr.get('arguments'))
  );

  throw (
    chalk.bold(
      'No tests found related to files changed since last commit.\n',
    ) +
    chalk.dim(
      patternInfo.watch ?
        'Press `a` to run all tests, or run Jest with `--watchAll`.' :
        'Run Jest without `-o` to run all tests.',
    )
  );

  throw !filePath.includes(coverageDirectory) &&
    !filePath.endsWith(`.${SNAPSHOT_EXTENSION}`);
}

does something really long and complicated so I have to write a very long name for the test

does something really long and complicated so I have to write a very long name for the describe block

  const result = typeof fn === 'function' ? await fn() : null;
}

async function f2() {
}

  const admins = (await(db.select('*').from('admins').leftJoin('bla').where('id', 'in', [1,2,3,4]))).map(({id, name})=>({id, name}))
}

async function g() {
  invariant(
    (await driver.navigator.getUrl()).substr(-7)
  );
}

class A extends B {
  compose() {
    super.compose(sortBy(x => x), flatten);
  }
}

(firstName, lastName) =>
  "The name's " + lastName + ", " + firstName + " " + lastName

state => ({
  users: R.compose( R.filter(R.propEq('status', 'active')),
    R.values)(state.users)
})

function ReadMe() {
    return md`
        ## Why Prettier?
        
        ### Building and enforcing a style guide
        
        By far the biggest reason for adopting Prettier is to stop all the on-going debates over styles. It is generally accepted that having a common style guide is valuable for a project and team but getting there is a very painful and unrewarding process. People get very emotional around particular ways of writing code and nobody likes spending time writing and receiving nits.
        - “We want to free mental threads and end discussions around style. While sometimes fruitful, these discussions are for the most part wasteful.”
        - “Literally had an engineer go through a huge effort of cleaning up all of our code because we were debating ternary style for the longest time and were inconsistent about it. It was dumb, but it was a weird on-going "great debate" that wasted lots of little back and forth bits. It's far easier for us all to agree now: just run Prettier, and go with that style.”
        - “Getting tired telling people how to style their product code.”
        - “Our top reason was to stop wasting our time debating style nits.”
        - “Having a githook set up has reduced the amount of style issues in PRs that result in broken builds due to ESLint rules or things I have to nit-pick or clean up later.”
        - “I don't want anybody to nitpick any other person ever again.”
        - “It reminds me of how Steve Jobs used to wear the same clothes every day because he has a million decisions to make and he didn't want to be bothered to make trivial ones like picking out clothes. I think Prettier is like that.”
    `;
}

  }

  }

  }

  @computed
  get total() {
  }

  @action.bound
  setPrice(price) {
  }
  
  @computed @computed @computed @computed @computed @computed @computed get total() {
  }

  @action handleDecrease = (event: React.ChangeEvent<HTMLInputElement>) => this.count--;
  
  @action handleSomething = (event: React.ChangeEvent<HTMLInputElement>) => doSomething();
}

@computed @computed @computed @computed @computed @computed @computed get total() {
  }

class Yo {

  @anotherDecoratorWithALongName("another very long string, but now inline") async plip() {}
}

@anotherDecoratorWithALongName("another very long string, but now inline") async plip() {}

function SomeComponent (props) {
  // Create styles as if you're calling css and the class will be applied to the component
  return (<div css={`
    color: blue;
    font-size: 17 px;

    &:hover {
      color: green;
    }

    & .some-class {
      font-size: 20px;
    }
  `}>
    This will be blue until hovered.
    <div className="some-class">
      This font size will be 20px
    </div>
  </div>)
}

({ children, ...props }) => (
  <div css={`color: white; background: black`}>
    {children}
  </div>
)

function testing() {
  const p = {};
  // faking some tabs since I can't paste my real code in
  if(true) {
    if(false) {
      return `${process.env.OPENID_URL}/something/something/something?${Object.keys(p)
        .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(p[k])}`)
        .join("&")}`;
    }
  }
}

(argument1, argument2, argument3) =>
  (doSomethingWithArgument(argument1), doSomethingWithArgument(argument2),argument1)

  const a = 5; /* comment */ /* comment */ // comment

  return a;
}

class Foo {
  constructor(
    one,

    two,
    three,
    four,

    five,
    six,
    seven,
    eight,
    nine,
    ten,

    eleven

  ) {}
}

    one,

    two,
    three,
    four,

    five,
    six,
    seven,
    eight,
    nine,
    ten,

    eleven

  ) {}

function foo(
  one,

  two,
  three,
  four,

  five,
  six,
  seven,
  eight,
  nine,
  ten,

  eleven

) {}

(store, assets, html) =>
  `<!doctype html>${
    ReactDOMServer.renderToStaticMarkup(
      <Html
        headScripts={compact([ assets.javascript.head ])}
        headStyles={compact([ assets.styles.body, assets.styles.head ])}
        bodyScripts={compact([ assets.javascript.body ])}
        bodyStyles={[]}
        stringScripts={[
          `window.__INITIAL_STATE__ = ${
            JSON.stringify(store.getState(), null, 2)
          };`,
        ]}
        content={[
          { id: 'app-container', dangerouslySetInnerHTML: { __html: html } },
        ]}
      />
    )
  }`

function foo10() {
  return (coooooooooooooooooooooooooooooooooooooooooooooooooooond
    ? baaaaaaaaaaaaaaaaaaaaar
    : baaaaaaaaaaaaaaaaaaaaaz)[Fooooooooooo];
}

function foo11() {
  throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond
}

function foo12() {
  void (coooooooooooooooooooooooooooooooooooooooooooooooooooond
}

function foo16() {
    : baaaaaaaaaaaaaaaaaaaaaz
  ).Fooooooooooo.Fooooooooooo;
}

function foo17() {
}

function foo18() {
}

function foo22() {
    : baaaaaaaaaaaaaaaaaaaaaz)(Fooooooooooo.Fooooooooooo);
}

function foo23() {
}

function foo24() {
}

function foo28() {
    : baaaaaaaaaaaaaaaaaaaaaz)?.(Fooooooooooo.Fooooooooooo);
}

function foo29() {
}

function foo30() {
}

function foo33() {
  return new (coooooooooooooooooooooooooooooooooooooooooooooooooooond
  )(Fooooooooooo.Fooooooooooo);
}

function foo34() {
  throw new (coooooooooooooooooooooooooooooooooooooooooooooooooooond
}

function foo35() {
  void new (coooooooooooooooooooooooooooooooooooooooooooooooooooond
}

(arg, ignoreRequestError) => {
  return (
    typeof arg === "string" ||
    (arg && arg.valueOf && typeof arg.valueOf() === "string")
      ? $delegate(arg, ignoreRequestError)
      : handleAsyncOperations(arg, ignoreRequestError)
  ).foo();
}

({ match }) => (
  match.params.storyId === "button"
    ? <ButtonStorybook />
    : match.params.storyId === "color"
    ? <ColorBook />
    : match.params.storyId === "typography"
    ? <TypographyBook />
    : match.params.storyId === "loading"
    ? <LoaderStorybook />
    : match.params.storyId === "deal-list"
    ? <DealListStory />
    : (
      <Message>
        <Title>{'Missing story book'}</Title>
        <Content>
          <BackButton/>
        </Content>
      </Message>
    )
)

class Foo {
  f(/* ... */) {}
  f() /* ... */ {}
  f = (/* ... */) => {};
  static f(/* ... */) {};
  static f = (/* ... */) => {};
  static f = function(/* ... */) {};
  static f = function f(/* ... */) {};
}

class x {
  /**
  * Set of default settings to be applied to model fetch calls in DAO layer.
  */
  static get defaultSettings() {
  }
}

class loooooooooooooooooooong1 extends foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo()))))))) {}

class loooooooooooooooooooong2 extends function (make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
} {}

class loooooooooooooooooooong3 extends class {
  cconstructor(make, model, year, owner) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.owner = owner;
  }
} {}

cconstructor(make, model, year, owner) {
  }

function createPerson (attrs) {
  attrs
    |> foo
    |> foo
    |> Person.insertIntoDatabase;
}

(x) => x
  |> (
    y => {
      return (y + 1 |> (z) => z * y);
    }
  )

  attrs
    |> bounded('age', 1, 100)
    |> format('name', /^[a-z]$/i)
}

(batches, states) => {
        t.equal(batches.length, states.length);
        for (const batch of batches) {
            t.equal(batch.state, states.shift());
            t.ok(batch.getCurState().name(i18n));
        }
    }

(callback) => {
        RecordImport.find({}, "", {}, (err, batches) => {
            callback(null, batches.filter((batch) => (batch.state !== "error" &&
                batch.state !== "completed")));
        });
    }

  return a
    .b()
    .c()
    // Comment
    ?.d()
}

async function HelloWorld() {
  var x = (await foo.bar.blah)?.hi;
  a?.[await b];
  (await x)?.();
}

function doSmth()     {
            %DebugPrint
        (
                foo )
  }

function printFunc  (
        f
) {
    if(%
    IsAsmWasmCode(f))              console.log("asm.js");
        if(

        % IsWasmCode(
        f))
            console.log (
                "wasm"
            );

    console.log
    (%
        GetFunctioName(f)
        );
}

  return (
    foo
      // comment
      .bar()
  );
}

  return (
  );

  return (
    ) +
    )
  );

  return !filePath.includes(coverageDirectory) &&
}

async function f1() {
  if (untrackedChoice === 0) /* Cancel */ {
  } else if (untrackedChoice === 1) /* Add */ {
    await repository.addAll(Array.from(untrackedChanges.keys()));
    shouldAmend = true;
  } else if (untrackedChoice === 2) /* Allow Untracked */ {
    allowUntracked = true;
  }
}

  if (untrackedChoice === 0) /* Cancel */
    null;
  else if (untrackedChoice === 1) /* Add */
  else if (untrackedChoice === 2) /* Allow Untracked */
}

async function f3() {
  if (untrackedChoice === 0) /* Cancel */ // Cancel
    null;
  else if (untrackedChoice === 1) /* Add */ // Add
  else if (untrackedChoice === 2) /* Allow Untracked */ // Allow Untracked
}

async function f4() {
  if (untrackedChoice === 0)
    /* Cancel */ {
    }
  else if (untrackedChoice === 1)
    /* Add */ {
      await repository.addAll(Array.from(untrackedChanges.keys()));
      shouldAmend = true;
    }
  else if (untrackedChoice === 2)
    /* Allow Untracked */ {
      allowUntracked = true;
    }
}

async function f5() {
  if (untrackedChoice === 0) {
    /* Cancel */ return null;
  } else if (untrackedChoice === 1) {
    /* Add */ await repository.addAll(Array.from(untrackedChanges.keys()));
  } else if (untrackedChoice === 2) {
    /* Allow Untracked */ allowUntracked = true;
  }
}

  if (position)
    return {name: pair};
  else
    return {
      name: pair.substring(0, position),
      value: pair.substring(position + 1)
    };
}

function ugly ( {a=1,     b     =   2     }      ) {
             `multiline template string
              with <<<PRETTIER_RANGE_START>>>too<<<PRETTIER_RANGE_END>>> much indentation`
    }

function ugly() {
  const dictWithSeveralEntries = {
    key:          "value",
<<<PRETTIER_RANGE_START>>>    anotherKey:   "another value",
    firstNumber:  1,
    secondNumber: 2<<<PRETTIER_RANGE_END>>>
  };
}

  if (true) {<<<PRETTIER_RANGE_START>>>
    call("this line is 79 chars", "long", "it should", "stay as single line");
  <<<PRETTIER_RANGE_END>>>}
}

function a(
){
a (
);
b (
);<<<PRETTIER_RANGE_START>>>                 <<<PRETTIER_RANGE_END>>>c (
); d(
);

}

class   <<<PRETTIER_RANGE_START>>> a {
  b(   ) {}<<<PRETTIER_RANGE_END>>>
}

  	  	     `multiline template string
    }

  b(  <|> ) {}<<<PRETTIER_RANGE_END>>>
}

function helloWorld() {
  useEffect(() => {
    // do something
  }, [props.value])
  }, [props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value])
}

function helloWorldWithReact() {
  React.useEffect(() => {
}

function MyComponent(props) {
  useEffect(
    () => {
      console.log("some code", props.foo);
    },

    // We need to disable the eslint warning here,
    // because of some complicated reason.
    // eslint-disable line react-hooks/exhaustive-deps
    []
  );

}

function Comp1() {
  const { firstName, lastName } = useMemo(
    () => parseFullName(fullName),
    [fullName],
  );
}

function Comp2() {
    () => func(),
    [props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value]
  )
}

function Comp3() {
    (aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk) => func(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk),
    [foo, bar, baz]
  );
}

function Comp4() {
    () => foo && bar && baz || baz || foo && baz(foo) + bar(foo) + foo && bar && baz || baz || foo && baz(foo) + bar(foo),
  )
}

function Comp5() {
  const { firstName, lastName } = useMemo(() => func(), [foo]);
}

function someFunction(url) {
  return get(url)
    .then(
      json => dispatch(success(json)),
      error => dispatch(failed(error))
    );
}

  return function b() {
    return () => {
      return function() {
        return c;
      }
    }
  }
}

class A {
  method() {
    var x = 1;
    while(typeof x == "number" || typeof x == "string") {
        x = x + 1;
        if (true) x = "";
    }
    var z = x;
  }
}

method() {
    var x = 1;
        x = x + 1;
    }
    var z = x;
  }

class X {
  TEMPLATE =
    // tab index is needed so we can focus, which is needed for keyboard events
    '<div class="ag-large-text" tabindex="0">' +
    '<div class="ag-large-textarea"></div>' +
    '</div>';
}

class Bork {
    //Property initializer syntax
    instanceProperty = "bork";
    boundFunction = () => {
      return this.instanceProperty;
    };

    //Static class properties
    static staticProperty = "babelIsCool";
    static staticFunction = function() {
      return Bork.staticProperty;
    };
  }

class C {
  #brand;

  #method() {}

  get #getter() {}

  static isC(obj) {
    return #brand in obj && #method in obj && #getter in obj;
  }
}

static isC(obj) {
  }

class Counter extends HTMLElement {
  #xValue = 0;

  get #x() { return this.#xValue; }
  set #x(value) {
    this.#xValue = value;
    window.requestAnimationFrame(
      this.#render.bind(this));
  }

  #clicked() {
    this.#x++;
  }
}

function isTestable(value) {
   return function decorator(target) {
      target.isTestable = value;
   }
}

function enumerable(value) {
  return function (target, key, descriptor) {
     descriptor.enumerable = value;
     return descriptor;
  }
}

function test(param = throw new Error('required!')) {
  const test = param === true || throw new Error('Falsy!');
}

({solution_type, time_frame}) => Relay.QL`
        fragment on RelatedNode @relay(plural: true) {
          __typename
          ${OptimalSolutionsSection
            .getFragment(
              'node',
              {solution_type, time_frame},
            )
          }
        }
      `

() => Relay.QL`
    query {
      ${foo},
      field,
    }
  `

() => {
  {
    {
      {
        return `
line 1
line 2
...
line n
${foo({
  many: keys,
  many: keys
})}
line n + 1
line n + 2
line n + n
`;
      }
    }
  }
}

function save(filename = throw new TypeError("Argument required")) {}

function getEncoder(encoding) {
  const encoder = encoding === "utf8" ? new UTF8Encoder()
                : encoding === "utf16le" ? new UTF16Encoder(false)
                : encoding === "utf16be" ? new UTF16Encoder(true)
                : throw new Error("Unsupported encoding");
}

class Product {
  get id() { return this._id; }
  set id(value) { this._id = value || throw new Error("Invalid value"); }
}

set id(value) { this._id = value || throw new Error("Invalid value"); }

url =>
        url.startsWith("/") || /^[a-z]+:/.test(url) ? url : `/static/${url}`

y => ({
  ...y,
  a: 'very, very, very long very, very long text'
})

y => {
  console.log('very, very, very long very, very long text')
}

function searchUsers(action$) {
  return action$.ofType(ActionTypes.SEARCHED_USERS)
    .map(action => action.payload.query)
    .filter(q => !!q)
    .switchMap(q =>
      Observable.timer(800) // debounce
        .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS))
        .mergeMap(() => Observable.merge(
          Observable.of(replace(`?q=${q}`)),
          ajax.getJSON(`https://api.github.com/search/users?q=${q}`)
            .map(res => res.items)
            .map(receiveUsers)
        ))
    );
}

function mySagas2() {
  return effects.takeEvery(
    rexpress.actionTypes.REQUEST_START,
    function({ id }) {
      console.log(id);
    }
  );
}

class C2 {
  get = () => {}; // The semicolon is *not* necessary
  x(){}
}

class C4 {
  set = () => {}; // The semicolon is *not* necessary
  x(){}
}

class A1 {
  a = 0;
  [b](){}

  c = 0;
  *d(){}

  e = 0;
  [f] = 0

  // none of the semicolons above this comment can be omitted.
  // none of the semicolons below this comment are necessary.

  q() {};
  [h](){}

  p() {};
  *i(){}

  a = 1;
  get ['y']() {}

  a = 1;
  static ['y']() {}

  a = 1;
  set ['z'](z) {}

  a = 1;
  async ['a']() {}

  a = 1;
  async *g() {}

  a = 0;
  b = 1;
}

class A2 {
  a = 0;
  [b](){}

  c = 0;
  *d(){}

  e = 0;
  [f] = 0

  q() {};
  [h](){}

  p() {};
  *i(){}

  a = 1;

  a = 1;

  a = 1;

  a = 1;

  a = 1;

  a = 0;
  b = 1;
}

function test(observable) {
    return observable
        ::filter(data => data.someTest)
        ::throttle(() =>
            interval(10)
                ::take(1)
                ::takeUntil(observable::filter(data => someOtherTest))
        )
        ::map(someFunction);
}

class X {
    this.testLongNameMethodAndSomethingElseLallala = ::this.testLongNameMethodAndSomethingElseLallala;
  }
  
  testLongNameMethodAndSomethingElseLallala() {
  }
}

  }

testLongNameMethodAndSomethingElseLallala() {
  }

class X {
    this.shortMethod = ::this.shortMethod;
  }
  
  shortMethod() {
  }
}

async () => {
    const request = doAsyncThing();
    return (await request)::doSyncThing();
}

  a = await 1 ? 1 : 1;
  a = (await 1) ? 1 : 1;
  a = 1 ? await 1 : await 1;
}

  return observableFromSubscribeFunction()
    // Debounce manually rather than using editor.onDidStopChanging so that the debounce time is
    // configurable.
    .debounceTime(debounceInterval);
}

(data) => crypto.createHash("sha256").update(data).digest("hex")

(data) =>
  crypto // breakme
    .createHash("sha256")
    .update(data)
    .digest("hex")

function palindrome(a, b) {
  return a.slice().reverse().join(',') === b.slice().sort().join(',');
}

  window.FooClient.setVars({
    locale: getFooLocale({ page }),
    authorizationToken: data.token,
  }).initVerify('foo_container');

  fejax.ajax({
    url: '/verification/',
    dataType: 'json',
  }).then(
    (data) => {
      this.setState({ isLoading: false });
      this.initWidget(data);
    },
    (data) => {
      this.logImpression('foo_fetch_error', data);
      Flash.error(I18n.t('offline_identity.foo_issue'));
    },
  );
}

class X {
  y() {
    const j = x.a(this).b(super.cde()).f(/g/).h(new i()).j();
  }
}

y() {
  }

  function b() {
	queryThenMutateDOM(
      () => {
        title = SomeThing.call(root, 'someLongStringThatPushesThisTextReallyFar')[0];
      }
    );
  }
}

function b() {
      () => {
      }
    );
  }

str => {
  const s = str.toLowerCase().replace(/[\W_]/g, '');
  return s === s.split('').reverse().join('');
}

function theFunction(action$, store) {
  return action$.ofType(THE_ACTION).switchMap(action => Observable
    .webSocket({
      url: THE_URL,
      more: stuff(),
      evenMore: stuff({
        value1: true,
        value2: false,
        value3: false
      })
    })
    .filter(data => theFilter(data))
    .map(({ theType, ...data }) => theMap(theType, data))
    .retryWhen(errors => errors));
}

  return this._getWorker(workerOptions)({
    filePath,
    hasteImplModulePath: this._options.hasteImplModulePath,
  }).then(
    metadata => {
      // `1` for truthy values instead of `true` to save cache space.
      fileMetadata[H.VISITED] = 1;
      const metadataId = metadata.id;
      const metadataModule = metadata.module;
      if (metadataId && metadataModule) {
        fileMetadata[H.ID] = metadataId;
        setModule(metadataId, metadataModule);
      }
      fileMetadata[H.DEPENDENCIES] = metadata.dependencies || [];
    }
  );
}

function assert(pet) {
        expect(pet).to.have.property("OwnerAddress").that.deep.equals({
          AddressLine1: "Alexanderstrasse",
          AddressLine2: "",
          PostalCode: "10999",
          Region: "Berlin",
          City: "Berlin",
          Country: "DE"
        });
      }

class A {
  func(id, { blog: { title } }) {
  }
}

function f2() {
  'ngInject';
  Object.assign(this, { $log, $uibModal });
}

function f3() {

}

function f4() {

}

  return {
    // this comment causes the problem
    bar: baz() + 1
  };
}

class C { f(...superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong): void; }

  superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong,
  ...args
) {}

  for await (num of asyncIterable) {
    console.log(num);
  }
  for await (num of asyncGeneratorFunc()) {
  }
}

async function bar2() {
  !(await x);
  !(await x /* foo */);
  !(/* foo */ await x);
  !(
  /* foo */
  await x
  );
  !(
    await x
    /* foo */
  );
  !(
    await x // foo
  );
}

  return (
    <nav>
      <Home />
      {
        do {
          if (loggedIn) {
            <LogoutButton />
          } else {
            <LoginButton />
          }
        }
      }
    </nav>
  );
}

  const appEntities = getAppEntities(loadObject).filter(
    entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled()
  )
}

  const appEntities = getAppEntities(loadObject).map(
    entity => entity && entity.isInstallAvailable() && !entity.isQueue() && entity.isDisabled() && {
      id: entity.id
    }
  )
}

() => {
  const result = doSomething();
  return (
    shouldReturn &&
    result.ok && {
      status: "ok",
      createdAt: result.createdAt,
      updatedAt: result.updatedAt
    }
  );
}

() => {
  return (
    shouldReturn && result.ok && result || {
    }
  );
}

  return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right;
}

function foo2() {
  return this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft.right
    ? true
    : false;
}

function foo3() {
  return this.calculate().compute().first.numberOfThings > this.calculate().compute().last.numberOfThings
    ? true
    : false;
}

class A {
  foobar =
    1 +
    2;
}

class B {
  someInstanceProperty = this.props.foofoofoofoofoofoo &&
    this.props.barbarbarbar;
  
  someInstanceProperty2 = { foo: this.props.foofoofoofoofoofoo &&
    this.props.barbarbarbar };
  
    someInstanceProperty3 =
  "foo";
}

  return (
    <div
      {...{} /*
      // @ts-ignore */ /* prettier-ignore */}
      invalidProp="HelloWorld"
    >
      test
    </div>
  );
}

  var fnString =
    '"' + this.USE + ' ' + this.STRICT + '";\n' +
    this.filterPrefix() +
    'var fn=' + this.generateFunction('fn', 's,l,a,i') +
    extra +
    this.watchFns() +
    'return fn;';

  const identity = Matrix.create(
    1, 0, 0,
    0, 1, 0,
    0, 0, 0
  );

  // Let's make sure that this comment doesn't interfere

  const commentsWithPrettierIgnore =   {
    "ewww":
            "gross-formatting",
  };

  function giveMeSome() {
    a(  a  ); // prettier-ignore
    // shouldn't I return something?  :shrug:
  }

  console.error(
    'In order to use ' + prompt + ', you need to configure a ' +
    'few environment variables to be able to commit to the ' +
    'repository. Follow those steps to get you setup:\n' +
    '\n' +
    'Go to https://github.com/settings/tokens/new\n' +
    ' - Fill "Token description" with "' + prompt + ' for ' +
      repoSlug + '"\n' +
    ' - Check "public_repo"\n' +
    ' - Press "Generate Token"\n' +
    '\n' +
    'In a different tab, go to https://travis-ci.org/' +
      repoSlug + '/settings\n' +
    ' - Make sure "Build only if .travis.yml is present" is ON\n' +
    ' - Fill "Name" with "GITHUB_USER" and "Value" with the name of the ' +
      'account you generated the token with. Press "Add"\n' +
    '\n' +
    'Once this is done, commit anything to the repository to restart ' +
      'Travis and it should work :)'
  );
}

function giveMeSome() {
  }

// prettier-ignore
'use strict';
[].forEach();
}

  var x = 0;
  var y = "...";
  var z = {};
  num(x+x);
  num(x+y); // error
  str(x+y);
  str(x+x); // error
  str(z+y); // error
}

class C {
  bar(n1: number, n2: number): number;
  bar(s1: string, s2: string): string;
}

function foo(c: C, x: any): string {
  let y = x.y;
  return c.bar(0, y); // should be able to select first case and error
}

function bar1(x: mixed) {
  if (any_fun1(x)) {
    (x: boolean);
  }
}

function bar2(x: mixed) {
  if (any_fun2(x)) {
  }
}

function foo(o: ?AsyncRequest) {
  if (o) {
    var n: number = o;
  }
}

() => {
  return (
      <Foo
        // one
        foo={123}
        // two
        bar="woof"
      />
  );
}

items => (
  <div>{ /* eslint-disable */
    	 items.map(item => null)
      /* eslint-enable */    }</div>
)

({ styles }) => (
  <div style={styles} key="something">
    Keep the wrapping parens. Put each key on its own line.
  </div>
)

({ styles }) => <div style={styles} key="something">
  Create wrapping parens.
</div>

({ styles }) => <div style={styles} key="something">Create wrapping parens.</div>

({ styles }) => <div style={styles} key="something">Create wrapping parens and indent <strong>all the things</strong>.</div>

  <div attr1="aaaaaaaaaaaaaaaaa" attr2="bbbbbbbbbbb" attr3="cccccccccccc">
    <div attr1="aaaaaaaaaaaaaaaaa" attr2="bbbbbbbbbbb" attr3="cccccccccccc" attr4>ddd d dd d d dddd dddd <strong>hello</strong></div>
    <div attr1="aaaaaaaaaaaaaaaaa" attr2="bbbbbbbbbbb" attr3="cccccccccccc" attr4>
      <div attr1="aaaaaaaaaaaaaaaaa" attr2="bbbbbbbbbbb" attr3="cccccccccccc" attr4>ddd d dd d d dddd dddd <strong>hello</strong></div> <strong>hello</strong></div>
  </div>
)

() =>
  <div>
    <span /><span>Dont break each elem onto its own line.</span> <span />
    <div /> <div />
  </div>

() => (
  <div>
    <span> <span/> Dont break plz</span>
    <span><span/>Dont break plz</span>
    <span>Dont break plz<span/></span>
  </div>
)

(props) => <div>{props.looooooooooooooooooooooooooooooong_text}</div>

(aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) => this.someLongCallWithParams(aaaaaa, bbbbbbb).anotherLongCallWithParams(cccccccccccc, dddddddddddddddddddddd)

(props) =>
  <BaseForm url="/auth/google" method="GET" colour="blue" size="large" submitLabel="Sign in with Google">
    {props.showTheThing ?
      <BaseForm url="/auth/google" method="GET" colour="blue" size="large" submitLabel="Sign in with Google">Hello world</BaseForm>
      : "hello " + "howdy! "}
      :
      null
    }
    {props.showTheThing ? null :
    }
    {props.showTheOtherThing ? <div>I am here</div> : <div attr="blah" />}
    {props.showTheOtherThing ? <div>I am here!!</div> : null}
  </BaseForm>

function DiffOverview(props) {
  const { source, target, since } = props;
  return (
    <div>
      <div className="alert alert-info">
        <p>
          This diff overview is computed against the current list of records in
          this collection and the list it contained on <b>{humanDate(since)}</b>.
        </p>
        <p>
          <b>Note:</b> <code>last_modified</code> and <code>schema</code> record metadata
          are omitted for easier review.
        </p>
      </div>
      <Diff source={source} target={target} />
    </div>
  );
}

() => {
  return (
    <div>
      Please state your
      {" "}
      <b>name</b>
      {" "}
      and
      {" "}
      <b>occupation</b>
      {" "}
      for the board of directors.
    </div>
  );
}

() => {
  return <div>
    <div>
      bla bla bla
    </div>
  </div>
}

class NonBreakingClass extends React.component {
  render() {
    return (
      <div />
    );
  }
}

render() {
    return <div>
      <div>
        bla bla bla
      </div>
    </div>;
  }

class BreakingClass extends React.component {
  render() {
      <div>
        bla bla bla
      </div>
    </div>;
  }
}

({ users }) => (
  <section>
    <h2>Users list</h2>
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  </section>
)

({ todos }) => (
  <div className="TodoList">
    <ul>{_.map(todos, (todo, i) => <TodoItem key={i} {...todo} />)}</ul>
  </div>
)

  return (
    // prettier-ignore
    /* $FlowFixMe(>=0.53.0) */
    <JSX />
  );
}

}

function C() {
  var o = new B();
  f(o.b);
  f(o.s);
  o.fn();
}

class C extends React.Component {
  foo(): number {
    return this.state.x; // error: need to declare type of state
  }
}

foo(): number {
  }

class JDiv extends React.Component {
  // static defaultProps: { };
  props: {
    id: string
  }

class Example extends React.Component {
  props: { bar: string }

class HelloMessage extends React.Component {
  props: { name: string }

class Foo extends React.Component {
  props: Props;
  state: State;
  static defaultProps: DefaultProps;

  is_mounted: boolean;

  static bar(): void {}

  qux(): void {
    var _: string = this.props.x;
  }

    super(props);
    this.state = { y: "" };
  }

  setState(o: { y_: string }): void { }

  componentDidMount(): void {
    this.is_mounted = true;
  }

  componentWillReceiveProps(
    nextProps: Object,
    nextContext: any
  ): void {
    this.qux();
  }

}

  }

componentWillReceiveProps(
  ): void {
  }

function test(obj: BaseClass): string {
  if (obj instanceof ChildClass) {
    return obj.childProp_TYPO; // error (obj: ChildClass)
  }
  return obj.baseProp;
}

function bar(x:B) {
  if (x instanceof A) {
    x.a();
    x.c(); // error
  } else {
    x++; // TODO no error? since unreachable (x: B implies x: A)
  }
}

function foo(x:A) {
  if (x instanceof C) {
    x.a();
    x.b();
    x.c();
    x.d(); // error
  } else {
    x.a();
  }
}

function baz(x:D) {
    // unreachable, TODO: this shouldn't throw
  }
}

  var c = "...";
  c = new C();
  if (bar()) {
    c.qux();
  }

}

function goofy() {
  var x = g();
  if (typeof x == 'function') {
    x();
  } else { // if (typeof x == 'number') {
    //f(x);
  }
}

function goofy2() {
  var o = {x : 0}
  if (typeof o.x == 'function') {
    o.x();
  }
  var y = o.x;
  if (typeof y == 'function') {
    y();
  } else {
    //f(y);
  }
}

function isActive(ad: {state: $Keys<{
    PAUSED: string;
    ACTIVE: string;
    DELETED: string;
}>}): boolean {
    return ad.state === 'ACTIVE';
}

function isActive2(ad: {state: $Keys<typeof MyStates>}): boolean {
    return ad.state === MyStates.ACTIVE;
}

    array = array.map (function () { return "..."; });
    var x:number = array[0]; // error: string !~> number
}

function g() {
    var foo1 = foo.map (function() { return "..."; });
    var x:number = foo1.get(); // error: string !~> number
    foo = foo1;
}

class NVerbose<E,I:E> {
    x: CovArrayVerbose<E,I>;
    foo(): CovArrayVerbose<mixed,I> { return this.x; }
}

if (x) {
    return {bar: 'baz'};  // OK, because of covariant type param
  }

async function run() {
  console.log(await foo(true));
  console.log(await foo(false));
}

function givesAFoo3Obj(): AliasFoo3 {
  return {
    givesANum(): number { return 42; }

class ClassFoo3 {
  givesANum(): number { return 42; }
  static givesAFoo3(): ClassFoo3 {
    return new ClassFoo3();
  }
}

static givesAFoo3(): ClassFoo3 {
  }

renderComponent(AudienceInsights: ReactClass<*>) {
    return <AudienceInsights />;
  }

render() {
    if (typeof this.props.prop === "string") {
      return <div>{this.props.prop}</div>
    } else {
      return <div>{this.props.prop.toFixed(2)}</div>
    }
  }

switch (this.props.name) {
      case 'a': return 'Bob';
      default: return 'Alice';
    }

render() {
    // But this never errored
    return <div id={this.props.name} />;
  }

m() {
    (this.props.foo: empty); // string ~> empty
    (this.state.foo: empty); // string ~> empty
  }

mm() {
    this.state.foo; // error: property fo not found (called by getInitialState)
  }

getDefaultProps() {
    (this.q: empty); // error: number ~> empty
    return {};
  }

componentWillMount() {
    return 0; // number ~> void
  }

  }

componentWillReceiveProps(nextProps) {
    (nextProps.foo: empty); // string ~> empty
  }

shouldComponentUpdate(nextProps, nextState) {
    (this.state.bar: empty); // number ~> empty
    (nextState.bar: empty); // number ~> empty
    return 0; // number ~> bool
  }

componentWillUpdate(nextProps, nextState) {
  }

componentDidUpdate(nextProps, nextState) {
  }

  }

foo(props, propName, componentName, href) {
      (props: empty); // ok: props is `any`
      (propName: empty); // error: propName is a string
      (componentName: empty); // error: componentName is a string
      (href: empty); // error: href is an optional string
      return (0: mixed); // error: should return ?Error
    }

  render() {
    const Cmp = Math.random() < 0.5 ? 'div' : Bar;
    return (<Cmp/>);
  }
}

render() {
  }

class Bar extends React.Component {
  props: {
    test: number,
  }

m() {
    (this.props.x.x: empty); // OK, T instantiated to `any`
  }

function f0() {
  var v = x * c;  // errors, let + const referenced before decl
  let x = 0;
  const c = 0;
}

function f1(b) {
  x = 10;         // error, attempt to write to let before decl
  let x = 0;
  if (b) {
    y = 10;       // error, attempt to write to let before decl
    let y = 0;
  }
}

  {
    var v = x * c; // errors, let + const referenced before decl
  }
  let x = 0;
  const c = 0;
}

  var s: string = foo();          // ok, finds hoisted outer
  {
    var n: number = foo();        // ok, finds hoisted inner
    function foo() { return 0; }
  }
  var s2: string = foo();         // ok, hoisted outer not clobbered
  function foo() { return ""; }
}

  function g() { return x + c; }  // ok, g doesn't run in TDZ
  let x = 0;
  const c = 0;
}

function f5() {
  function g() { return x; }
  g();          // should error, but doesn't currently
  let x = 0;
  const c = 0;
}

function block_scope() {
  let a: number = 0;
  var b: number = 0;
  {
    let a = ""; // ok: local to block
    var b = ""; // error: string ~> number
  }
}

function switch_scope(x: string) {
  switch (x) {
    case "foo":
      let a = ""; // ok: local to switch
      var b = ""; // error: string ~> number
      break;
    case "bar":
      let a = ""; // error: a already bound in switch
      break;
  }
}

function switch_scope2(x: number) {
    case 0:
     a = "";     // error: assign before declaration
     break;
    case 1:
     var b = a;  // error: use before declaration
     break;
    case 2:
      let a = "";
      break;
    case 3:
      a = "";     // error: skipped initializer
      break;
    case 4:
      var c:string = a;  // error: skipped initializer
      break;
  }
  a = ""; // error: a no longer in scope
}

function try_scope() {
  try {
    let a = ""; // ok
  } finally {
  }
}

function for_scope_let() {
  for (let a = "" /* ok: local to init */;;) {}
}

function for_scope_var() {
  var a: number = 0;
  for (var a = "" /* error: string ~> number */;;) {}
}

function for_in_scope_let(o: Object) {
  for (let a /* ok: local to init */ in o) {}
}

function for_in_scope_var(o: Object) {
  for (var a /* error: string ~> number */ in o) {}
}

function for_of_scope_let(xs: string[]) {
  for (let a /* ok: local to init */ of xs) {}
}

function for_of_scope_var(xs: string[]) {
  for (var a /* error: string ~> number */ of xs) {}
}

function f0(x = () => a): number {
    let a = 0;
    return x(); // error: string ~> number
  }

function f1(x = b /* error: cannot resolve b */): number {
    let b = 0;
    return x;
  }

function type_type() {
  type A = number;
  type A = number;  // error: name already bound
}

function type_class() {
  class A {}        // error: name already bound
}

function type_let() {
  let A = 0;        // error: name already bound
}

function type_const() {
  const A = 0;     // error: name already bound
}

function type_var() {
  var A = 0;        // error: name already bound
}

function type_reassign() {
  A = 42;           // error: type alias ref'd from value pos
}

function class_type() {
  class A {}
}

function class_class() {
  class A {}
}

function class_let() {
  class A {}
}

function class_const() {
  class A {}
}

function class_var() {
  class A {}
}

function let_type() {
  let A = 0;
}

function let_class() {
  let A = 0;
}

function let_let() {
  let A = 0;
}

function let_const() {
  let A = 0;
}

function let_var() {
  let A = 0;
}

function const_type() {
  const A = 0;
}

function const_class() {
  const A = 0;
}

function const_let() {
  const A = 0;
}

function const_const() {
  const A = 0;
}

function const_var() {
  const A = 0;
}

function const_reassign() {
  const A = 0;
  A = 42;           // error: cannot be reassigned
}

function var_type() {
  var A = 0;
}

function var_class() {
  var A = 0;
}

function var_let() {
  var A = 0;
}

function var_const() {
  var A = 0;
  const A = 0;      // error: name already bound
}

function function_toplevel() {
  function a() {};
  function a() {}; // OK
}

function function_block() {
  {
    function a() {};
    function a() {}; // error: name already bound
  }
}

function var_shadow_nested_scope() {
  {
    let x = 0;
    {
      var x = 0; // error: name already bound
    }
  }
}

function type_shadow_nested_scope() {
  {
    let x = 0;
    {
      type x = string; // error: name already bound
    }
  }
}

function fn_params_name_clash(x, x /* error: x already bound */) {}

function fn_params_clash_fn_binding(x,y) {
  let x = 0; // error: x already bound
  var y = 0; // OK
}

class C5 {
  m() { }
  get m() { return 42; }
  set m(x: number) { }
}

function foo(): AImplementation { return new AImplementation(); }

class MyReactThing extends React.Component {
  getFoo(): number { return this.props.foo; }
}

function func1(f) {
  function fix_f(x:number):number { return f(x); }
  return fix_f;
}

function func2(f) {
  function fix_f(x:string):string { return f(x); }
}

function fix(fold) {
  var delta = function(delta) {
    return fold(
      function(x) { var eta = delta(delta); return eta(x); }
    );
  };
  return delta(delta);
}

function mk_factorial() {
  return fix(function(factorial) {
    return function(n) {
      if (eq (n, 1)) { return 1; }
      return mul (factorial (sub (n, 1)), n);
    };
  });
}

class MyClass2<T, U = string> {
  x: T;
  y: U;
  constructor(x: T, y: U) {
    this.x = x;
    this.y = y;
  }
}

class MySubclass extends MyClass { // ok, type arg inferred
  y: number;
  constructor(y: number) {
    super(y);
  }
}

function subtyping(
  v1: Variance<A,B>,
  v2: Variance<B,A>
) {
  (v1: Variance<B,A>); // error on both targs (A ~/~> B)
  (v2: Variance<A,B>); // OK for both targs (B ~> A)
}

class StaticOverload {
  static foo(x: number): number;
  static foo(x: string): string;
}

function f5(x: mixed): %checks (x !== null) { return x !== null }

function foo(x: boolean) {
  var ii = 10;
  while (ii-- >= 0) {
    if (x) {
      continue;
    }
    return;
  }
  //console.log('this is still reachable');
}

function bar(x: boolean) {
  var ii = 0;
  while (ii > 0) {
    return;
  }
}

class C {
    static x: number;
    static foo(x: number): void;

    constructor(x: string): void;
}

function callback(arr: Array<MutationRecord>, observer: MutationObserver): void {
  return;
}

class A {
  _property1: number;
  static _sProperty: number;

    this._property1 = 5;
  }
  _method1(): number {
    return 1;
  }
  static _sMethod(): string {
    return "some string";
  }
}

    super();
    this._property1 = "another string";
  }

class B extends A {
  _property1: string;
  static _sProperty: string;

    super();
  }
  _method1(): string {
    return "yet another string";
  }
  static _sMethod(): number {
    return 23;
  }
}

  foo(x:A):A { return x; }
  bar(x) { }
  qux<X,Y>(x:X,y:Y):X { return x;}
}

function hasObjectMode_bad(options: DuplexStreamOptions): boolean {
  return options.objectMode
    || options.readableObjectMode
    || options.writableObjectMode; // error, undefined ~> boolean
}

function hasObjectMode_ok(options: DuplexStreamOptions): boolean {
  return !!(options.objectMode
    || options.writableObjectMode);
}

function funWithRestArray(x: 'hi', y: 123, ...rest: Array<number>) {}

function x0(y: string): number {
  return +y; // ok, + exists solely for coercion
}

function x1(y: string): number {
  return -y; // error, we don't allow coercion here
}

function x3(y: string) {
  return ~y;  // error, we don't allow coercion here
}

function x4(y: string): boolean {
  return !y; // ok, coercion is allowed
}

class CustomComponent extends React.Component {
  props: {
    prop: string
  }

function switch_scope(x: mixed) {
  let a = "";
  let b = "";
      let a;
      a = 0; // doesn't add lower bound to outer a
      b = 0;
  }
  (a : string); // OK
  (b : string); // error: number ~> string
}

function try_scope_finally() {
  let a;
  let b;
  try {
    a = "";
    b = "";
  } finally {
    let a;
    a = 0; // doesn't add lower bound to outer a
    b = 0;
  }
  (a : string); // ok
}

function for_scope() {
  let a = "";
  let b = "";
  for (let a;;) {
    b = 0;
  }
  (a : string);
}

function for_in_scope(o: Object) {
  let a = 0;
  let b = 0;
  for (let a in o) {
    a = ""; // doesn't add lower bound to outer a
    b = "";
  }
  (a : number);
  (b : number); // error: string ~> number
}

function for_of_scope(xs: number[]) {
  let a = "";
  let b = "";
  for (let a of xs) {
    b = 0;
  }
}

function sorry(really: bool) {
    if (really) {
        var x: number | string = 1337;
    } else {
        var x: bool = true;
    }
    foo(x);
}

function foo0(b: bool): number {
  var x = 0;
  if (b) {
    var x = ""; // error: string ~> number
  }
  return x;
}

function f(x : $Tainted<string>, y : $Tainted<number>) {
  var z : $Tainted<bool> = x < y;
}

function f1(x : string, y : $Tainted<number>) {
}

function f2(x : $Tainted<string>, y : number) {
}

function f3(x : $Tainted<string>, y : string) {
  var z : bool = x < y;
}

function foo(x : $Tainted<string>, o : Object) {
  // Error
  o.f(x);
}

function foo1(x : $Tainted<string>, o : {f : (y : $Tainted<string>) => void}) {
  o.f(x);
}

function foo2(o1 : Object, o2 : {t : $Tainted<string>}) {
  o1.f(o2.t);
}

function f(x : $Tainted<number>, y : $Tainted<number>) {
  var z : $Tainted<number> = x + y;
}

function f1(x : $Tainted<number>, y : number) {
}

function f2(x : number, y : $Tainted<number>) {
}

function f3(x : $Tainted<number>, y : number) {
  var z : number = x + y;
}

function f4(x : number, y : $Tainted<number>) {
}

function f5(x : number, y : $Tainted<number>) {
  var z : string = x + y;
}

function f6(x : string, y : $Tainted<number>) {
}

function f7(x : $Tainted<string>, y : $Tainted<number>) {
}

class A {
  f(x : $Tainted<FakeLocation>) {
    fakeDocument.location = x; // error
    doStuff(x); // ok
  }
  f1(x : $Tainted<FakeLocation>) {
    // TODO(rcastano): should cause an error.
    window.fakeLocation = x;
  }
}

f(x : $Tainted<FakeLocation>) {
  }

f1(x : $Tainted<FakeLocation>) {
  }

class A {
  f(tainted : $Tainted<string>) {
    // This *should* give a warning.
    fakeDocument.location.assign(tainted);
  }
}

f(tainted : $Tainted<string>) {
  }

class A {
    // This shouldn't give a warning (both are tainted)
    var also_tainted : $Tainted<string> = tainted;
  }
}

  }

class A {
    // The Tainted annotation should still flow.
    var safe = tainted;
    // This should give a warning.
    var loc : string = safe;
  }
}

  }

function foo (x : $Tainted<number>) {
  var should_fail : number = x * 42;
}

function foo1 (x : $Tainted<{f: number}>) {
  var ok : number = x.f;
}

function foo2 (o : {f (y:number):number}, t: $Tainted<number>) {
  return o.f(t);
}

function foo3 (x : $Tainted<{f: number}>) {
  var also_tainted : $Tainted<number> = x.f;
}

function foo4 (a : $Tainted<Array<string>>) {
  var trusted : string = a[0];
}

function foo5 (a : $Tainted<Array<string>>) {
  var trusted_number : number = a[0];
}

function foo6 (a : $Tainted<Array<string>>) {
  var trusted : $Tainted<string> = a[0];
}

class D extends C {
  foo() { this.override() }
  bar() { this.override }
  override() { }
}

class Foo {
  get a(): number;
  set b(x: number): void;
  c: 10;
}

class Bar {
  get a() { return 4; }
  set b(x: number) { this.c = x; }
  c: number;
  get ['d']() { return 'foo'; }
  set ['d'](x: number) {}
}

class B extends A<string, number, bool> {}
class C<X, Y, Z> extends B {}

function bar() {
  a = a.concat([]); // terminate despite expanding types:
  // a ~> .concat(Array<Y>)
  // Array<X> ~> .concat(Array<Y>)
  // Array<X|Y> ~> a
  // Array<X|Y> ~> .concat(Array<Y>)
  // Array<X|Y|Y> ~> a
}

function foo(x: ?string): $NonMaybeType<?string> {
  if (x != null) { return x; }
  else return 0; // this should be an error
}

function testKeysOfObject(str: string, lit: 'hi') {
  (str: $Keys<Object>); // Any string should be fine
  if (str) {
    (str: $Keys<Object>); // No error, truthy string should be fine
  }
  ('hi': $Keys<Object>); // String literal should be fine

  (123: $Keys<Object>); // Error: number -> keys of Object
}

function testKeysOfStrDict(str: string, lit: 'hi') {
  (str: $Keys<StrDict>); // Any string should be fine
  if (str) {
    (str: $Keys<StrDict>); // No error, truthy string should be fine
  }
  ('hi': $Keys<StrDict>); // String literal should be fine

  (123: $Keys<StrDict>); // Error: number -> keys of StrDict
}

function testKeysOfStrLitDict(str: string, lit: 'hi') {
  (str: $Keys<StrLitDict>); // Error: Not all strings are allowed
  if (str) {
    (str: $Keys<StrLitDict>); // Error: Not all truthy strings are allowed
  }
  ('hi': $Keys<StrLitDict>); // The right string literal is allowed
  ('bye': $Keys<StrLitDict>); // Error: The wrong string literal is not allowed

  (123: $Keys<StrLitDict>); // Error: number -> keys of StrLitDict
}

function testKeysOfOtherObj(str: string, lit: 'hi') {
  (str: $Keys<ObjLit>); // Error: string -> keys of ObjLit
  if (str) {
    (str: $Keys<ObjLit>); // Error: truthy string -> keys of ObjLit
  }
  ('hi': $Keys<ObjLit>); // String literal should be fine

  (123: $Keys<ObjLit>); // Error: number -> keys of ObjLit
}

function is_string(y): %checks {
  return typeof y === "string";
}

function is_bool(y): %checks {
  return typeof y === "boolean";
}

function is_number(y): %checks {
  return typeof y === "number";
}

function check(y): %checks(typeof y === "string") {
}

function indirect_is_number(y): %checks {
  var y = 1;
}

function multi_param(w,x,y,z): %checks {
  return typeof z === "string";
}

if (is_string(x)) {
    // The use of `is_string` as a conditional check
    // should guarantee the narrowing of the type of `x`
    // to string.
    return x;
  }

function dotAccess(head, create) {
  const path = 'path.location';
  const stack = path.split('.');
  do {
    const key = stack.shift();
    head = head[key] || create && (head[key] = {});
  } while (stack.length && head);
  return head;
}

class A {

    b: string;

    c(d = this.b) { // ok - can use `this` in function default parameter values

    }

    e() {
        return this.b;
    }

    f(g = this.e()) { // ok - can use `this` in function default parameter values

    }

    h(i: number = this.b) { // error

    }

}

c(d = this.b) { // ok - can use `this` in function default parameter values

    }

f(g = this.e()) { // ok - can use `this` in function default parameter values

    }

function consumer1(b) {
    var g = x(b);
    if (g instanceof X2) g.foo = '1337';
    else g.foo = 1337;
}

function consumer2(b) {
    if (g instanceof X1) g.foo = '1337';  // oops
}

function consumer3(b) {
    var g = y(b);
    if (g.bar instanceof X2) g.bar.foo = '1337';
    else g.bar.foo = 1337;
}

function consumer4(b) {
    if (g.bar instanceof X1) g.bar.foo = '1337';  // oops
}

function consumer5(b) {
    var g = z(b);
    if (g.baz.bar instanceof X2) g.baz.bar.foo = '1337';
    else g.baz.bar.foo = 1337;
}

function consumer6(b) {
    if (g.baz.bar instanceof X1) g.baz.bar.foo = '1337';  // oops
}

class C {
  m() {
    if (this instanceof D)
      alert(this.s);
    else
      alert("nope");
  }
}

m() {
    else
  }

  s: string;
    super();
    this.s = "yup";
  }
}

function foo0(x: Array<number> | number) {
  if (x instanceof Array) {
    x[0] = 123;
  } else {
    x++;
  }
}

function foo1(x: Array<number> | number) {
    x++; // error
  } else {
    x[0] = 123; // error
  }
}

class Foo extends mixin(Bar) {
  m() {
    var x: string = this.x;
    this.y = "";
  }
}

class A {
  static x: number;
  static y: string;
  static foo(x: number) { }
  static bar(y: string) { }
}

static foo(): string {
    this.bar(); // error
    return this.x; // error
  }

  static x: string; // error?
  static foo(x: string) { } // error?
  static main() {
    B.x = 0; // error
    B.x = "";
    B.foo(0); // error
    B.foo("");
    B.y = 0; // error
    B.bar(0); // error
    B.qux(0); // error
  }
  static create(): A {
    return new this();
  }

  static badCreate(): number {
    return new this(); // error B ~> number
  }
}

static main() {
    B.x = "";
  }

static badCreate(): number {
  }

@decorator4
class Foo {
  @decorator1
  method1() {}

  @decorator2
  @decorator3
  method2() {}
}

function f(b): React.Element<*> {
  if (b) {
    return <A foo="hey"/>;
  } else {
    return <B bar="hey"/>;
  }
}

function propTest5(y: {[key: string]: string}) {
  (y: IHasXString); // OK
}

function propTest6(y: {[key: string]: number}) {
  (y: IHasXString); // error: string != number
}

function set_prop_to_string_key(
  o: {[k:string]:any},
) {
  o.prop = "ok";
}

function unsound_dict_has_every_key(
  o: {[k:string]:X},
) {
  (o.p: X); // ok
  (o["p"]: X); // ok
}

function set_prop_covariant(
  o: {[k:string]:B},
) {
  o.p = new A; // error, A ~> B
  o.p = new B; // ok
  o.p = new C; // ok
}

function get_prop_contravariant(
) {
  (o.p: A); // ok
  (o.p: B); // ok
  (o.p: C); // error, C ~> B
}

function add_prop_to_nonstring_key_dot(
  o: {[k:number]:any},
) {
  o.prop = "err"; // error: string ~> number
}

function add_prop_to_nonstring_key_bracket(
) {
  o[0] = "ok";
}

function mix_with_declared_props(
  o: {[k:number]:X,p:Y},
  x: X,
  y: Y,
) {
  (o[0]: X); // ok
  (o.p: Y); // ok
  o[0] = x; // ok
  o.p = y; // ok
}

function object_prototype(
  o: {[k:string]:number},
): {[k:string]:number, +toString: () => string}

function unsound_string_conversion_alias_declared_prop(
  o: {[k:number]:any, "0":X},
) {
  o[0] = "not-x"; // a["0"] no longer X
}

function unification_dict_values_invariant(
  x: Array<{[k:string]:B}>,
) {
  let a: Array<{[k:string]:A}> = x; // error
  a[0].p = new A; // in[0].p no longer B

  let b: Array<{[k:string]:B}> = x; // ok

  let c: Array<{[k:string]:C}> = x; // error
  (x[0].p: C); // not true
}

function subtype_dict_values_invariant(
  x: {[k:string]:B},
) {
  let a: {[k:string]:A} = x; // error
  a.p = new A; // x[0].p no longer B

  let b: {[k:string]:B} = x; // ok

  let c: {[k:string]:C} = x; // error
  (x.p: C); // not true
}

function subtype_dict_values_fresh_exception() {
  let a: {[k:string]:A} = {
    a: new A, // ok, A == A
    b: new B, // ok, B <: A
    c: new C, // ok, C <: A
  };

  let b: {[k:string]:B} = {
    a: new A, // error, A not <: B
    b: new B, // ok, B == B
  };

  let c: {[k:string]:C} = {
    a: new A, // error, A not <: C
    b: new B, // error, A not <: C
    c: new C, // ok, C == C
  };
}

function unification_dict_keys_invariant(
  x: Array<{[k:B]:any}>,
) {
  let a: Array<{[k:A]:any}> = x; // error
  let b: Array<{[k:B]:any}> = x; // ok
  let c: Array<{[k:C]:any}> = x; // error
}

function subtype_dict_keys_invariant(
  x: {[k:B]:any},
) {
  let a: {[k:A]:any} = x; // error
  let b: {[k:B]:any} = x; // ok
  let c: {[k:C]:any} = x; // error
}

function unification_mix_with_declared_props_invariant_l(
) {
  let a: Array<{[k:string]:B, p:A}> = x; // error: A ~> B
  a[0].p = new A; // x[0].p no longer B

  let b: Array<{[k:string]:B, p:B}> = x; // ok

  let c: Array<{[k:string]:B, p:C}> = x; // error
}

function unification_mix_with_declared_props_invariant_r(
  xa: Array<{[k:string]:A, p:B}>,
  xb: Array<{[k:string]:B, p:B}>,
  xc: Array<{[k:string]:C, p:B}>,
) {
  let a: Array<{[k:string]:A}> = xa; // error
  a[0].p = new A; // xa[0].p no longer B

  let b: Array<{[k:string]:B}> = xb; // ok

  let c: Array<{[k:string]:C}> = xc; // error
  (xc[0].p: C); // not true
}

function subtype_mix_with_declared_props_invariant_l(
) {
  let a: {[k:string]:B, p:A} = x; // error: A ~> B
  a.p = new A; // x.p no longer B

  let b: {[k:string]:B, p:B} = x; // ok

  let c: {[k:string]:B, p:C} = x; // error
}

function subtype_mix_with_declared_props_invariant_r(
  xa: {[k:string]:A, p:B},
  xb: {[k:string]:B, p:B},
  xc: {[k:string]:C, p:B},
) {
  let a: {[k:string]:A} = xa; // error
  a.p = new A; // xa.p no longer B

  let b: {[k:string]:B} = xb; // ok

  let c: {[k:string]:C} = xc; // error
  (xc.p: C); // not true
}

function subtype_dict_to_obj(
) {
  let a: {p:A} = x; // error

  let b: {p:B} = x; // ok

  let c: {p:C} = x; // error
}

function subtype_obj_to_dict(
  x: {p:B},
) {

  let b: {[k:string]:B} = x;

}

function subtype_obj_to_mixed(
  x: {p:B, x:X},
) {
  let a: {[k:string]:A,x:X} = x; // error (as above), but exclusive of x
  let b: {[k:string]:B,x:X} = x; // ok,
  let c: {[k:string]:C,x:X} = x; // error (as above), but exclusive of x
}

function unification_dict_to_mixed(
) {
  let a: Array<{[k:string]:B, p:A}> = x; // error
}

function subtype_dict_to_mixed(
) {
  let a: {[k:string]:B, p:A} = x; // error
}

function subtype_dict_to_optional_a(
) {
  let a: {p?:A}

function subtype_dict_to_optional_b(
) {
  let b: {p?:B}

function subtype_dict_to_optional_c(
) {
  let c: {p?:C}

foo(params) {
    return params.count; // error, number ~/~ string
  }

function test1(): string {
  return bar();

  function bar() {
    return 0;
  }
}

  const n = 0;

  return;

  function f() {
    var x: typeof n = 0;  // no error, n is still number
    var y: string = n;    // error, n is number (EmptyT would work)
  }
}

  }

function foo(x, y) {
  "use strict";
  return bar(x) + baz(y);

  // function declaration is hoisted, should not generate warning
  function bar (ecks) {
    return x + ecks;
  }

  // assignment is not hoisted, should generate warning
  var baz = function (why) {
    return y + why;
  };

  // variable declaration is hoisted, should not generate warning
  var x, y, z;

  // assignments are not hoisted, should generate 2 warnings
  var t,
      u = 5,
      v,
      w = 7;
}

function block_scope(x: string | number) {
  {
    let x;
    x = ""; // doesn't refine outer x
  }
  (x : string); // error: number ~> string
}

function switch_scope(x: string | number) {
    default:
      let x;
      x = ""; // doesn't refine outer x
  }
}

function try_scope(x: string | number) {
  try {
    let x;
    x = ""; // refinement would only escape if both sides refined
  }
}

function try_scope_catch(x: string | number) {
  try {
    let x;
  }
}

class A {
  p: ?string;

  ensure0(): string {
    if (typeof this.p == "string")
      return this.p;
    else
      return "";
  }

  ensure1(): string {
    if (typeof this.p != "string")
      return "";
    else
     return this.p;
  }

  ensure2(): string | void {
    if (typeof this.p === "string")
    else
      return "";
  }

  ensure3(): string | void {
    if (typeof this.p !== "string")
      return "";
    else
  }
}

ensure0(): string {
    else
      return "";
  }

ensure1(): string {
      return "";
    else
  }

ensure2(): string | void {
    else
      return "";
  }

ensure3(): string | void {
      return "";
    else
  }

class A {

    if (this.p !== void(0) && this.p !== null)
    else
      return "";
  }

    if (this.p === void(0) || this.p === null)
      return "";
    else
  }
}

    else
      return "";
  }

      return "";
    else
  }

class C {

    if (this.p != null)
    else
      return "";
  }

    if (this.p == null)
      return "";
    return this.p;
  }

    if (this.p !== null)
    else
      return "";
  }

    if (this.p === null)
      return "";
  }
}

    else
      return "";
  }

      return "";
  }

    else
      return "";
  }

      return "";
  }

  ensure100(): string {
    if (super.p != null)
      return super.p;
    else
      return "";
  }

  ensure101(): string {
    if (super.p == null)
      return "";
    else
  }

  ensure103(): string {
    if (super.p != null) {
      alert("");
      return super.p;  // not ok
    }
    return "";
  }
}

ensure100(): string {
    else
      return "";
  }

ensure101(): string {
      return "";
    else
  }

ensure103(): string {
    }
    return "";
  }

class A {

    if (this.p !== undefined && this.p !== null)
    else
      return "";
  }

    if (this.p === undefined || this.p === null)
      return "";
    else
  }
}

    else
      return "";
  }

      return "";
    else
  }

function foo(a,b,c) {
  switch (c) {
  case a.x.y: // OK
  case b.x.y: // OK
    return;
  default:
    return;
  }
}

function exhaustion1(x): number {
  var foo;
  case 0: // falls through
  case 1:
    foo = 3;
    break;
  default:
    throw new Error('Invalid state');
  }
  return foo; // no error
}

function exhaustion2(x, y): number {
  var foo;
  case 0:
    if (y) {
      break;  // leaks uninitialized foo out of switch
    }
    /**
     * TODO this shouldn't cause an error, because the path that
     * runs it will always go on to assign a number to foo. But
     * we'll need true isolation in env snapshots to model this.
     * Currently tvars are always shared between clones - we'd
     * have to rework envs pretty extensively to avoid it.
     *
    foo = "";
     */
  case 1:
    foo = 3;
    break;
  default:
  }
  return foo; // error, possibly uninitialized
}

function exhaustion3(x): number {
  let foo = null;
  case 1:
    foo = 3;
    break;
  default:
  }
}

function foo(b) {
    var x = b? 0 : null;
    while (typeof x == "string" || typeof x == "number") {
        var y:string = x;
        x = false;
    }
    var z:string = x;
}

function bar(b) {
    do {
        x = false;
    } while (x === null);
}

function qux() {
    var x = 0;
    try {
        maybe_throw();
        x = "hello";
    } finally {
        // NOTE: the values understood to flow to x at this point
        // include the number 42 written downstream;
        // so if we did y:string, we would get at least a spurious error
        // (among other reasonable errors caused by values written upstream)
        var y:number = x;
        x = 42;
    }
}

function corge(b) {
    for (var x = b? 0 : null;
         typeof x == "string" || typeof x == "number";
         x = false) {
    }
}

function waldo() {
    var o = {};
    var x = false;
    for (x in o) {
        x = 0; // commenting this out would propagate x:string downstream
    }
    var z:number = x;
}

function global_in_conditional0(x: number) {
    // merge_env
    if (x != 0) {
        if (BAZ) {
        }
    }
}

function global_in_conditional2(x: number) {
    // copy_env
    for (var i = 0; i < 100; i++) {
        if (BAZ) {
        }
    }
}

function testProperty(a: A) {
  if (a.b_c) {
    stuff(a.b_c)
  }
}

function testLiteralProperty(a: A) {
  if (a['b_c']) {
    stuff(a['b_c'])
  }
}

function foo(x: ?bool) {
  if (x === false) {
    return;
  }

  if (x === true) {
    return;
  }

  x[0]; // error on null and undefined
}

function bar(x: ?bool) {
  if (x !== true) {
    if (x !== false) {
      x[0]; // error on null and undefined
    }
  }
}

function baz(x: ?bool) {
  if (100 * false) {
    return;
  }
  if (false * 100) {
    return;
  }
}

class A {
  prop: string;
  method(): string {
    return "A";
  }
}

class B {
  test(): string {
    if (super.prop) { // super.prop doesn't exist
      return super.prop; // error, unknown type passed to string expected
    }
    return "B";
  }
}

test(): string {
    }
  }

    if (super.prop) {
      return super.prop; // OK
    }
    return "C";
  }

class C extends A {
    }
  }
}

function void_var(x: ?number) {
  if (x !== null && x !== void(0)) {
    var y = x * 1000;
  }
}

function void_var_rev(x: ?number) {
  if (x === null || x === void(0)) {
  } else {
  }
}

function void_pro(x: { x: ?number }) {
  if (x.x !== null && x.x !== void(0)) {
    var y = x.x * 1000;
  }
}

function void_pro_rev(x: { x: ?number }) {
  if (x.x === null || x.x === void(0)) {
  } else {
  }
}

function void_var_fail(x: ?number) {
  if (x !== void(0)) {
  }
}

function void_var_fail_rev(x: ?number) {
  if (x === void(0)) {
  } else {
  }
}

function void_pro_fail(x: { x: ?number }) {
  if (x.x !== void(0)) {
  }
}

function void_pro_fail_rev(x: { x: ?number }) {
  if (x.x === void(0)) {
  } else {
  }
}

function void_var_side_effect(x: ?number) {
  if (x !== null && x !== void(x * 1000)) {
  }
}

function void_var_side_effect_rev(x: ?number) {
  if (x === null || x === void(x * 1000)) {
  } else {
  }
}

function void_prop_side_effect(x: { x: ?number }) {
  if (x.x !== null && x.x !== void(x.x * 1000)) {
  }
}

function void_prop_side_effect_rev(x: { x: ?number }) {
  if (x.x === null || x.x === void(x.x * 1000)) {
  } else {
  }
}

function void_bogus_comparison() {
  if (100 * void(0)) {
    return;
  }
  if (void(0) * 100) {
    return;
  }
}

function void_redefined_undefined(x: ?number) {
  var undefined = "foo";
  }
}

function handleStatus(status: Success | Error) {
  switch(status.type) {
    case SUCCESS:
      console.log(`Successful: ${status.message}`);
      break;
    default:
      console.log(`Errored: ${status.error}`);
  }
}

function def_assign_function_havoc(obj: Obj) {
    obj.p = 10;                 // (obj.p : number)
    f();                        // clears refi
    var x: number = obj.p;      // error, obj.p : number | string
}

function def_assign_setprop_havoc(obj: Obj, obj2: Obj) {
    obj2.p = 'hey';             // clears refi
}

function def_assign_index_havoc(obj: Obj, obj2: Obj) {
    obj2['p'] = 'hey';          // clears refi
}

function def_assign_within_if(b: boolean, obj: Obj) {
    if (b) {
        obj.p = 10;             // (obj.p : number)
        var x: number = obj.p   // ok by def assign
    }
    var y: number = obj.p;      // error, obj.p : number | string
}

function def_assign_within_while(b: boolean, obj: Obj) {
    while (b) {
    }
}

function def_assign_within_do(b: boolean, obj: Obj) {
    do {
    } while (b);
    var y: number = obj.p;      // no error, loop runs at least once
}

function def_assign_within_try(b: boolean, obj: Obj) {
    try {
        f();                    // clears refi and might throw
        obj.p = 'hey';
    } finally {
        // NOTE: the values understood to flow to obj.p at this point
        var y: number = obj.p;  // error, string ~/~ number
        obj.p = 42;
    }
    var z:string = obj.p;       // error, number ~/~ string
}

function def_assign_within_for(b: boolean, obj: Obj) {
    for (; b; ) {
    }
    var z: number = obj.p;      // error, (number | string) ~/~ number
}

function def_assign_setprop_nohavoc(obj: Obj, obj2: Obj2) {
    obj2.q = 'hey';             // doesn't clear refi of .p
    var x: number = obj.p;      // still ok
}

function foo(x: bool | number) {
  if (typeof x === "boolean") {
    x[0]; // error for boolean, not number
  }
}

function bar(): number {
  var x = null;
  if (typeof x === "object") {
    return x; // error, null
  }
  return 0;
}

function fn0() {
  if (typeof BAZ !== 'undefined' &&
      typeof BAZ.stuff === 'function') {
    BAZ.stuff(123);
  }
  BAZ.stuff(123); // error, refinement is gone
}

function fn1() {
  BAZ.stuff; // error, could be undefined
    BAZ.stuff(123); // ok
    BAZ.stuff(123); // error, refinement is gone
  }
}

function undef_var(x: ?number) {
  if (x !== null && x !== undefined) {
  }
}

function undef_var_rev(x: ?number) {
  if (x === null || x === undefined) {
  } else {
  }
}

function undef_prop(x: { x: ?number }) {
  if (x.x !== null && x.x !== undefined) {
  }
}

function undef_prop_rev(x: { x: ?number }) {
  if (x.x === null || x.x === undefined) {
  } else {
  }
}

function undef_var_fail(x: ?number) {
  if (x !== undefined) {
  }
}

function undef_var_fail_rev(x: ?number) {
  if (x === undefined) {
  } else {
  }
}

function undef_prop_fail(x: { x: ?number }) {
  if (x.x !== undefined) {
  }
}

function undef_prop_fail_rev(x: { x: ?number }) {
  if (x.x === undefined) {
  } else {
  }
}

function undef_unreachable(x: number) {
    var y = x * 1000; // unreachable
  }
  if (x == undefined) {
    var z = x * 1000; // unreachable
  }
}

function undef_var_nonstrict(x: ?number, y: ?number) {
  if (x != undefined) {
    var a = x * 1000;
  }
  if (y == undefined){
    var b = y * 1000; // error
  }
}

function undef_bogus_comparison() {
  if (100 * undefined) {
    return;
  }
  if (undefined * 100) {
    return;
  }
}

function num(x: mixed) {
  if (typeof x === "number") {
    takesString(x); // error
    (!x: false); // error: we don't know the truthiness of x
  }
  if (typeof x === "number" && x) {
    (!x: false); // ok
  }
  if (x && typeof x === "number") {
  }
}

function str(x: mixed) {
  if (typeof x === "string") {
    takesNumber(x); // error
  }
  if (typeof x === "string" && x) {
  }
  if (x && typeof x === "string") {
  }
}

function bool(x: mixed) {
    (x: true); // error: we don't know the truthiness of x
  }
  if (typeof x === "boolean" && x) {
    (x: true); // ok
  }
  if (x && typeof x === "boolean") {
  }
}

function fun(x: mixed) {
  if (typeof x === "function") {
  }
}

function obj0(x: mixed) {
  }
}

function obj1(x: mixed) {
  if (Array.isArray(x)) {
  }
}

function undef(x: mixed) {
  if (typeof x === "undefined") {
  }
}

function null_(x: mixed) {
  if (x === null) {
  }
}

function maybe(x: mixed) {
  if (x == null) {
  }
}

function true_(x: mixed) {
  }
}

function false_(x: mixed) {
  }
}

function obj2(x: mixed) {
  if (typeof x === "object" && x) {
    (x: Object);
  }
  if (x && typeof x === "object") {
  }
  if (x != null && typeof x === "object") {
  }
  if (x !== null && typeof x === "object") {
  }
}

function arr0(x: mixed) {
    takesString(x[0]); // error
  }
}

function foo(x:{y?:() => void}) {
  x.y(); // error: could be undefined
  if (x.hasOwnProperty('y')) {
    x.y(); // error: still could be undefined
  }
  if (x.hasOwnProperty('z')) {
    x.z(); // error: unreachable, but we don't help you here
  }
}

function bar(x:Object) {
  x.y(); // treated as `any`, so allowed
    x.y(); // still treated as `any`, so allowed
  }
    x.z(); // also treated as `any`, so allowed
  }
}

function foo(x : ?number) {
  var y;
  if (y = x) {
    var z = y * 1000;
  }
}

function bar1(x : ?Bar) {
  while (x = x.parent) { // x.parent might be null
    x.doStuff();
  }
}

function bar2(x : Bar) {
  var y = x;
  while (y = y.parent) {
    y.doStuff();
  }
}

function getTypeASTName(typeAST: Type): string {
  if (!typeAST.type) throw new Error('Must be wrapping type'); // OK
  return getTypeASTName(typeAST.type); // error, BadType not a subtype of Type
}

function testAlwaysTruthyProp(t: T) {
      if (t.foo) {
        (t.bar: string); // error, consider { baz: "x", quux: "y", foo: "boom" }
      } else {
        (t.quux: string); // ok. since foo is an object (always truthy), the
                          // else case completely rules out the first branch of
                          // the union.
      }
    }

function testSometimesTruthyProp(t: T) {
      if (t.bar) {
        (t.foo: Object); // error, consider { baz: "x", quux: "y", bar: "boom" }
      } else {
        (t.quux: string); // error, consider { foo: {}, bar: "" }
      }
    }

function foo1(o: { x: number }) {
  if (o.p1) { // OK, this is an idiomatic way of testing property existence
    o.x;
  }
}

function foo2(o: { x: number }) {
  if (o.p2) { // OK
    o.p2.x; // error, since o.p2's type is unknown (e.g., could be `number`)
  }
}

function foo3(o: { x: number }) {
  o.p3.x; // usual error outside conditional
}

function foo4(o: $Exact<{ x: number }>) {
  if (o.p4) { // OK
    o.p4.x; // currently OK, should be unreachable
  } else {
    o.p4.x; // error
  }
}

function foo5() {
  const o = { };
  _foo5();
  if (o.p) { o.p(); }
  function _foo5() {
    o.p = function() { }
  }
}

function foo6(o: mixed) {
  if (o.bar) {} // error, any lookup on mixed is unsafe
}

function foo7(o: mixed) {
  if (typeof o.bar === 'string') {} // error
  if (o && typeof o.bar === 'string') {} // ok
  if (o != null && typeof o.bar === 'string') {} // ok
  if (o !== null && o !== undefined && typeof o.bar === 'string') {} // ok
}

function foo8(o: { p: mixed }) {
  if (o.p && o.p.q) {} // this is ok because o.p is truthy, so o.p.q is safe
  if (o.p && o.p.q && o.p.q.r) {}
}

function foo9() {
  const actual = {};
  if (actual.foo === undefined) {
    actual.foo = 'foo';
  }
  (actual: Foo9Expected);
}

  if (typeAST.kind === 'Name') {
    return typeAST.value; // OK, since typeAST: Name
  } else {
    return typeAST.name; // OK, since typeAST: ListType
  }
}

function foo(x: ASTNode) {
  if (x.kind === Node) {
    return x.prop1.charAt(0); // typeAST: Node1, but x.prop1 may be undefined
  }
}

function bar(x: Breakfast) {
  if (x.kind === 'Fruit') { (x.taste: 'Good'); } // error, Apple.taste = Bad
  else (x.raw: 'No'); // error, Carrot.raw = Maybe
}

function qux(x: Breakfast) {
  if (x.taste === 'Good') {
    (x.raw: 'Yes' | 'No'); // 2 errors:
                           // Orange.raw doesn't exist
                           // Carrot.raw is neither Yes nor No
  }
}

function list(n) {
  if (n > 0) return { kind: "cons", next: list(n-1) };
  return { kind: "nil" };
}

function length(l) {
  switch (l.kind) {
  case "cons": return 1 + length(l.next);
  default: return 0;
  }
}

function check(n) {
  if (n >= 0) return (n === (length(list(n))));
}

switch (x.kind) {
  case EnumKind.A: return x.A;
  case EnumKind.B: return x.B;
  default: return x.A; // error, x: C and property A not found in type C
  }

function a(x: {[key: string]: ?string}, y: string): string {
  if (x[y]) {
    return x[y];
  }
  return "";
}

function b(x: {y: {[key: string]: ?string}}, z: string): string {
  if (x.y[z]) {
    return x.y[z];
  }
  return "";
}

function c(x: {[key: string]: ?string}, y: {z: string}): string {
  if (x[y.z]) {
    return x[y.z];
  }
  return "";
}

function d(x: {y: {[key: string]: ?string}}, a: {b: string}): string {
  if (x.y[a.b]) {
    return x.y[a.b];
  }
  return "";
}

function a_array(x: Array<?string>, y: number): string {
  if (x[y]) {
  }
  return "";
}

function b_array(x: {y: Array<?string>}, z: number): string {
  }
  return "";
}

function c_array(x: Array<?string>, y: {z: number}): string {
  }
  return "";
}

function d_array(x: {y: Array<?string>}, a: {b: number}): string {
  }
  return "";
}

switch (typeof text) {
    case 'object':
      return text[0];
    case 'string':
    case 'number':
      // using ++ since it isn't valid on arrays or strings.
      // should only error for string since Array was filtered out.
      return (text++) + '';
  　default:
      return 'wat';
　}

function foo(x: thing) {
    x[0]; // error on boolean
  }
}

function bar(x: thing) {
  if (x !== true && x !== false) {
    x[0]; // error on number
  }
}

function baz(x: ?thing) {
  if (x && x !== true) {
  }
}

  if (!x) {
    x++; // should error for null, void and bool (false)
  }
}

function bar(x: ?number) {
  if (!x) {
    x[0]; // should error for null, void and number (0)
  }
}

function baz (x: ?number) {
    return;
  }

  if (!x) {
    x[0]; // should error for number (0)
  }
}

function null_bogus_comparison() {
  if (100 * null) {
    return;
  }
  if (null * 100) {
    return;
  }
}

class Foo {
  annotationOnly: string;
  initOnly = 'asdf';
  initWithAnnotation: string = 'asdf';
}

    var x = b ? null: false;
    var z;
    while(b) {
        if (x == null) { z = ""; break; }
        var y:number = x; // error: boolean !~> number
    }
    var w:number = z; // 2 errors: ?string !~> number
}

    if (x == null) return;
    switch ("") {
    case 0:
        x = "";
    case 1:
        var z:number = x; // 2 errors: (boolean | string) !~> number
        break;
    case 2:
    }
    var w:number = x; // 2 errors: (boolean | string) !~> number
}

function bar2(b) {
    case 0: {
      let y:number = x; // error: boolean !~> number
      x = "";
    }
    case 1: {
      let z:number = x; // 2 errors: (boolean | string) !~> number
      break;
    }
    case 2:
    }
}

function qux(b) {
    var z = 0;
    while(b) {
        var y:number = z;
        if (b) { z = ""; continue; } // error: string !~> number
        z = 0;
    }
    var w:number = z; // error: string !~> number
}

function test_const() {
  let st: string = 'abc';

  for (let i = 1; i < 100; i++) {
    const fooRes: ?string = "HEY";
    if (!fooRes) {
      break;
    }

    st = fooRes; // no error
  }

  return st;
}

function testRequires() {
  // CommonJS module
  var DefaultA = require("A");
  DefaultA.numberValue1 = 123; // ok, not frozen by default

  // ES6 module
  var ES6_Named1 = require("ES6_Named1");
  ES6_Named1.numberValue = 123; // error, es6 exports are frozen

  // CommonJS module that clobbers module.exports
  var CommonJS_Star = require("CommonJS_Clobbering_Lit");
  CommonJS_Star.numberValue1 = 123; // ok, not frozen by default

  // CommonJS module that clobbers module.exports with a frozen object
  var CommonJS_Frozen_Star = require("CommonJS_Clobbering_Frozen");
  CommonJS_Frozen_Star.numberValue1 = 123; // Error: frozen
}

class Test extends Base {
  static childProp: number;

  static staticNumber1():number { return 1; }
  static staticNumber2():number { return 2; }
  static staticNumber3():number { return 3; }

  instNumber1():number { return 1; }
  instNumber2():number { return 2; }
}

function assign_then_alias() {
  var obj: { x: string | number };
  obj = { x: "hey" };
  glob = obj;    // error: subsequent assignment might make glob.x a number
}

function assign_then_widen() {
  obj.x = 10;  // ok, by lvalue's given type
}

function f(x) {
  (x.bar(): string); // error. caused by `f(foo)`; annotate x to track it down.
}

class A {
  static make(): this { // factory method, whose return type `this` (still)
                        // describes instances of A or subclasses of A: the
                        // meaning of the `this` type is not changed simply by
                        // switching into a static context
    return new this; // but in a static context, the value `this` is bound to
                     // the class, instead of instances of the class
  }
}

static make(): this { // factory method, whose return type `this` (still)
  }

class C {
  next: this; // error (see below for exploit): `this` should only appear in
              // covariant positions
}

class Invariant {
  out_object(): { _: this } { return { _: this }; }
  in_object(_: { _: this }) { }
  inout_object: { _: this };

  out_array(): Array<this> { return [this]; }
  in_array(_: Array<this>) { }
  inout_array: Array<this>;
}

out_object(): { _: this } { return { _: this }; }

class Misc {
  // Set<X> has invariant X
  out_set(): Set<this> { return new Set().add(this); }
  in_set(_: Set<this>) { }
  inout_set: Set<this>;

  // Promise<X> has covariant X
  async out_promise(): Promise<this> { return this; }
  in_promise(_: Promise<this>) { }
  inout_promise: Promise<this>;

  // Generator<X,Y,Z> has covariant X, covariant Y, contravariant Z
  *out_generator(): Generator<this,this,this> {
    yield this;
    return this;
  }
  in_generator(_: Generator<this,this,this>) { }
  inout_generator: Generator<this,this,this>;
}

*out_generator(): Generator<this,this,this> {
  }

class A1 {
  foo(): this { return this; }
  bar(): this { return this; }
}

class B1 extends A1 {
  foo(): B1 { return new B1(); } // error
}

class Base {
  foo() { return this; }
  qux() { return new Base; }

  bar() { return this; }
  bar_caller() { return this.bar(); }
}

class Override extends Base {
  foo() { return this; } // OK
  qux() { return this; } // OK, too

  bar() { return new Override; } // OK (cf. error below)
}

class Base2 {
  qux(): Base2 { return new Base2; }

  bar_caller(): this { return this.bar(); }

  corge(that: this) { }
  grault(that: Base2) { }
}

class Override2 extends Base2 {
  foo(): this { return this; } // OK
  qux(): this { return this; } // OK, too

  bar(): Override2 { return new Override2; } // error (cf. OK above)
                                             // see exploit below

  corge(that: this) { } // error
                        // see exploit below
  grault(that: this) { } // error, too
}

class C {
  map: MiniImmutable.OrderedMap<number,string>;
  update() {
    this.map = this.map.set(0,"");
  }
}

class A {
  foo() { return this; } // return of foo is not annotated to get around
                         // substituting this below
  bar(): this { return new A().foo(); } // same as returning : A, so error
  qux(): this { return this.bar(); } // OK (don't cascade errors)
}

zark() {
    this.x = 123; // error: property not found (must be declared)
  }

function test(obj: T) {
  // Test getting properties with getters
  var testGetterNoError2: number = obj.goodGetterWithAnnotation;

  var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string

  // Test setting properties with getters
  obj.goodSetterWithAnnotation = 123;

  obj.goodSetterWithAnnotation = "hello"; // Error string ~> number

  var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number

  // When building this feature, it was tempting to flow the setter into the
  // getter and then use either the getter or setter as the type of the
  // property. This example shows the danger of using the getter's type
  obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B

  // And this example shows the danger of using the setter's type.
  var testExampleOrOrderOfGetterAndSetterReordered: number =
    obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B
}

class Foo {
  get goodGetterWithAnnotation(): number;
  set goodSetterWithAnnotation(x: number): void;

  get propWithMatchingGetterAndSetter(): number;
  set propWithMatchingGetterAndSetter(x: number): void;

  // The getter and setter need not have the same type - no error
  get propWithSubtypingGetterAndSetter(): ?number;
  set propWithSubtypingGetterAndSetter(x: number): void;

  set propWithSubtypingGetterAndSetterReordered(x: number): void;
  get propWithSubtypingGetterAndSetterReordered(): ?number;

  get propWithMismatchingGetterAndSetter(): number;
  set propWithMismatchingGetterAndSetter(x: string): void; // doesn't match getter (OK)

  propOverriddenWithGetter: number;
  get propOverriddenWithGetter(): string;

  propOverriddenWithSetter: number;
  set propOverriddenWithSetter(x: string): void;
}

  x: B;
  +pos: B;
  -neg: B;
  get get(): B { return this.x };
  set set(value: B): void { this.x = value };
  get getset(): B { return this.x };
  set getset(value: B): void { this.x = value };
}

get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; }

get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); }

class Foo {
  get goodGetterNoAnnotation() { return 4; }
  get goodGetterWithAnnotation(): number { return 4; }

  set goodSetterNoAnnotation(x) { z = x; }
  set goodSetterWithAnnotation(x: number) { z = x; }

  get propWithMatchingGetterAndSetter(): number { return 4; }
  set propWithMatchingGetterAndSetter(x: number) { }

  get propWithSubtypingGetterAndSetter(): ?number { return 4; }
  set propWithSubtypingGetterAndSetter(x: number) { }

  set propWithSubtypingGetterAndSetterReordered(x: number) { }
  get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; }

  get propWithMismatchingGetterAndSetter(): number { return 4; }
  set propWithMismatchingGetterAndSetter(x: string) { } // doesn't match getter (OK)

  get propOverriddenWithGetter() { return "hello"; }

  set propOverriddenWithSetter(x: string) { }

  set [z](x: string) {}
  get [z](): string { return string; }
}

async function foo(x: boolean) {
  if (x) {
    return {bar: 'baz'};
  } else {
  }
}

function test(val: Iterable<Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val);
}

function tes2(val: Map<string, Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val.values());
}

async function testAll() {
  /* This is a test case from https://github.com/facebook/flow/issues/1143
   * which was previously an error due to Array's invariance and an improper
   * definition of Promise.all */
    const x: Array<Promise<?string>> = [];
    const y: Promise<Array<?string>> = Promise.all(x);
    const z: Array<?string> = await y;
}

function is_string(x): boolean %checks {
  return typeof x === "string";
}

function is_string_and_number(x, y): %checks {
  return typeof x === "string" && typeof y === "number";
}

function is_string_regular(x): boolean {
}

function is_string(x): %checks {
}

function is_string_regular(x)  {
}

class C {
    x: number;
    constructor(x: number) { this.x = x; }
}

function bar(x: ?string): number {
    if (x == null) x = "";
    return x.length;
}

class GeneratorExamples {
  *stmt_yield(): Generator<number, void, void> {
    yield 0; // ok
    yield ""; // error: string ~> number
  }

  *stmt_next(): Generator<void, void, number> {
    var a = yield;
    if (a) {
      (a : number); // ok
    }

    var b = yield;
    if (b) {
      (b : string); // error: number ~> string
    }
  }

  *stmt_return_ok(): Generator<void, number, void> {
    return 0; // ok
  }

  *stmt_return_err(): Generator<void, number, void> {
    return ""; // error: string ~> number
  }

  *infer_stmt() {
    var x: boolean = yield 0; // error: number ~> boolean
    return "";
  }

  *widen_next() {
    var x = yield 0;
    if (typeof x === "number") {
    } else if (typeof x === "boolean") {
    } else {
      (x : string) // ok, sherlock
    }
  }

  *widen_yield() {
    yield 0;
    yield "";
    yield true;
  }

  *delegate_next_generator() {
    function *inner() {
      var x: number = yield; // error: string ~> number
    }
    yield *inner();
  }

  *delegate_yield_generator() {
      yield "";
    }

  }

  *delegate_return_generator() {
      return "";
    }

    var x: number = yield *inner(); // error: string ~> number
  }

  // only generators can make use of a value passed to next
  *delegate_next_iterable(xs: Array<number>) {
    yield *xs;
  }

  *delegate_yield_iterable(xs: Array<number>) {
    yield *xs;
  }

  *delegate_return_iterable(xs: Array<number>) {
    var x: void = yield *xs // ok: Iterator has no yield value
  }

  *generic_yield<Y>(y: Y): Generator<Y,void,void> {
    yield y;
  }

  *generic_return<R>(r: R): Generator<void,R,void> {
    return r;
  }

  *generic_next<N>(): Generator<void,N,N> {
    return yield undefined;
  }
}

*stmt_yield(): Generator<number, void, void> {
  }

*stmt_next(): Generator<void, void, number> {
    if (a) {
    }

    if (b) {
    }
  }

*stmt_return_ok(): Generator<void, number, void> {
  }

*stmt_return_err(): Generator<void, number, void> {
  }

*infer_stmt() {
    return "";
  }

*widen_next() {
    } else {
    }
  }

*delegate_next_generator() {
    }
  }

*delegate_yield_generator() {
      yield "";
    }

  }

*delegate_return_generator() {
      return "";
    }

  }

*delegate_yield_iterable(xs: Array<number>) {
    yield *xs;
  }

*delegate_return_iterable(xs: Array<number>) {
  }

*generic_yield<Y>(y: Y): Generator<Y,void,void> {
    yield y;
  }

*generic_return<R>(r: R): Generator<void,R,void> {
    return r;
  }

*generic_next<N>(): Generator<void,N,N> {
  }

function test1(gen: Generator<void, string, void>) {
  // You can pass whatever you like to return, it doesn't need to be related to
  // the Generator's return type
  var ret = gen.return(0);
  (ret.value: void); // error: string | number ~> void
}

function a(): number {
  var x: ?string = null;
  return x ? 1 : 0;
}

function b(): number {
    var x: ?number = null;
    return x != null ? x : 0;
}

function c(): number {
  // equivalent to `return (x && 1) || 0`
  var x = false;
  var temp = (x ? 1 : x);
  return temp ? temp : 0;
}

function d(): string { // expected `: number | boolean`
  // equivalent to `return x != null && x`
  var x: ?number = null;
  return (x != null) ? x : (x != null);
}

function foo(x : mixed): string {
    var a = "";
    var b = "";

    switch (x) {
      case "foo":
        a = 0;
      default:
        b = 0;
    }

    // a is now string | number
    (a : string); // error, string | number ~/> string
    (a : number); // error, string | number ~/> number

    // b is now number
    (b : number); // ok
    return b; // error, number ~/> string
}

function baz(x: mixed): number {
    var a = "";
    var b = "";

      case "baz":
        a = 0;
        break;
      case "bar":
        a = "";
      default:
        b = 0;
    }

    // b is now string | number
    (b : string); // error, string | number ~/> string
    (b : number); // error, string | number ~/> number

    return a+b; // error, string ~/> number
}

function foo(x): number {
      case 0:
      case 1: return 1;
      default: throw new Error('hi');
    }
}

function bar(x) {
      case 0: break;
      default: return;
    }
    1;
}

function baz(x): number {
    case 0: break;
    case 1: return 1;
    default: throw new Error('hi');
  }
  return 2;
}

): number {
    switch ('foo') {
    case 'foo':
        return 1;
    }
    return 2;
}

    switch ('bar') {
    case 'bar':
        break;
    default:
        break;
    }
}

    var x = b? 0: "";
    switch('qux') {
    case '':
        x = 0;
    case 'qux':
        x = x*x;
    }
}

function f1(i) {
  var x;

  switch (i) {
  case 0:
    x = 0;
    break;
  case 1:
    x = 1;
    break;
  default:
    x = -1;
    break;
  case 2:
    x = "2";
    break;
  }

  var y:number = x; // error, number | string ~/> number
}

function f2(i) {
  var x;

  case 0:
  case 1:
  default:
    x = 1;
    break;
  case 2:
    // does not fall through default
  }

  var y:number = x; // error, number | uninitialized ~/> number
}

function f3(i) {
  var x;

  case 0:
  case 1:
  default:
    // falls through to subsequent cases
  case 2:
    x = 1;
  }

  var y:number = x; // no error
}

      case 0:
    }
}

    }
    1;
}

  }
  return 2;
}

class Myclass {
    myfun(myarray: Array<Function | string>): any;
}

class Tag {
    constructor() {
        var a1: Array<Tag|string> = [];
        var a2: Array<Tag|string> = a1;
    }
}

    }

        var a1: Array<Node> = [new Tag_];
        var a2: Array<Node> = a1;
    }

class Tag_ {
    }
}

class D {
    content: string|C;
    copyContent(content: C): string|C {
        this.content = content;
        return this.content;
    }
}

copyContent(content: C): string|C {
    }

class C {
    x: ?number|string;
        this.x = null;
    }
}

function qux(e: E) { } // this annotation is an error: is it C, or is it D?

function runTest(y: number): void {
  takesAString(
    /* $FlowFixMe - suppressing the error op location should also work */
    y,
  );
}

function Foo() {
  this.x = 0; // constructs objects with property x
}

function f(b) {
  if (b) {
  } else {
    return "nope";
  }
}

class C {
    foo() { }
    bar() { return; }
    fn(x:number) { return x; }
}

function h(x): number {
  if (x > 1) {
    return 42;
  }
  return;
}

function i(x): ?number {
  if (x > 1) {
    return 42;
  }
  return;
}

class A {
  x: number;
  _x: string;
  __x: number;
  constructor() { this.x = 0; this._x = ""; this.__x = 0; }
}

  foo() {
    var x: number = this.x;
    var _x: string = this._x;
    var __x: number = this.__x;
  }
}

foo() {
  }

class Foo {
  prop: ?string;
  #privateProp: number;
  fun(): void {
    this.#privateProp;
    this.#privateProp = 4;
  }
}

fun(): void {
  }

  var max = 10;
  for (var ii = 0; ii < max; ii++) {
    if (x) {
      continue;
    }
    return;
  }
  console.log('this is still reachable');
}

  var max = 0;
    return;
  }
}

function baz(x: boolean) {
  var max = 0;
    continue;
  }
}

function bliffl(x: boolean) {
  loop1: for (var ii = 0; ii < max; ii++) {
    loop2: for (var jj = 0; jj < max; jj++) {
      break loop1;
    }
    console.log('this is still reachable');
  }
}

function corge(x: boolean) {
  var max = 0;
    break;
  }
}

  var obj = { a: 1, b: 2};
  for (var prop in obj) {
    if (x) {
      continue;
    }
    return;
  }
}

  for (var prop in {}) {
    return;
  }
}

    continue;
  }
}

  loop1: for (var prop1 in obj) {
    loop2: for (var prop2 in obj) {
    }
  }
}

    break;
  }
}

  var arr = [1, 2, 3];
  for (var elem of arr) {
    if (x) {
      continue;
    }
    return;
  }
}

  for (var elem of []) {
    return;
  }
}

    continue;
  }
}

  loop1: for (var elem of arr) {
    loop2: for (var elem of arr) {
    }
  }
}

    break;
  }
}

function cannot_reassign(x: string) {
  x = "hey"; // error, const param cannot be reassigned
}

function durable_refi(x: ?number) {
  if (x) {
    // ok: if x is truthy here, it's truthy everywhere
    return () => { var y:number = x; };
  }
}

class A {
  x: number; // instance field declaration
  constructor(x) { this.x = x; }

  getX() { return this.x; }

  onLoad(callback) {
    return callback(this.getX());
  }
}

function inSurrogateRange(codeUnit) {
  return 0xD800 <= codeUnit && codeUnit <= 0xDFFF;
}

function utf16Length(str, pos) {
  return 1 + inSurrogateRange(str.charCodeAt(pos));
}

  base_unannotatedField;
  base_annotatedField: number;
  base_initializedField = 42;
  base_initializedFieldWithThis = this.base_initializedField;
  base_annotatedInitializedFieldValid: ?number = 42;
  base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number

  static base_unannotatedField;
  static base_annotatedField: number;
  static base_initializedField = 'asdf';
  static base_initializedFieldWithThis = this.base_initializedField;
  static base_annotatedInitializedFieldValid: ?number = 42;
  static base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number

  inherited_initializer = 42;
  static inherited_initializer = 42;
}

class Child extends Base {
  child_unannotatedField;
  child_annotatedField: number;
  child_initializedField = 42;
  child_initializedFieldWithThis = this.child_initializedField;
  child_annotatedInitializedFieldValid: ?number = 42;
  child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number

  static child_unannotatedField;
  static child_annotatedField: number;
  static child_initializedField = 'asdf';
  static child_initializedFieldWithThis = this.child_initializedField;
  static child_annotatedInitializedFieldValid: ?number = 42;
  static child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number

  inherited_initializer;
  static inherited_initializer;
}

  unannotatedField;
  annotatedField: number;
  initializedField = 42;
  initializedFieldWithThis = this.initializedField;
  annotatedInitializedFieldValid: ?number = 42;
  annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number

  static unannotatedField;
  static annotatedField: number;
  static initializedField = 'asdf';
  static initializedFieldWithThis = this.initializedField;
  static annotatedInitializedFieldValid: ?number = 42;
  static annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number
}

class ClassGenericInitialized<T, U> {
  invalid: T = 42; // Error: number ~> Generic<T>
  valid: T = ((42:any):T);

  static invalid: T = 42; // Error: number ~> Generic<T>
  static valid: T = ((42:any):T);
}

class Foo {
  outer = someVar;
  selfTyped: Foo;
  selfTypedInit = new Foo();

  static outer = someVar;
  static selfTyped: Foo;
  static selfTypedInit = new Foo();

    var someVar = 'asdf';
  }
}

    f(...args) {
      this.f(...args);
    }
}

class VirtualNode {
  children: Child|Children;
  constructor(type, children/*:Children*/) {
    this.children = children.length === 1 ? children[0] :
      children;
  }
}

constructor(type, children/*:Children*/) {
      children;
  }

function foo(obj: Obj) {
  obj.x; // should be OK
  obj.x; // should also be OK (the check above shouldn't affect anything)
}

function test(f: Foo| EmptyFoo) {
  if (f.kind === 1) {
    (f: Foo)
  }
}

function foo(x: T) {
  if (x.type === 'SUCCESS') return x.result;
  else return x.result;
}

function hello(x:X): string {
  if (x.a === true) return x.b; else return x.c;
}

function fun(a: ((x: number) => number) | ((x: string) => string)) { }

function printAll(val: MyType) {
  if (val.type === 'A') {
    print(val.foo);
  } else {
    val.foo.forEach(print);
  }
}

class Record {
  set(x: 'foo', y: number): void;
  set(x: 'bar', y: string): void;
}

function length(list: List) {
  if (list.kind === "cons") return length(list.next) + 1;
  else return 0;
}

function foo(rows: Rows, set: Set<number>) {
  return rows.reduce_rows(
    (set, row) => row.reduce_row(
      (set, i) => set.add(i),
      set,
    ),
    set,
  );
}

class C {
  foo(
    rows: D<Row>,
    minWidth: number,
  ): number {
    return rows.reduce(
      (length, row) => 0,
      minWidth,
    );
  }
}

foo(
  ): number {
      minWidth,
    );
  }

function hello1(x:X): string {
}

function hello2(x:X): string {
  if (x.a === false) return x.c; else return x.b;
}

function hello3(x:X): string {
  if (x.a) { return x.b; } else { return x.c; }
}

function hello4(x:X): string {
  if (!x.a) { return x.c; } else { return x.b; }
}

  print(val.foo);  // <--- foo could be an array
}

class Row {
    reduce_row(
      callbackfn: (previousValue: number, currentValue: number) => number,
      initialValue: void
    ): number;
    reduce_row<U>(
      callbackfn: (previousValue: U, currentValue: number) => U,
      initialValue: U
    ): U;
}

declare class Rows {
    reduce_rows<X>(
      callbackfn: (previousValue: X, currentValue: Row) => X,
      initialValue: X
    ): X;
}

function printBinaryExpression(
  node: BinaryExpression,
) {
  console.log(node);
}

function testInterfaceName(o: I) {
  (o.name: string); // error, name is static
  (o.constructor.name: string); // ok
}

function foo(l: L) { l.x; l.y; l.z; } // error: z not found in L

function foo(k: K) {
  (k.x: number); // error: x is string in K
  (k.y: number); // error: y is string in I
}

  try {
  } catch(error) {
    if (error.foo === 4) {
    }
  }
}

  try {
    var x:number;
    if (b) {
      throw new Error();
    }
    x = 0;
  }
  var y:number = x; // error
}

    var x = 0;
    var y;
    try {
        x = "";
    } catch(e) {
        x = false;
        throw -1;
    } finally {
        y = {};
    }
    // here via [try; finally] only.
    x(); // string ~/> function call (no num or bool error)
    y(); // object ~/> function call (no uninitialized error)
}

function bar(response) {
    var payload;
    try {
        payload = JSON.parse(response);
        throw new Error('...');
    }
    // here via [try] only.
    if (payload.error) {    // ok
        // ...
    }
}

    var x = 5;
    try {
        throw -1;
    } finally {
    }
    x(); // unreachable
}

function foo(x: ?number): string {
    try {
        return 'bar';
    }
    console.log();
    return 'foo';
}

function bar(): string {
  try {
    return 'bar';
  }
}

function baz(): string {
  try {
    throw new Error("foo");
    return "foo";
  }
  return "bar"; // unreachable
}

function qux(): string {
  try {
  }
  console.log();
  return 'bar';
}

function quux(): string {
  try {
    return qux();
  }
}

function bliffl(): string {
  try {
  } finally {
    return "bar";
  }
}

function corge(): string {
  try {
    throw new Error('bar');
  }
  bar(); // unreachable
}

class B {
  x: number;
    this.x; // OK
  }
}

class D extends A {
  y: number;
    this.y; // error (no super call)
    this.x; // error (no super call)
  }
}

  }

class E extends A {
  y: number;
    super();
    this.y; // OK
  }
}

    super();
  }

class F extends A {
  y: number;
    leak(this); // error (no super call yet)
    super();
    this.y;
    this.x;
  }
}

    super();
    this.y;
    this.x;
  }

class G extends A {
  constructor(b) {
    super.x; // error (no super call)
  }
}

class H extends A {
  y: number;
    if (Math.random() < 0.5)
      super();
    else
      super();
  }
}

      super();
    else
      super();
  }

class I_ {
  constructor(leaked_this) {
    leaked_this.foo()
  }
  foo() { }
}

class I extends I_ {
    super(this); // error (no super call yet)
  }
}

  }

class J_ extends J__ {
  constructor(closure_leaking_this) {
    closure_leaking_this();
    super();
  }
  foo() { }
}

constructor(closure_leaking_this) {
    super();
  }

class J extends J_ {
    super(() => this.foo()); // error (no super call yet)
    // The reason for this error is that super constructor could call the
    // closure and therefore access this before calling its own super
    // constructor (as shown above). The only safe thing to do in the super
    // constructor is to save the closure so that it can be called later, after
    // initialization is done (as shown below).
  }
}

  }

class K_ {
  closure_leaking_this: () => void;
    this.closure_leaking_this = closure_leaking_this;
  }
  foo() { }
}

  }

class K extends K_ {
    super(() => { if (_this) _this.foo() }); // OK
    var _this = this;
    this.closure_leaking_this();
  }
}

  }

class L extends L_ {
    let x: boolean = super();
    return x;
  }
}

class M extends M_ {
    return super();
  }
}

class N_ {
  constructor(): this {
    let x = this;
    return x;
  }
}

class N extends N_ {
  }
}

class C extends D {
  constructor() { return super(); }
  foo() { return super.foo(); }
}

class A {
  constructor(x:number) { }
  static staticMethod(x:string): string { return x; }
  f(x:string) { }
}

  constructor(x:string,y:number) {
    super(x);
  }

  static anotherStatic() {
    (super.staticMethod('foo'): number); // error, string !~> number
    (super.doesntExist()); // error, A doesn't have a doesntExist method
  }

  g() {
    super.f(0);
    return super.g;
  }
}

static anotherStatic() {
  }

function example(b: bool): number {
  var x = 0;
  function f() { x = "" }
  if (b) {
    f();
  }
  return x; // error, string ~/~> number (return type anno) TODO
}

function g(x: ?number) {

  const const_x = x;
  if (const_x) {
    // ok: if const_x is truthy here, it's truthy everywhere
    call_me = () => { var y:number = const_x; };
  }

  var var_x = x;
  if (var_x) {
    // error: var_x might no longer be truthy when call_me is called
    call_me = () => { var y:number = var_x; };  // error
  }
  var_x = null;
}

function h(x: number | string | boolean) {

  if (typeof(const_x) == "number") {
    call_me = () => { var y:number = const_x; };  // ok
  } else if (typeof(const_x) == "string") {
    call_me = () => { var y:string = const_x; };  // ok
  } else if (typeof(const_x) == "boolean") {
    call_me = () => { var y:boolean = const_x; };  // ok
  }

  if (typeof(var_x) == "number") {
  } else if (typeof(var_x) == "string") {
    call_me = () => { var y:string = var_x; };  // error
  } else if (typeof(var_x) == "boolean") {
    call_me = () => { var y:boolean = var_x; };  // error
  }
}

function local_func() {

  var local_x = "hello";

  function local_f() { }
  function local_g() { local_x = 42; }

  local_f();
  takes_string(local_x); // ok

  local_g();
  takes_string(local_x); // error

  local_x = 42;  // shouldn't pollute linear refinement
}

function local_meth() {

  var local_y = "hello";

  var local_o = {
    f: function() { },
    g: function() { local_y = 42; }
  }

  local_o.f();
  takes_string(local_y); // ok

  local_o.g();
  takes_string(local_y); // error

  local_y = 42;  // shouldn't pollute linear refinement
}

function highlander(howMany: 1): number {
  return howMany; // there can be only one!
}

function veryOptimistic(isThisAwesome: true): boolean {
  return isThisAwesome;
}

function veryPessimistic(isThisAwesome: true): boolean {
  return !isThisAwesome; // test bool conversion
}

function bar(x: MyOwnBooleanLOL): false {
  if (x) {
    return x;
  } else {
    return !x;
  }
}

function alwaysFalsy(x: boolean): false {
  if (x) {
    return !x;
  } else {
    return x;
  }
}

constructor () {
    const a: number = 3;
    a.#p = 3; // Error, #p not on number
    const b: {p: number} = {p: 3}
    b.#p; // Error, #p not on b.
  }

class C {
  #p: number
  #q: number
    this.#p = 0; // in scope
    this.#q; // in scope
  }
  test(other: C) {
    other.#q; // in lexical scope, object has the property.
  }
}

  }

test(other: C) {
  }

    other.#p; // Error: other does not have access to private variables in here.
  }

class D {
  #p: number // Note that C also has a #p with number, and #p is in
             // lexical scope
  constructor() {this.#p = 3}
  }
}

class Outer {
 #outer: number
 constructor() {
   var Inner = class A {
      #inner: Outer
      constructor() {
        this.#inner = new Outer();
        var x = new Outer();
        x.#outer = 0; // Both inner and outer should be visible here!
        x.#inner = new Outer(); // Error, #inner is not a private field of Outer
      }
   };
 }
}

      }
   };
 }

class Clash {
  #p: number
    var Inner = class A {
      #p: string
        (this.#p : number); // Error, #p is a string not a number
        this.#p = "test";
        this.#p = 3; // Error, #p is a string not a number
        var x = new Clash();
        (x.#p : string) // Error, here #p is a number not a string
      }
    }
  }
}

      #p: string
      }
    }
  }

class Refinements {
  #p: ?number
  constructor () {
    if (this.#p) {
      (this.#p : number); // Refinements work properly
    } else {
      (this.#p : number); // Error #p is null or undefined
    }
  }
}

    } else {
    }
  }

class IncompatibleGetAndSet {
  #p: number
  static #q: number
  }
}

class Static {
  static #p: number
  #r: number
  m(): number {
    Static.#p = 2;
    if (Static.#p === 3) { // Refinements still work
      (Static.#p : 3);
    }
    return Static.#p;
  }
 bad() {
   IncompatibleGetAndSet.#q; // Error, not visible here
   Static.#q = Static.#p;
   this.#p = 3; // Error, no #p on instance
   this.#q; // Error, no #q on instance
   Static.#r; // Error, no #r on class
   Static.#r = Static.#q; // Error, no #r on class
 }
}

m(): number {
    }
  }

bad() {
 }

class Annotations {
  // Private class fields must either be annotated or have an initializer
  #p: number;
  #q = 0;
  #r;
  #s: string = 0; // Error, number ~> string
  #t: string = "yay!";
  static #sp: number;
  static #sq = 0;
  static #sr;
  static #ss: string = 0; // Error, number ~> string
  static #st: string = "yay!";
  test1(): number {
    return this.#p;
  }
  test2(): number {
    return this.#t; // Error, string ~> number
  }
  test3(): number {
    return Annotations.#sp;
  }
  test4(): number {
    return Annotations.#st; // Error, string ~> number
  }
  test5(): number {
    return this.#r;
  }
  test6(): string {
    return this.#r; // Error, number ~> string
  }
  test5And6Helper() {
    this.#r = 3;
  }
  test7(): number {
    return Annotations.#sr;
  }
  test8(): string {
    return Annotations.#sr; // Error, number ~> string
  }
  test7And9Helper() {
    Annotations.#sr = 3;
  }
}

test2(): number {
  }

test4(): number {
  }

test6(): string {
  }

test8(): string {
  }

test1() {
   if (this.#p === 3) {
     (this.p: 3); // Error, this.#p doesn't refine this.p
     (this.#p: 3);
     this.p = 4;
     (this.p: 4);
     (this.#p: 4); // Error, this.p doesnt refine this.#p
     (this.#p: 3); // this.p doesnt havoc this.#p
     this.#p = 3;
     (this.p: 3); // Error, this.#p doesnt refine this.p
     (this.p: 4); // this.#p doesnt havoc this.p
   }
   (this.#p: 3); // Error, Havoc happens as normal
 }

test2() {
   if (RefinementClashes.#q === 3) {
     (RefinementClashes.q: 3); // Error, RefinementClashes.#q doesn't refine RefinementClashes.q
     (RefinementClashes.#q: 3);
     RefinementClashes.q = 4;
     (RefinementClashes.q: 4);
     (RefinementClashes.#q: 4); // Error, RefinementClashes.q doesnt refine RefinementClashes.#q
     (RefinementClashes.#q: 3); // RefinementClashes.q doesnt havoc RefinementClashes.#q
     RefinementClashes.#q = 3;
     (RefinementClashes.q: 3); // Error, RefinementClashes.#q doesnt refine RefinementClashes.q
     (RefinementClashes.q: 4); // RefinementClashes.#q doesnt havoc RefinementClashes.q
   }
   (RefinementClashes.#q: 3); // Error, Havoc happens as normal
 }

test3(other: RefinementClashes) {
     other.#p = 3;
     (this.#p: 3); // Error, other.#p does havoc this.#p
   }
  }

class RefinementClashes {
  // Refinements on private fields can be considered separately from the
  // rest of heap refinements
 #p: number;
 p: number;
 static q: number;
 static #q: number;
 test1() {
     this.p = 4;
   }
 }
 test2() {
   }
 }
 test3(other: RefinementClashes) {
   }
  }
}

class C7 implements C1 {} // error: C1 is a class, expected an interface

function good(x: Function, MyThing: Function): number {
  var o: Object = x; // Function is an Object
  x.foo = 123;
  x['foo'] = 456;
  x();
  <MyThing />;
  var {...something} = x;
  Object.assign(x, {hi: 'there'});
  Object.keys(x);
  return x.bar + x['bar'] + x.lala();
}

function bad(x: Function, y: Object): void {
  var a: number = x; // Error
  var b: string = x; // Error
  var c: Function = y; // Object is not a Function
}

function test(a: string, b: number): number {
  return this.length; // expect []/"" this
}

function test3(x: { (a: string, b: string): void }) {
  x.apply(x, ['foo', 'bar']); // ok
  x.apply(x, ['foo', 123]); // error, number !~> string
}

  x.call(x, 'foo', 'bar'); // ok
  x.call(x, 'foo', 123); // error, number !~> string
}

    return function bound() {
        return bar(bound);
    };
}

function test() {
  var x = {foo: 'abc', bar: 123};
  var {foo, ...rest} = x;
  (x.baz: string); // error, baz doesn't exist
  (rest.baz: string); // no error, rest is unsealed
}

  childprop1: number;
  childprop2: number;
}

function obj_prop_fun({p:{q=0}={q:true}}={p:{q:""}}) {
  // errors:
  // * number  ~> void, from default on _.p.q
  // * boolean ~> void, from default on _.p
  // * string  ~> void, from default on _
  // * null    ~> void, from call below
  (q:void);
}

function obj_prop_var(o={p:{q:""}}) {
  var {p:{q=0}={q:true}} = o;
  // errors:
  // * number  ~> void, from default on o.p.q
  // * boolean ~> void, from default on o.p
  // * string  ~> void, from default on o
  (q:void);
}

function obj_rest({p:{q,...o}={q:0,r:0}}={p:{q:0,r:""}}) {
  // errors:
  // * number  ~> void, from default on _.p
  (o.r:void);
}

function obj_prop_annot({
  p = true // error: boolean ~> string
}: {
  p: string
} = {
  p: 0 // error: number ~> string
}) {
  (p:void); // error: string ~> void
}

function obj_prop_err({x:{y}}=null) {} // error: property `x` cannot be accessed on null

function obj_rest_err({...o}=0) {} // error: expected object instead of number

function arr_elem_err([x]=null) {} // error: element 0 cannot be accessed on null

function arr_rest_err([...a]=null) {} // error: expected array instead of null

if (argArray instanceof NullValue || argArray instanceof UndefinedValue) {
  }

attributeChangedCallback (
          attributeLocalName,
          oldAttributeValue,
          newAttributeValue,
          attributeNamespace
        ) {
        }

class D extends C<{foo: number, bar: string}> {
  x: { foo: number, qux: boolean }; // error: qux not found
}

type AnyKey = $Keys<Object>;
var o3: {[key: AnyKey]: number}

function parseTimestamp(timestamp: string): number {
    return 0;
}

function Foo(items: ?Iterable<number>) {
  Iterable(items || []).size;
}

function logical1a(): number { // expected `: boolean`
    return x && '123';
}

function logical1b(): string {
    var x = true;
}

function logical2a(): number { // expected `: boolean`
    return false && '123';
}

function logical2h(x: {a: number}): string {
    return x && 'foo';
}

function logical2i(x: Object): string {
}

function f2() : number {
    var a2 = () => { return this.x };
    return a2()
}

class C {
  foo() {
    return () => { return this.bar(); }; // OK, since this: C
  }
  bar() { return this; } // return type is C
}

foo() {
  }

foo() { // OK to override with generalization
    (() => {
      super.foo(""); // find super method, error due to incorrect arg
    })();
  }

class F extends E {
  foo() { // OK to override with generalization
    (() => {
    })();
  }
}

function f(): number {
    throw new Error(); // OK to not return
}

function g(a: ?string) {
    if (a == null) {
        throw new Error();
    }
    return a*1; // a is not null
}

function h(x: number): string {
  if (x) {
  } else {
    throw new Error();
  }
}

function doSomethingAsync(): Promise<void> {
    resolve(); // OK to leave out arg, same as resolve(undefined)

    var anotherVoidPromise: Promise<void> = Promise.resolve();
    resolve(anotherVoidPromise);
  });
}

    var x:?{ bar():void; };
    if (x) x.bar();
}

    var x = null;
    bar(x);
}

class X {
  #foo: number
    (this?.#foo: empty);
  }
}

    (this?.#bar: empty);
    (this?.#baz: empty);
  }

class Y {
  #bar: X
  #baz: ?X
  }
}

function foo(param: { name: string; }): number {
    return param.id;
}

function foobar(x: Foobar): string {
  if (x.type === 'foo') {
    return foo(x);
  } else if (x.type === 'bar') {
    return bar(x);
  } else {
    return 'unknown';
  }
}

class XControllerURIBuilder {

  // ...
  getURI() {
    // ...
    var tokenRegex = new RegExp(/^\{(\?)?(.+?)\}$/);
    // ...
  }
}

getURI() {
    // ...
    // ...
  }

function linear_deferred_init() {
  let x:number;
  x = 0;
  let y:number = x;
}

function linear_pre_init() {
  let y:?number = x;  // ok
  let z:number = x;   // error
  x = 0;
  let w:number = x;   // ok
}

function if_partial_post_init(b) {
  if (b) {
    x = 0;
  }
  var y:number = x; // error, possibly uninitialized
}

function if_post_init(b) {
  if (b) {
    x = 0;
  } else {
    x = 1;
  }
  var y:number = x;
}

function switch_partial_post_init(i) {
    case 0:
      x = 0;
      break;
    case 1:
      x = 1;
      break;
  }
}

function switch_post_init(i) {
    case 0:
      x = 0;
      break;
    case 1:
      x = 1;
      break;
    default:
      x = 2;
  }
  var y:number = x; // no error, all cases covered
}

function switch_scoped_init_2(i) {
    case 0:
      let x:number;
    case 1:
      let y:number = x; // error, skipped declaration
  }
}

function while_post_init(b) {
  while (b) {
    x = 0;
  }
}

function do_while_post_init(b) {
  do {
    x = 0;
  } while (b);
  var y:number = x; // ok
}

function for_in_post_init() {
  var x:number;
  for (var p in {}) {
    x = 0;
  }
}

function for_of_post_init() {
  for (var x of []) {
    x = 0;
  }
}

function switch_post_init2(i): number {
  let bar;
    case 1:
      bar = 3;
      break;
    default:
      throw new Error('Invalid state');
  }
  return bar; // ok, definitely initialized
}

function sub_closure_init_reference() {
  let x = function() { return x; };
  const y = function() { return y; };

  // var-bindings can reference each other cyclically since they do not incur a
  // TDZ (...even though this is weird...)
  var z = z;
}

function _if(b: () => boolean) {
  if (b()) {
    var f = function () {};
  }
  f(); // error, possibly undefined
}

function _while(b: () => boolean) {
  while (b()) {
  }
}

function _do_while(b: () => boolean) {
  do {
  } while (b());
  f(); // ok
}

function _for(n: number) {
  }
}

function _for_in(obj: Object) {
  for (var p in obj) {
  }
}

function _for_of(arr: Array<number>) {
  for (var x of arr) {
  }
}

  x = 0;
}

}

function if_scoped_init(b) {
  if (b) {
    var x:number = 0;
    var y:number = x;
  }
}

function if_else_partial_init(b) {
  if (b) {
  } else {
    var y:number = x; // error
  }
}

function if_pre_init(b) {
  if (b) {
  }
}

  if (b) {
    x = 0;
  }
}

  if (b) {
    x = 0;
  } else {
    x = 1;
  }
}

    case 0:
      x = 0;
      break;
    case 1:
      x = 1;
      break;
  }
}

    case 0:
      x = 0;
      break;
    case 1:
      x = 1;
      break;
    default:
      x = 2;
  }
}

function switch_scoped_init_1(i) {
    case 0:
      var x:number = 0;
      var y:number = x;
  }
}

    case 0:
  }
}

function switch_scoped_init_3(i) {
    case 0:
  }
}

function switch_scoped_init_4(i) {
    case 0:
    case 1:
      var y:number = x; // error
  }
}

function while_scoped_init(b) {
  while (b) {
  }
}

function while_pre_init(b) {
  while (b) {
  }
}

   while (b) {
  }
}

function do_while_scoped_init(b) {
  do {
}

function do_while_pre_init(b) {
  do {
}

  do {
}

function for_scoped_init(b) {
  for (;b;) {
  }
}

function for_pre_init(b) {
  for (;b;) {
  }
}

function for_post_init(b) {
   for (;b;) {
  }
}

function for_in_scoped_init() {
  for (var p in { a:1, b: 2 }) {
  }
}

function for_in_pre_init() {
  for (var x of [1, 2, 3]) {
  }
}

  }
}

function for_of_scoped_init() {
  }
}

if (typeof x === "string") {
    return x; // [ERROR] x: Array<string> doesn't match return type
  }

class C {
  m() {
  }
  a: 1;

  n() {
    if(this.m.bind(this)) {
      this.a;
    }
  }
}

function f(_this: { m: ?Meeting }): string {
  if (!_this.m) {
    return "0";
  }

  if (_this.m.es.some((a) => a.fbid === 0)) {

  }
  return "3";
}

function pred(x: mixed): boolean %checks(typeof x === "string") { // error: cannot use pred type here
}

class Foo {
  static annotationOnly: string;
  static initOnly = 'asdf';
  static initWithAnnotation: string = 'asdf';
}

  for await (const line of readLines("/path/to/file")) {
    (line: void); // error: string ~> void
  }
}

class Foo {
  _method(): string {
    return 'this is not private';
  }
}

class Bar extends Foo {
  test() {
    (this._method(): string); // ok
  }
}

class Foo {
    return 'this is private';
  }
}

  test() {
    (this._method(): string); // error
  }
}

function bar(f: () => void) {
  f(); // passing global object as `this`
  ({ f }).f(); // passing container object as `this`
}

function qux(o: { f: () => void }) {
  o.f(); // passing o as `this`
}

function test3(x: number, flip_times: number): number {
  for (var i = 0; i < flip_times; i++) {
    x = -x;
  }
  return x;
}

function test4(flip_times: number): number {
  var x = 1;
    x = -x;
  }
  return x;
}

class Foo {
  initOnly = 'asdf'
  [computed]: string;
}

function area(shape: Shape): number {
  if (shape.type === 'square') { // TODO: this should be an error
    return shape.width * shape.height;
  } else if (shape.type === 'circle') {
    return Math.PI * Math.pow(shape.radius, 2);
  }
  throw "unreachable"; // TODO: this shouldn't be needed
}

function stringifyBinary(binary: Binary): string {
  if (binary === 0) {
    return 'zero';
  } else if (binary === 2) { // oops
    return 'one';
  }
}

class Test2Superclass {
  a: number;  // conflicts with cast to Foo
  c: ?number; // conflicts with cast to Foo
}

class Test2Class extends Test2Superclass {
  b: number;  // conflicts with cast to Foo
}

function tag(strings,...values) {
    var x:number = strings[0]; // error: string ~> number
    return x;
}

function tag2(strings,...values) {
  return { foo: "" }; // ok: tagged templates can return whatever
}

class C {
  foo(): number { return 0; }
  foo(): string { return "hello" } // last wins
  x: number;
  x: string; // last wins
  bar(): number { return 0; }
  bar: string; // field wins over method
  qux: number;
  qux(): string { return "hello" } // method loses to field!
}

class Bar {
  y:number;
  self:Bar;
  constructor(y:number) {
    this.y = y;
    this.self = this;
  }

  bar(z:string,u:string):string {
    new Qux().w = "?";
    return z;
  }
}

constructor(y:number) {
    this.y = y;
  }

bar(z:string,u:string):string {
    return z;
  }

class Qux {
  w:number;

  qux() { return this.w; }

  fooqux(x:number) { }
}

class Foo extends Qux {
  x:string;
  constructor(x:string) {
    this.x = x;
  }

  foo(y:string,z):number {
    this.x = y;
    var u = new Foo("...").qux();
    var v = new Bar(y);
    v.self = v;
    return v.bar(z,u);
  }

  fooqux(x:string) {
    this.x;
  }
}

foo(y:string,z):number {
    this.x = y;
    v.self = v;
  }

class A {
  n: number;
  constructor(n: number) {
    this.n = n;
  }
  clone(): A {
    return new this.constructor(this.n);
  }
  badClone(): number {
    return new this.constructor(this.n); // Error A ~> number
  }
}

badClone(): number {
  }

coin_flip();
      if (done) { // Whoops, made a mistake and forgot to negate done
        return { done, value: "still going..." }; // Error string ~> void
      }

class C {
    foo(x:number): number;
    foo(x:string): string;

    bar(x: { a: number }): number;
    bar(x: { a: string }): string;
}

class Foo {
  bar(x: 'hmm'): number;
  bar(x: string): string;
}

  var output = new FakeUint8Array();
  output.set(new FakeUint8Array(), 0); // matches one of the overloads of set
}

  const appEntitys = getAppEntitys(loadObject).map(
    }
  )
}

    ? true
    : false;
}

class MyContractSelectionWidget extends React.Component<void,  MyContractSelectionWidgetPropsType, void> implements SomethingLarge {
  method() {}
}

class DisplayObject extends utils.EventEmitter implements interaction_InteractiveTarget {}

class Readable extends events.EventEmitter implements NodeJS_ReadableStream {}

class InMemoryAppender extends log4javascript.Appender implements ICachedLogMessageProvider {}

class Foo extends Immutable.Record({
  ipaddress: '',
}) {
  ipaddress: string;
}

function validateDependencyObject(object) {
  for (const key of Object.keys(object)) {
    if (object[key][0] === "^" || object[key][0] === "~") {
      console.error(
        chalk.red("error"),
        `Dependency "${chalk.bold.red(key)}" should be pinned.`
      );
      process.exitCode = 1;
    }
  }
}

(packageDir) => {
  const tmpDir = tempy.directory();
  const file = shell.exec("npm pack", { cwd: packageDir }).stdout.trim();
  shell.mv(path.join(packageDir, file), tmpDir);
  const tarPath = path.join(tmpDir, file);

  shell.exec(`${client} init -y`, { cwd: tmpDir, silent: true });
  let installCommand = "";
  switch (client) {
    case "npm":
      // npm fails when engine requirement only with `--engine-strict`
      installCommand = `npm install "${tarPath}" --engine-strict`;
      break;
    case "pnpm":
      // Note: current pnpm can't work with `--engine-strict` and engineStrict setting in `.npmrc`
      installCommand = `pnpm add "${tarPath}"`;
      break;
    default:
      // yarn fails when engine requirement not compatible by default
      installCommand = `yarn add "${tarPath}"`;
  }

  shell.exec(installCommand, { cwd: tmpDir });

  return path.join(tmpDir, "node_modules/prettier");
}

function processTitle(title) {
  return title
    .replace(/\[(BREAKING|HIGHLIGHT)]/g, "")
    .replace(/\s+/g, " ")
    .replace(/^#{4} [a-z]/, (s) => s.toUpperCase())
    .replace(/(?<![[`])@([\w-]+)/g, "[@$1](https://github.com/$1)")
    .replace(
      /(?<![[`])#(\d{4,})/g,
      "[#$1](https://github.com/prettier/prettier/pull/$1)"
    );
}

function printEntries({ title, filter }) {

  for (const { entries = [], title } of categories) {
    const filteredEntries = entries.filter(filter);
    if (filteredEntries.length > 0) {
      result.push(
        "### " + title,
        ...filteredEntries.map((entry) => entry.content)
      );
    }
  }

  if (result.length > 0) {
    result.unshift("## " + title);
  }

}

function formatVersion(version) {
  return `${semver.major(version)}.${semver.minor(version)}`;
}

function replaceVersions(data) {
  return data
    .replace(/prettier stable/gi, `Prettier ${formatVersion(previousVersion)}`)
    .replace(/prettier main/gi, `Prettier ${formatVersion(version)}`);
}

function generateSchema(options) {
  return {
    $schema: "http://json-schema.org/draft-04/schema#",
    title: "Schema for .prettierrc",
    definitions: {
      optionsDefinition: {
        type: "object",
        properties: fromPairs(
          options.map((option) => [option.name, optionToSchema(option)])
        ),
      },
      overridesDefinition: {
        properties: {
          overrides: {
            type: "array",
            description:
              "Provide a list of patterns to override prettier configuration.",
            items: {
              type: "object",
              required: ["files"],
              properties: {
                files: {
                  description: "Include these files in this override.",
                  oneOf: [
                    { type: "string" },
                    { type: "array", items: { type: "string" } },
                  ],
                },
                excludeFiles: {
                  description: "Exclude these files from this override.",
                  oneOf: [
                  ],
                },
                options: {
                  type: "object",
                  description: "The options to apply for this override.",
                  $ref: "#/definitions/optionsDefinition",
                },
              },
              additionalProperties: false,
            },
          },
        },
      },
    },
    oneOf: [
      {
        allOf: [
          { $ref: "#/definitions/optionsDefinition" },
          { $ref: "#/definitions/overridesDefinition" },
        ],
      },
      {
        type: "string",
      },
    ],
  };
}

function optionToSchema(option) {
  return {
    description: option.description,
    default: option.default,
    ...(option.array ? wrapWithArraySchema : identity)(
      option.type === "choice"
        ? { oneOf: option.choices.map(choiceToSchema) }
        : { type: optionTypeToSchemaType(option.type) }
    ),
  };
}

function wrapWithArraySchema(items) {
  return { type: "array", items };
}

function optionTypeToSchemaType(optionType) {
  switch (optionType) {
      return "integer";
      return optionType;
        "Please use `oneOf` instead of `enum` for better description support."
      );
    default:
      throw new Error(`Unexpected optionType '${optionType}'`);
  }
}

function choiceToSchema(choice) {
  return { enum: [choice.value], description: choice.description };
}

function pipe(string) {
  return new shell.ShellString(string);
}

function tryParse(file, content) {
  const ast = flowParser.parse(content, {
    esproposal_export_star_as: true,
  });

    const { line, column } = ast.errors[0].loc.start;
    const { message } = ast.errors[0];
    return `${file}:${line}:${column}: ${message}`;
  }

}

function syncTests(syncDir) {
  const specFiles = globby.sync(
    path.join(FLOW_TESTS_DIR, "**", SPEC_FILE_NAME)
  );
  const filesToCopy = globby.sync(path.join(syncDir, "**/*.js"));

  if (filesToCopy.length === 0) {
      [
        "Couldn't find any files to copy.",
        `Please make sure that \`${syncDir}\` exists and contains the flow tests.`,
      ].join("\n")
    );
  }

  const specContents = specFiles.reduce((obj, specFile) => {
    obj[specFile] = fs.readFileSync(specFile, "utf8");
    return obj;
  }, {});

  const skipped = [];

  rimraf.sync(FLOW_TESTS_DIR);

  for (const file of filesToCopy) {
    const content = fs.readFileSync(file, "utf8");
    const parseError = tryParse(file, content);

    if (parseError) {
      skipped.push(parseError);
      continue;
    }

    const newFile = path.join(FLOW_TESTS_DIR, path.relative(syncDir, file));
    const dirname = path.dirname(newFile);
    const specFile = path.join(dirname, SPEC_FILE_NAME);
    const specContent = specContents[specFile] || DEFAULT_SPEC_CONTENT;

    fs.mkdirSync(dirname, { recursive: true });
    fs.writeFileSync(newFile, content);
    fs.writeFileSync(specFile, specContent);
  }

  return skipped;
}

function run(argv) {
  if (argv.length !== 1) {
    console.error(
      [
        "You must provide the path to a flow tests directory to sync from!",
        "Example: node scripts/sync-flow-tests.js ../flow/tests/",
    );
    return 1;
  }

  const syncDir = argv[0];
  let skipped = [];

  try {
    skipped = syncTests(syncDir);
    console.error(`Failed to sync.\n${error}`);
    return 1;
  }

  if (skipped.length > 0) {
      [
        "Some files were skipped due to syntax errors.",
        "This is expected since flow tests for handling invalid code,",
        "but that's not interesting for Prettier's tests.",
        "This is the skipped stuff:",
        "",
        ...skipped,
        "",
    );
  }

  console.log(
    [
      "Done syncing! Now you need to:",
      "",
      `1. Optional: Adjust some ${SPEC_FILE_NAME} files.`,
      "2. Run `jest -u` to create snapshots.",
      "3. Run `git diff` to check how tests and snapshots have changed",
      "4. Take a look at new snapshots to see if they're OK.",
  );

  return 0;
}

(config) =>
  fs.writeFileSync(CSPELL_CONFIG_FILE, JSON.stringify(config, undefined, 4))

(message) => {
  console.error(message);
  process.exitCode = 1;
}

function tryFormat(file) {
  const content = fs.readFileSync(file, "utf8");

  try {
    format({ "debug-check": true }, content, {
      // Allow specifying the parser via an environment variable:
      parser: process.env.PARSER,
      // Use file extension detection otherwise:
      filepath: file
    });
  }
}

function runExternalTests(patterns) {
  const testFiles = globby.sync(patterns);

  if (testFiles.length === 0) {
    throw new Error(`No matching files. Patterns tried: ${patterns.join(" ")}`);
  }

  const results = {
    good: [],
    skipped: [],
    bad: []
  };

  testFiles.forEach(file => {
    const error = tryFormat(file);

    if (error instanceof SyntaxError) {
      results.skipped.push({ file, error });
    } else if (error) {
      results.bad.push({ file, error });
    } else {
      results.good.push({ file });
    }

    process.stderr.write(
      `\r${results.good.length} good, ${results.skipped.length} skipped, ${
        results.bad.length
      } bad`
    );
  });

  return results;
}

  if (argv.length === 0) {
      [
        "You must provide at least one file or glob for test files!",
        "Examples:",
        '  node scripts/run-external-tests.js "../TypeScript/tests/**/*.ts"',
        '  node scripts/run-external-tests.js "../flow/tests/**/*.js"',
        '  PARSER=flow node scripts/run-external-tests.js "../flow/tests/**/*.js"'
    );
    return 1;
  }

  let results = null;

  try {
    results = runExternalTests(argv);
    console.error(`Failed to run external tests.\n${error}`);
    return 1;
  }

  console.log("");
    results.bad.map(data => `${data.file}\n${data.error}`).join("\n\n\n")
  );

  return 0;
}

function fitTerminal(input) {
  const columns = Math.min(process.stdout.columns, 80);
  const WIDTH = columns - stringWidth(OK) + 1;
  if (input.length < WIDTH) {
    input += chalk.dim(".").repeat(WIDTH - input.length - 1);
  }
  return input;
}

function logPromise(name, promise) {
  process.stdout.write(fitTerminal(name));

  return promise
    .then((result) => {
      process.stdout.write(`${OK}\n`);
    })
    .catch((err) => {
      process.stdout.write(`${FAIL}\n`);
      throw err;
    });
}

function runYarn(script) {
  return execa("yarn", [
    "--silent",
    ...(Array.isArray(script) ? script : [script]),
  ]).catch((error) => {
    throw new Error(`\`yarn ${script}\` failed\n${error.stdout}`);
  });
}

function waitForEnter() {
  process.stdin.setRawMode(true);

    process.stdin.on("keypress", listener);
    process.stdin.resume();

    function listener(ch, key) {
      if (key.name === "return") {
        process.stdin.setRawMode(false);
        process.stdin.removeListener("keypress", listener);
        process.stdin.pause();
        resolve();
      } else if (key.ctrl && key.name === "c") {
        reject(new Error("Process terminated by the user"));
      }
    }
  });
}

function listener(ch, key) {
      }
    }

function readJson(filename) {
  return JSON.parse(fs.readFileSync(filename, "utf-8"));
}

function writeJson(filename, content) {
  fs.writeFileSync(filename, JSON.stringify(content, null, 2) + "\n");
}

function processFile(filename, fn) {
  const content = fs.readFileSync(filename, "utf-8");
  fs.writeFileSync(filename, fn(content));
}

  const chalk = require("chalk");
  const { string: outdentString } = require("outdent");
  const minimist = require("minimist");
  const semver = require("semver");

  const { readJson } = require("./utils");

  const params = minimist(process.argv.slice(2), {
    string: ["version"],
    boolean: ["dry"],
    alias: { v: "version" },
  });

  const previousVersion = execSync("git describe --tags --abbrev=0")
    .toString()
    .trim();

  if (semver.parse(previousVersion) === null) {
    throw new Error(`Unexpected previousVersion: ${previousVersion}`);
  } else {
    params.previousVersion = previousVersion;
    params.previousVersionOnDefaultBranch = (
      await readJson("package.json")
    ).version;
  }

  const steps = [
    require("./steps/validate-new-version"),
    require("./steps/check-git-status"),
    require("./steps/install-dependencies"),
    require("./steps/run-tests"),
    require("./steps/update-version"),
    require("./steps/generate-bundles"),
    require("./steps/update-changelog"),
    require("./steps/push-to-git"),
    require("./steps/publish-to-npm"),
    require("./steps/bump-prettier"),
    require("./steps/update-dependents-count"),
    require("./steps/post-publish-steps"),
  ];

  try {
    for (const step of steps) {
      await step(params);
    }
    const message = outdentString(error.message.trim());
    const stack = error.stack.replace(message, "");
    console.error(`${chalk.red("error")} ${message}\n${stack}`);
  }
}

async function format() {
  await execa("yarn", ["lint:eslint", "--fix"]);
  await execa("yarn", ["lint:prettier", "--write"]);
}

async function commit(version) {
  await execa("git", [
    "commit",
    "-am",
    `Bump Prettier dependency to ${version}`,
  ]);

  // Add rev to `.git-blame-ignore-revs` file
  const file = ".git-blame-ignore-revs";
  const mark = "# Prettier bump after release";
  const rev = await execa.stdout("git", ["rev-parse", "HEAD"]);
  let text = fs.readFileSync(file, "utf8");
  text = text.replace(mark, `${mark}\n# ${version}\n${rev}`);
  fs.writeFileSync(file, text);
  await execa("git", ["commit", "-am", `Git blame ignore ${version}`]);

  await execa("git", ["push"]);
}

async function bump({
  version,
  previousVersion,
  previousVersionOnDefaultBranch,
}) {
  const pkg = await readJson("package.json");
  if (semver.diff(version, previousVersion) === "patch") {
    pkg.version = previousVersionOnDefaultBranch; // restore the `-dev` version
  } else {
    pkg.version = semver.inc(version, "minor") + "-dev";
  }
  await writeJson("package.json", pkg, { spaces: 2 });
}

async function install() {
  await execa("rm", ["-rf", "node_modules"]);
  await execa("yarn", ["install"]);

  const status = await execa.stdout("git", ["ls-files", "-m"]);
  if (status) {
      "The lockfile needs to be updated, commit it before making the release."
    );
  }
}

function getBlogPostInfo(version) {
  const date = new Date();
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");

  return {
    file: `website/blog/${year}-${month}-${day}-${version}.md`,
    path: `blog/${year}/${month}/${day}/${version}.html`,
  };
}

function writeChangelog({ version, previousVersion, releaseNotes }) {
  const changelog = fs.readFileSync("CHANGELOG.md", "utf-8");
  const newEntry = outdent`
    # ${version}

    [diff](https://github.com/prettier/prettier/compare/${previousVersion}...${version})

    ${releaseNotes}
  `;
  fs.writeFileSync("CHANGELOG.md", newEntry + "\n\n" + changelog);
}

async function bump({ version }) {
  pkg.version = version;

  // Update github issue templates
  processFile(".github/ISSUE_TEMPLATE/formatting.md", (content) =>
    content.replace(/^(\*\*Prettier ).*?(\*\*)$/m, `$1${version}$2`)
  );
  processFile(".github/ISSUE_TEMPLATE/integration.md", (content) =>
    content.replace(/^(- Prettier Version: ).*?$/m, `$1${version}`)
  );
  processFile("docs/install.md", (content) =>
    content.replace(/^(npx prettier@)\S+/m, `$1${version}`)
  );

  // Update unpkg link in docs
  processFile("docs/browser.md", (content) =>
    content.replace(/(\/\/unpkg\.com\/prettier@).*?\//g, `$1${version}/`)
  );

  await execa("yarn", ["update-stable-docs"], {
    cwd: "./website",
  });
}

async function checkSchema() {
  const schema = await execa.stdout("node", ["scripts/generate-schema.js"]);
  const remoteSchema = await logPromise(
    "Checking current schema in SchemaStore",
    fetch(RAW_URL)
      .then((r) => r.text())
      .then((t) => t.trim())
  );

  if (schema === remoteSchema) {
    return;
  }

  return outdentString(chalk`
    {bold.underline The schema in {yellow SchemaStore} needs an update.}
    - Open {cyan.underline ${EDIT_URL}}
    - Run {yellow node scripts/generate-schema.js} and copy the new schema
    - Paste it on GitHub interface
    - Open a PR
  `);
}

function twitterAnnouncement() {
    {bold.underline Announce on Twitter}
    - Open {cyan.underline https://tweetdeck.twitter.com}
    - Make sure you are tweeting from the {yellow @PrettierCode} account.
    - Tweet about the release, including the blog post URL.
  `);
}

async function pushGit({ version }) {
  await execa("git", ["commit", "-am", `Release ${version}`]);
  await execa("git", ["tag", "-a", version, "-m", `Release ${version}`]);
  await execa("git", ["push", "--tags"]);
}

async function update() {
  const npmPage = await logPromise(
    "Fetching npm dependents count",
    fetch("https://www.npmjs.com/package/prettier").then((response) =>
      response.text()
    )
  );
  const dependentsCountNpm = Number(
    npmPage.match(/"dependentsCount":(\d+),/)[1]
  );
  if (Number.isNaN(dependentsCountNpm)) {
      "Invalid data from https://www.npmjs.com/package/prettier"
    );
  }

  const githubPage = await logPromise(
    "Fetching github dependents count",
    fetch(
      "https://github.com/prettier/prettier/network/dependents"
    ).then((response) => response.text())
  );
  const dependentsCountGithub = Number(
    githubPage
      .replace(/\n/g, "")
      .match(
        /<svg.*?octicon-code-square.*?>.*?<\/svg>\s*([\d,]+?)\s*Repositories\s*<\/a>/
      )[1]
      .replace(/,/g, "")
  );
      "Invalid data from https://github.com/prettier/prettier/network/dependents"
    );
  }

  processFile("website/pages/en/index.js", (content) =>
    content
      .replace(
        /(<strong data-placeholder="dependent-npm">)(.*?)(<\/strong>)/,
        `$1${formatNumber(dependentsCountNpm)}$3`
      )
      .replace(
        /(<strong data-placeholder="dependent-github">)(.*?)(<\/strong>)/,
        `$1${formatNumber(dependentsCountGithub)}$3`
      )
  );

  const isUpdated = await logPromise(
    "Checking if dependents count has been updated",
    execa("git", ["diff", "--name-only"]).then(
      ({ stdout }) => stdout === "website/pages/en/index.js"
    )
  );

  if (isUpdated) {
    logPromise(
      "Committing and pushing to remote",
      (async () => {
        await execa("git", ["add", "."]);
        await execa("git", ["commit", "-m", "Update dependents count"]);
        await execa("git", ["push"]);
      })()
    );
  }
}

function formatNumber(value) {
  if (value < 1e4) {
    return String(value).slice(0, 1) + "0".repeat(String(value).length - 1);
  }
  if (value < 1e6) {
    return Math.floor(value / 1e2) / 10 + "k";
  }
  return Math.floor(value / 1e5) / 10 + " million";
}

create(context) {
    return {
      [selector](node) {
        const [breakContents] = node.arguments;
        context.report({
          node,
          messageId,
          fix: (fixer) =>
            fixer.removeRange([breakContents.range[1], node.range[1] - 1]),
        });
      },
    };
  }

(fixer) =>
            fixer.removeRange([breakContents.range[1], node.range[1] - 1])

    const sourceCode = context.getSourceCode();

    return {
        const indentDoc = node.arguments[0].arguments[0];
        const doc = node.arguments[1];

        // Use text to compare same `doc`
        if (sourceCode.getText(indentDoc) !== sourceCode.getText(doc)) {
          return;
        }

          node,
          *fix(fixer) {
            yield fixer.replaceText(node.callee, "indentIfBreak");
            const openingParenthesisToken = sourceCode.getTokenAfter(
              node.callee
            );
            const commaToken = sourceCode.getTokenBefore(
              doc,
              ({ type, value }) => type === "Punctuator" && value === ","
            );
            yield fixer.replaceTextRange(
              [openingParenthesisToken.range[1], commaToken.range[1]],
              ""
            );
          },
        });
      },
    };
  }

*fix(fixer) {
            );
              doc,
            );
              ""
            );
          }

    return {
          node,
          fix: (fixer) => fixer.replaceText(node, "each"),
        });
      },
    };
  }

    if (path.basename(context.getFilename()) !== "needs-parens.js") {
      return {};
    }

    return {
      [parentPropertyCheckSelector](node) {
        const { operator, left, right } = node;
        const { property } = [left, right].find(
          ({ type }) => type === "MemberExpression"
        );
        const propertyText =
          property.type === "Identifier"
            ? `"${property.name}"`
            : sourceCode.getText(property);

          node,
          messageId: MESSAGE_ID_PREFER_NAME_CHECK,
          data: {
            property: sourceCode.getText(property),
            propertyText,
            operator,
          },
            fixer.replaceText(node, `name ${operator} ${propertyText}`),
        });
      },
      [nameCheckSelector](node) {
          node,
          messageId: MESSAGE_ID_NAME_CHECK_FIRST,
        });
      },
    };
  }

(fixer) =>
            fixer.replaceText(node, `name ${operator} ${propertyText}`)

(ruleId, tests) => {
  new RuleTester({ parserOptions: { ecmaVersion: 2021 } }).run(
    ruleId,
    rules[ruleId],
    tests
  );
}

    return {
          node,
          messageId: MESSAGE_ID,
          data: { function: node.property.name },
            fixer.replaceTextRange([node.range[0], node.property.range[0]], ""),
        });
      },
    };
  }

(fixer) =>
            fixer.replaceTextRange([node.range[0], node.property.range[0]], "")

    const ignored = new Set(context.options);
    return {
      "Identifier[name=/JSX/]:not(ObjectExpression > Property.properties > .key)"(
        node
      ) {
        const { name } = node;

        if (ignored.has(name)) {
          return;
        }

        const fixed = name.replace(/JSX/g, "Jsx");
          node,
          data: { name, fixed },
          fix: (fixer) => fixer.replaceText(node, fixed),
        });
      },
    };
  }

    const fileName = context.getFilename();
    const ignored = new Map(
      context.options.map((option) => {
        if (typeof option === "string") {
          option = { file: option };
        }
        const { file, functions } = option;
        return [
          path.join(__dirname, "../../..", file),
          functions ? new Set(functions) : true,
        ];
      })
    );
    // avoid report on `const {comments} = node` twice
    const reported = new Set();
    return {
        if (reported.has(node)) {
          return;
        }

        if (ignored.has(fileName)) {
          const functionNames = ignored.get(fileName);
          if (functionNames === true) {
            return;
          }
          let isIgnored;
          let currentNode = node.parent;
          while (currentNode) {
            if (
              currentNode.type === "FunctionDeclaration" &&
              currentNode.id &&
              currentNode.id.type === "Identifier" &&
              functionNames.has(currentNode.id.name)
            ) {
              isIgnored = true;
              break;
            }
            currentNode = currentNode.parent;
          }
          if (isIgnored) {
            return;
          }
        }
        reported.add(node);
          node,
        });
      },
    };
  }

    return {
          node,
          fix: (fixer) => fixer.replaceText(node, ""),
        });
      },
    };
  }

(path) =>
  `[${path}.type="MemberExpression"][${path}.property.type="Identifier"][${path}.property.name="length"]`

(node) =>
  node.type === "CallExpression" &&
  node.callee.type === "MemberExpression" &&
  node.callee.object.type === "Identifier" &&
  node.callee.object.name === "Array" &&
  node.callee.property.type === "Identifier" &&
  node.callee.property.name === "isArray"

    return {
        let { left, right } = node;

        while (left.type === "LogicalExpression" && left.operator === "&&") {
          left = left.right;
        }

        let leftObject = left;
        // `Array.isArray(foo)`
        if (isArrayIsArrayCall(leftObject)) {
          leftObject = leftObject.arguments[0];
        }

        const rightObject =
          right.type === "BinaryExpression" ? right.left.object : right.object;
        const objectText = sourceCode.getText(rightObject);
        // Simple compare with code
        if (sourceCode.getText(leftObject) !== objectText) {
          return;
        }

        const [start] = left.range;
        const [, end] = node.range;
          loc: {
            start: sourceCode.getLocFromIndex(start),
            end: sourceCode.getLocFromIndex(end),
          },
          fix(fixer) {
            return fixer.replaceTextRange(
              [start, end],
              `isNonEmptyArray(${objectText})`
            );
          },
        });
      },
      [negativeSelector](node) {

        while (left.type === "LogicalExpression" && left.operator === "||") {
        }

        if (!left.type === "UnaryExpression" || left.operator !== "!") {
          return;
        }

          right.type === "UnaryExpression"
            ? right.argument.object
            : right.left.object;
        let leftObject = left.argument;
        }

          return;
        }

          loc: {
          },
              `!isNonEmptyArray(${objectText})`
            );
          },
        });
      },
    };
  }

fix(fixer) {
            );
          }

(directory, id) => {
  try {
    return require.resolve(id, { paths: [directory] });
  } catch {
    // noop
  }
}

    const filename = context.getFilename();
    const directory = path.dirname(filename);
    const resolve = (id) => resolveModuleInDirectory(directory, id);

    return {
      [SELECTOR](node) {
        const id = node.value;

        if (id.endsWith(".json") || !id.includes("/")) {
          return;
        }

        const file = resolve(id);

        if (!file) {
          return;
        }

        const extension = path.extname(file);
        if (extension !== ".json") {
          return;
        }

        let fix;
        if (resolve(`${id}.json`) === file) {
          fix = (fixer) => {
            const [start, end] = node.range;
            return fixer.replaceTextRange([start + 1, end - 1], `${id}.json`);
          };
        }

          node,
          data: { id },
          fix,
        });
      },
    };
  }

function Se(Rg,Mg){return Mg={exports:{}},Rg(Mg,Mg.exports),Mg.exports}

function Pe(Rg){return hp[63&Rg>>18]+hp[63&Rg>>12]+hp[63&Rg>>6]+hp[63&Rg]}

function Ne(Rg,Mg,Og){var Yg,Vg=[];for(var Ug=Mg;Ug<Og;Ug+=3)Yg=(Rg[Ug]<<16)+(Rg[Ug+1]<<8)+Rg[Ug+2],Vg.push(Pe(Yg));return Vg.join('')}

function Oe(){return Ve.TYPED_ARRAY_SUPPORT?2147483647:1073741823}

function Ye(Rg,Mg){if(Oe()<Mg)throw new RangeError('Invalid typed array length');return Ve.TYPED_ARRAY_SUPPORT?(Rg=new Uint8Array(Mg),Rg.__proto__=Ve.prototype):(null===Rg&&(Rg=new Ve(Mg)),Rg.length=Mg),Rg}

function Ve(Rg,Mg,Og){if(!Ve.TYPED_ARRAY_SUPPORT&&!(this instanceof Ve))return new Ve(Rg,Mg,Og);if('number'==typeof Rg){if('string'==typeof Mg)throw new Error('If encoding is specified then the first argument must be a string');return Je(this,Rg)}return Ue(this,Rg,Mg,Og)}

function Ue(Rg,Mg,Og,Yg){if('number'==typeof Mg)throw new TypeError('"value" argument must not be a number');return'undefined'!=typeof ArrayBuffer&&Mg instanceof ArrayBuffer?Qe(Rg,Mg,Og,Yg):'string'==typeof Mg?Ze(Rg,Mg,Og):$e(Rg,Mg)}

function Xe(Rg){if('number'!=typeof Rg)throw new TypeError('"size" argument must be a number');else if(0>Rg)throw new RangeError('"size" argument must not be negative')}

function We(Rg,Mg,Og,Yg){return Xe(Mg),0>=Mg?Ye(Rg,Mg):void 0===Og?Ye(Rg,Mg):'string'==typeof Yg?Ye(Rg,Mg).fill(Og,Yg):Ye(Rg,Mg).fill(Og)}

function Ze(Rg,Mg,Og){if(('string'!=typeof Og||''===Og)&&(Og='utf8'),!Ve.isEncoding(Og))throw new TypeError('"encoding" must be a valid string encoding');var Yg=0|_t(Mg,Og);Rg=Ye(Rg,Yg);var Vg=Rg.write(Mg,Og);return Vg!==Yg&&(Rg=Rg.slice(0,Vg)),Rg}

function Ke(Rg,Mg){var Og=0>Mg.length?0:0|St(Mg.length);Rg=Ye(Rg,Og);for(var Yg=0;Yg<Og;Yg+=1)Rg[Yg]=255&Mg[Yg];return Rg}

function Qe(Rg,Mg,Og,Yg){if(Mg.byteLength,0>Og||Mg.byteLength<Og)throw new RangeError('\'offset\' is out of bounds');if(Mg.byteLength<Og+(Yg||0))throw new RangeError('\'length\' is out of bounds');return Mg=void 0===Og&&void 0===Yg?new Uint8Array(Mg):void 0===Yg?new Uint8Array(Mg,Og):new Uint8Array(Mg,Og,Yg),Ve.TYPED_ARRAY_SUPPORT?(Rg=Mg,Rg.__proto__=Ve.prototype):Rg=Ke(Rg,Mg),Rg}

function $e(Rg,Mg){if(Tt(Mg)){var Og=0|St(Mg.length);return(Rg=Ye(Rg,Og),0===Rg.length)?Rg:(Mg.copy(Rg,0,0,Og),Rg)}if(Mg){if('undefined'!=typeof ArrayBuffer&&Mg.buffer instanceof ArrayBuffer||'length'in Mg)return'number'!=typeof Mg.length||Za(Mg.length)?Ye(Rg,0):Ke(Rg,Mg);if('Buffer'===Mg.type&&Rp(Mg.data))return Ke(Rg,Mg.data)}throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')}

function St(Rg){if(Rg>=Oe())throw new RangeError('Attempt to allocate Buffer larger than maximum size: 0x'+Oe().toString(16)+' bytes');return 0|Rg}

function _t(Rg,Mg){if(Tt(Rg))return Rg.length;if('undefined'!=typeof ArrayBuffer&&'function'==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(Rg)||Rg instanceof ArrayBuffer))return Rg.byteLength;'string'!=typeof Rg&&(Rg=''+Rg);var Og=Rg.length;if(0===Og)return 0;for(var Yg=!1;;)switch(Mg){case'ascii':case'latin1':case'binary':return Og;case'utf8':case'utf-8':case void 0:return Va(Rg).length;case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return 2*Og;case'hex':return Og>>>1;case'base64':return Wa(Rg).length;default:if(Yg)return Va(Rg).length;Mg=(''+Mg).toLowerCase(),Yg=!0;}}

function Lt(Rg,Mg,Og,Yg,Vg){if(0===Rg.length)return-1;if('string'==typeof Og?(Yg=Og,Og=0):2147483647<Og?Og=2147483647:-2147483648>Og&&(Og=-2147483648),Og=+Og,isNaN(Og)&&(Og=Vg?0:Rg.length-1),0>Og&&(Og=Rg.length+Og),Og>=Rg.length){if(Vg)return-1;Og=Rg.length-1}else if(0>Og)if(Vg)Og=0;else return-1;if('string'==typeof Mg&&(Mg=Ve.from(Mg,Yg)),Tt(Mg))return 0===Mg.length?-1:It(Rg,Mg,Og,Yg,Vg);if('number'==typeof Mg)return Mg&=255,Ve.TYPED_ARRAY_SUPPORT&&'function'==typeof Uint8Array.prototype.indexOf?Vg?Uint8Array.prototype.indexOf.call(Rg,Mg,Og):Uint8Array.prototype.lastIndexOf.call(Rg,Mg,Og):It(Rg,[Mg],Og,Yg,Vg);throw new TypeError('val must be string, number or Buffer')}

function Rt(Rg,Mg,Og,Yg){Og=+Og||0;var Vg=Rg.length-Og;Yg?(Yg=+Yg,Yg>Vg&&(Yg=Vg)):Yg=Vg;var Ug=Mg.length;if(0!=Ug%2)throw new TypeError('Invalid hex string');Yg>Ug/2&&(Yg=Ug/2);for(var Xg=0;Xg<Yg;++Xg){var Wg=parseInt(Mg.substr(2*Xg,2),16);if(isNaN(Wg))return Xg;Rg[Og+Xg]=Wg}return Xg}

function Mt(Rg,Mg,Og,Yg){return Ja(Va(Mg,Rg.length-Og),Rg,Og,Yg)}

function Ut(Rg,Mg,Og,Yg){return Ja(Xa(Mg,Rg.length-Og),Rg,Og,Yg)}

function Xt(Rg,Mg,Og){return 0===Mg&&Og===Rg.length?Le(Rg):Le(Rg.slice(Mg,Og))}

function Jt(Rg){var Mg=Rg.length;if(Mg<=Mp)return String.fromCharCode.apply(String,Rg);for(var Og='',Yg=0;Yg<Mg;)Og+=String.fromCharCode.apply(String,Rg.slice(Yg,Yg+=Mp));return Og}

function Zt(Rg,Mg,Og){var Yg='';Og=Math.min(Rg.length,Og);for(var Vg=Mg;Vg<Og;++Vg)Yg+=String.fromCharCode(127&Rg[Vg]);return Yg}

function Kt(Rg,Mg,Og){var Yg='';Og=Math.min(Rg.length,Og);for(var Vg=Mg;Vg<Og;++Vg)Yg+=String.fromCharCode(Rg[Vg]);return Yg}

function Qt(Rg,Mg,Og){var Yg=Rg.length;(!Mg||0>Mg)&&(Mg=0),(!Og||0>Og||Og>Yg)&&(Og=Yg);var Vg='';for(var Ug=Mg;Ug<Og;++Ug)Vg+=Ya(Rg[Ug]);return Vg}

function $t(Rg,Mg,Og){var Yg=Rg.slice(Mg,Og),Vg='';for(var Ug=0;Ug<Yg.length;Ug+=2)Vg+=String.fromCharCode(Yg[Ug]+256*Yg[Ug+1]);return Vg}

function Sa(Rg,Mg,Og){if(0!=Rg%1||0>Rg)throw new RangeError('offset is not uint');if(Rg+Mg>Og)throw new RangeError('Trying to access beyond buffer length')}

function Ta(Rg,Mg,Og,Yg,Vg,Ug){if(!Tt(Rg))throw new TypeError('"buffer" argument must be a Buffer instance');if(Mg>Vg||Mg<Ug)throw new RangeError('"value" argument is out of bounds');if(Og+Yg>Rg.length)throw new RangeError('Index out of range')}

function Na(Rg,Mg,Og,Yg){if(Og+Yg>Rg.length)throw new RangeError('Index out of range');if(0>Og)throw new RangeError('Index out of range')}

function Oa(Rg){return Rg.trim?Rg.trim():Rg.replace(/^\s+|\s+$/g,'')}

function Ya(Rg){return 16>Rg?'0'+Rg.toString(16):Rg.toString(16)}

function Ua(Rg){var Mg=[];for(var Og=0;Og<Rg.length;++Og)Mg.push(255&Rg.charCodeAt(Og));return Mg}

function Xa(Rg,Mg){var Og,Yg,Vg,Ug=[];for(var Xg=0;Xg<Rg.length&&!(0>(Mg-=2));++Xg)Og=Rg.charCodeAt(Xg),Yg=Og>>8,Vg=Og%256,Ug.push(Vg),Ug.push(Yg);return Ug}

function Ja(Rg,Mg,Og,Yg){for(var Vg=0;Vg<Yg&&!(Vg+Og>=Mg.length||Vg>=Rg.length);++Vg)Mg[Vg+Og]=Rg[Vg];return Vg}

function Ka(Rg){return null!=Rg&&(!!Rg._isBuffer||Qa(Rg)||$a(Rg))}

function $a(Rg){return'function'==typeof Rg.readFloatLE&&'function'==typeof Rg.slice&&Qa(Rg.slice(0,0))}

function Sn(){throw new Error('setTimeout has not been defined')}

function Tn(){throw new Error('clearTimeout has not been defined')}

function _n(Rg){if(Up===setTimeout)return setTimeout(Rg,0);if((Up===Sn||!Up)&&setTimeout)return Up=setTimeout,setTimeout(Rg,0);try{return Up(Rg,0)}catch(Mg){try{return Up.call(null,Rg,0)}catch(Og){return Up.call(this,Rg,0)}}}

function Pn(Rg){if(Xp===clearTimeout)return clearTimeout(Rg);if((Xp===Tn||!Xp)&&clearTimeout)return Xp=clearTimeout,clearTimeout(Rg);try{return Xp(Rg)}catch(Mg){try{return Xp.call(null,Rg)}catch(Og){return Xp.call(this,Rg)}}}

function Rn(Rg,Mg){var Og=In.styles[Mg];return Og?'\x1B['+In.colors[Og][0]+'m'+Rg+'\x1B['+In.colors[Og][1]+'m':Rg}

function On(Rg){var Mg={};return Rg.forEach(function(Og){Mg[Og]=!0}),Mg}

(text) => {
  const cwd = process.cwd();

  const variants = /^[a-z]:\\/i.test(cwd)
    ? [
        cwd.charAt(0).toLowerCase() + cwd.slice(1),
        cwd.charAt(0).toUpperCase() + cwd.slice(1),
      ]
    : [cwd];

  for (const variant of variants) {
    while (text.includes(variant)) {
      text = text.replace(variant, "<cwd>");
    }
  }

}

(value) =>
    typeof value === "string" &&
    (value.includes("\\") || value.includes(process.cwd()))

(value, serializer) =>
    serializer(replaceCWD(value).replace(/\\/g, "/"))

  // This dummy plugin ignores the input and simply returns the given doc.
  // This is to make sure that the doc will go through all the stages a real doc
  // returned by a real plugin would go (e.g. `propagateBreaks`).
  const dummyPlugin = {
    parsers: {
      dummy: {
        parse: () => ({}),
        astFormat: "dummy",
      },
    },
      dummy: {
        print: () => doc,
      },
    },
  };

  return prettier.format("_", {
    plugins: [dummyPlugin],
    parser: "dummy",
  });
}

function runPrettier(dir, args = [], options = {}) {
  args = Array.isArray(args) ? args : [args];

  let status;
  let stdout = "";
  let stderr = "";

  jest.spyOn(process, "exit").mockImplementation((exitCode) => {
    if (status === undefined) {
      status = exitCode || 0;
    }
  });

  jest
    .spyOn(process.stdout, "write")
    .mockImplementation((text) => appendStdout(text));

  jest
    .spyOn(process.stderr, "write")
    .mockImplementation((text) => appendStderr(text));

  jest
    .spyOn(console, "log")
    .mockImplementation((text) => appendStdout(text + "\n"));

  jest
    .spyOn(console, "warn")
    .mockImplementation((text) => appendStderr(text + "\n"));

  jest
    .spyOn(console, "error")

  jest.spyOn(Date, "now").mockImplementation(() => 0);

  const write = [];

  jest.spyOn(fs, "writeFileSync").mockImplementation((filename, content) => {
    write.push({ filename, content });
  });

  const origStatSync = fs.statSync;

  jest.spyOn(fs, "statSync").mockImplementation((filename) => {
    if (path.basename(filename) === "virtualDirectory") {
      return origStatSync(path.join(__dirname, __filename));
    }
    return origStatSync(filename);
  });

  const originalCwd = process.cwd();
  const originalArgv = process.argv;
  const originalExitCode = process.exitCode;
  const originalStdinIsTTY = process.stdin.isTTY;
  const originalStdoutIsTTY = process.stdout.isTTY;

  process.chdir(normalizeDir(dir));
  process.stdin.isTTY = Boolean(options.isTTY);
  process.stdout.isTTY = Boolean(options.stdoutIsTTY);
  process.argv = ["path/to/node", "path/to/prettier/bin", ...args];

  jest.resetModules();

  // We cannot use `jest.setMock("get-stream", impl)` here, because in the
  // production build everything is bundled into one file so there is no
  // "get-stream" module to mock.
  jest
    .spyOn(require(thirdParty), "getStdin")
    .mockImplementation(() => SynchronousPromise.resolve(options.input || ""));
  jest
    .spyOn(require(thirdParty), "isCI")
    .mockImplementation(() => Boolean(options.ci));
  jest
    .spyOn(require(thirdParty), "cosmiconfig")
    .mockImplementation((moduleName, options) =>
      require("cosmiconfig").cosmiconfig(moduleName, {
        stopDir: path.join(__dirname, "cli"),
      })
    );
  jest
    .spyOn(require(thirdParty), "cosmiconfigSync")
      require("cosmiconfig").cosmiconfigSync(moduleName, {
      })
    );
  jest
    .spyOn(require(thirdParty), "findParentDir")
    .mockImplementation(() => process.cwd());

  try {
    require(prettierCli);
    status = (status === undefined ? process.exitCode : status) || 0;
    status = 1;
    stderr += error.message;
  } finally {
    process.chdir(originalCwd);
    process.argv = originalArgv;
    process.exitCode = originalExitCode;
    process.stdin.isTTY = originalStdinIsTTY;
    process.stdout.isTTY = originalStdoutIsTTY;
    jest.restoreAllMocks();
  }

  const result = { status, stdout, stderr, write };

  const testResult = (testOptions) => {
    for (const name of Object.keys(result)) {
      test(`(${name})`, () => {
        const value =
          // \r is trimmed from jest snapshots by default;
          // manually replacing this character with /*CR*/ to test its true presence
          // If ignoreLineEndings is specified, \r is simply deleted instead
          typeof result[name] === "string"
            ? options.ignoreLineEndings
              ? stripAnsi(result[name]).replace(/\r/g, "")
              : stripAnsi(result[name]).replace(/\r/g, "/*CR*/")
            : result[name];
        if (name in testOptions) {
          if (name === "status" && testOptions[name] === "non-zero") {
            expect(value).not.toEqual(0);
          } else {
            expect(value).toEqual(testOptions[name]);
          }
        } else {
          expect(value).toMatchSnapshot();
        }
      });
    }

  };

  return { test: testResult, ...result };

  function appendStdout(text) {
      stdout += text;
    }
  }
  function appendStderr(text) {
      stderr += text;
    }
  }
}

(testOptions) => {
          } else {
          }
        } else {
        }
      });
    }

  }

function appendStdout(text) {
    }
  }

function appendStderr(text) {
    }
  }

function normalizeDir(dir) {
  const isRelative = dir[0] !== "/";
  return isRelative ? path.resolve(__dirname, dir) : dir;
}

(path, options) =>
        options.fooString ? `foo:${options.fooString}` : path.getValue().text

        options.fooOption ? `foo:${options.fooOption}` : path.getValue().text

        JSON.stringify({
          tabWidth: options.tabWidth,
          bracketSpacing: options.bracketSpacing
        })

path =>
        concat([
          "content from `prettier-plugin-bar.js` file + ",
          path.getValue().text
        ])

function rcJson() {
  console.log.apply(null, [
    "rc-json/file.js",
    "should have trailing comma",
    "and single quotes"
  ]);
}

  console.log("should have space width 2 despite ../.editorconfig specifying 8, because ./.hg is present");
}

function rcToml() {
    "rc-toml/file.js",
  ]);
}

function js() {
  console.log("js/file.js should have tab width 8 (1 if CLI)");
}

function rcYaml() {
    "rc-yaml/file.js",
  ]);
}

function packageJs() {
  console.log("package/file.js should have tab width 3");
}

function noConfigJs() {
  console.log("no-config/file.js should have no semicolons");
}

This config should not be evaluated since the directory is ignored

multiple patterns by with ignore pattern, ignores node_modules by default

multiple patterns by with ignore pattern, ignores node_modules by with ./**/*.js

multiple patterns by with ignore pattern, doesn't ignore node_modules with --with-node-modules flag

multiple patterns, throw error and exit with non zero code on non existing files

throw error with invalid config precedence option (configPrecedence)

parser(text, parsers) {
      const ast = parsers.babel(text);

      // This may happens in this use case https://github.com/prettier/prettier/pull/5497#issuecomment-439841965
      // Simply simulate it
      const callExpression = ast.program.body[0].expression;
      callExpression.extra = { parenthesized: true };
      callExpression.trailingComments = [];

    }

doesn't ignore node_modules with --with-node-modules flag for file list

plugin search should not crash when prettier isn't inside a directory

function getCoreInfo() {
  const supportInfo = prettier.getSupportInfo();
  const languages = supportInfo.languages.reduce(
    (obj, language) => ({ [language.name]: language.parsers, ...obj }),
    {}
  );
  const options = supportInfo.options.reduce(
    (obj, option) => ({
      [option.name]: {
        type: option.type,
        default: option.default,
        ...(option.type === "int"
          ? { range: option.range }
          : option.type === "choice"
          ? { choices: option.choices.map((choice) => choice.value) }
          : null),
      },
      ...obj,
    }),
    {}
  );
}

should not exit non-zero for already prettified code with --debug-check + --check

should not exit non-zero for already prettified code with --debug-check + --list-different

fixtures-2: Should match all js files and all supported files in the '!dir.js' directory

fixtures-3: Should match `outside.js`, `dir/inside.js` and `dir/node_modules/in-node_modules.js`

function runPrettierWithLogLevel(logLevel, patterns) {
  const result = runPrettier("cli/loglevel", [
    "--loglevel",
    logLevel,
    "--unknown-option",
    "--parser",
    "unknown-parser",
    "not-found.js",
  ]);

  expect(result.status).toEqual(2);

  const stderr = stripAnsi(result.stderr);

  if (patterns) {
    for (const pattern of patterns) {
      expect(stderr).toMatch(pattern);
    }
  } else {
    expect(stderr).toMatch(/^\s*$/);
  }
}

prints information for debugging comment attachment with --debug-print-comments

automatically loads 'prettier-plugin-*' from --plugin-search-dir (same as autoload dir)

automatically loads '@prettier/plugin-*' from --plugin-search-dir (same as autoload dir)

automatically loads '@<name>/prettier-plugin-*' from --plugin-search-dir (same as autoload dir)

automatically loads 'prettier-plugin-*' from --plugin-search-dir (different to autoload dir)

automatically loads '@prettier/plugin-*' from --plugin-search-dir (different to autoload dir)

does not crash when --plugin-search-dir does not contain node_modules

loads --plugin by relative path to its directory (assuming index.js)

loads --plugin by relative path to its directory without leading ./ (assuming index.js)

loads --plugin by filename without leading ./ and ext, should resolve to file, not package

loads --plugin by bespoke plugin name (assuming it is installed in cwd)

resolves configuration from external files and overrides by extname

API resolveConfig.sync with file arg and .editorconfig (key = unset)

API resolveConfig with nested file arg and .editorconfig and indent_size = tab

API resolveConfig.sync with nested file arg and .editorconfig and indent_size = tab

API resolveConfig resolves relative path values based on config filepath

CLI overrides take precedence with --config-precedence cli-override

CLI overrides take lower precedence with --config-precedence file-override

CLI overrides are still applied when no config is found with --config-precedence file-override

CLI overrides gets ignored when config exists with --config-precedence prefer-file

CLI overrides gets applied when no config exists with --config-precedence prefer-file

CLI --stdin-filepath works with --config-precedence file-override

CLI --stdin-filepath works with --config-precedence cli-override

typescript parser should throw the first error when both JSX and non-JSX mode failed

Adjacent JSX' error should not be swallowed by Babel's error recovery

function testPatterns(namePrefix, cliArgs, expected = {}) {
  const testName =
    (namePrefix ? namePrefix + ": " : "") +
    "prettier " +
    cliArgs
      .map((arg) => (/^[\w./=-]+$/.test(arg) ? arg : `'${arg}'`))
      .join(" ");

  describe(testName, () => {
    runPrettier("cli/patterns-dirs", [...cliArgs, "-l"]).test({
      write: [],
      ...(!("status" in expected) && { stderr: "", status: 1 }),
      ...expected,
    });
  });
}

extracts file-info with ignored=true for a file in .prettierignore

extracts file-info with ignored=true for a file in a hand-picked .prettierignore

extracts file-info with with ignored=true for a file in node_modules

extracts file-info with ignored=false for a file in node_modules when --with-node-modules provided

extracts file-info with inferredParser=foo when plugins are autoloaded

extracts file-info with inferredParser=foo when plugins are loaded with --plugin-search-dir

extracts file-info with inferredParser=foo when a plugin is hand-picked

extracts file-info for a JS file with no extension but a standard shebang

extracts file-info for a JS file with no extension but an env-based shebang

API getFileInfo with ignorePath and resolveConfig should infer parser with correct filepath

format correctly if stdin content compatible with stdin-filepath

apply editorconfig for stdin-filepath with nonexistent directory

don’t apply editorconfig outside project for stdin-filepath with nonexistent directory

output file as-is if stdin-filepath matched patterns in ignore-path