Ejemplo n.º 1
0
  /**
   * Compiles this Soy file set into JS source code files and writes these JS files to disk.
   *
   * @param outputPathFormat The format string defining how to build the output file path
   *     corresponding to an input file path.
   * @param inputFilePathPrefix The prefix prepended to all input file paths (can be empty string).
   * @param jsSrcOptions The compilation options for the JS Src output target.
   * @param locales The list of locales. Can be an empty list if not applicable.
   * @param messageFilePathFormat The message file path format, or null if not applicable.
   * @throws SoySyntaxException If a syntax error is found.
   * @throws IOException If there is an error in opening/reading a message file or opening/writing
   *     an output JS file.
   */
  void compileToJsSrcFiles(
      String outputPathFormat,
      String inputFilePathPrefix,
      SoyJsSrcOptions jsSrcOptions,
      List<String> locales,
      @Nullable String messageFilePathFormat)
      throws SoySyntaxException, IOException {

    boolean doEnforceSyntaxVersionV2 = !jsSrcOptions.shouldAllowDeprecatedSyntax();
    SoyFileSetNode soyTree =
        (new SoyFileSetParser(soyFileSuppliers))
            .setDoEnforceSyntaxVersionV2(doEnforceSyntaxVersionV2)
            .parse();
    runMiddleendPasses(soyTree, doEnforceSyntaxVersionV2);

    if (locales.size() == 0) {
      // Not generating localized JS.
      jsSrcMainProvider
          .get()
          .genJsFiles(soyTree, jsSrcOptions, null, null, outputPathFormat, inputFilePathPrefix);

    } else {
      // Generating localized JS.
      for (String locale : locales) {

        SoyFileSetNode soyTreeClone = soyTree.clone();

        String msgFilePath =
            JsSrcUtils.buildFilePath(messageFilePathFormat, locale, null, inputFilePathPrefix);

        SoyMsgBundle msgBundle =
            msgBundleHandlerProvider.get().createFromFile(new File(msgFilePath));
        if (msgBundle.getLocaleString() == null) {
          // TODO: Remove this check (but make sure no projects depend on this behavior).
          // There was an error reading the message file. We continue processing only if the locale
          // begins with "en", because falling back to the Soy source will proably be fine.
          if (!locale.startsWith("en")) {
            throw new IOException("Error opening or reading message file " + msgFilePath);
          }
        }

        jsSrcMainProvider
            .get()
            .genJsFiles(
                soyTreeClone,
                jsSrcOptions,
                locale,
                msgBundle,
                outputPathFormat,
                inputFilePathPrefix);
      }
    }
  }
  /**
   * Returns the contextually rewritten source.
   *
   * <p>The Soy tree may have multiple files, but only the source code for the first is returned.
   */
  private void assertInjected(String expectedOutput, String input) throws SoyAutoescapeException {
    SoyFileSetNode soyTree = parseAndInjectIntoScriptTags(input, " INJE='CTED'");

    StringBuilder src = new StringBuilder();
    src.append(soyTree.getChild(0).toSourceString());

    String output = src.toString().trim();
    if (output.startsWith("{namespace ns")) {
      output = output.substring(output.indexOf('}') + 1).trim();
    }

    assertThat(output).isEqualTo(expectedOutput);
  }
  public void testFindCalleesNotInFile() {

    String testFileContent =
        ""
            + "{namespace boo.foo autoescape=\"deprecated-noncontextual\"}\n"
            + "\n"
            + "/** Test template 1. */\n"
            + "{template .goo}\n"
            + "  {call .goo data=\"all\" /}\n"
            + "  {call .moo data=\"all\" /}\n"
            + "  {call boo.woo.hoo data=\"all\" /}\n"
            + // not defined in this file
            "{/template}\n"
            + "\n"
            + "/** Test template 2. */\n"
            + "{template .moo}\n"
            + "  {for $i in range(8)}\n"
            + "    {call boo.foo.goo data=\"all\" /}\n"
            + "    {call .too data=\"all\" /}\n"
            + // not defined in this file
            "    {call .goo}"
            + "      {param a}{call .moo /}{/param}"
            + "      {param b}{call .zoo /}{/param}"
            + // not defined in this file
            "    {/call}"
            + "  {/for}\n"
            + "{/template}\n"
            + "\n"
            + "/** Test template 3. */\n"
            + "{deltemplate booHoo}\n"
            + "  {call .goo data=\"all\" /}\n"
            + "  {call .moo data=\"all\" /}\n"
            + "  {call boo.hoo.roo data=\"all\" /}\n"
            + // not defined in this file
            "{/deltemplate}\n";

    ErrorReporter boom = ExplodingErrorReporter.get();
    SoyFileSetNode soyTree =
        SoyFileSetParserBuilder.forFileContents(testFileContent).errorReporter(boom).parse();
    SoyFileNode soyFile = soyTree.getChild(0);

    Set<String> calleesNotInFile = new FindCalleesNotInFileVisitor(boom).exec(soyFile);
    assertThat(calleesNotInFile).doesNotContain("boo.foo.goo");
    assertThat(calleesNotInFile).doesNotContain("boo.foo.moo");
    assertThat(calleesNotInFile).contains("boo.woo.hoo");
    assertThat(calleesNotInFile).contains("boo.foo.too");
    assertThat(calleesNotInFile).contains("boo.foo.zoo");
    assertThat(calleesNotInFile).contains("boo.hoo.roo");
  }
  private SoyFileSetNode parseAndInjectIntoScriptTags(String input, String toInject) {
    String namespace = "{namespace ns autoescape=\"deprecated-contextual\"}\n\n";
    ErrorReporter boom = ExplodingErrorReporter.get();
    SoyFileSetNode soyTree =
        SoyFileSetParserBuilder.forFileContents(namespace + input).errorReporter(boom).parse();

    ContextualAutoescaper contextualAutoescaper =
        new ContextualAutoescaper(SOY_PRINT_DIRECTIVES, boom);
    List<TemplateNode> extras = contextualAutoescaper.rewrite(soyTree);

    SoyFileNode file = soyTree.getChild(soyTree.numChildren() - 1);
    file.addChildren(file.numChildren(), extras);

    insertTextAtEndOfScriptOpenTag(contextualAutoescaper.getSlicedRawTextNodes(), toInject);
    return soyTree;
  }
