text: 'use strict';
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  var compilerDom = require('@vue/compiler-dom');
  var shared = require('@vue/shared');
  
  const SSR_INTERPOLATE = Symbol(`ssrInterpolate`);
  const SSR_RENDER_VNODE = Symbol(`ssrRenderVNode`);
  const SSR_RENDER_COMPONENT = Symbol(`ssrRenderComponent`);
  const SSR_RENDER_SLOT = Symbol(`ssrRenderSlot`);
  const SSR_RENDER_CLASS = Symbol(`ssrRenderClass`);
  const SSR_RENDER_STYLE = Symbol(`ssrRenderStyle`);
  const SSR_RENDER_ATTRS = Symbol(`ssrRenderAttrs`);
  const SSR_RENDER_ATTR = Symbol(`ssrRenderAttr`);
  const SSR_RENDER_DYNAMIC_ATTR = Symbol(`ssrRenderDynamicAttr`);
  const SSR_RENDER_LIST = Symbol(`ssrRenderList`);
  const SSR_INCLUDE_BOOLEAN_ATTR = Symbol(`ssrIncludeBooleanAttr`);
  const SSR_LOOSE_EQUAL = Symbol(`ssrLooseEqual`);
  const SSR_LOOSE_CONTAIN = Symbol(`ssrLooseContain`);
  const SSR_RENDER_DYNAMIC_MODEL = Symbol(`ssrRenderDynamicModel`);
  const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`);
  const SSR_RENDER_TELEPORT = Symbol(`ssrRenderTeleport`);
  const SSR_RENDER_SUSPENSE = Symbol(`ssrRenderSuspense`);
  const ssrHelpers = {
      [SSR_INTERPOLATE]: `ssrInterpolate`,
      [SSR_RENDER_VNODE]: `ssrRenderVNode`,
      [SSR_RENDER_COMPONENT]: `ssrRenderComponent`,
      [SSR_RENDER_SLOT]: `ssrRenderSlot`,
      [SSR_RENDER_CLASS]: `ssrRenderClass`,
      [SSR_RENDER_STYLE]: `ssrRenderStyle`,
      [SSR_RENDER_ATTRS]: `ssrRenderAttrs`,
      [SSR_RENDER_ATTR]: `ssrRenderAttr`,
      [SSR_RENDER_DYNAMIC_ATTR]: `ssrRenderDynamicAttr`,
      [SSR_RENDER_LIST]: `ssrRenderList`,
      [SSR_INCLUDE_BOOLEAN_ATTR]: `ssrIncludeBooleanAttr`,
      [SSR_LOOSE_EQUAL]: `ssrLooseEqual`,
      [SSR_LOOSE_CONTAIN]: `ssrLooseContain`,
      [SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`,
      [SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`,
      [SSR_RENDER_TELEPORT]: `ssrRenderTeleport`,
      [SSR_RENDER_SUSPENSE]: `ssrRenderSuspense`
  };
  // Note: these are helpers imported from @vue/server-renderer
  // make sure the names match!
  compilerDom.registerRuntimeHelpers(ssrHelpers);
  
  // Plugin for the first transform pass, which simply constructs the AST node
  const ssrTransformIf = compilerDom.createStructuralDirectiveTransform(/^(if|else|else-if)$/, compilerDom.processIf);
  // This is called during the 2nd transform pass to construct the SSR-specific
  // codegen nodes.
  function ssrProcessIf(node, context, disableNestedFragments = false) {
      const [rootBranch] = node.branches;
      const ifStatement = compilerDom.createIfStatement(rootBranch.condition, processIfBranch(rootBranch, context, disableNestedFragments));
      context.pushStatement(ifStatement);
      let currentIf = ifStatement;
      for (let i = 1; i < node.branches.length; i++) {
          const branch = node.branches[i];
          const branchBlockStatement = processIfBranch(branch, context, disableNestedFragments);
          if (branch.condition) {
              // else-if
              currentIf = currentIf.alternate = compilerDom.createIfStatement(branch.condition, branchBlockStatement);
          }
          else {
              // else
              currentIf.alternate = branchBlockStatement;
          }
      }
      if (!currentIf.alternate) {
          currentIf.alternate = compilerDom.createBlockStatement([
              compilerDom.createCallExpression(`_push`, ['`<!---->`'])
          ]);
      }
  }
  function processIfBranch(branch, context, disableNestedFragments = false) {
      const { children } = branch;
      const needFragmentWrapper = !disableNestedFragments &&
          (children.length !== 1 || children[0].type !== 1 /* ELEMENT */) &&
          // optimize away nested fragments when the only child is a ForNode
          !(children.length === 1 && children[0].type === 11 /* FOR */);
      return processChildrenAsStatement(children, context, needFragmentWrapper);
  }
  
  // Plugin for the first transform pass, which simply constructs the AST node
  const ssrTransformFor = compilerDom.createStructuralDirectiveTransform('for', compilerDom.processFor);
  // This is called during the 2nd transform pass to construct the SSR-specific
  // codegen nodes.
  function ssrProcessFor(node, context, disableNestedFragments = false) {
      const needFragmentWrapper = !disableNestedFragments &&
          (node.children.length !== 1 || node.children[0].type !== 1 /* ELEMENT */);
      const renderLoop = compilerDom.createFunctionExpression(compilerDom.createForLoopParams(node.parseResult));
      renderLoop.body = processChildrenAsStatement(node.children, context, needFragmentWrapper);
      // v-for always renders a fragment unless explicitly disabled
      if (!disableNestedFragments) {
          context.pushStringPart(`<!--[-->`);
      }
      context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_LIST), [
          node.source,
          renderLoop
      ]));
      if (!disableNestedFragments) {
          context.pushStringPart(`<!--]-->`);
      }
  }
  
  const ssrTransformSlotOutlet = (node, context) => {
      if (compilerDom.isSlotOutlet(node)) {
          const { slotName, slotProps } = compilerDom.processSlotOutlet(node, context);
          const args = [
              `_ctx.$slots`,
              slotName,
              slotProps || `{}`,
              // fallback content placeholder. will be replaced in the process phase
              `null`,
              `_push`,
              `_parent`
          ];
          // inject slot scope id if current template uses :slotted
          if (context.scopeId && context.slotted !== false) {
              args.push(`"${context.scopeId}-s"`);
          }
          node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(SSR_RENDER_SLOT), args);
      }
  };
  function ssrProcessSlotOutlet(node, context) {
      const renderCall = node.ssrCodegenNode;
      // has fallback content
      if (node.children.length) {
          const fallbackRenderFn = compilerDom.createFunctionExpression([]);
          fallbackRenderFn.body = processChildrenAsStatement(node.children, context);
          // _renderSlot(slots, name, props, fallback, ...)
          renderCall.arguments[3] = fallbackRenderFn;
      }
      // Forwarded <slot/>. Merge slot scope ids
      if (context.withSlotScopeId) {
          const slotScopeId = renderCall.arguments[6];
          renderCall.arguments[6] = slotScopeId
              ? `${slotScopeId} + _scopeId`
              : `_scopeId`;
      }
      context.pushStatement(node.ssrCodegenNode);
  }
  
  function createSSRCompilerError(code, loc) {
      return compilerDom.createCompilerError(code, loc, SSRErrorMessages);
  }
  const SSRErrorMessages = {
      [61 /* X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM */]: `Custom directive is missing corresponding SSR transform and will be ignored.`,
      [62 /* X_SSR_UNSAFE_ATTR_NAME */]: `Unsafe attribute name for SSR.`,
      [63 /* X_SSR_NO_TELEPORT_TARGET */]: `Missing the 'to' prop on teleport element.`,
      [64 /* X_SSR_INVALID_AST_NODE */]: `Invalid AST node during SSR transform.`
  };
  
  // Note: this is a 2nd-pass codegen transform.
  function ssrProcessTeleport(node, context) {
      const targetProp = compilerDom.findProp(node, 'to');
      if (!targetProp) {
          context.onError(createSSRCompilerError(63 /* X_SSR_NO_TELEPORT_TARGET */, node.loc));
          return;
      }
      let target;
      if (targetProp.type === 6 /* ATTRIBUTE */) {
          target =
              targetProp.value && compilerDom.createSimpleExpression(targetProp.value.content, true);
      }
      else {
          target = targetProp.exp;
      }
      if (!target) {
          context.onError(createSSRCompilerError(63 /* X_SSR_NO_TELEPORT_TARGET */, targetProp.loc));
          return;
      }
      const disabledProp = compilerDom.findProp(node, 'disabled', false, true /* allow empty */);
      const disabled = disabledProp
          ? disabledProp.type === 6 /* ATTRIBUTE */
              ? `true`
              : disabledProp.exp || `false`
          : `false`;
      const contentRenderFn = compilerDom.createFunctionExpression([`_push`], undefined, // Body is added later
      true, // newline
      false, // isSlot
      node.loc);
      contentRenderFn.body = processChildrenAsStatement(node.children, context);
      context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_TELEPORT), [
          `_push`,
          contentRenderFn,
          target,
          disabled,
          `_parent`
      ]));
  }
  
  const wipMap = new WeakMap();
  // phase 1
  function ssrTransformSuspense(node, context) {
      return () => {
          if (node.children.length) {
              const wipEntry = {
                  slotsExp: null,
                  wipSlots: []
              };
              wipMap.set(node, wipEntry);
              wipEntry.slotsExp = compilerDom.buildSlots(node, context, (_props, children, loc) => {
                  const fn = compilerDom.createFunctionExpression([], undefined, // no return, assign body later
                  true, // newline
                  false, // suspense slots are not treated as normal slots
                  loc);
                  wipEntry.wipSlots.push({
                      fn,
                      children
                  });
                  return fn;
              }).slots;
          }
      };
  }
  // phase 2
  function ssrProcessSuspense(node, context) {
      // complete wip slots with ssr code
      const wipEntry = wipMap.get(node);
      if (!wipEntry) {
          return;
      }
      const { slotsExp, wipSlots } = wipEntry;
      for (let i = 0; i < wipSlots.length; i++) {
          const { fn, children } = wipSlots[i];
          fn.body = processChildrenAsStatement(children, context);
      }
      // _push(ssrRenderSuspense(slots))
      context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_SUSPENSE), [
          `_push`,
          slotsExp
      ]));
  }
  
  function ssrProcessTransitionGroup(node, context) {
      const tag = compilerDom.findProp(node, 'tag');
      if (tag) {
          if (tag.type === 7 /* DIRECTIVE */) {
              // dynamic :tag
              context.pushStringPart(`<`);
              context.pushStringPart(tag.exp);
              context.pushStringPart(`>`);
              processChildren(node.children, context, false, 
              /**
               * TransitionGroup has the special runtime behavior of flattening and
               * concatenating all children into a single fragment (in order for them to
               * be pathced using the same key map) so we need to account for that here
               * by disabling nested fragment wrappers from being generated.
               */
              true);
              context.pushStringPart(`</`);
              context.pushStringPart(tag.exp);
              context.pushStringPart(`>`);
          }
          else {
              // static tag
              context.pushStringPart(`<${tag.value.content}>`);
              processChildren(node.children, context, false, true);
              context.pushStringPart(`</${tag.value.content}>`);
          }
      }
      else {
          // fragment
          processChildren(node.children, context, true, true);
      }
  }
  
  // We need to construct the slot functions in the 1st pass to ensure proper
  // scope tracking, but the children of each slot cannot be processed until
  // the 2nd pass, so we store the WIP slot functions in a weakmap during the 1st
  // pass and complete them in the 2nd pass.
  const wipMap$1 = new WeakMap();
  const componentTypeMap = new WeakMap();
  // ssr component transform is done in two phases:
  // In phase 1. we use `buildSlot` to analyze the children of the component into
  // WIP slot functions (it must be done in phase 1 because `buildSlot` relies on
  // the core transform context).
  // In phase 2. we convert the WIP slots from phase 1 into ssr-specific codegen
  // nodes.
  const ssrTransformComponent = (node, context) => {
      if (node.type !== 1 /* ELEMENT */ ||
          node.tagType !== 1 /* COMPONENT */) {
          return;
      }
      const component = compilerDom.resolveComponentType(node, context, true /* ssr */);
      componentTypeMap.set(node, component);
      if (shared.isSymbol(component)) {
          if (component === compilerDom.SUSPENSE) {
              return ssrTransformSuspense(node, context);
          }
          return; // built-in component: fallthrough
      }
      // Build the fallback vnode-based branch for the component's slots.
      // We need to clone the node into a fresh copy and use the buildSlots' logic
      // to get access to the children of each slot. We then compile them with
      // a child transform pipeline using vnode-based transforms (instead of ssr-
      // based ones), and save the result branch (a ReturnStatement) in an array.
      // The branch is retrieved when processing slots again in ssr mode.
      const vnodeBranches = [];
      const clonedNode = clone(node);
      return function ssrPostTransformComponent() {
          // Using the cloned node, build the normal VNode-based branches (for
          // fallback in case the child is render-fn based). Store them in an array
          // for later use.
          if (clonedNode.children.length) {
              compilerDom.buildSlots(clonedNode, context, (props, children) => {
                  vnodeBranches.push(createVNodeSlotBranch(props, children, context));
                  return compilerDom.createFunctionExpression(undefined);
              });
          }
          const props = node.props.length > 0
              ? // note we are not passing ssr: true here because for components, v-on
                  // handlers should still be passed
                  compilerDom.buildProps(node, context).props || `null`
              : `null`;
          const wipEntries = [];
          wipMap$1.set(node, wipEntries);
          const buildSSRSlotFn = (props, children, loc) => {
              const fn = compilerDom.createFunctionExpression([props || `_`, `_push`, `_parent`, `_scopeId`], undefined, // no return, assign body later
              true, // newline
              true, // isSlot
              loc);
              wipEntries.push({
                  fn,
                  children,
                  // also collect the corresponding vnode branch built earlier
                  vnodeBranch: vnodeBranches[wipEntries.length]
              });
              return fn;
          };
          const slots = node.children.length
              ? compilerDom.buildSlots(node, context, buildSSRSlotFn).slots
              : `null`;
          if (typeof component !== 'string') {
              // dynamic component that resolved to a `resolveDynamicComponent` call
              // expression - since the resolved result may be a plain element (string)
              // or a VNode, handle it with `renderVNode`.
              node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(SSR_RENDER_VNODE), [
                  `_push`,
                  compilerDom.createCallExpression(context.helper(compilerDom.CREATE_VNODE), [
                      component,
                      props,
                      slots
                  ]),
                  `_parent`
              ]);
          }
          else {
              node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(SSR_RENDER_COMPONENT), [component, props, slots, `_parent`]);
          }
      };
  };
  function ssrProcessComponent(node, context) {
      const component = componentTypeMap.get(node);
      if (!node.ssrCodegenNode) {
          // this is a built-in component that fell-through.
          if (component === compilerDom.TELEPORT) {
              return ssrProcessTeleport(node, context);
          }
          else if (component === compilerDom.SUSPENSE) {
              return ssrProcessSuspense(node, context);
          }
          else if (component === compilerDom.TRANSITION_GROUP) {
              return ssrProcessTransitionGroup(node, context);
          }
          else {
              // real fall-through: Transition / KeepAlive
              // just render its children.
              processChildren(node.children, context);
          }
      }
      else {
          // finish up slot function expressions from the 1st pass.
          const wipEntries = wipMap$1.get(node) || [];
          for (let i = 0; i < wipEntries.length; i++) {
              const { fn, children, vnodeBranch } = wipEntries[i];
              // For each slot, we generate two branches: one SSR-optimized branch and
              // one normal vnode-based branch. The branches are taken based on the
              // presence of the 2nd `_push` argument (which is only present if the slot
              // is called by `_ssrRenderSlot`.
              fn.body = compilerDom.createIfStatement(compilerDom.createSimpleExpression(`_push`, false), processChildrenAsStatement(children, context, false, true /* withSlotScopeId */), vnodeBranch);
          }
          // component is inside a slot, inherit slot scope Id
          if (context.withSlotScopeId) {
              node.ssrCodegenNode.arguments.push(`_scopeId`);
          }
          if (typeof component === 'string') {
              // static component
              context.pushStatement(compilerDom.createCallExpression(`_push`, [node.ssrCodegenNode]));
          }
          else {
              // dynamic component (`resolveDynamicComponent` call)
              // the codegen node is a `renderVNode` call
              context.pushStatement(node.ssrCodegenNode);
          }
      }
  }
  const rawOptionsMap = new WeakMap();
  const [baseNodeTransforms, baseDirectiveTransforms] = compilerDom.getBaseTransformPreset(true);
  const vnodeNodeTransforms = [...baseNodeTransforms, ...compilerDom.DOMNodeTransforms];
  const vnodeDirectiveTransforms = Object.assign(Object.assign({}, baseDirectiveTransforms), compilerDom.DOMDirectiveTransforms);
  function createVNodeSlotBranch(props, children, parentContext) {
      // apply a sub-transform using vnode-based transforms.
      const rawOptions = rawOptionsMap.get(parentContext.root);
      const subOptions = Object.assign(Object.assign({}, rawOptions), { 
          // overwrite with vnode-based transforms
          nodeTransforms: [
              ...vnodeNodeTransforms,
              ...(rawOptions.nodeTransforms || [])
          ], directiveTransforms: Object.assign(Object.assign({}, vnodeDirectiveTransforms), (rawOptions.directiveTransforms || {})) });
      // wrap the children with a wrapper template for proper children treatment.
      const wrapperNode = {
          type: 1 /* ELEMENT */,
          ns: 0 /* HTML */,
          tag: 'template',
          tagType: 3 /* TEMPLATE */,
          isSelfClosing: false,
          // important: provide v-slot="props" on the wrapper for proper
          // scope analysis
          props: [
              {
                  type: 7 /* DIRECTIVE */,
                  name: 'slot',
                  exp: props,
                  arg: undefined,
                  modifiers: [],
                  loc: compilerDom.locStub
              }
          ],
          children,
          loc: compilerDom.locStub,
          codegenNode: undefined
      };
      subTransform(wrapperNode, subOptions, parentContext);
      return compilerDom.createReturnStatement(children);
  }
  function subTransform(node, options, parentContext) {
      const childRoot = compilerDom.createRoot([node]);
      const childContext = compilerDom.createTransformContext(childRoot, options);
      // this sub transform is for vnode fallback branch so it should be handled
      // like normal render functions
      childContext.ssr = false;
      // inherit parent scope analysis state
      childContext.scopes = Object.assign({}, parentContext.scopes);
      childContext.identifiers = Object.assign({}, parentContext.identifiers);
      childContext.imports = parentContext.imports;
      // traverse
      compilerDom.traverseNode(childRoot, childContext);
      ['helpers', 'components', 'directives'].forEach(key => {
          childContext[key].forEach((value, helperKey) => {
              if (key === 'helpers') {
                  const parentCount = parentContext.helpers.get(helperKey);
                  if (parentCount === undefined) {
                      parentContext.helpers.set(helperKey, value);
                  }
                  else {
                      parentContext.helpers.set(helperKey, value + parentCount);
                  }
              }
              else {
                  parentContext[key].add(value);
              }
          });
      });
      // imports/hoists are not merged because:
      // - imports are only used for asset urls and should be consistent between
      //   node/client branches
      // - hoists are not enabled for the client branch here
  }
  function clone(v) {
      if (shared.isArray(v)) {
          return v.map(clone);
      }
      else if (shared.isObject(v)) {
          const res = {};
          for (const key in v) {
              res[key] = clone(v[key]);
          }
          return res;
      }
      else {
          return v;
      }
  }
  
  // for directives with children overwrite (e.g. v-html & v-text), we need to
  // store the raw children so that they can be added in the 2nd pass.
  const rawChildrenMap = new WeakMap();
  const ssrTransformElement = (node, context) => {
      if (node.type !== 1 /* ELEMENT */ ||
          node.tagType !== 0 /* ELEMENT */) {
          return;
      }
      return function ssrPostTransformElement() {
          // element
          // generate the template literal representing the open tag.
          const openTag = [`<${node.tag}`];
          // some tags need to be passed to runtime for special checks
          const needTagForRuntime = node.tag === 'textarea' || node.tag.indexOf('-') > 0;
          // v-bind="obj" or v-bind:[key] can potentially overwrite other static
          // attrs and can affect final rendering result, so when they are present
          // we need to bail out to full `renderAttrs`
          const hasDynamicVBind = compilerDom.hasDynamicKeyVBind(node);
          if (hasDynamicVBind) {
              const { props } = compilerDom.buildProps(node, context, node.props, true /* ssr */);
              if (props) {
                  const propsExp = compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTRS), [props]);
                  if (node.tag === 'textarea') {
                      const existingText = node.children[0];
                      // If interpolation, this is dynamic <textarea> content, potentially
                      // injected by v-model and takes higher priority than v-bind value
                      if (!existingText || existingText.type !== 5 /* INTERPOLATION */) {
                          // <textarea> with dynamic v-bind. We don't know if the final props
                          // will contain .value, so we will have to do something special:
                          // assign the merged props to a temp variable, and check whether
                          // it contains value (if yes, render is as children).
                          const tempId = `_temp${context.temps++}`;
                          propsExp.arguments = [
                              compilerDom.createAssignmentExpression(compilerDom.createSimpleExpression(tempId, false), props)
                          ];
                          rawChildrenMap.set(node, compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [
                              compilerDom.createConditionalExpression(compilerDom.createSimpleExpression(`"value" in ${tempId}`, false), compilerDom.createSimpleExpression(`${tempId}.value`, false), compilerDom.createSimpleExpression(existingText ? existingText.content : ``, true), false)
                          ]));
                      }
                  }
                  else if (node.tag === 'input') {
                      // <input v-bind="obj" v-model>
                      // we need to determine the props to render for the dynamic v-model
                      // and merge it with the v-bind expression.
                      const vModel = findVModel(node);
                      if (vModel) {
                          // 1. save the props (san v-model) in a temp variable
                          const tempId = `_temp${context.temps++}`;
                          const tempExp = compilerDom.createSimpleExpression(tempId, false);
                          propsExp.arguments = [
                              compilerDom.createSequenceExpression([
                                  compilerDom.createAssignmentExpression(tempExp, props),
                                  compilerDom.createCallExpression(context.helper(compilerDom.MERGE_PROPS), [
                                      tempExp,
                                      compilerDom.createCallExpression(context.helper(SSR_GET_DYNAMIC_MODEL_PROPS), [
                                          tempExp,
                                          vModel.exp // model
                                      ])
                                  ])
                              ])
                          ];
                      }
                  }
                  if (needTagForRuntime) {
                      propsExp.arguments.push(`"${node.tag}"`);
                  }
                  openTag.push(propsExp);
              }
          }
          // book keeping static/dynamic class merging.
          let dynamicClassBinding = undefined;
          let staticClassBinding = undefined;
          // all style bindings are converted to dynamic by transformStyle.
          // but we need to make sure to merge them.
          let dynamicStyleBinding = undefined;
          for (let i = 0; i < node.props.length; i++) {
              const prop = node.props[i];
              // ignore true-value/false-value on input
              if (node.tag === 'input' && isTrueFalseValue(prop)) {
                  continue;
              }
              // special cases with children override
              if (prop.type === 7 /* DIRECTIVE */) {
                  if (prop.name === 'html' && prop.exp) {
                      rawChildrenMap.set(node, prop.exp);
                  }
                  else if (prop.name === 'text' && prop.exp) {
                      node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
                  }
                  else if (prop.name === 'slot') {
                      context.onError(compilerDom.createCompilerError(40 /* X_V_SLOT_MISPLACED */, prop.loc));
                  }
                  else if (isTextareaWithValue(node, prop) && prop.exp) {
                      if (!hasDynamicVBind) {
                          node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
                      }
                  }
                  else {
                      // Directive transforms.
                      const directiveTransform = context.directiveTransforms[prop.name];
                      if (!directiveTransform) {
                          // no corresponding ssr directive transform found.
                          context.onError(createSSRCompilerError(61 /* X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM */, prop.loc));
                      }
                      else if (!hasDynamicVBind) {
                          const { props, ssrTagParts } = directiveTransform(prop, node, context);
                          if (ssrTagParts) {
                              openTag.push(...ssrTagParts);
                          }
                          for (let j = 0; j < props.length; j++) {
                              const { key, value } = props[j];
                              if (compilerDom.isStaticExp(key)) {
                                  let attrName = key.content;
                                  // static key attr
                                  if (attrName === 'key' || attrName === 'ref') {
                                      continue;
                                  }
                                  if (attrName === 'class') {
                                      openTag.push(` class="`, (dynamicClassBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_CLASS), [value])), `"`);
                                  }
                                  else if (attrName === 'style') {
                                      if (dynamicStyleBinding) {
                                          // already has style binding, merge into it.
                                          mergeCall(dynamicStyleBinding, value);
                                      }
                                      else {
                                          openTag.push(` style="`, (dynamicStyleBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_STYLE), [value])), `"`);
                                      }
                                  }
                                  else {
                                      attrName =
                                          node.tag.indexOf('-') > 0
                                              ? attrName // preserve raw name on custom elements
                                              : shared.propsToAttrMap[attrName] || attrName.toLowerCase();
                                      if (shared.isBooleanAttr(attrName)) {
                                          openTag.push(compilerDom.createConditionalExpression(compilerDom.createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [value]), compilerDom.createSimpleExpression(' ' + attrName, true), compilerDom.createSimpleExpression('', true), false /* no newline */));
                                      }
                                      else if (shared.isSSRSafeAttrName(attrName)) {
                                          openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTR), [
                                              key,
                                              value
                                          ]));
                                      }
                                      else {
                                          context.onError(createSSRCompilerError(62 /* X_SSR_UNSAFE_ATTR_NAME */, key.loc));
                                      }
                                  }
                              }
                              else {
                                  // dynamic key attr
                                  // this branch is only encountered for custom directive
                                  // transforms that returns properties with dynamic keys
                                  const args = [key, value];
                                  if (needTagForRuntime) {
                                      args.push(`"${node.tag}"`);
                                  }
                                  openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_ATTR), args));
                              }
                          }
                      }
                  }
              }
              else {
                  // special case: value on <textarea>
                  if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
                      rawChildrenMap.set(node, shared.escapeHtml(prop.value.content));
                  }
                  else if (!hasDynamicVBind) {
                      if (prop.name === 'key' || prop.name === 'ref') {
                          continue;
                      }
                      // static prop
                      if (prop.name === 'class' && prop.value) {
                          staticClassBinding = JSON.stringify(prop.value.content);
                      }
                      openTag.push(` ${prop.name}` +
                          (prop.value ? `="${shared.escapeHtml(prop.value.content)}"` : ``));
                  }
              }
          }
          // handle co-existence of dynamic + static class bindings
          if (dynamicClassBinding && staticClassBinding) {
              mergeCall(dynamicClassBinding, staticClassBinding);
              removeStaticBinding(openTag, 'class');
          }
          if (context.scopeId) {
              openTag.push(` ${context.scopeId}`);
          }
          node.ssrCodegenNode = compilerDom.createTemplateLiteral(openTag);
      };
  };
  function isTrueFalseValue(prop) {
      if (prop.type === 7 /* DIRECTIVE */) {
          return (prop.name === 'bind' &&
              prop.arg &&
              compilerDom.isStaticExp(prop.arg) &&
              (prop.arg.content === 'true-value' || prop.arg.content === 'false-value'));
      }
      else {
          return prop.name === 'true-value' || prop.name === 'false-value';
      }
  }
  function isTextareaWithValue(node, prop) {
      return !!(node.tag === 'textarea' &&
          prop.name === 'bind' &&
          compilerDom.isBindKey(prop.arg, 'value'));
  }
  function mergeCall(call, arg) {
      const existing = call.arguments[0];
      if (existing.type === 17 /* JS_ARRAY_EXPRESSION */) {
          existing.elements.push(arg);
      }
      else {
          call.arguments[0] = compilerDom.createArrayExpression([existing, arg]);
      }
  }
  function removeStaticBinding(tag, binding) {
      const regExp = new RegExp(`^ ${binding}=".+"$`);
      const i = tag.findIndex(e => typeof e === 'string' && regExp.test(e));
      if (i > -1) {
          tag.splice(i, 1);
      }
  }
  function findVModel(node) {
      return node.props.find(p => p.type === 7 /* DIRECTIVE */ && p.name === 'model' && p.exp);
  }
  function ssrProcessElement(node, context) {
      const isVoidTag = context.options.isVoidTag || shared.NO;
      const elementsToAdd = node.ssrCodegenNode.elements;
      for (let j = 0; j < elementsToAdd.length; j++) {
          context.pushStringPart(elementsToAdd[j]);
      }
      // Handle slot scopeId
      if (context.withSlotScopeId) {
          context.pushStringPart(compilerDom.createSimpleExpression(`_scopeId`, false));
      }
      // close open tag
      context.pushStringPart(`>`);
      const rawChildren = rawChildrenMap.get(node);
      if (rawChildren) {
          context.pushStringPart(rawChildren);
      }
      else if (node.children.length) {
          processChildren(node.children, context);
      }
      if (!isVoidTag(node.tag)) {
          // push closing tag
          context.pushStringPart(`</${node.tag}>`);
      }
  }
  
  // Because SSR codegen output is completely different from client-side output
  // (e.g. multiple elements can be concatenated into a single template literal
  // instead of each getting a corresponding call), we need to apply an extra
  // transform pass to convert the template AST into a fresh JS AST before
  // passing it to codegen.
  function ssrCodegenTransform(ast, options) {
      const context = createSSRTransformContext(ast, options);
      // inject SFC <style> CSS variables
      // we do this instead of inlining the expression to ensure the vars are
      // only resolved once per render
      if (options.ssrCssVars) {
          const varsExp = compilerDom.processExpression(compilerDom.createSimpleExpression(options.ssrCssVars, false), compilerDom.createTransformContext(compilerDom.createRoot([]), options));
          context.body.push(compilerDom.createCompoundExpression([`const _cssVars = { style: `, varsExp, `}`]));
      }
      const isFragment = ast.children.length > 1 && ast.children.some(c => !compilerDom.isText(c));
      processChildren(ast.children, context, isFragment);
      ast.codegenNode = compilerDom.createBlockStatement(context.body);
      // Finalize helpers.
      // We need to separate helpers imported from 'vue' vs. '@vue/server-renderer'
      ast.ssrHelpers = Array.from(new Set([...ast.helpers.filter(h => h in ssrHelpers), ...context.helpers]));
      ast.helpers = ast.helpers.filter(h => !(h in ssrHelpers));
  }
  function createSSRTransformContext(root, options, helpers = new Set(), withSlotScopeId = false) {
      const body = [];
      let currentString = null;
      return {
          root,
          options,
          body,
          helpers,
          withSlotScopeId,
          onError: options.onError ||
              (e => {
                  throw e;
              }),
          helper(name) {
              helpers.add(name);
              return name;
          },
          pushStringPart(part) {
              if (!currentString) {
                  const currentCall = compilerDom.createCallExpression(`_push`);
                  body.push(currentCall);
                  currentString = compilerDom.createTemplateLiteral([]);
                  currentCall.arguments.push(currentString);
              }
              const bufferedElements = currentString.elements;
              const lastItem = bufferedElements[bufferedElements.length - 1];
              if (shared.isString(part) && shared.isString(lastItem)) {
                  bufferedElements[bufferedElements.length - 1] += part;
              }
              else {
                  bufferedElements.push(part);
              }
          },
          pushStatement(statement) {
              // close current string
              currentString = null;
              body.push(statement);
          }
      };
  }
  function createChildContext(parent, withSlotScopeId = parent.withSlotScopeId) {
      // ensure child inherits parent helpers
      return createSSRTransformContext(parent.root, parent.options, parent.helpers, withSlotScopeId);
  }
  function processChildren(children, context, asFragment = false, disableNestedFragments = false) {
      if (asFragment) {
          context.pushStringPart(`<!--[-->`);
      }
      for (let i = 0; i < children.length; i++) {
          const child = children[i];
          switch (child.type) {
              case 1 /* ELEMENT */:
                  switch (child.tagType) {
                      case 0 /* ELEMENT */:
                          ssrProcessElement(child, context);
                          break;
                      case 1 /* COMPONENT */:
                          ssrProcessComponent(child, context);
                          break;
                      case 2 /* SLOT */:
                          ssrProcessSlotOutlet(child, context);
                          break;
                      case 3 /* TEMPLATE */:
                          // TODO
                          break;
                      default:
                          context.onError(createSSRCompilerError(64 /* X_SSR_INVALID_AST_NODE */, child.loc));
                          // make sure we exhaust all possible types
                          const exhaustiveCheck = child;
                          return exhaustiveCheck;
                  }
                  break;
              case 2 /* TEXT */:
                  context.pushStringPart(shared.escapeHtml(child.content));
                  break;
              case 3 /* COMMENT */:
                  // no need to escape comment here because the AST can only
                  // contain valid comments.
                  context.pushStringPart(`<!--${child.content}-->`);
                  break;
              case 5 /* INTERPOLATION */:
                  context.pushStringPart(compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [child.content]));
                  break;
              case 9 /* IF */:
                  ssrProcessIf(child, context, disableNestedFragments);
                  break;
              case 11 /* FOR */:
                  ssrProcessFor(child, context, disableNestedFragments);
                  break;
              case 10 /* IF_BRANCH */:
                  // no-op - handled by ssrProcessIf
                  break;
              case 12 /* TEXT_CALL */:
              case 8 /* COMPOUND_EXPRESSION */:
                  // no-op - these two types can never appear as template child node since
                  // `transformText` is not used during SSR compile.
                  break;
              default:
                  context.onError(createSSRCompilerError(64 /* X_SSR_INVALID_AST_NODE */, child.loc));
                  // make sure we exhaust all possible types
                  const exhaustiveCheck = child;
                  return exhaustiveCheck;
          }
      }
      if (asFragment) {
          context.pushStringPart(`<!--]-->`);
      }
  }
  function processChildrenAsStatement(children, parentContext, asFragment = false, withSlotScopeId = parentContext.withSlotScopeId) {
      const childContext = createChildContext(parentContext, withSlotScopeId);
      processChildren(children, childContext, asFragment);
      return compilerDom.createBlockStatement(childContext.body);
  }
  
  const ssrTransformModel = (dir, node, context) => {
      const model = dir.exp;
      function checkDuplicatedValue() {
          const value = compilerDom.findProp(node, 'value');
          if (value) {
              context.onError(compilerDom.createDOMCompilerError(57 /* X_V_MODEL_UNNECESSARY_VALUE */, value.loc));
          }
      }
      if (node.tagType === 0 /* ELEMENT */) {
          const res = { props: [] };
          const defaultProps = [
              // default value binding for text type inputs
              compilerDom.createObjectProperty(`value`, model)
          ];
          if (node.tag === 'input') {
              const type = compilerDom.findProp(node, 'type');
              if (type) {
                  const value = findValueBinding(node);
                  if (type.type === 7 /* DIRECTIVE */) {
                      // dynamic type
                      res.ssrTagParts = [
                          compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_MODEL), [
                              type.exp,
                              model,
                              value
                          ])
                      ];
                  }
                  else if (type.value) {
                      // static type
                      switch (type.value.content) {
                          case 'radio':
                              res.props = [
                                  compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
                                      model,
                                      value
                                  ]))
                              ];
                              break;
                          case 'checkbox':
                              const trueValueBinding = compilerDom.findProp(node, 'true-value');
                              if (trueValueBinding) {
                                  const trueValue = trueValueBinding.type === 6 /* ATTRIBUTE */
                                      ? JSON.stringify(trueValueBinding.value.content)
                                      : trueValueBinding.exp;
                                  res.props = [
                                      compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
                                          model,
                                          trueValue
                                      ]))
                                  ];
                              }
                              else {
                                  res.props = [
                                      compilerDom.createObjectProperty(`checked`, compilerDom.createConditionalExpression(compilerDom.createCallExpression(`Array.isArray`, [model]), compilerDom.createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
                                          model,
                                          value
                                      ]), model))
                                  ];
                              }
                              break;
                          case 'file':
                              context.onError(compilerDom.createDOMCompilerError(56 /* X_V_MODEL_ON_FILE_INPUT_ELEMENT */, dir.loc));
                              break;
                          default:
                              checkDuplicatedValue();
                              res.props = defaultProps;
                              break;
                      }
                  }
              }
              else if (compilerDom.hasDynamicKeyVBind(node)) ;
              else {
                  // text type
                  checkDuplicatedValue();
                  res.props = defaultProps;
              }
          }
          else if (node.tag === 'textarea') {
              checkDuplicatedValue();
              node.children = [compilerDom.createInterpolation(model, model.loc)];
          }
          else if (node.tag === 'select') ;
          else {
              context.onError(compilerDom.createDOMCompilerError(54 /* X_V_MODEL_ON_INVALID_ELEMENT */, dir.loc));
          }
          return res;
      }
      else {
          // component v-model
          return compilerDom.transformModel(dir, node, context);
      }
  };
  function findValueBinding(node) {
      const valueBinding = compilerDom.findProp(node, 'value');
      return valueBinding
          ? valueBinding.type === 7 /* DIRECTIVE */
              ? valueBinding.exp
              : compilerDom.createSimpleExpression(valueBinding.value.content, true)
          : compilerDom.createSimpleExpression(`null`, false);
  }
  
  const ssrTransformShow = (dir, node, context) => {
      if (!dir.exp) {
          context.onError(compilerDom.createDOMCompilerError(58 /* X_V_SHOW_NO_EXPRESSION */));
      }
      return {
          props: [
              compilerDom.createObjectProperty(`style`, compilerDom.createConditionalExpression(dir.exp, compilerDom.createSimpleExpression(`null`, false), compilerDom.createObjectExpression([
                  compilerDom.createObjectProperty(`display`, compilerDom.createSimpleExpression(`none`, true))
              ]), false /* no newline */))
          ]
      };
  };
  
  const hasSingleChild = (node) => node.children.filter(n => n.type !== 3 /* COMMENT */).length === 1;
  const ssrInjectFallthroughAttrs = (node, context) => {
      // _attrs is provided as a function argument.
      // mark it as a known identifier so that it doesn't get prefixed by
      // transformExpression.
      if (node.type === 0 /* ROOT */) {
          context.identifiers._attrs = 1;
      }
      if (node.type === 1 /* ELEMENT */ &&
          node.tagType === 1 /* COMPONENT */ &&
          (compilerDom.isBuiltInType(node.tag, 'Transition') ||
              compilerDom.isBuiltInType(node.tag, 'KeepAlive'))) {
          if (hasSingleChild(node)) {
              injectFallthroughAttrs(node.children[0]);
          }
          return;
      }
      const parent = context.parent;
      if (!parent || parent.type !== 0 /* ROOT */) {
          return;
      }
      if (node.type === 10 /* IF_BRANCH */ && hasSingleChild(node)) {
          injectFallthroughAttrs(node.children[0]);
      }
      else if (hasSingleChild(parent)) {
          injectFallthroughAttrs(node);
      }
  };
  function injectFallthroughAttrs(node) {
      if (node.type === 1 /* ELEMENT */ &&
          (node.tagType === 0 /* ELEMENT */ ||
              node.tagType === 1 /* COMPONENT */) &&
          !compilerDom.findDir(node, 'for')) {
          node.props.push({
              type: 7 /* DIRECTIVE */,
              name: 'bind',
              arg: undefined,
              exp: compilerDom.createSimpleExpression(`_attrs`, false),
              modifiers: [],
              loc: compilerDom.locStub
          });
      }
  }
  
  const ssrInjectCssVars = (node, context) => {
      if (!context.ssrCssVars) {
          return;
      }
      // _cssVars is initialized once per render function
      // the code is injected in ssrCodegenTransform when creating the
      // ssr transform context
      if (node.type === 0 /* ROOT */) {
          context.identifiers._cssVars = 1;
      }
      const parent = context.parent;
      if (!parent || parent.type !== 0 /* ROOT */) {
          return;
      }
      if (node.type === 10 /* IF_BRANCH */) {
          for (const child of node.children) {
              injectCssVars(child);
          }
      }
      else {
          injectCssVars(node);
      }
  };
  function injectCssVars(node) {
      if (node.type === 1 /* ELEMENT */ &&
          (node.tagType === 0 /* ELEMENT */ ||
              node.tagType === 1 /* COMPONENT */) &&
          !compilerDom.findDir(node, 'for')) {
          if (compilerDom.isBuiltInType(node.tag, 'Suspense')) {
              for (const child of node.children) {
                  if (child.type === 1 /* ELEMENT */ &&
                      child.tagType === 3 /* TEMPLATE */) {
                      // suspense slot
                      child.children.forEach(injectCssVars);
                  }
                  else {
                      injectCssVars(child);
                  }
              }
          }
          else {
              node.props.push({
                  type: 7 /* DIRECTIVE */,
                  name: 'bind',
                  arg: undefined,
                  exp: compilerDom.createSimpleExpression(`_cssVars`, false),
                  modifiers: [],
                  loc: compilerDom.locStub
              });
          }
      }
  }
  
  function compile(template, options = {}) {
      options = Object.assign(Object.assign(Object.assign({}, options), compilerDom.parserOptions), { ssr: true, inSSR: true, scopeId: options.mode === 'function' ? null : options.scopeId, 
          // always prefix since compiler-ssr doesn't have size concern
          prefixIdentifiers: true, 
          // disable optimizations that are unnecessary for ssr
          cacheHandlers: false, hoistStatic: false });
      const ast = compilerDom.baseParse(template, options);
      // Save raw options for AST. This is needed when performing sub-transforms
      // on slot vnode branches.
      rawOptionsMap.set(ast, options);
      compilerDom.transform(ast, Object.assign(Object.assign({}, options), { hoistStatic: false, nodeTransforms: [
              ssrTransformIf,
              ssrTransformFor,
              compilerDom.trackVForSlotScopes,
              compilerDom.transformExpression,
              ssrTransformSlotOutlet,
              ssrInjectFallthroughAttrs,
              ssrInjectCssVars,
              ssrTransformElement,
              ssrTransformComponent,
              compilerDom.trackSlotScopes,
              compilerDom.transformStyle,
              ...(options.nodeTransforms || []) // user transforms
          ], directiveTransforms: Object.assign({ 
              // reusing core v-bind
              bind: compilerDom.transformBind, 
              // model and show has dedicated SSR handling
              model: ssrTransformModel, show: ssrTransformShow, 
              // the following are ignored during SSR
              on: compilerDom.noopDirectiveTransform, cloak: compilerDom.noopDirectiveTransform, once: compilerDom.noopDirectiveTransform }, (options.directiveTransforms || {}) // user transforms
          ) }));
      // traverse the template AST and convert into SSR codegen AST
      // by replacing ast.codegenNode.
      ssrCodegenTransform(ast, options);
      return compilerDom.generate(ast, options);
  }
  
  exports.compile = compile;
  