Example #1
0
// BuildSource invokes the compiler starting at the given root source file path.
func BuildSource(rootSourceFilePath string, debug bool, vcsDevelopmentDirectories ...string) bool {
	// Disable logging unless the debug flag is on.
	if !debug {
		log.SetOutput(ioutil.Discard)
	}

	// Build a scope graph for the project. This will conduct parsing and type graph
	// construction on our behalf.
	log.Println("Starting build")
	scopeResult := scopegraph.ParseAndBuildScopeGraph(rootSourceFilePath, vcsDevelopmentDirectories, CORE_LIBRARY)

	outputWarnings(scopeResult.Warnings)
	if !scopeResult.Status {
		outputErrors(scopeResult.Errors)
		return false
	}

	// Generate the program's source.
	filename := path.Base(rootSourceFilePath) + ".js"
	mapname := filename + ".map"

	log.Println("Generating ES5")
	generated, sourceMap, err := es5.GenerateES5(scopeResult.Graph, mapname, "")
	if err != nil {
		panic(err)
	}

	marshalledMap, err := sourceMap.Build().Marshal()
	if err != nil {
		panic(err)
	}

	generated += "\n//# sourceMappingURL=" + mapname

	// Write the source and its map.
	filepath := path.Join(path.Dir(rootSourceFilePath), filename)
	mappath := path.Join(path.Dir(rootSourceFilePath), mapname)

	log.Printf("Writing generated source to %s\n", filepath)
	ioutil.WriteFile(filepath, []byte(generated), 0644)
	ioutil.WriteFile(mappath, marshalledMap, 0644)

	log.Println("Work completed")
	return true
}
Example #2
0
// Build performs the build of the source, writing the result to the response writer.
func (dt *developTransaction) Build(w http.ResponseWriter, r *http.Request) {
	// Build a scope graph for the project. This will conduct parsing and type graph
	// construction on our behalf.
	scopeResult := scopegraph.ParseAndBuildScopeGraph(dt.rootSourceFilePath,
		dt.vcsDevelopmentDirectories,
		builder.CORE_LIBRARY)

	if !scopeResult.Status {
		dt.sourceMap = sourcemap.NewSourceMap(dt.name+".develop.js", "source/")

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}

		for _, err := range scopeResult.Errors {
			dt.emitError(w, err)
		}

		dt.emitInfo(w, "Build failed")
		dt.closeGroup(w)
	} else {
		// Generate the program's source.
		generated, sourceMap, err := es5.GenerateES5(scopeResult.Graph, dt.name+".develop.js", "source/")
		if err != nil {
			panic(err)
		}

		dt.sourceMap = sourceMap

		fmt.Fprint(w, generated)
		dt.emitInfo(w, "Build completed successfully")
		dt.closeGroup(w)

		dt.offsetCount = len(strings.Split(string(generated), "\n"))

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}
	}

	fmt.Fprintf(w, "//# sourceMappingURL=/%s.develop.js.map\n", dt.name)
}
Example #3
0
func TestSourceMapping(t *testing.T) {
	for _, test := range sourceMappingTests {
		entrypointFile := "tests/sourcemapping/" + test.name + ".seru"

		if os.Getenv("FILTER") != "" && !strings.Contains(test.name, os.Getenv("FILTER")) {
			continue
		}

		// Parse and scope.
		fmt.Printf("Running mapping test %v...\n", test.name)
		scopeResult := scopegraph.ParseAndBuildScopeGraph(entrypointFile, []string{}, packageloader.Library{TESTLIB_PATH, false, ""})
		if !assert.True(t, scopeResult.Status, "Got error for ScopeGraph construction %v: %s", test.name, scopeResult.Errors) {
			continue
		}

		filename := path.Base(entrypointFile) + ".js"
		mapname := filename + ".map"

		// Generate the formatted ES5 code.
		generated, sourceMap, err := GenerateES5(scopeResult.Graph, mapname, "")
		if !assert.Nil(t, err, "Error when generating ES5 for mapping test %s", test.name) {
			continue
		}

		builtMap := sourceMap.Build()

		// Create a variant of the ES5 code, with inline comments to the original source.
		var buf bytes.Buffer

	outer:
		for lineNumber, line := range strings.Split(generated, "\n") {
			for colPosition, character := range line {
				mapping, hasMapping := builtMap.LookupMapping(lineNumber, colPosition)
				if hasMapping {
					buf.WriteString("/*#")
					sourcePath := mapping.SourcePath
					snippet, err := getSnippet(sourcePath, mapping.LineNumber, mapping.ColumnPosition)
					if !assert.Nil(t, err, "Error reading snippet from file %s", sourcePath) {
						break outer
					}

					buf.WriteString(snippet)
					buf.WriteString("#*/")
				}

				buf.WriteRune(character)
			}

			buf.WriteRune('\n')
		}

		source := buf.String()

		if os.Getenv("REGEN") == "true" {
			test.writeExpected(source)
		} else {
			// Compare the generated source to the expected.
			expectedSource := test.expected()
			assert.Equal(t, expectedSource, source, "Mapped mismatch on test %s\nExpected: %v\nActual: %v\n\n", test.name, expectedSource, source)
		}
	}
}
Example #4
0
func TestGenerator(t *testing.T) {
	for _, test := range generationTests {
		entrypointFile := "tests/" + test.input + "/" + test.entrypoint + ".seru"

		if os.Getenv("FILTER") != "" && !strings.Contains(test.name, os.Getenv("FILTER")) {
			continue
		}

		fmt.Printf("Running test %v...\n", test.name)

		result := scopegraph.ParseAndBuildScopeGraph(entrypointFile, []string{}, packageloader.Library{TESTLIB_PATH, false, ""})
		if !assert.True(t, result.Status, "Got error for ScopeGraph construction %v: %s", test.name, result.Errors) {
			continue
		}

		module, found := result.Graph.TypeGraph().LookupModule(compilercommon.InputSource(entrypointFile))
		if !assert.True(t, found, "Could not find entrypoint module %s for test: %s", entrypointFile, test.name) {
			continue
		}

		moduleMap := generateModules(result.Graph)
		builder, hasBuilder := moduleMap[module]
		if !assert.True(t, hasBuilder, "Could not find builder for module %s for test: %s", entrypointFile, test.name) {
			continue
		}

		buf := esbuilder.BuildSource(builder)
		source, err := escommon.FormatECMASource(buf.String())

		if !assert.Nil(t, err, "Could not format module source under test %v: %v", test.name, err) {
			continue
		}

		if os.Getenv("REGEN") == "true" {
			test.writeExpected(source)
		} else {
			// Compare the generated source to the expected.
			expectedSource := test.expected()
			assert.Equal(t, expectedSource, source, "Source mismatch on test %s\nExpected: %v\nActual: %v\n\n", test.name, expectedSource, source)

			if test.integrationTest != integrationTestNone {
				fullSource, _, err := GenerateES5(result.Graph, "", "")
				if !assert.Nil(t, err, "Error generating full source for test %s: %v", test.name, err) {
					continue
				}

				if os.Getenv("DEBUGLINE") != "" {
					lines := strings.Split(fullSource, "\n")
					lineNumber, _ := strconv.Atoi(os.Getenv("DEBUGLINE"))
					t.Errorf("Line %v: %v", lineNumber, lines[lineNumber-1])
					continue
				}

				vm := otto.New()
				vm.Set("debugprint", func(call otto.FunctionCall) otto.Value {
					t.Errorf("DEBUG: %v\n", call.Argument(0).String())
					return otto.Value{}
				})
				vm.Set("testprint", func(call otto.FunctionCall) otto.Value {
					t.Errorf("TEST: %v\n", call.Argument(0).String())
					return otto.Value{}
				})

				vm.Run(`this.debugprint = debugprint;
						this.testprint = testprint;
						
				function setTimeout(f, t) {
					f()
				}
				`)

				promiseFile, _ := os.Open("es6-promise.js")
				defer promiseFile.Close()

				promiseSource, _ := ioutil.ReadAll(promiseFile)
				promiseScript, cerr := vm.Compile("promise", promiseSource)
				if !assert.Nil(t, cerr, "Error compiling promise: %v", cerr) {
					continue
				}

				_, perr := vm.Run(promiseScript)
				if !assertNoOttoError(t, test.name, string(promiseSource), perr) {
					continue
				}

				generatedScript, cgerr := vm.Compile("generated", fullSource)
				if !assert.Nil(t, cgerr, "Error compiling generated code for test %v: %v", test.name, cgerr) {
					continue
				}

				_, verr := vm.Run(generatedScript)
				if !assertNoOttoError(t, test.name, fullSource, verr) {
					continue
				}

				if !assert.Nil(t, verr, "Error running full source for test %s: %v", test.name, verr) {
					continue
				}

				testCall := `
					$resolved = undefined;
					$rejected = undefined;

					this.boolValue = true;

					this.Serulian.then(function(g) {
						g.` + test.entrypoint + `.TEST().then(function(r) {
							$resolved = r.$wrapped;
						}).catch(function(err) {
							$rejected = err;
						});
					});
					
					if ($rejected) {
						throw $rejected;
					}

					$resolved`

				testScript, cterr := vm.Compile("test", testCall)
				if !assert.Nil(t, cterr, "Error compiling test call: %v", cterr) {
					continue
				}

				rresult, rerr := vm.Run(testScript)

				if test.integrationTest == integrationTestSuccessExpected {
					if !assertNoOttoError(t, test.name, testCall, rerr) {
						continue
					}

					if !assert.True(t, rresult.IsBoolean(), "Non-boolean result for running test case %s: %v", test.name, rresult) {
						continue
					}

					boolValue, _ := rresult.ToBoolean()
					if !assert.True(t, boolValue, "Non-true boolean result for running test case %s: %v", test.name, boolValue) {
						continue
					}
				} else {
					if !assert.Equal(t, test.expectedErrorMessage, rerr.Error(), "Error message mismatch for test case %v: %v", test.name, rerr) {
						continue
					}
				}
			}
		}
	}
}
Example #5
0
// buildAndRunTests builds the source found at the given path and then runs its tests via the runner.
func buildAndRunTests(filePath string, runner TestRunner) (bool, error) {
	log.Printf("Building %s...", filePath)

	filename := path.Base(filePath)

	scopeResult := scopegraph.ParseAndBuildScopeGraph(filePath,
		[]string{},
		builder.CORE_LIBRARY)

	if !scopeResult.Status {
		// TODO: better output
		return false, fmt.Errorf("Compilation errors for test %s: %v", filePath, scopeResult.Errors)
	}

	// Generate the source.
	generated, sourceMap, err := es5.GenerateES5(scopeResult.Graph, filename+".js", "")
	if err != nil {
		log.Fatal(err)
	}

	// Save the source (with an adjusted call), in a temporary directory.
	moduleName := filename[0 : len(filename)-len(parser.SERULIAN_FILE_EXTENSION)]
	adjusted := fmt.Sprintf(`
		%s

		window.Serulian.then(function(global) {
			global.%s.TEST().then(function(a) {
			}).catch(function(err) {
		    throw err;     
		  })
		})

		//# sourceMappingURL=/%s.js.map
	`, generated, moduleName, filename)

	dir, err := ioutil.TempDir("", "testing")
	if err != nil {
		log.Fatal(err)
	}

	// Clean up once complete.
	defer os.RemoveAll(dir)

	// Write the source and map into the directory.
	marshalled, err := sourceMap.Build().Marshal()
	if err != nil {
		log.Fatal(err)
	}

	err = ioutil.WriteFile(path.Join(dir, filename+".js"), []byte(adjusted), 0777)
	if err != nil {
		log.Fatal(err)
	}

	err = ioutil.WriteFile(path.Join(dir, filename+".js.map"), marshalled, 0777)
	if err != nil {
		log.Fatal(err)
	}

	// Call the runner with the test file.
	return runner.Run(path.Join(dir, filename+".js"))
}