Ejemplo n.º 5
0
 private void doContextualEscaping(SoyFileSetNode soyTree) throws SoySyntaxException {
   List<TemplateNode> extraTemplates = contextualAutoescaper.rewrite(soyTree);
   // TODO: Run the redundant template remover here and rename after CL 16642341 is in.
   if (!extraTemplates.isEmpty()) {
     // TODO: pull out somewhere else.  Ideally do the merge as part of the redundant template
     // removal.
     Map<String, SoyFileNode> containingFile = Maps.newHashMap();
     for (SoyFileNode fileNode : soyTree.getChildren()) {
       for (TemplateNode templateNode : fileNode.getChildren()) {
         String name =
             templateNode instanceof TemplateDelegateNode
                 ? ((TemplateDelegateNode) templateNode).getDelTemplateName()
                 : templateNode.getTemplateName();
         containingFile.put(DerivedTemplateUtils.getBaseName(name), fileNode);
       }
     }
     for (TemplateNode extraTemplate : extraTemplates) {
       String name =
           extraTemplate instanceof TemplateDelegateNode
               ? ((TemplateDelegateNode) extraTemplate).getDelTemplateName()
               : extraTemplate.getTemplateName();
       containingFile.get(DerivedTemplateUtils.getBaseName(name)).addChild(extraTemplate);
     }
   }
 }
  /**
   * Generates Incremental DOM JS source files given a Soy parse tree, an options object, an
   * optional bundle of translated messages, and information on where to put the output files.
   *
   * @param soyTree The Soy parse tree to generate JS source code for.
   * @param jsSrcOptions The compilation options relevant to this backend.
   * @param outputPathFormat The format string defining how to build the output file path
   *     corresponding to an input file path.
   * @throws SoySyntaxException If a syntax error is found.
   * @throws IOException If there is an error in opening/writing an output JS file.
   */
  public void genJsFiles(
      SoyFileSetNode soyTree, SoyJsSrcOptions jsSrcOptions, String outputPathFormat)
      throws SoySyntaxException, IOException {

    List<String> jsFileContents = genJsSrc(soyTree, jsSrcOptions);

    ImmutableList<SoyFileNode> srcsToCompile =
        ImmutableList.copyOf(
            Iterables.filter(soyTree.getChildren(), SoyFileNode.MATCH_SRC_FILENODE));

    if (srcsToCompile.size() != jsFileContents.size()) {
      throw new AssertionError(
          String.format(
              "Expected to generate %d code chunk(s), got %d",
              srcsToCompile.size(), jsFileContents.size()));
    }

    Multimap<String, Integer> outputs =
        MainEntryPointUtils.mapOutputsToSrcs(
            null /* locale */, outputPathFormat, "" /* inputPathsPrefix */, srcsToCompile);

    for (String outputFilePath : outputs.keySet()) {
      Writer out = Files.newWriter(new File(outputFilePath), UTF_8);
      try {
        boolean isFirst = true;
        for (int inputFileIndex : outputs.get(outputFilePath)) {
          if (isFirst) {
            isFirst = false;
          } else {
            // Concatenating JS files is not safe unless we know that the last statement from one
            // couldn't combine with the isFirst statement of the next.  Inserting a semicolon will
            // prevent this from happening.
            out.write("\n;\n");
          }
          out.write(jsFileContents.get(inputFileIndex));
        }
      } finally {
        out.close();
      }
    }
  }
  /** Visits a {@link SoyFileNode}, getting its id generator. */
  @Override
  protected void visitSoyFileSetNode(SoyFileSetNode node) {
    idGen = node.getNodeIdGenerator();

    visitChildren(node);
  }